The *Full* Cubox-i series
Subsystems (40)
PATCH 152/222 imx-drm: ipu-dc: wait for DC_FC_1 / DP_SF_END interrupt
In reply to Russell King - ARM LinuxFrom: Philipp Zabel <[email protected]>
To: linux-arm-kernel at lists.infradead.org
Wait for the DC Frame Complete or DP Sync Flow End interrupts before disabling DC channels.
--- drivers/staging/imx-drm/ipu-v3/ipu-dc.c | 71 +++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 21 deletions(-)
drivers/staging/imx-drm/ipu-v3/ipu-dc.c +50 -21
@@ -18,6 +18,7 @@#include <linux/types.h> #include <linux/errno.h> #include <linux/delay.h> +#include <linux/interrupt.h> #include <linux/io.h> #include "../imx-drm.h"
@@ -111,6 +112,9 @@ struct ipu_dc_priv {struct device *dev;struct ipu_dc channels[IPU_DC_NUM_CHANNELS ];struct mutex mutex; +struct completion comp; +int dc_irq; +int dp_irq; };static void dc_link_event (struct ipu_dc *dc,int event,int addr,int priority)
@@ -242,38 +246,46 @@ void ipu_dc_enable_channel(struct ipu_dc *dc) }EXPORT_SYMBOL_GPL (ipu_dc_enable_channel); +static irqreturn_t dc_irq_handler (int irq,void *dev_id) +{ +struct ipu_dc *dc = dev_id; +u32 reg; + + reg =readl (dc->base +DC_WR_CH_CONF ); + reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK ; +writel (reg, dc->base +DC_WR_CH_CONF ); + +/* The Freescale BSP kernel clears DIx_COUNTER_RELEASE here */ + +complete (&dc->priv->comp); +return IRQ_HANDLED ; +} +void ipu_dc_disable_channel (struct ipu_dc *dc) {struct ipu_dc_priv *priv = dc->priv; +int irq, ret;u32 val; -int irq =0 , timeout =50 ; +/* TODO: Handle MEM_FG_SYNC differently from MEM_BG_SYNC */ if (dc->chno ==1 ) - irq =IPU_IRQ_DC_FC_1 ; + irq = priv->dc_irq;else if (dc->chno ==5 ) - irq =IPU_IRQ_DP_SF_END ; + irq = priv->dp_irq;else return ; -/* should wait for the interrupt here */ -mdelay (50 ); +init_completion (&priv->comp); +enable_irq (irq); + ret =wait_for_completion_timeout (&priv->comp,msecs_to_jiffies (50 )); +disable_irq (irq); +if (ret <=0 ) { +dev_warn (priv->dev,"DC stop timeout after 50 ms\n" ); -if (dc->di ==0 ) - val =0x00000002 ; -else - val =0x00000020 ; - -/* Wait for DC triple buffer to empty */ -while ((readl (priv->dc_reg +DC_STAT ) & val) != val) { -usleep_range (2000 ,20000 ); - timeout -=2 ; -if (timeout <=0 ) -break ; + val =readl (dc->base +DC_WR_CH_CONF ); + val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK ; +writel (val, dc->base +DC_WR_CH_CONF ); } - - val =readl (dc->base +DC_WR_CH_CONF ); - val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK ; -writel (val, dc->base +DC_WR_CH_CONF ); }EXPORT_SYMBOL_GPL (ipu_dc_disable_channel);
@@ -343,7 +355,7 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,struct ipu_dc_priv *priv;static int channel_offsets[] = {0 ,0x1c ,0x38 ,0x54 ,0x58 ,0x5c ,0x78 ,0 ,0x94 ,0xb4 }; -int i; +int i, ret; priv =devm_kzalloc (dev,sizeof (*priv),GFP_KERNEL );if (!priv)
@@ -364,6 +376,23 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, priv->channels[i].base = priv->dc_reg + channel_offsets[i]; } + priv->dc_irq =ipu_map_irq (ipu,IPU_IRQ_DC_FC_1 ); +if (!priv->dc_irq) +return -EINVAL ; + ret =devm_request_irq (dev, priv->dc_irq, dc_irq_handler,0 ,NULL , + &priv->channels[1 ]); +if (ret <0 ) +return ret; +disable_irq (priv->dc_irq); + priv->dp_irq =ipu_map_irq (ipu,IPU_IRQ_DP_SF_END ); +if (!priv->dp_irq) +return -EINVAL ; + ret =devm_request_irq (dev, priv->dp_irq, dc_irq_handler,0 ,NULL , + &priv->channels[5 ]); +if (ret <0 ) +return ret; +disable_irq (priv->dp_irq); +writel (DC_WR_CH_CONF_WORD_SIZE_24 |DC_WR_CH_CONF_DISP_ID_PARALLEL (1 ) |DC_WR_CH_CONF_PROG_DI_ID , priv->channels[1 ].base +DC_WR_CH_CONF );
Signature · 1 line
1.8.3.1
PATCH 153/222 imx-drm: ipu-dp: split disabling the DP foreground channel from disabling the DP module
In reply to Russell King - ARM LinuxFrom: Philipp Zabel <[email protected]>
To: linux-arm-kernel at lists.infradead.org
The former has to be done before disabling the DMFC, the latter has to be done afterwards. Otherwise the DMFC FIFOs never get cleared properly.
--- drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h | 2 + drivers/staging/imx-drm/ipu-v3/ipu-dp.c | 68 +++++++++++++++++++---------- drivers/staging/imx-drm/ipuv3-plane.c | 4 ++ 3 files changed, 51 insertions(+), 23 deletions(-)
drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h +2 -0
@@ -153,8 +153,10 @@ void ipu_dmfc_put(struct dmfc_channel *dmfc);struct ipu_dp *ipu_dp_get (struct ipu_soc *ipu,unsigned int flow);void ipu_dp_put (struct ipu_dp *); +int ipu_dp_enable (struct ipu_soc *ipu);int ipu_dp_enable_channel (struct ipu_dp *dp);void ipu_dp_disable_channel (struct ipu_dp *dp); +void ipu_dp_disable (struct ipu_soc *ipu);int ipu_dp_setup_channel (struct ipu_dp *dp,enum ipu_color_space in,enum ipu_color_space out);int ipu_dp_set_window_pos (struct ipu_dp *,u16 x_pos,u16 y_pos);
drivers/staging/imx-drm/ipu-v3/ipu-dp.c +45 -23
102 lines not on this page · raw message
drivers/staging/imx-drm/ipuv3-plane.c +4 -0
@@ -239,6 +239,8 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane)void ipu_plane_enable (struct ipu_plane *ipu_plane) { +if (ipu_plane->dp) +ipu_dp_enable (ipu_plane->ipu);ipu_dmfc_enable_channel (ipu_plane->dmfc);ipu_idmac_enable_channel (ipu_plane->ipu_ch);if (ipu_plane->dp)
@@ -257,6 +259,8 @@ void ipu_plane_disable(struct ipu_plane *ipu_plane)ipu_dp_disable_channel (ipu_plane->dp);ipu_idmac_disable_channel (ipu_plane->ipu_ch);ipu_dmfc_disable_channel (ipu_plane->dmfc); +if (ipu_plane->dp) +ipu_dp_disable (ipu_plane->ipu); }static void ipu_plane_dpms (struct ipu_plane *ipu_plane,int mode)
Signature · 1 line
1.8.3.1
PATCH 154/222 imx-drm: imx-dp: when disabling the DP foreground channel, wait until the DP background channel is finished before disabling the IDMAC channel
In reply to Russell King - ARM LinuxFrom: Philipp Zabel <[email protected]>
To: linux-arm-kernel at lists.infradead.org
--- drivers/staging/imx-drm/ipu-v3/ipu-dp.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/staging/imx-drm/ipu-v3/ipu-dp.c +3 -0
@@ -277,6 +277,9 @@ void ipu_dp_disable_channel(struct ipu_dp *dp)writel (0 , flow->base +DP_FG_POS );ipu_srm_dp_sync_update (priv->ipu); +if (ipu_idmac_channel_busy (priv->ipu,IPUV3_CHANNEL_MEM_BG_SYNC )) +ipu_wait_interrupt (priv->ipu,IPU_IRQ_DP_SF_END ,50 ); +mutex_unlock (&priv->mutex); }EXPORT_SYMBOL_GPL (ipu_dp_disable_channel);
Signature · 1 line
1.8.3.1
PATCH 155/222 imx-drm: ipuv3-crtc: change display enable/disable order
In reply to Russell King - ARM LinuxFrom: Philipp Zabel <[email protected]>
To: linux-arm-kernel at lists.infradead.org
Now that ipu_dc_disable_channel correctly waits for the channel to finish, we can reorder the enable/disable order to first stop the DC and DI and only then disable the IDMAC. Enabling is done the other way around: IDMAC first, then DC, then DI.
This avoids an issue where sometimes the channel would not correctly start, leading to non-working LVDS displays.
--- drivers/staging/imx-drm/ipuv3-crtc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/staging/imx-drm/ipuv3-crtc.c +7 -3
@@ -63,9 +63,11 @@ static void ipu_fb_enable(struct ipu_crtc *ipu_crtc)if (ipu_crtc->enabled)return ; -ipu_di_enable (ipu_crtc->di); -ipu_dc_enable_channel (ipu_crtc->dc); +/* TODO: Enable DC module here, right now it is never disabled */ ipu_plane_enable (ipu_crtc->plane[0 ]); +/* Start DC channel and DI after IDMAC */ +ipu_dc_enable_channel (ipu_crtc->dc); +ipu_di_enable (ipu_crtc->di); ipu_crtc->enabled =1 ; }
@@ -75,9 +77,11 @@ static void ipu_fb_disable(struct ipu_crtc *ipu_crtc)if (!ipu_crtc->enabled)return ; -ipu_plane_disable (ipu_crtc->plane[0 ]); +/* Stop DC channel and DI before IDMAC */ ipu_dc_disable_channel (ipu_crtc->dc);ipu_di_disable (ipu_crtc->di); +ipu_plane_disable (ipu_crtc->plane[0 ]); +/* TODO: Disable DC module here */ ipu_crtc->enabled =0 ; }
Signature · 1 line
1.8.3.1
PATCH 156/222 imx-drm: ipu-dc: disable DC module when not in use
In reply to Russell King - ARM LinuxFrom: Philipp Zabel <[email protected]>
To: linux-arm-kernel at lists.infradead.org
--- drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h | 2 ++ drivers/staging/imx-drm/ipu-v3/ipu-dc.c | 14 ++++++++++++-- drivers/staging/imx-drm/ipuv3-crtc.c | 8 ++++++-- 3 files changed, 20 insertions(+), 4 deletions(-)
drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h +2 -0
@@ -115,8 +115,10 @@ struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel);void ipu_dc_put (struct ipu_dc *dc);int ipu_dc_init_sync (struct ipu_dc *dc,struct ipu_di *di,bool interlaced,u32 pixel_fmt,u32 width); +void ipu_dc_enable (struct ipu_soc *ipu);void ipu_dc_enable_channel (struct ipu_dc *dc);void ipu_dc_disable_channel (struct ipu_dc *dc); +void ipu_dc_disable (struct ipu_soc *ipu);/* * IPU Display Interface (di) functions
drivers/staging/imx-drm/ipu-v3/ipu-dc.c +12 -2
@@ -227,12 +227,16 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,writel (0x0 , dc->base +DC_WR_CH_ADDR );writel (width, priv->dc_reg +DC_DISP_CONF2 (dc->di)); -ipu_module_enable (priv->ipu,IPU_CONF_DC_EN ); -return 0 ; }EXPORT_SYMBOL_GPL (ipu_dc_init_sync); +void ipu_dc_enable (struct ipu_soc *ipu) +{ +ipu_module_enable (ipu,IPU_CONF_DC_EN ); +} +EXPORT_SYMBOL_GPL (ipu_dc_enable); +void ipu_dc_enable_channel (struct ipu_dc *dc) {int di;
@@ -289,6 +293,12 @@ void ipu_dc_disable_channel(struct ipu_dc *dc) }EXPORT_SYMBOL_GPL (ipu_dc_disable_channel); +void ipu_dc_disable (struct ipu_soc *ipu) +{ +ipu_module_disable (ipu,IPU_CONF_DC_EN ); +} +EXPORT_SYMBOL_GPL (ipu_dc_disable); +static void ipu_dc_map_config (struct ipu_dc_priv *priv,enum ipu_dc_map map,int byte_num,int offset,int mask) {
drivers/staging/imx-drm/ipuv3-crtc.c +6 -2
@@ -60,10 +60,12 @@ struct ipu_crtc {static void ipu_fb_enable (struct ipu_crtc *ipu_crtc) { +struct ipu_soc *ipu =dev_get_drvdata (ipu_crtc->dev->parent); +if (ipu_crtc->enabled)return ; -/* TODO: Enable DC module here, right now it is never disabled */ +ipu_dc_enable (ipu);ipu_plane_enable (ipu_crtc->plane[0 ]);/* Start DC channel and DI after IDMAC */ ipu_dc_enable_channel (ipu_crtc->dc);
@@ -74,6 +76,8 @@ static void ipu_fb_enable(struct ipu_crtc *ipu_crtc)static void ipu_fb_disable (struct ipu_crtc *ipu_crtc) { +struct ipu_soc *ipu =dev_get_drvdata (ipu_crtc->dev->parent); +if (!ipu_crtc->enabled)return ;
@@ -81,7 +85,7 @@ static void ipu_fb_disable(struct ipu_crtc *ipu_crtc)ipu_dc_disable_channel (ipu_crtc->dc);ipu_di_disable (ipu_crtc->di);ipu_plane_disable (ipu_crtc->plane[0 ]); -/* TODO: Disable DC module here */ +ipu_dc_disable (ipu); ipu_crtc->enabled =0 ; }
Signature · 1 line
1.8.3.1
PATCH 157/222 imx-drm: imx-hdmi: fix hdmi hotplug detection initial state
In reply to Russell King - ARM LinuxThe initial state at boot is assumed to be disconnected, and we hope to receive an interrupt to update the status. Let's be more explicit about the current state - reading the PHY status register tells us the current level of the hotplug signal, which we can report back in the _detect() method.
--- drivers/staging/imx-drm/imx-hdmi.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
drivers/staging/imx-drm/imx-hdmi.c +3 -6
@@ -120,8 +120,6 @@ struct imx_hdmi {struct clk *isfr_clk;struct clk *iahb_clk; -enum drm_connector_status connector_status; -struct hdmi_data_info hdmi_data;int vic;
@@ -1382,7 +1380,9 @@ static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector { struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi, connector); -return hdmi->connector_status; + +return hdmi_readb (hdmi,HDMI_PHY_STAT0 ) &HDMI_PHY_HPD ? + connector_status_connected : connector_status_disconnected; }static int imx_hdmi_connector_get_modes (struct drm_connector *connector)
@@ -1524,7 +1524,6 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)hdmi_modb (hdmi,0 ,HDMI_PHY_HPD ,HDMI_PHY_POL0 ); - hdmi->connector_status = connector_status_connected;imx_hdmi_poweron (hdmi); }else {dev_dbg (hdmi->dev,"EVENT=plugout\n" );
@@ -1532,7 +1531,6 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)hdmi_modb (hdmi,HDMI_PHY_HPD ,HDMI_PHY_HPD ,HDMI_PHY_POL0 ); - hdmi->connector_status = connector_status_disconnected;imx_hdmi_poweroff (hdmi); }drm_helper_hpd_irq_event (hdmi->connector.dev);
@@ -1606,7 +1604,6 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)return -ENOMEM ; hdmi->dev = dev; - hdmi->connector_status = connector_status_disconnected; hdmi->sample_rate =48000 ; hdmi->ratio =100 ;
Signature · 1 line
1.8.3.1
PATCH 158/222 dw-hdmi-audio: add audio driver
In reply to Russell King - ARM LinuxAdd ALSA based HDMI audio driver for imx-hdmi. The imx-hdmi is a Synopsis DesignWare module, so let's name it after that. The only buffer format supported is its own special IEC958 based format, which is not compatible with any ALSA format. To avoid doing too much data manipulation within the driver, we support only ALSAs IEC958 LE, and 24-bit PCM formats for 2 to 6 channels.
This allows us to modify the buffer in place as each period is passed for DMA without needing a separate buffer.
A more desirable solution would be to have this conversion in userspace, but ALSA does not appear to allow such transformations outside of libasound itself.
--- drivers/staging/imx-drm/Kconfig | 8 + drivers/staging/imx-drm/Makefile | 1 + drivers/staging/imx-drm/dw-hdmi-audio.c | 547 ++++++++++++++++++++++++++++++++ drivers/staging/imx-drm/dw-hdmi-audio.h | 14 + drivers/staging/imx-drm/imx-hdmi.c | 29 ++ 5 files changed, 599 insertions(+) create mode 100644 drivers/staging/imx-drm/dw-hdmi-audio.c create mode 100644 drivers/staging/imx-drm/dw-hdmi-audio.h
drivers/staging/imx-drm/Kconfig +8 -0
@@ -61,3 +61,11 @@ config DRM_IMX_HDMI depends on DRM_IMX help Choose this if you want to use HDMI on i.MX6. + +config DRM_DW_HDMI_AUDIO + tristate "Synopsis Designware Audio interface" + depends on DRM_IMX_HDMI != n + help + Support the Audio interface which is part of the Synopsis + Designware HDMI block. This is used in conjunction with + the i.MX HDMI driver.
drivers/staging/imx-drm/Makefile +1 -0
@@ -11,3 +11,4 @@ obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/ imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o +obj-$(CONFIG_DRM_DW_HDMI_AUDIO) += dw-hdmi-audio.o
drivers/staging/imx-drm/dw-hdmi-audio.c new file +547 -0
547 lines not on this page · raw message
drivers/staging/imx-drm/dw-hdmi-audio.h new file +14 -0
@@ -0,0 +1,14 @@ +#ifndef DW_HDMI_AUDIO_H +#define DW_HDMI_AUDIO_H + +struct imx_hdmi ; + +struct dw_hdmi_audio_data { +phys_addr_t phys; +void __iomem *base; +int irq; +struct imx_hdmi *hdmi; +void (*set_sample_rate)(struct imx_hdmi *,unsigned ); +}; + +#endif
drivers/staging/imx-drm/imx-hdmi.c +29 -0
@@ -28,6 +28,7 @@#include <drm/drm_edid.h> #include <drm/drm_encoder_slave.h> +#include "dw-hdmi-audio.h" #include "ipu-v3/imx-ipu-v3.h" #include "imx-hdmi.h" #include "imx-drm.h"
@@ -115,6 +116,7 @@ struct imx_hdmi {struct drm_connector connector;struct drm_encoder encoder; +struct platform_device *audio;enum imx_hdmi_devtype dev_type;struct device *dev;struct clk *isfr_clk;
@@ -360,6 +362,12 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)hdmi_set_clk_regenerator (hdmi, hdmi->hdmi_data.video_mode.mpixelclock); } +static void imx_hdmi_set_sample_rate (struct imx_hdmi *hdmi,unsigned rate) +{ + hdmi->sample_rate = rate; +hdmi_set_clk_regenerator (hdmi, hdmi->hdmi_data.video_mode.mpixelclock); +} +/* * this submodule is responsible for the video data synchronization. * for example, for RGB 4:4:4 input, the data map is defined as
@@ -1590,11 +1598,13 @@ MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);static int imx_hdmi_bind (struct device *dev,struct device *master,void *data) {struct platform_device *pdev =to_platform_device (dev); +struct platform_device_info pdevinfo;const struct of_device_id *of_id =of_match_device (imx_hdmi_dt_ids, dev);struct drm_device *drm = data;struct device_node *np = dev->of_node;struct device_node *ddc_node; +struct dw_hdmi_audio_data audio;struct imx_hdmi *hdmi;struct resource *iores;int ret, irq;
@@ -1708,6 +1718,22 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)/* Unmute interrupts */ hdmi_writeb (hdmi, ~HDMI_IH_PHY_STAT0_HPD ,HDMI_IH_MUTE_PHY_STAT0 ); +memset (&pdevinfo,0 ,sizeof (pdevinfo)); + pdevinfo.parent = dev; + pdevinfo.id =PLATFORM_DEVID_AUTO ; + + audio.phys = iores->start; + audio.base = hdmi->regs; + audio.irq = irq; + audio.hdmi = hdmi; + audio.set_sample_rate = imx_hdmi_set_sample_rate; + + pdevinfo.name ="dw-hdmi-audio" ; + pdevinfo.data = &audio; + pdevinfo.size_data =sizeof (audio); + pdevinfo.dma_mask =DMA_BIT_MASK (32 ); + hdmi->audio =platform_device_register_full (&pdevinfo); +dev_set_drvdata (dev, hdmi);return 0 ;
@@ -1725,6 +1751,9 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master, {struct imx_hdmi *hdmi =dev_get_drvdata (dev); +if (!IS_ERR (hdmi->audio)) +platform_device_unregister (hdmi->audio); +/* Disable all interrupts */ hdmi_writeb (hdmi, ~0 ,HDMI_IH_MUTE_PHY_STAT0 );
Signature · 1 line
1.8.3.1
PATCH 159/222 dw-hdmi-audio: better hardware position tracking
In reply to Russell King - ARM Linux--- drivers/staging/imx-drm/dw-hdmi-audio.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/staging/imx-drm/dw-hdmi-audio.c +6 -4
@@ -238,6 +238,11 @@ static void dw_hdmi_start_dma(struct snd_dw_hdmi *dw)writeb_relaxed ((u8 )~HDMI_AHB_DMA_MASK_DONE , base +HDMI_AHB_DMA_MASK );writeb (HDMI_AHB_DMA_START_START , base +HDMI_AHB_DMA_START ); + + offset += period; +if (offset >= dw->buf_size) + offset =0 ; + dw->buf_offset = offset; }static void dw_hdmi_stop_dma (struct snd_dw_hdmi *dw)
@@ -263,10 +268,6 @@ static irqreturn_t snd_dw_hdmi_irq(int irq, void *data) substream = dw->substream;if (stat &HDMI_IH_AHBDMAAUD_STAT0_DONE && substream) { - dw->buf_offset += dw->buf_period; -if (dw->buf_offset >= dw->buf_size) - dw->buf_offset =0 ; -snd_pcm_period_elapsed (substream);if (dw->substream)dw_hdmi_start_dma (dw);
@@ -427,6 +428,7 @@ static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd) dw->buf_offset =0 ; dw->substream = substream;dw_hdmi_start_dma (dw); + substream->runtime->delay = substream->runtime->period_size;break ;case SNDRV_PCM_TRIGGER_STOP :
Signature · 1 line
1.8.3.1
PATCH 160/222 dw-hdmi-audio: parse ELD from HDMI driver
In reply to Russell King - ARM LinuxParse the ELD (EDID like data) stored from the HDMI driver to restrict the sample rates and channels which are available to ALSA. This causes the ALSA device to reflect the capabilities of the overall audio path, not just what is supported at the HDMI source interface level.
--- drivers/staging/imx-drm/dw-hdmi-audio.c | 51 +++++++++++++++++++++++++++++++++ drivers/staging/imx-drm/dw-hdmi-audio.h | 1 + drivers/staging/imx-drm/imx-hdmi.c | 3 ++ 3 files changed, 55 insertions(+)
drivers/staging/imx-drm/dw-hdmi-audio.c +51 -0
@@ -300,6 +300,56 @@ static struct snd_pcm_hardware dw_hdmi_hw = { .fifo_size = 0, }; +static unsigned rates_mask[] = { +SNDRV_PCM_RATE_32000 , +SNDRV_PCM_RATE_44100 , +SNDRV_PCM_RATE_48000 , +SNDRV_PCM_RATE_88200 , +SNDRV_PCM_RATE_96000 , +SNDRV_PCM_RATE_176400 , +SNDRV_PCM_RATE_192000 , +}; + +static void dw_hdmi_parse_eld (struct snd_dw_hdmi *dw, +struct snd_pcm_runtime *runtime) +{ +u8 *sad, *eld = dw->data.eld; +unsigned eld_ver, mnl, sad_count, rates, rate_mask, i; +unsigned max_channels; + + eld_ver = eld[0 ] >>3 ; +if (eld_ver !=2 && eld_ver !=31 ) +return ; + + mnl = eld[4 ] &0x1f ; +if (mnl >16 ) +return ; + + sad_count = eld[5 ] >>4 ; + sad = eld +20 + mnl; + +/* Start from the basic audio settings */ + max_channels =2 ; + rates =7 ; +while (sad_count >0 ) { +switch (sad[0 ] &0x78 ) { +case 0x08 :/* PCM */ + max_channels =max (max_channels, (sad[0 ] &7 ) +1u ); + rates |= sad[1 ]; +break ; + } + sad +=3 ; + sad_count -=1 ; + } + +for (rate_mask = i =0 ; i <ARRAY_SIZE (rates_mask); i++) +if (rates &1 << i) + rate_mask |= rates_mask[i]; + + runtime->hw.rates &= rate_mask; + runtime->hw.channels_max =min (runtime->hw.channels_max, max_channels); +} +static int dw_hdmi_open (struct snd_pcm_substream *substream) {struct snd_pcm_runtime *runtime = substream->runtime;
@@ -330,6 +380,7 @@ static int dw_hdmi_open(struct snd_pcm_substream *substream) base + HDMI_IH_MUTE_AHBDMAAUD_STAT0); runtime->hw = dw_hdmi_hw; +dw_hdmi_parse_eld (dw, runtime);snd_pcm_limit_hw_rates (runtime);return 0 ;
drivers/staging/imx-drm/dw-hdmi-audio.h +1 -0
@@ -8,6 +8,7 @@ struct dw_hdmi_audio_data {void __iomem *base;int irq;struct imx_hdmi *hdmi; +u8 *eld;void (*set_sample_rate)(struct imx_hdmi *,unsigned ); };
drivers/staging/imx-drm/imx-hdmi.c +3 -0
@@ -1410,6 +1410,8 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector)drm_mode_connector_update_edid_property (connector, edid); ret =drm_add_edid_modes (connector, edid); +/* Store the ELD */ +drm_edid_to_eld (connector, edid);kfree (edid); }else {dev_dbg (hdmi->dev,"failed to get edid\n" );
@@ -1726,6 +1728,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) audio.base = hdmi->regs; audio.irq = irq; audio.hdmi = hdmi; + audio.eld = hdmi->connector.eld; audio.set_sample_rate = imx_hdmi_set_sample_rate; pdevinfo.name ="dw-hdmi-audio" ;
Signature · 1 line
1.8.3.1
PATCH 161/222 dw-hdmi-audio: try to fix burbling audio
In reply to Russell King - ARM Linux--- drivers/staging/imx-drm/dw-hdmi-audio.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/staging/imx-drm/dw-hdmi-audio.c +8 -0
@@ -61,6 +61,7 @@ enum {HDMI_REVISION_ID =0x0001 ,HDMI_IH_AHBDMAAUD_STAT0 =0x0109 ,HDMI_IH_MUTE_AHBDMAAUD_STAT0 =0x0189 , +HDMI_AUD_N1 =0x3200 ,HDMI_AHB_DMA_CONF0 =0x3600 ,HDMI_AHB_DMA_START =0x3601 , HDMI_AHB_DMA_STOP = 0x3602,
@@ -479,6 +480,13 @@ static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd) dw->buf_offset =0 ; dw->substream = substream;dw_hdmi_start_dma (dw); +if (dw->revision ==0x0a ) { +void __iomem *base = dw->data.base; +unsigned val; + + val =readb_relaxed (base +HDMI_AUD_N1 ); +writeb_relaxed (val, base +HDMI_AUD_N1 ); + } substream->runtime->delay = substream->runtime->period_size;break ;
Signature · 1 line
1.8.3.1
PATCH 162/222 dw-hdmi-audio: try implementing ERR005174 to fix burbling audio
In reply to Russell King - ARM Linux--- drivers/staging/imx-drm/dw-hdmi-audio.c | 35 +++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-)
drivers/staging/imx-drm/dw-hdmi-audio.c +29 -6
@@ -7,6 +7,7 @@* * Written and tested against the (alleged) DW HDMI Tx found in iMX6S. */ +#include <linux/delay.h> #include <linux/io.h> #include <linux/interrupt.h> #include <linux/module.h>
@@ -68,6 +69,8 @@ enum {HDMI_AHB_DMA_THRSLD =0x3603 ,HDMI_AHB_DMA_STRADDR0 =0x3604 ,HDMI_AHB_DMA_STPADDR0 =0x3608 , +HDMI_AHB_DMA_STAT =0x3612 , +HDMI_AHB_DMA_STAT_FULL =BIT (1 ),HDMI_AHB_DMA_MASK =0x3614 ,HDMI_AHB_DMA_POL =0x3615 , HDMI_AHB_DMA_CONF1 = 0x3616,
@@ -473,20 +476,40 @@ static int dw_hdmi_prepare(struct snd_pcm_substream *substream)static int dw_hdmi_trigger (struct snd_pcm_substream *substream,int cmd) {struct snd_dw_hdmi *dw = substream->private_data; -int ret =0 ; +void __iomem *base = dw->data.base; +unsigned val[3 ]; +unsigned timeout =10000 ; +int ret =0 , i; +bool err005174;switch (cmd) {case SNDRV_PCM_TRIGGER_START : + err005174 = dw->revision ==0x0a ; +if (err005174) { +for (i =2 ; i >=0 ; i--) { + val[i] =readb_relaxed (base +HDMI_AUD_N1 + i); +writeb_relaxed (0 , base +HDMI_AUD_N1 + i); + } + } + dw->buf_offset =0 ; dw->substream = substream;dw_hdmi_start_dma (dw); -if (dw->revision ==0x0a ) { -void __iomem *base = dw->data.base; -unsigned val; - val =readb_relaxed (base +HDMI_AUD_N1 ); -writeb_relaxed (val, base +HDMI_AUD_N1 ); +if (err005174) { +do { +if (readb_relaxed (base +HDMI_AHB_DMA_STAT ) &HDMI_AHB_DMA_STAT_FULL ) +break ; +udelay (1 ); + }while (timeout--); + +if (!(readb_relaxed (base +HDMI_AHB_DMA_STAT ) &HDMI_AHB_DMA_STAT_FULL )) +pr_info ("timeout!\n" ); + +for (i =2 ; i >=0 ; i--) +writeb_relaxed (val[i], base +HDMI_AUD_N1 + i); } + substream->runtime->delay = substream->runtime->period_size;break ;
Signature · 1 line
1.8.3.1
PATCH 163/222 dw-hdmi-audio: another attempt at fixing burbling
In reply to Russell King - ARM Linux--- drivers/staging/imx-drm/dw-hdmi-audio.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-)
drivers/staging/imx-drm/dw-hdmi-audio.c +10 -15
@@ -63,6 +63,7 @@ enum {HDMI_IH_AHBDMAAUD_STAT0 =0x0109 ,HDMI_IH_MUTE_AHBDMAAUD_STAT0 =0x0189 ,HDMI_AUD_N1 =0x3200 , +HDMI_AUD_CTS1 =0x3203 ,HDMI_AHB_DMA_CONF0 =0x3600 ,HDMI_AHB_DMA_START =0x3601 , HDMI_AHB_DMA_STOP = 0x3602,
@@ -477,8 +478,7 @@ static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd) {struct snd_dw_hdmi *dw = substream->private_data;void __iomem *base = dw->data.base; -unsigned val[3 ]; -unsigned timeout =10000 ; +unsigned n[3 ], cts[3 ];int ret =0 , i;bool err005174;
@@ -486,9 +486,11 @@ static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd)case SNDRV_PCM_TRIGGER_START : err005174 = dw->revision ==0x0a ;if (err005174) { -for (i =2 ; i >=0 ; i--) { - val[i] =readb_relaxed (base +HDMI_AUD_N1 + i); +for (i =2 ; i >=1 ; i--) { + n[i] =readb_relaxed (base +HDMI_AUD_N1 + i); + cts[i] =readb_relaxed (base +HDMI_AUD_CTS1 + i);writeb_relaxed (0 , base +HDMI_AUD_N1 + i); +writeb_relaxed (0 , base +HDMI_AUD_CTS1 + i); } }
@@ -497,17 +499,10 @@ static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd)dw_hdmi_start_dma (dw);if (err005174) { -do { -if (readb_relaxed (base +HDMI_AHB_DMA_STAT ) &HDMI_AHB_DMA_STAT_FULL ) -break ; -udelay (1 ); - }while (timeout--); - -if (!(readb_relaxed (base +HDMI_AHB_DMA_STAT ) &HDMI_AHB_DMA_STAT_FULL )) -pr_info ("timeout!\n" ); - -for (i =2 ; i >=0 ; i--) -writeb_relaxed (val[i], base +HDMI_AUD_N1 + i); +for (i =2 ; i >=1 ; i--) +writeb_relaxed (cts[i], base +HDMI_AUD_CTS1 + i); +for (i =2 ; i >=1 ; i--) +writeb_relaxed (n[i], base +HDMI_AUD_N1 + i); } substream->runtime->delay = substream->runtime->period_size;
Signature · 1 line
1.8.3.1
PATCH 164/222 dw-hdmi-audio: basic suspend/resume support
In reply to Russell King - ARM Linux--- drivers/staging/imx-drm/dw-hdmi-audio.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
drivers/staging/imx-drm/dw-hdmi-audio.c +28 -0
@@ -611,12 +611,40 @@ static int snd_dw_hdmi_remove(struct platform_device *pdev)return 0 ; } +#ifdef CONFIG_PM_SLEEP +static int snd_dw_hdmi_suspend (struct device *dev) +{ +struct snd_dw_hdmi *dw =dev_get_drvdata (dev); + +snd_power_change_state (dw->card, SNDRV_CTL_POWER_D3cold); +snd_pcm_suspend_all (dw->pcm); + +return 0 ; +} + +static int snd_dw_hdmi_resume (struct device *dev) +{ +struct snd_dw_hdmi *dw =dev_get_drvdata (dev); + +snd_power_change_state (dw->card,SNDRV_CTL_POWER_D0 ); + +return 0 ; +} + +static SIMPLE_DEV_PM_OPS(snd_dw_hdmi_pm, snd_dw_hdmi_suspend, + snd_dw_hdmi_resume); +#define PM_OPS &snd_dw_hdmi_pm +#else +#define PM_OPS NULL +#endif +static struct platform_driver snd_dw_hdmi_driver = { .probe = snd_dw_hdmi_probe, .remove = snd_dw_hdmi_remove, .driver = { .name ="dw-hdmi-audio" , .owner =THIS_MODULE , + .pm =PM_OPS , }, };
Signature · 1 line
1.8.3.1
PATCH 165/222 cec: add generic HDMI CEC driver
In reply to Russell King - ARM LinuxAdd a generic userspace API to support HDMI Consumer Electronics Control interfaces.
--- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/cec/Kconfig | 14 ++ drivers/cec/Makefile | 1 + drivers/cec/cec-dev.c | 384 +++++++++++++++++++++++++++++++++++++++++++ include/linux/cec-dev.h | 69 ++++++++ include/uapi/linux/cec-dev.h | 34 ++++ 7 files changed, 505 insertions(+) create mode 100644 drivers/cec/Kconfig create mode 100644 drivers/cec/Makefile create mode 100644 drivers/cec/cec-dev.c create mode 100644 include/linux/cec-dev.h create mode 100644 include/uapi/linux/cec-dev.h
drivers/Kconfig +2 -0
@@ -174,4 +174,6 @@ source "drivers/powercap/Kconfig" source "drivers/mcb/Kconfig" +source "drivers/cec/Kconfig" + endmenu
drivers/Makefile +1 -0
@@ -157,3 +157,4 @@ obj-$(CONFIG_NTB) += ntb/ obj-$(CONFIG_FMC) += fmc/ obj-$(CONFIG_POWERCAP) += powercap/ obj-$(CONFIG_MCB) += mcb/ +obj-$(CONFIG_CEC) += cec/
drivers/cec/Kconfig new file +14 -0
@@ -0,0 +1,14 @@ +# +# Consumer Electroncs Control support +# + +menu "Consumer Electronics Control devices" + +config CEC + bool + +config HDMI_CEC_CORE + tristate + select CEC + +endmenu
drivers/cec/Makefile new file +1 -0
@@ -0,0 +1 @@ +obj-$(CONFIG_HDMI_CEC_CORE) += cec-dev.o
drivers/cec/cec-dev.c new file +384 -0
384 lines not on this page · raw message
include/linux/cec-dev.h new file +69 -0
69 lines not on this page · raw message
include/uapi/linux/cec-dev.h new file +34 -0
@@ -0,0 +1,34 @@ +#ifndef _UAPI_LINUX_CEC_DEV_H +#define _UAPI_LINUX_CEC_DEV_H + +#include <linux/ioctl.h> +#include <linux/types.h> + +#define MAX_MESSAGE_LEN 16 + +enum { +HDMICEC_IOC_MAGIC ='H' , +/* This is wrong: we pass the argument as a number, not a pointer */ + HDMICEC_IOC_O_SETLOGICALADDRESS = _IOW(HDMICEC_IOC_MAGIC, 1, unsigned char), +HDMICEC_IOC_SETLOGICALADDRESS =_IO (HDMICEC_IOC_MAGIC ,1 ), +HDMICEC_IOC_STARTDEVICE =_IO (HDMICEC_IOC_MAGIC ,2 ), +HDMICEC_IOC_STOPDEVICE =_IO (HDMICEC_IOC_MAGIC ,3 ), + HDMICEC_IOC_GETPHYADDRESS = _IOR(HDMICEC_IOC_MAGIC, 4, unsigned char[4]), +}; + +enum { +MESSAGE_TYPE_RECEIVE_SUCCESS =1 , +MESSAGE_TYPE_NOACK , +MESSAGE_TYPE_DISCONNECTED , +MESSAGE_TYPE_CONNECTED , +MESSAGE_TYPE_SEND_SUCCESS , +MESSAGE_TYPE_SEND_ERROR , +}; + +struct cec_user_event { +__u32 event_type; +__u32 msg_len; +__u8 msg[MAX_MESSAGE_LEN ]; +}; + +#endif
Signature · 1 line
1.8.3.1
PATCH 166/222 imx-drm: dw-hdmi-cec: add HDMI CEC driver
In reply to Russell King - ARM LinuxThis adds a HDMI Consumer Electronics Control driver, making use of the generic HDMI CEC driver to provide a common user API for these devices.
--- drivers/staging/imx-drm/Kconfig | 9 ++ drivers/staging/imx-drm/Makefile | 1 + drivers/staging/imx-drm/dw-hdmi-cec.c | 205 ++++++++++++++++++++++++++++++++++ drivers/staging/imx-drm/dw-hdmi-cec.h | 16 +++ drivers/staging/imx-drm/imx-hdmi.c | 63 +++++++++-- 5 files changed, 284 insertions(+), 10 deletions(-) create mode 100644 drivers/staging/imx-drm/dw-hdmi-cec.c create mode 100644 drivers/staging/imx-drm/dw-hdmi-cec.h
drivers/staging/imx-drm/Kconfig +9 -0
@@ -69,3 +69,12 @@ config DRM_DW_HDMI_AUDIO Support the Audio interface which is part of the Synopsis Designware HDMI block. This is used in conjunction with the i.MX HDMI driver. + +config DRM_DW_HDMI_CEC + tristate "Synopsis Designware CEC interface" + depends on DRM_IMX_HDMI != n + select HDMI_CEC_CORE + help + Support the CEC interface which is part of the Synposis + Designware HDMI block. This is used in conjunction with + the i.MX HDMI driver.
drivers/staging/imx-drm/Makefile +1 -0
@@ -12,3 +12,4 @@ imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o obj-$(CONFIG_DRM_DW_HDMI_AUDIO) += dw-hdmi-audio.o +obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o
drivers/staging/imx-drm/dw-hdmi-cec.c new file +205 -0
205 lines not on this page · raw message
drivers/staging/imx-drm/dw-hdmi-cec.h new file +16 -0
@@ -0,0 +1,16 @@ +#ifndef DW_HDMI_CEC_H +#define DW_HDMI_CEC_H + +struct dw_hdmi_cec_ops { +void (*enable)(void *); +void (*disable)(void *); +}; + +struct dw_hdmi_cec_data { +void __iomem *base; +int irq; +const struct dw_hdmi_cec_ops *ops; +void *ops_data; +}; + +#endif
drivers/staging/imx-drm/imx-hdmi.c +53 -10
132 lines not on this page · raw message
Signature · 1 line
1.8.3.1
PATCH 167/222 ARM: imx: add HDMI support for SolidRun HummingBoard and Cubox-i
In reply to Russell King - ARM LinuxAdd the HDMI DT configuration for the SolidRun HummingBoard and Cubox-i.
--- arch/arm/boot/dts/imx6dl-hummingboard.dts | 28 ++++++++++++++++++++++++++++ arch/arm/boot/dts/imx6qdl-cubox-i.dtsi | 28 ++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+)
arch/arm/boot/dts/imx6dl-hummingboard.dts +28 -0
@@ -67,6 +67,14 @@ status = "okay"; }; +&hdmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard_hdmi>; + ddc-i2c-bus = <&i2c2>; + status = "okay"; + crtcs = <&ipu1 0>; +}; + &i2c1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hummingboard_i2c1>;
@@ -82,6 +90,13 @@ */ }; +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard_i2c2>; + status = "okay"; +}; + &iomuxc { hummingboard { pinctrl_hummingboard_flexcan1: hummingboard-flexcan1 {
@@ -97,6 +112,12 @@ >; }; + pinctrl_hummingboard_hdmi: hummingboard-hdmi { + fsl,pins = < + MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 + >; + }; + pinctrl_hummingboard_i2c1: hummingboard-i2c1 { fsl,pins = < MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1
@@ -104,6 +125,13 @@ >; }; + pinctrl_hummingboard_i2c2: hummingboard-i2c2 { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + pinctrl_hummingboard_spdif: hummingboard-spdif { fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>; };
arch/arm/boot/dts/imx6qdl-cubox-i.dtsi +28 -0
@@ -55,6 +55,21 @@ }; }; +&hdmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cubox_i_hdmi>; + ddc-i2c-bus = <&i2c2>; + status = "okay"; + crtcs = <&ipu1 0>; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cubox_i_i2c2>; + status = "okay"; +}; + &i2c3 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_cubox_i_i2c3>;
@@ -69,6 +84,19 @@ &iomuxc { cubox_i { + pinctrl_cubox_i_hdmi: cubox-i-hdmi { + fsl,pins = < + MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 + >; + }; + + pinctrl_cubox_i_i2c2: cubox-i-i2c2 { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + pinctrl_cubox_i_i2c3: cubox-i-i2c3 { fsl,pins = < MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1
Signature · 1 line
1.8.3.1
PATCH 168/222 ARM: imx: enable HDMI DRM support for imx_v6_v7_defconfig
In reply to Russell King - ARM Linux--- arch/arm/configs/imx_v6_v7_defconfig | 1 + 1 file changed, 1 insertion(+)
arch/arm/configs/imx_v6_v7_defconfig +1 -0
@@ -245,6 +245,7 @@ CONFIG_DRM_IMX_TVE=y CONFIG_DRM_IMX_LDB=y CONFIG_DRM_IMX_IPUV3_CORE=y CONFIG_DRM_IMX_IPUV3=y +CONFIG_DRM_IMX_HDMI=y CONFIG_COMMON_CLK_DEBUG=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_PWM=y
Signature · 1 line
1.8.3.1
PATCH 169/222 drm/i915: don't disable disconnected outputs
In reply to Russell King - ARM LinuxConflicts:
drivers/gpu/drm/drm_crtc_helper.c
--- drivers/gpu/drm/drm_crtc_helper.c | 6 ------ 1 file changed, 6 deletions(-)
drivers/gpu/drm/drm_crtc_helper.c +0 -6
@@ -281,16 +281,10 @@ drm_encoder_disable(struct drm_encoder *encoder)static void __drm_helper_disable_unused_functions (struct drm_device *dev) {struct drm_encoder *encoder; -struct drm_connector *connector;struct drm_crtc *crtc;drm_warn_on_modeset_not_all_locked (dev); -list_for_each_entry (connector, &dev->mode_config.connector_list, head) { -if (!connector->encoder) -continue ; - } -list_for_each_entry (encoder, &dev->mode_config.encoder_list, head) {if (!drm_helper_encoder_in_use (encoder)) {drm_encoder_disable (encoder);
Signature · 1 line
1.8.3.1
PATCH 170/222 drm: add generic ddc connector
In reply to Russell King - ARM Linux--- drivers/staging/imx-drm/Makefile | 1 + drivers/staging/imx-drm/drm-ddc-connector.c | 92 +++++++++++++++++++++++++++++ drivers/staging/imx-drm/drm-ddc-connector.h | 26 ++++++++ drivers/staging/imx-drm/imx-hdmi.c | 82 ++++++------------------- drivers/staging/imx-drm/imx-tve.c | 63 ++++---------------- 5 files changed, 150 insertions(+), 114 deletions(-) create mode 100644 drivers/staging/imx-drm/drm-ddc-connector.c create mode 100644 drivers/staging/imx-drm/drm-ddc-connector.h
drivers/staging/imx-drm/Makefile +1 -0
@@ -3,6 +3,7 @@ imxdrm-objs := imx-drm-core.o obj-$(CONFIG_DRM_IMX) += imxdrm.o +obj-$(CONFIG_DRM_IMX) += drm-ddc-connector.o obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
drivers/staging/imx-drm/drm-ddc-connector.c new file +92 -0
92 lines not on this page · raw message
drivers/staging/imx-drm/drm-ddc-connector.h new file +26 -0
@@ -0,0 +1,26 @@ +#ifndef DRM_DDC_CONNECTOR_H +#define DRM_DDC_CONNECTOR_H + +struct drm_ddc_connector { +struct i2c_adapter *ddc; +struct drm_connector connector; +enum drm_connector_status (*detect)(struct drm_connector *,bool ); +void *private; +}; + +#define to_ddc_conn (c) container_of(c, struct drm_ddc_connector, connector) + +int drm_ddc_connector_get_modes (struct drm_connector *connector); +int drm_ddc_connector_add (struct drm_device *drm, +struct drm_ddc_connector *ddc_conn,int connector_type); +struct drm_ddc_connector *drm_ddc_connector_create (struct drm_device *drm, +struct device_node *np,void *private); + +static inline void *drm_ddc_private (struct drm_connector *connector) +{ +struct drm_ddc_connector *ddc_conn =to_ddc_conn (connector); + +return ddc_conn->private; +} + +#endif
drivers/staging/imx-drm/imx-hdmi.c +18 -64
174 lines not on this page · raw message
drivers/staging/imx-drm/imx-tve.c +13 -50
138 lines not on this page · raw message
Signature · 1 line
1.8.3.1
PATCH 171/222 ARM: l2c: trial at enabling some Cortex-A9 optimisations
In reply to Russell King - ARM Linux--- arch/arm/include/asm/hardware/cache-l2x0.h | 8 ++++ arch/arm/mm/cache-l2x0.c | 73 ++++++++++++++++++++++++++++-- 2 files changed, 78 insertions(+), 3 deletions(-)
arch/arm/include/asm/hardware/cache-l2x0.h +8 -0
@@ -134,6 +134,14 @@#define L310_ADDR_FILTER_EN 1 +#define L310_PREFETCH_CTRL_OFFSET_MASK 0x1f +#define L310_PREFETCH_CTRL_DBL_LINEFILL_INCR BIT(23) +#define L310_PREFETCH_CTRL_PREFETCH_DROP BIT(24) +#define L310_PREFETCH_CTRL_DBL_LINEFILL_WRAP BIT(27) +#define L310_PREFETCH_CTRL_DATA_PREFETCH BIT(28) +#define L310_PREFETCH_CTRL_INSTR_PREFETCH BIT(29) +#define L310_PREFETCH_CTRL_DBL_LINEFILL BIT(30) +#define L2X0_CTRL_EN 1#define L2X0_WAY_SIZE_SHIFT 3
arch/arm/mm/cache-l2x0.c +70 -3
125 lines not on this page · raw message
Signature · 1 line
1.8.3.1
PATCH 172/222 ARM: l2c: move L2 cache register saving to a more sensible location
In reply to Russell King - ARM LinuxMove the L2 cache register saving to a more sensible location - after the cache has been enabled, and fixups have been run. We move the saving of the auxiliary control register into the ->save function as well which makes everything operate in a sane and maintainable way.
--- arch/arm/mm/cache-l2x0.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-)
arch/arm/mm/cache-l2x0.c +22 -12
@@ -202,6 +202,11 @@ static void l2x0_disable(void)raw_spin_unlock_irqrestore (&l2x0_lock, flags); } +static void l2c_save (void __iomem *base) +{ + l2x0_saved_regs.aux_ctrl =readl_relaxed (l2x0_base +L2X0_AUX_CTRL ); +} +/* * L2C-210 specific code. *
@@ -295,6 +300,7 @@ static const struct l2c_init_data l2c210_data __initconst = { .way_size_0 = SZ_8K, .num_lock = 1, .enable = l2c_enable, + .save = l2c_save, .outer_cache = { .inv_range = l2c210_inv_range, .clean_range = l2c210_clean_range,
@@ -439,6 +445,7 @@ static const struct l2c_init_data l2c220_data = { .way_size_0 = SZ_8K, .num_lock = 1, .enable = l2c_enable, + .save = l2c_save, .outer_cache = { .inv_range = l2c220_inv_range, .clean_range = l2c220_clean_range,
@@ -570,6 +577,8 @@ static void __init l2c310_save(void __iomem *base) {unsigned revision; +l2c_save (base); + l2x0_saved_regs.tag_latency =readl_relaxed (base +L310_TAG_LATENCY_CTRL ); l2x0_saved_regs.data_latency = readl_relaxed(base +
@@ -792,13 +801,6 @@ static void __init __l2c_init(const struct l2c_init_data *data,if (aux_val & aux_mask)pr_alert ("L2C: platform provided aux values permit register corruption.\n" ); -/* -* It is strange to save the register state before initialisation, -* but hey, this is what the DT implementations decided to do. -*/ -if (data->save) - data->save (l2x0_base); - old_aux = aux =readl_relaxed (l2x0_base +L2X0_AUX_CTRL ); aux &= aux_mask; aux |= aux_val;
@@ -860,13 +862,17 @@ static void __init __l2c_init(const struct l2c_init_data *data,if (!(readl_relaxed (l2x0_base +L2X0_CTRL ) &L2X0_CTRL_EN )) data->enable (l2x0_base, aux, data->num_lock); -/* Re-read it in case some bits are reserved. */ - aux =readl_relaxed (l2x0_base +L2X0_AUX_CTRL ); + outer_cache = fns; -/* Save the value for resuming. */ - l2x0_saved_regs.aux_ctrl = aux; +/* +* It is strange to save the register state before initialisation, +* but hey, this is what the DT implementations decided to do. +*/ +if (data->save) + data->save (l2x0_base); - outer_cache = fns; +/* Re-read it in case some bits are reserved. */ + aux =readl_relaxed (l2x0_base +L2X0_AUX_CTRL );pr_info ("%s cache controller enabled, %d ways, %d kB\n" , data->type, ways, l2x0_size >>10 );
@@ -948,6 +954,7 @@ static const struct l2c_init_data of_l2c210_data __initconst = { .num_lock = 1, .of_parse = l2x0_of_parse, .enable = l2c_enable, + .save = l2c_save, .outer_cache = { .inv_range = l2c210_inv_range, .clean_range = l2c210_clean_range,
@@ -965,6 +972,7 @@ static const struct l2c_init_data of_l2c220_data __initconst = { .num_lock = 1, .of_parse = l2x0_of_parse, .enable = l2c_enable, + .save = l2c_save, .outer_cache = { .inv_range = l2c220_inv_range, .clean_range = l2c220_clean_range,
@@ -1388,6 +1396,8 @@ static const struct l2c_init_data of_bcm_l2x0_data __initconst = {static void __init tauros3_save (void __iomem *base) { +l2c_save (base); + l2x0_saved_regs.aux2_ctrl =readl_relaxed (base +TAUROS3_AUX2_CTRL ); l2x0_saved_regs.prefetch_ctrl =
Signature · 1 line
1.8.3.1
PATCH 173/222 ARM: l2c: always enable low power modes
In reply to Russell King - ARM LinuxAlways enable the L2C low power modes on L2C-310 R3P0 and newer parts.
--- Documentation/devicetree/bindings/arm/l2cc.txt | 2 -- arch/arm/mm/cache-l2x0.c | 22 ++++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-)
Documentation/devicetree/bindings/arm/l2cc.txt +0 -2
@@ -40,8 +40,6 @@ implementations of the L2 cache controller with compatible programming models. - arm,filter-ranges : <start length> Starting address and length of window to filter. Addresses in the filter window are directed to the M1 port. Other addresses will go to the M0 port. -- arm,dynamic-clk-gating : Enables dynamic clock gating (PL310) -- arm,standby-mode : Enables standby mode (PL310) - interrupts : 1 combined interrupt. - cache-id-part: cache id part number to be used if it is not present on hardware
arch/arm/mm/cache-l2x0.c +12 -10
@@ -695,6 +695,18 @@ static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock) 1 + (prefetch & L310_PREFETCH_CTRL_OFFSET_MASK)); } +/* r3p0 or later has power control register */ +if (rev >=L310_CACHE_ID_RTL_R3P0 ) { +u32 power_ctrl; + +l2c_write_sec (L310_DYNAMIC_CLK_GATING_EN |L310_STNDBY_MODE_EN , + base,L310_POWER_CTRL ); + power_ctrl =readl_relaxed (base +L310_POWER_CTRL ); +pr_info ("L2C-310 dynamic clock gating %sabled, standby mode %sabled\n" , + power_ctrl &L310_DYNAMIC_CLK_GATING_EN ?"en" :"dis" , + power_ctrl &L310_STNDBY_MODE_EN ?"en" :"dis" ); + } +l2c_enable (base, aux, num_lock);if (aux &L310_AUX_CTRL_FULL_LINE_ZERO ) {
@@ -990,7 +1002,6 @@ static void __init l2c310_of_parse(const struct device_node *np,u32 data[3 ] = {0 ,0 ,0 };u32 tag[3 ] = {0 ,0 ,0 };u32 filter[2 ] = {0 ,0 }; -u32 val;of_property_read_u32_array (np,"arm,tag-latency" , tag,ARRAY_SIZE (tag));if (tag[0 ] && tag[1 ] && tag[2 ])
@@ -1017,15 +1028,6 @@ static void __init l2c310_of_parse(const struct device_node *np,writel_relaxed ((filter[0 ] & ~(SZ_1M -1 )) |L310_ADDR_FILTER_EN , l2x0_base +L310_ADDR_FILTER_START ); } - - val =0 ; -if (of_property_read_bool (np,"arm,dynamic-clk-gating" )) - val |=L310_DYNAMIC_CLK_GATING_EN ; -if (of_property_read_bool (np,"arm,standby-mode" )) - val |=L310_STNDBY_MODE_EN ; - -if (val) -l2c_write_sec (val, l2x0_base,L310_POWER_CTRL ); }static const struct l2c_init_data of_l2c310_data__initconst = {
Signature · 1 line
1.8.3.1
PATCH 174/222 ARM: l2c: imx: remove direct write to power control register
In reply to Russell King - ARM LinuxNow that we handle this in core code, we don't need platforms enabling the low power modes directly.
--- arch/arm/mach-imx/system.c | 2 -- 1 file changed, 2 deletions(-)
arch/arm/mach-imx/system.c +0 -2
@@ -138,8 +138,6 @@ void __init imx_init_l2cache(void)if (cpu_is_imx6q ()) val &= ~(1 <<30 |1 <<23 );writel_relaxed (val, l2x0_base +L310_PREFETCH_CTRL ); - val =L310_DYNAMIC_CLK_GATING_EN |L310_STNDBY_MODE_EN ; -writel_relaxed (val, l2x0_base +L310_POWER_CTRL );iounmap (l2x0_base);of_node_put (np);
Signature · 1 line
1.8.3.1
PATCH 175/222 ARM: l2c: omap2: avoid reading directly from the L2 registers in platform code
In reply to Russell King - ARM LinuxAvoid reading directly from the L2 registers in platform code. The L2 code will have already saved the register values itself into the l2x0_saved_regs structure, so platform code should just move these values to where they're required.
This is safe because the L2x0 will have been initialised by an early initcall, whereas the OMAP4 PM code is initialised late.
--- arch/arm/mach-omap2/omap-mpuss-lowpower.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-)
arch/arm/mach-omap2/omap-mpuss-lowpower.c +6 -10
@@ -187,19 +187,15 @@ static void l2x0_pwrst_prepare(unsigned int cpu_id, unsigned int save_state)* in every restore MPUSS OFF path. */ #ifdef CONFIG_CACHE_L2X0 -static void save_l2x0_context (void ) +static void __init save_l2x0_context (void ) { -u32 val; -void __iomem *l2x0_base =omap4_get_l2cache_base (); -if (l2x0_base) { - val =__raw_readl (l2x0_base +L2X0_AUX_CTRL ); -__raw_writel (val, sar_base +L2X0_AUXCTRL_OFFSET ); - val =__raw_readl (l2x0_base +L310_PREFETCH_CTRL ); -__raw_writel (val, sar_base +L2X0_PREFETCH_CTRL_OFFSET ); - } +__raw_writel (l2x0_saved_regs.aux_ctrl, + sar_base +L2X0_AUXCTRL_OFFSET ); +__raw_writel (l2x0_saved_regs.prefetch_ctrl, + sar_base +L2X0_PREFETCH_CTRL_OFFSET ); }#else -static void save_l2x0_context (void ) +static void __init save_l2x0_context (void ) {}#endif
Signature · 1 line
1.8.3.1
PATCH 176/222 ARM: l2c: provide common PL310 early resume code
In reply to Russell King - ARM Linux--- arch/arm/mm/Makefile | 2 +- arch/arm/mm/l2c-l2x0-resume.S | 58 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mm/l2c-l2x0-resume.S
arch/arm/mm/Makefile +1 -1
@@ -97,6 +97,6 @@ AFLAGS_proc-v7.o :=-Wa,-march=armv7-a obj-$(CONFIG_OUTER_CACHE) += l2c-common.o obj-$(CONFIG_CACHE_FEROCEON_L2) += cache-feroceon-l2.o -obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o +obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o l2c-l2x0-resume.o obj-$(CONFIG_CACHE_XSC3L2) += cache-xsc3l2.o obj-$(CONFIG_CACHE_TAUROS2) += cache-tauros2.o
arch/arm/mm/l2c-l2x0-resume.S new file +58 -0
58 lines not on this page · raw message
Signature · 1 line
1.8.3.1
PATCH 177/222 ARM: l2c: exynos: convert to common l2c310 early resume functionality
In reply to Russell King - ARM Linux--- arch/arm/mach-exynos/common.h | 1 - arch/arm/mach-exynos/exynos.c | 12 +----------- arch/arm/mach-exynos/sleep.S | 30 +----------------------------- arch/arm/plat-samsung/s5p-sleep.S | 1 - 4 files changed, 2 insertions(+), 42 deletions(-)
arch/arm/mach-exynos/common.h +0 -1
@@ -55,7 +55,6 @@ enum sys_powerdown { NUM_SYS_POWERDOWN, }; -extern unsigned long l2x0_regs_phys;struct exynos_pmu_conf {void __iomem *reg;unsigned int val[NUM_SYS_POWERDOWN ];
arch/arm/mach-exynos/exynos.c +1 -11
@@ -318,17 +318,7 @@ core_initcall(exynos_core_init);static int __init exynos4_l2x0_cache_init (void ) { -int ret; - - ret =l2x0_of_init (0x3c400001 ,0xc20fffff ); -if (ret) -return ret; - -if (IS_ENABLED (CONFIG_S5P_SLEEP )) { - l2x0_regs_phys =virt_to_phys (&l2x0_saved_regs); -clean_dcache_area (&l2x0_regs_phys,sizeof (unsigned long )); - } -return 0 ; +return l2x0_of_init (0x3c400001 ,0xc20fffff ); }early_initcall (exynos4_l2x0_cache_init);
arch/arm/mach-exynos/sleep.S +1 -29
@@ -16,8 +16,6 @@ */ #include <linux/linkage.h> -#include <asm/asm-offsets.h> -#include <asm/hardware/cache-l2x0.h> #define CPU_MASK 0xff0ffff0 #define CPU_CORTEX_A9 0x410fc090
@@ -53,33 +51,7 @@ ENTRY(exynos_cpu_resume) and r0, r0, r1 ldr r1, =CPU_CORTEX_A9 cmp r0, r1 - bne skip_l2_resume - adr r0, l2x0_regs_phys - ldr r0, [r0] - cmp r0, #0 - beq skip_l2_resume - ldr r1, [r0, #L2X0_R_PHY_BASE] - ldr r2, [r1, #L2X0_CTRL] - tst r2, #0x1 - bne skip_l2_resume - ldr r2, [r0, #L2X0_R_AUX_CTRL] - str r2, [r1, #L2X0_AUX_CTRL] - ldr r2, [r0, #L2X0_R_TAG_LATENCY] - str r2, [r1, #L310_TAG_LATENCY_CTRL] - ldr r2, [r0, #L2X0_R_DATA_LATENCY] - str r2, [r1, #L310_DATA_LATENCY_CTRL] - ldr r2, [r0, #L2X0_R_PREFETCH_CTRL] - str r2, [r1, #L310_PREFETCH_CTRL] - ldr r2, [r0, #L2X0_R_PWR_CTRL] - str r2, [r1, #L310_POWER_CTRL] - mov r2, #1 - str r2, [r1, #L2X0_CTRL] -skip_l2_resume: + bleq l2c310_early_resume #endif b cpu_resume ENDPROC(exynos_cpu_resume) -#ifdef CONFIG_CACHE_L2X0 - .globl l2x0_regs_phys -l2x0_regs_phys: - .long 0 -#endif
arch/arm/plat-samsung/s5p-sleep.S +0 -1
@@ -22,7 +22,6 @@ */ #include <linux/linkage.h> -#include <asm/asm-offsets.h> .data .align
Signature · 1 line
1.8.3.1
PATCH 178/222 ARM: l2c: tegra: convert to common l2c310 early resume functionality
In reply to Russell King - ARM Linux--- arch/arm/mach-tegra/pm.h | 2 -- arch/arm/mach-tegra/reset-handler.S | 11 +++-------- arch/arm/mach-tegra/sleep.h | 31 ------------------------------- arch/arm/mach-tegra/tegra.c | 6 +----- 4 files changed, 4 insertions(+), 46 deletions(-)
arch/arm/mach-tegra/pm.h +0 -2
@@ -35,8 +35,6 @@ void tegra20_sleep_core_init(void);void tegra30_lp1_iram_hook (void );void tegra30_sleep_core_init (void ); -extern unsigned long l2x0_saved_regs_addr; -void tegra_clear_cpu_in_lp2 (void );bool tegra_set_cpu_in_lp2 (void );
arch/arm/mach-tegra/reset-handler.S +3 -8
@@ -19,7 +19,6 @@ #include <asm/cache.h> #include <asm/asm-offsets.h> -#include <asm/hardware/cache-l2x0.h> #include "flowctrl.h" #include "fuse.h"
@@ -78,8 +77,10 @@ ENTRY(tegra_resume) str r1, [r0] #endif +#ifdef CONFIG_CACHE_L2X0 /* L2 cache resume & re-enable */ - l2_cache_resume r0, r1, r2, l2x0_saved_regs_addr + bl l2c310_early_resume +#endif end_ca9_scu_l2_resume: mov32 r9, 0xc0f cmp r8, r9
@@ -89,12 +90,6 @@ end_ca9_scu_l2_resume: ENDPROC(tegra_resume) #endif -#ifdef CONFIG_CACHE_L2X0 - .globl l2x0_saved_regs_addr -l2x0_saved_regs_addr: - .long 0 -#endif - .align L1_CACHE_SHIFT ENTRY(__tegra_cpu_reset_handler_start)
arch/arm/mach-tegra/sleep.h +0 -31
@@ -120,37 +120,6 @@ mov \tmp1, \tmp1, lsr #8 .endm -/* Macro to resume & re-enable L2 cache */ -#ifndef L2X0_CTRL_EN -#define L2X0_CTRL_EN 1 -#endif - -#ifdef CONFIG_CACHE_L2X0 -.macro l2_cache_resume, tmp1, tmp2, tmp3, phys_l2x0_saved_regs - W(adr) \tmp1, \phys_l2x0_saved_regs - ldr \tmp1, [\tmp1] - ldr \tmp2, [\tmp1, #L2X0_R_PHY_BASE] - ldr \tmp3, [\tmp2, #L2X0_CTRL] - tst \tmp3, #L2X0_CTRL_EN - bne exit_l2_resume - ldr \tmp3, [\tmp1, #L2X0_R_TAG_LATENCY] - str \tmp3, [\tmp2, #L310_TAG_LATENCY_CTRL] - ldr \tmp3, [\tmp1, #L2X0_R_DATA_LATENCY] - str \tmp3, [\tmp2, #L310_DATA_LATENCY_CTRL] - ldr \tmp3, [\tmp1, #L2X0_R_PREFETCH_CTRL] - str \tmp3, [\tmp2, #L310_PREFETCH_CTRL] - ldr \tmp3, [\tmp1, #L2X0_R_PWR_CTRL] - str \tmp3, [\tmp2, #L310_POWER_CTRL] - ldr \tmp3, [\tmp1, #L2X0_R_AUX_CTRL] - str \tmp3, [\tmp2, #L2X0_AUX_CTRL] - mov \tmp3, #L2X0_CTRL_EN - str \tmp3, [\tmp2, #L2X0_CTRL] -exit_l2_resume: -.endm -#else /* CONFIG_CACHE_L2X0 */ -.macro l2_cache_resume, tmp1, tmp2, tmp3, phys_l2x0_saved_regs -.endm -#endif /* CONFIG_CACHE_L2X0 */ #else void tegra_pen_lock(void);void tegra_pen_unlock (void );
arch/arm/mach-tegra/tegra.c +1 -5
@@ -73,11 +73,7 @@ u32 tegra_uart_config[3] = {static void __init tegra_init_cache (void ) {#ifdef CONFIG_CACHE_L2X0 -int ret; - - ret =l2x0_of_init (0x3c400001 ,0xc20fc3fe ); -if (!ret) - l2x0_saved_regs_addr =virt_to_phys (&l2x0_saved_regs); +l2x0_of_init (0x3c400001 ,0xc20fc3fe );#endif }
Signature · 1 line
1.8.3.1
PATCH 179/222 ARM: l2c: imx: convert to common l2c310 early resume functionality
In reply to Russell King - ARM Linux--- arch/arm/mach-imx/suspend-imx6.S | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-)
arch/arm/mach-imx/suspend-imx6.S +3 -21
@@ -334,28 +334,10 @@ ENDPROC(imx6_suspend) * turned into relative ones. */ -#ifdef CONFIG_CACHE_L2X0 - .macro pl310_resume - adr r0, l2x0_saved_regs_offset - ldr r2, [r0] - add r2, r2, r0 - ldr r0, [r2, #L2X0_R_PHY_BASE] @ get physical base of l2x0 - ldr r1, [r2, #L2X0_R_AUX_CTRL] @ get aux_ctrl value - str r1, [r0, #L2X0_AUX_CTRL] @ restore aux_ctrl - mov r1, #0x1 - str r1, [r0, #L2X0_CTRL] @ re-enable L2 - .endm - -l2x0_saved_regs_offset: - .word l2x0_saved_regs - . - -#else - .macro pl310_resume - .endm -#endif - ENTRY(v7_cpu_resume) bl v7_invalidate_l1 - pl310_resume +#ifdef CONFIG_CACHE_L2X0 + bl l2c310_early_resume +#endif b cpu_resume ENDPROC(v7_cpu_resume)
Signature · 1 line
1.8.3.1
PATCH 180/222 ARM: l2c: always enable non-secure access to lockdown registers
In reply to Russell King - ARM LinuxSince we always write to these during the cache initialisation, it is a good idea to always have the non-secure access bit set. Set it in core code and remove it from OMAP4. Remove the NS access bit for the interrupt registers from OMAP4 as well - nothing in the kernel accesses that yet, and we can add it in core code when we have the need.
--- arch/arm/mach-omap2/omap4-common.c | 6 ++---- arch/arm/mm/cache-l2x0.c | 23 +++++++++++++++++++++-- 2 files changed, 23 insertions(+), 6 deletions(-)
arch/arm/mach-omap2/omap4-common.c +2 -4
@@ -214,17 +214,15 @@ static int __init omap_l2_cache_init(void)/* 16-way associativity, parity disabled, way size - 64KB (es2.0 +) */ aux_ctrl =L310_AUX_CTRL_CACHE_REPLACE_RR | -L310_AUX_CTRL_NS_LOCKDOWN | -L310_AUX_CTRL_NS_INT_CTRL |L2C_AUX_CTRL_SHARED_OVERRIDE |L310_AUX_CTRL_DATA_PREFETCH |L310_AUX_CTRL_INSTR_PREFETCH ; outer_cache.write_sec = omap4_l2c310_write_sec;if (of_have_populated_dt ()) -l2x0_of_init (aux_ctrl,0xc19fffff ); +l2x0_of_init (aux_ctrl,0xcd9fffff );else -l2x0_init (l2cache_base, aux_ctrl,0xc19fffff ); +l2x0_init (l2cache_base, aux_ctrl,0xcd9fffff );return 0 ; }
arch/arm/mm/cache-l2x0.c +21 -2
@@ -440,11 +440,23 @@ static void l2c220_sync(void)raw_spin_unlock_irqrestore (&l2x0_lock, flags); } +static void l2c220_enable (void __iomem *base,u32 aux,unsigned num_lock) +{ +/* +* Always enable non-secure access to the lockdown registers - +* we write to them as part of the L2C enable sequence so they +* need to be accessible. +*/ + aux |=L220_AUX_CTRL_NS_LOCKDOWN ; + +l2c_enable (base, aux, num_lock); +} +static const struct l2c_init_data l2c220_data = { .type ="L2C-220" , .way_size_0 =SZ_8K , .num_lock =1 , - .enable = l2c_enable, + .enable = l2c220_enable, .save = l2c_save, .outer_cache = { .inv_range = l2c220_inv_range,
@@ -707,6 +719,13 @@ static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock) power_ctrl & L310_STNDBY_MODE_EN ? "en" : "dis"); } +/* +* Always enable non-secure access to the lockdown registers - +* we write to them as part of the L2C enable sequence so they +* need to be accessible. +*/ + aux |=L310_AUX_CTRL_NS_LOCKDOWN ; +l2c_enable (base, aux, num_lock);if (aux &L310_AUX_CTRL_FULL_LINE_ZERO ) {
@@ -983,7 +1002,7 @@ static const struct l2c_init_data of_l2c220_data __initconst = { .way_size_0 = SZ_8K, .num_lock = 1, .of_parse = l2x0_of_parse, - .enable = l2c_enable, + .enable = l2c220_enable, .save = l2c_save, .outer_cache = { .inv_range = l2c220_inv_range,
Signature · 1 line
1.8.3.1
PATCH 181/222 ARM: l2c: omap2+: get rid of redundant cache replacement policy setting
In reply to Russell King - ARM LinuxFrom: Sekhar Nori <[email protected]>
To: linux-arm-kernel at lists.infradead.org
L2 cache initialization for OMAP4 redundantly sets the cache policy to Round-Robin. This is not needed since thats the PL310 default anyway.
Removing this reduces the number of platform specific aux control settings.
--- arch/arm/mach-omap2/omap4-common.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
arch/arm/mach-omap2/omap4-common.c +3 -4
@@ -213,16 +213,15 @@ static int __init omap_l2_cache_init(void)return -ENOMEM ;/* 16-way associativity, parity disabled, way size - 64KB (es2.0 +) */ - aux_ctrl =L310_AUX_CTRL_CACHE_REPLACE_RR | -L2C_AUX_CTRL_SHARED_OVERRIDE | + aux_ctrl =L2C_AUX_CTRL_SHARED_OVERRIDE |L310_AUX_CTRL_DATA_PREFETCH |L310_AUX_CTRL_INSTR_PREFETCH ; outer_cache.write_sec = omap4_l2c310_write_sec;if (of_have_populated_dt ()) -l2x0_of_init (aux_ctrl,0xcd9fffff ); +l2x0_of_init (aux_ctrl,0xcf9fffff );else -l2x0_init (l2cache_base, aux_ctrl,0xcd9fffff ); +l2x0_init (l2cache_base, aux_ctrl,0xcf9fffff );return 0 ; }
Signature · 1 line
1.8.3.1
PATCH 182/222 ARM: l2c: omap2+: get rid of init call
In reply to Russell King - ARM LinuxFrom: Sekhar Nori <[email protected]>
To: linux-arm-kernel at lists.infradead.org
Get rid of init call to initialize L2 cache. Instead use the init_early machine hook. This helps in using the initialization routine across SoCs without the need of ugly cpu_is_*() checks.
--- arch/arm/mach-omap2/common.h | 1 + arch/arm/mach-omap2/io.c | 1 + arch/arm/mach-omap2/omap4-common.c | 10 +--------- 3 files changed, 3 insertions(+), 9 deletions(-)
arch/arm/mach-omap2/common.h +1 -0
@@ -91,6 +91,7 @@ extern void omap3_sync32k_timer_init(void);extern void omap3_secure_sync32k_timer_init (void );extern void omap3_gptimer_timer_init (void );extern void omap4_local_timer_init (void ); +int omap_l2_cache_init (void );extern void omap5_realtime_timer_init (void );void omap2420_init_early (void );
arch/arm/mach-omap2/io.c +1 -0
@@ -640,6 +640,7 @@ void __init omap4430_init_early(void)omap44xx_clockdomains_init ();omap44xx_hwmod_init ();omap_hwmod_init_postsetup (); +omap_l2_cache_init (); omap_clk_soc_init = omap4xxx_dt_clk_init; }
arch/arm/mach-omap2/omap4-common.c +1 -9
@@ -196,17 +196,10 @@ static void omap4_l2c310_write_sec(unsigned long val, unsigned reg)omap_smc1 (smc_op, val); } -static int __init omap_l2_cache_init (void ) +int __init omap_l2_cache_init (void ) {u32 aux_ctrl; -/* -* To avoid code running on other OMAPs in -* multi-omap builds -*/ -if (!cpu_is_omap44xx ()) -return -ENODEV ; -/* Static mapping, never released */ l2cache_base =ioremap (OMAP44XX_L2CACHE_BASE ,SZ_4K );if (WARN_ON (!l2cache_base))
@@ -225,7 +218,6 @@ static int __init omap_l2_cache_init(void) return 0; } -omap_early_initcall (omap_l2_cache_init);#endif void __iomem *omap4_get_sar_ram_base (void )
Signature · 1 line
1.8.3.1
PATCH 183/222 ARM: l2c: AM43x: add L2 cache support
In reply to Russell King - ARM LinuxFrom: Sekhar Nori <[email protected]>
To: linux-arm-kernel at lists.infradead.org
Add support for L2 cache controller (PL310) on AM437x SoC.
--- arch/arm/mach-omap2/Kconfig | 1 + arch/arm/mach-omap2/io.c | 1 + 2 files changed, 2 insertions(+)
arch/arm/mach-omap2/Kconfig +1 -0
@@ -65,6 +65,7 @@ config SOC_AM43XX select ARCH_HAS_OPP select ARM_GIC select MACH_OMAP_GENERIC + select MIGHT_HAVE_CACHE_L2X0 config SOC_DRA7XX bool "TI DRA7XX"
arch/arm/mach-omap2/io.c +1 -0
@@ -609,6 +609,7 @@ void __init am43xx_init_early(void)am43xx_clockdomains_init ();am43xx_hwmod_init ();omap_hwmod_init_postsetup (); +omap_l2_cache_init (); omap_clk_soc_init = am43xx_dt_clk_init; }
Signature · 1 line
1.8.3.1
PATCH 184/222 ARM: l2c: permit flush_all() on large flush_range() XXX Needs more thought XXX
In reply to Russell King - ARM LinuxIn order to allow flush_all() to be used in normal operation, we need some locking to prevent any other cache operations being issued while a background flush_all() operation is proceeding. The read-write spinlock provides what's necessary here, but we must avoid bringing lockdep issues into this code. Hence we continue to use the raw_* operations, and use the arch read/write spinlock implementation directly.
--- arch/arm/mm/cache-l2x0.c | 90 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 79 insertions(+), 11 deletions(-)
arch/arm/mm/cache-l2x0.c +79 -11
@@ -56,6 +56,54 @@ struct l2x0_regs l2x0_saved_regs;/* * Common code for all cache controllers. */ +#ifdef CONFIG_SMP +static arch_rwlock_t l2c_rw_lock = __ARCH_RW_LOCK_UNLOCKED; + +static unsigned long l2c_lock_exclusive (void ) +{ +unsigned long flags; +raw_local_irq_save (flags); +arch_write_lock (&l2c_rw_lock); +return flags; +} + +static void l2c_unlock_exclusive (unsigned long flags) +{ +arch_write_unlock (&l2c_rw_lock); +raw_local_irq_restore (flags); +} + +static void l2c_lock_shared (void ) +{ +arch_read_lock (&l2c_rw_lock); +} + +static void l2c_unlock_shared (void ) +{ +arch_read_unlock (&l2c_rw_lock); +} +#else +static unsigned long l2c_lock_exclusive (void ) +{ +unsigned long flags; +raw_local_irq_save (flags); +return flags; +} + +static void l2c_unlock_exclusive (unsigned long flags) +{ +raw_local_irq_restore (flags); +} + +static void l2c_lock_shared (void ) +{ +} + +static void l2c_unlock_shared (void ) +{ +} +#endif +static inline void l2c_wait_mask (void __iomem *reg,unsigned long mask) {/* wait for cache operation by line or way to complete */
@@ -239,6 +287,7 @@ static void l2c210_inv_range(unsigned long start, unsigned long end) {void __iomem *base = l2x0_base; +l2c_lock_shared ();if (start & (CACHE_LINE_SIZE -1 )) { start &= ~(CACHE_LINE_SIZE -1 );writel_relaxed (start, base +L2X0_CLEAN_INV_LINE_PA );
@@ -252,6 +301,7 @@ static void l2c210_inv_range(unsigned long start, unsigned long end)__l2c210_op_pa_range (base +L2X0_INV_LINE_PA , start, end);__l2c210_cache_sync (base); +l2c_unlock_shared (); }static void l2c210_clean_range (unsigned long start,unsigned long end)
@@ -259,8 +309,10 @@ static void l2c210_clean_range(unsigned long start, unsigned long end)void __iomem *base = l2x0_base; start &= ~(CACHE_LINE_SIZE -1 ); +l2c_lock_shared ();__l2c210_op_pa_range (base +L2X0_CLEAN_LINE_PA , start, end);__l2c210_cache_sync (base); +l2c_unlock_shared (); }static void l2c210_flush_range (unsigned long start,unsigned long end)
@@ -268,23 +320,33 @@ static void l2c210_flush_range(unsigned long start, unsigned long end)void __iomem *base = l2x0_base; start &= ~(CACHE_LINE_SIZE -1 ); +if ((end - start) >= l2x0_size) { + outer_cache.flush_all (); +return ; + } + +l2c_lock_shared ();__l2c210_op_pa_range (base +L2X0_CLEAN_INV_LINE_PA , start, end);__l2c210_cache_sync (base); +l2c_unlock_shared (); }static void l2c210_flush_all (void ) {void __iomem *base = l2x0_base; +unsigned long flags; -BUG_ON (!irqs_disabled ()); - + flags =l2c_lock_exclusive ();__l2c_op_way (base +L2X0_CLEAN_INV_WAY );__l2c210_cache_sync (base); +l2c_unlock_exclusive (flags); }static void l2c210_sync (void ) { +l2c_lock_shared ();__l2c210_cache_sync (l2x0_base); +l2c_unlock_shared (); }static void l2c210_resume (void )
@@ -521,7 +583,7 @@ static void l2c310_inv_range_erratum(unsigned long start, unsigned long end)unsigned long flags;/* Erratum 588369 for both clean+invalidate operations */ -raw_spin_lock_irqsave (&l2x0_lock, flags); + flags =l2c_lock_exclusive ();l2c_set_debug (base,0x03 );if (start & (CACHE_LINE_SIZE -1 )) {
@@ -538,20 +600,26 @@ static void l2c310_inv_range_erratum(unsigned long start, unsigned long end) }l2c_set_debug (base,0x00 ); -raw_spin_unlock_irqrestore (&l2x0_lock, flags); +l2c_unlock_exclusive (flags); } +l2c_lock_shared ();__l2c210_op_pa_range (base +L2X0_INV_LINE_PA , start, end);__l2c210_cache_sync (base); +l2c_unlock_shared (); }static void l2c310_flush_range_erratum (unsigned long start,unsigned long end) { -raw_spinlock_t *lock = &l2x0_lock;unsigned long flags;void __iomem *base = l2x0_base; -raw_spin_lock_irqsave (lock, flags); +if ((end - start) >= l2x0_size) { + outer_cache.flush_all (); +return ; + } + + flags =l2c_lock_exclusive ();while (start < end) {unsigned long blk_end = start +min (end - start,4096UL );
@@ -564,12 +632,12 @@ static void l2c310_flush_range_erratum(unsigned long start, unsigned long end)l2c_set_debug (base,0x00 );if (blk_end < end) { -raw_spin_unlock_irqrestore (lock, flags); -raw_spin_lock_irqsave (lock, flags); +l2c_unlock_exclusive (flags); + flags =l2c_lock_exclusive (); } } -raw_spin_unlock_irqrestore (lock, flags);__l2c210_cache_sync (base); +l2c_unlock_exclusive (flags); }static void l2c310_flush_all_erratum (void )
@@ -577,12 +645,12 @@ static void l2c310_flush_all_erratum(void)void __iomem *base = l2x0_base;unsigned long flags; -raw_spin_lock_irqsave (&l2x0_lock, flags); + flags =l2c_lock_exclusive ();l2c_set_debug (base,0x03 );__l2c_op_way (base +L2X0_CLEAN_INV_WAY );l2c_set_debug (base,0x00 );__l2c210_cache_sync (base); -raw_spin_unlock_irqrestore (&l2x0_lock, flags); +l2c_unlock_exclusive (flags); }static void __init l2c310_save (void __iomem *base)
Signature · 1 line
1.8.3.1
PATCH 185/222 mmc: sdio_irq: rework sdio irq handling
In reply to Russell King - ARM LinuxRather than the SDIO support spawning it's own thread for handling card interrupts, use the generic IRQ infrastructure for this, triggering it from the host interface's interrupt handling directly.
This avoids a race between the parent thread waiting to receive an interrupt response from the card, and the slow startup from the sdio irq thread, which can occur as a result of high system load (eg, while udev is running.)
--- drivers/mmc/core/sdio_irq.c | 41 +++++++++++++++++++++++++++++++---------- include/linux/mmc/host.h | 3 +++ 2 files changed, 34 insertions(+), 10 deletions(-)
drivers/mmc/core/sdio_irq.c +31 -10
@@ -90,6 +90,15 @@ static int process_sdio_pending_irqs(struct mmc_host *host)return ret; } +void sdio_run_irqs (struct mmc_host *host) +{ +mmc_claim_host (host); + host->sdio_irq_pending = true; +process_sdio_pending_irqs (host); +mmc_release_host (host); +} +EXPORT_SYMBOL_GPL (sdio_run_irqs); +static int sdio_irq_thread (void *_host) {struct mmc_host *host = _host;
@@ -189,14 +198,20 @@ static int sdio_card_irq_get(struct mmc_card *card)WARN_ON (!host->claimed);if (!host->sdio_irqs++) { -atomic_set (&host->sdio_irq_thread_abort,0 ); - host->sdio_irq_thread = -kthread_run (sdio_irq_thread, host,"ksdioirqd/%s" , -mmc_hostname (host)); -if (IS_ERR (host->sdio_irq_thread)) { -int err =PTR_ERR (host->sdio_irq_thread); - host->sdio_irqs--; -return err; +if (!(host->caps2 &MMC_CAP2_SDIO_IRQ_NOTHREAD )) { +atomic_set (&host->sdio_irq_thread_abort,0 ); + host->sdio_irq_thread = +kthread_run (sdio_irq_thread, host, +"ksdioirqd/%s" ,mmc_hostname (host)); +if (IS_ERR (host->sdio_irq_thread)) { +int err =PTR_ERR (host->sdio_irq_thread); + host->sdio_irqs--; +return err; + } + }else { +mmc_host_clk_hold (host); + host->ops->enable_sdio_irq (host,1 ); +mmc_host_clk_release (host); } }
@@ -211,8 +226,14 @@ static int sdio_card_irq_put(struct mmc_card *card)BUG_ON (host->sdio_irqs <1 );if (!--host->sdio_irqs) { -atomic_set (&host->sdio_irq_thread_abort,1 ); -kthread_stop (host->sdio_irq_thread); +if (!(host->caps2 &MMC_CAP2_SDIO_IRQ_NOTHREAD )) { +atomic_set (&host->sdio_irq_thread_abort,1 ); +kthread_stop (host->sdio_irq_thread); + }else { +mmc_host_clk_hold (host); + host->ops->enable_sdio_irq (host,0 ); +mmc_host_clk_release (host); + } }return 0 ;
include/linux/mmc/host.h +3 -0
@@ -278,6 +278,7 @@ struct mmc_host {#define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \ MMC_CAP2_PACKED_WR)#define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)/* Don't power up before scan */ +#define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 15)mmc_pm_flag_t pm_caps;/* supported pm features */
@@ -391,6 +392,8 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)wake_up_process (host->sdio_irq_thread); } +void sdio_run_irqs (struct mmc_host *host); +#ifdef CONFIG_REGULATOR int mmc_regulator_get_ocrmask (struct regulator *supply); int mmc_regulator_set_ocr(struct mmc_host *mmc,
Signature · 1 line
1.8.3.1
PATCH 186/222 mmc: sdhci: clean up interrupt handling
In reply to Russell King - ARM Linuxsdhci interrupt handling is a mess; there is a lot of code doing very similar things. Let's clean this up a bit:
1. set's clear down cmd, data and bus power interrupts in one go - we're always going to handle these.
2. use a do { } while () loop for looping while there are pending interrupts.
3. group clearing of bits in intmask into one place.
This results in the code becoming simpler and easier to read.
--- drivers/mmc/host/sdhci.c | 124 ++++++++++++++++++++++------------------------- 1 file changed, 58 insertions(+), 66 deletions(-)
drivers/mmc/host/sdhci.c +58 -66
@@ -2426,7 +2426,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) {irqreturn_t result;struct sdhci_host *host = dev_id; -u32 intmask, unexpected =0 ; +u32 intmask, mask, unexpected =0 ;int cardint =0 , max_loops =16 ;spin_lock (&host->lock);
@@ -2437,88 +2437,80 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) } intmask =sdhci_readl (host,SDHCI_INT_STATUS ); -if (!intmask || intmask ==0xffffffff ) { result =IRQ_NONE ; goto out; } -again: -DBG ("*** %s got interrupt: 0x%08x\n" , -mmc_hostname (host->mmc), intmask); - -if (intmask & (SDHCI_INT_CARD_INSERT |SDHCI_INT_CARD_REMOVE )) { -u32 present =sdhci_readl (host,SDHCI_PRESENT_STATE ) & -SDHCI_CARD_PRESENT ; - -/* -* There is a observation on i.mx esdhc. INSERT bit will be -* immediately set again when it gets cleared, if a card is -* inserted. We have to mask the irq to prevent interrupt -* storm which will freeze the system. And the REMOVE gets -* the same situation. -* -* More testing are needed here to ensure it works for other -* platforms though. -*/ -sdhci_mask_irqs (host, present ?SDHCI_INT_CARD_INSERT : -SDHCI_INT_CARD_REMOVE ); -sdhci_unmask_irqs (host, present ?SDHCI_INT_CARD_REMOVE : -SDHCI_INT_CARD_INSERT ); - -sdhci_writel (host, intmask & (SDHCI_INT_CARD_INSERT | -SDHCI_INT_CARD_REMOVE ),SDHCI_INT_STATUS ); - intmask &= ~(SDHCI_INT_CARD_INSERT |SDHCI_INT_CARD_REMOVE ); -tasklet_schedule (&host->card_tasklet); - } +do { +/* Clear selected interrupts. */ + mask = intmask & (SDHCI_INT_CMD_MASK |SDHCI_INT_DATA_MASK | +SDHCI_INT_BUS_POWER ); +sdhci_writel (host, mask,SDHCI_INT_STATUS ); -if (intmask &SDHCI_INT_CMD_MASK ) { -sdhci_writel (host, intmask &SDHCI_INT_CMD_MASK , -SDHCI_INT_STATUS ); -sdhci_cmd_irq (host, intmask &SDHCI_INT_CMD_MASK ); - } +DBG ("*** %s got interrupt: 0x%08x\n" , +mmc_hostname (host->mmc), intmask); -if (intmask &SDHCI_INT_DATA_MASK ) { -sdhci_writel (host, intmask &SDHCI_INT_DATA_MASK , -SDHCI_INT_STATUS ); -sdhci_data_irq (host, intmask &SDHCI_INT_DATA_MASK ); - } +if (intmask & (SDHCI_INT_CARD_INSERT |SDHCI_INT_CARD_REMOVE )) { +u32 present =sdhci_readl (host,SDHCI_PRESENT_STATE ) & +SDHCI_CARD_PRESENT ; - intmask &= ~(SDHCI_INT_CMD_MASK |SDHCI_INT_DATA_MASK ); +/* +* There is a observation on i.mx esdhc. INSERT +* bit will be immediately set again when it gets +* cleared, if a card is inserted. We have to mask +* the irq to prevent interrupt storm which will +* freeze the system. And the REMOVE gets the +* same situation. +* +* More testing are needed here to ensure it works +* for other platforms though. +*/ +sdhci_mask_irqs (host, present ?SDHCI_INT_CARD_INSERT : +SDHCI_INT_CARD_REMOVE ); +sdhci_unmask_irqs (host, present ?SDHCI_INT_CARD_REMOVE : +SDHCI_INT_CARD_INSERT ); + +sdhci_writel (host, intmask & (SDHCI_INT_CARD_INSERT | +SDHCI_INT_CARD_REMOVE ),SDHCI_INT_STATUS ); +tasklet_schedule (&host->card_tasklet); + } - intmask &= ~SDHCI_INT_ERROR ; +if (intmask &SDHCI_INT_CMD_MASK ) +sdhci_cmd_irq (host, intmask &SDHCI_INT_CMD_MASK ); -if (intmask &SDHCI_INT_BUS_POWER ) { -pr_err ("%s: Card is consuming too much power!\n" , -mmc_hostname (host->mmc)); -sdhci_writel (host,SDHCI_INT_BUS_POWER ,SDHCI_INT_STATUS ); - } +if (intmask &SDHCI_INT_DATA_MASK ) +sdhci_data_irq (host, intmask &SDHCI_INT_DATA_MASK ); - intmask &= ~SDHCI_INT_BUS_POWER ; +if (intmask &SDHCI_INT_BUS_POWER ) +pr_err ("%s: Card is consuming too much power!\n" , +mmc_hostname (host->mmc)); -if (intmask &SDHCI_INT_CARD_INT ) - cardint =1 ; +if (intmask &SDHCI_INT_CARD_INT ) + cardint =1 ; - intmask &= ~SDHCI_INT_CARD_INT ; + intmask &= ~(SDHCI_INT_CARD_INSERT |SDHCI_INT_CARD_REMOVE | +SDHCI_INT_CMD_MASK |SDHCI_INT_DATA_MASK | +SDHCI_INT_ERROR |SDHCI_INT_BUS_POWER | +SDHCI_INT_CARD_INT ); -if (intmask) { - unexpected |= intmask; -sdhci_writel (host, intmask,SDHCI_INT_STATUS ); - } +if (intmask) { + unexpected |= intmask; +sdhci_writel (host, intmask,SDHCI_INT_STATUS ); + } - result =IRQ_HANDLED ; + result =IRQ_HANDLED ; - intmask =sdhci_readl (host,SDHCI_INT_STATUS ); + intmask =sdhci_readl (host,SDHCI_INT_STATUS ); -/* -* If we know we'll call the driver to signal SDIO IRQ, disregard -* further indications of Card Interrupt in the status to avoid a -* needless loop. -*/ -if (cardint) - intmask &= ~SDHCI_INT_CARD_INT ; -if (intmask && --max_loops) - goto again; +/* +* If we know we'll call the driver to signal SDIO IRQ, +* disregard further indications of Card Interrupt in +* the status to avoid a needless loop. +*/ +if (cardint) + intmask &= ~SDHCI_INT_CARD_INT ; + }while (intmask && --max_loops); out:spin_unlock (&host->lock);
Signature · 1 line
1.8.3.1
PATCH 187/222 mmc: sdhci: clean up sdio interrupt enable handling
In reply to Russell King - ARM LinuxWe don't need to change the SDHCI_SDIO_IRQ_ENABLED flag when we're merely receiving an interrupt - IRQ handling thread in the MMC core will either re-enable or disable the interrupt via the enable_sdio_irq callback, which will update this status appropriately.
--- drivers/mmc/host/sdhci.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-)
drivers/mmc/host/sdhci.c +17 -18
@@ -1709,24 +1709,14 @@ static int sdhci_get_ro(struct mmc_host *mmc)static void sdhci_enable_sdio_irq_nolock (struct sdhci_host *host,int enable) { -if (host->flags &SDHCI_DEVICE_DEAD ) - goto out; - -if (enable) - host->flags |=SDHCI_SDIO_IRQ_ENABLED ; -else - host->flags &= ~SDHCI_SDIO_IRQ_ENABLED ; -/* SDIO IRQ will be enabled as appropriate in runtime resume */ -if (host->runtime_suspended) - goto out; - -if (enable) -sdhci_unmask_irqs (host,SDHCI_INT_CARD_INT ); -else -sdhci_mask_irqs (host,SDHCI_INT_CARD_INT ); -out: -mmiowb (); +if (!(host->flags &SDHCI_DEVICE_DEAD ) || host->runtime_suspended) { +if (enable) +sdhci_unmask_irqs (host,SDHCI_INT_CARD_INT ); +else +sdhci_mask_irqs (host,SDHCI_INT_CARD_INT ); +mmiowb (); + } }static void sdhci_enable_sdio_irq (struct mmc_host *mmc,int enable)
@@ -1734,9 +1724,18 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)struct sdhci_host *host =mmc_priv (mmc);unsigned long flags; +sdhci_runtime_pm_get (host); +spin_lock_irqsave (&host->lock, flags); +if (enable) + host->flags |=SDHCI_SDIO_IRQ_ENABLED ; +else + host->flags &= ~SDHCI_SDIO_IRQ_ENABLED ; +sdhci_enable_sdio_irq_nolock (host, enable);spin_unlock_irqrestore (&host->lock, flags); + +sdhci_runtime_pm_put (host); } static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
@@ -2721,7 +2720,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) host->runtime_suspended = false;/* Enable SDIO IRQ */ -if ((host->flags &SDHCI_SDIO_IRQ_ENABLED )) +if (host->flags &SDHCI_SDIO_IRQ_ENABLED )sdhci_enable_sdio_irq_nolock (host, true);/* Enable Card Detection */
Signature · 1 line
1.8.3.1
PATCH 188/222 mmc: sdhci: convert to new SDIO IRQ handling
In reply to Russell King - ARM LinuxUse a generic threaded interrupt handler for SDIO interrupt handling, rather than allowing the SDIO core code to buggily spawn its own thread. This results in host drivers to be more in control of how SDIO interrupts are acknowledged in the hardware, rather than having the internals of the SDIO core placed upon them, possibly resulting in sub-standard handling.
At least one SDHCI implementation specifies a very specific sequence to deal with a card interrupt.
--- drivers/mmc/host/sdhci.c | 62 +++++++++++++++++++++++++++++------------------ include/linux/mmc/sdhci.h | 2 ++ 2 files changed, 41 insertions(+), 23 deletions(-)
drivers/mmc/host/sdhci.c +39 -23
@@ -2423,10 +2423,10 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)static irqreturn_t sdhci_irq (int irq,void *dev_id) { -irqreturn_t result; +irqreturn_t result =IRQ_NONE ;struct sdhci_host *host = dev_id;u32 intmask, mask, unexpected =0 ; -int cardint =0 , max_loops =16 ; +int max_loops =16 ;spin_lock (&host->lock);
@@ -2485,8 +2485,11 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)pr_err ("%s: Card is consuming too much power!\n" ,mmc_hostname (host->mmc)); -if (intmask &SDHCI_INT_CARD_INT ) - cardint =1 ; +if (intmask &SDHCI_INT_CARD_INT ) { +sdhci_enable_sdio_irq_nolock (host, false); + host->thread_isr |=SDHCI_INT_CARD_INT ; + result =IRQ_WAKE_THREAD ; + } intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE | SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
@@ -2498,17 +2501,10 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)sdhci_writel (host, intmask,SDHCI_INT_STATUS ); } - result =IRQ_HANDLED ; +if (result ==IRQ_NONE ) + result =IRQ_HANDLED ; intmask =sdhci_readl (host,SDHCI_INT_STATUS ); - -/* -* If we know we'll call the driver to signal SDIO IRQ, -* disregard further indications of Card Interrupt in -* the status to avoid a needless loop. -*/ -if (cardint) - intmask &= ~SDHCI_INT_CARD_INT ; }while (intmask && --max_loops); out:spin_unlock (&host->lock);
@@ -2518,15 +2514,33 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) mmc_hostname(host->mmc), unexpected);sdhci_dumpregs (host); } -/* -* We have to delay this as it calls back into the driver. -*/ -if (cardint) -mmc_signal_sdio_irq (host->mmc);return result; } +static irqreturn_t sdhci_thread_irq (int irq,void *dev_id) +{ +struct sdhci_host *host = dev_id; +unsigned long flags; +u32 isr; + +spin_lock_irqsave (&host->lock, flags); + isr = host->thread_isr; + host->thread_isr =0 ; +spin_unlock_irqrestore (&host->lock, flags); + +if (isr &SDHCI_INT_CARD_INT ) { +sdio_run_irqs (host->mmc); + +spin_lock_irqsave (&host->lock, flags); +if (host->flags &SDHCI_SDIO_IRQ_ENABLED ) +sdhci_enable_sdio_irq_nolock (host, true); +spin_unlock_irqrestore (&host->lock, flags); + } + +return isr ?IRQ_HANDLED :IRQ_NONE ; +} +/*****************************************************************************\ * * * Suspend/resume *
@@ -2596,8 +2610,9 @@ int sdhci_resume_host(struct sdhci_host *host) }if (!device_may_wakeup (mmc_dev (host->mmc))) { - ret =request_irq (host->irq, sdhci_irq,IRQF_SHARED , -mmc_hostname (host->mmc), host); + ret =request_threaded_irq (host->irq, sdhci_irq, + sdhci_thread_irq,IRQF_SHARED , +mmc_hostname (host->mmc), host);if (ret)return ret; }else {
@@ -2676,7 +2691,7 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)sdhci_mask_irqs (host,SDHCI_INT_ALL_MASK );spin_unlock_irqrestore (&host->lock, flags); -synchronize_irq (host->irq); +synchronize_hardirq (host->irq);spin_lock_irqsave (&host->lock, flags); host->runtime_suspended = true;
@@ -2932,6 +2947,7 @@ int sdhci_add_host(struct sdhci_host *host) mmc->max_busy_timeout = (1 <<27 ) / host->timeout_clk; mmc->caps |=MMC_CAP_SDIO_IRQ |MMC_CAP_ERASE |MMC_CAP_CMD23 ; + mmc->caps2 |=MMC_CAP2_SDIO_IRQ_NOTHREAD ;if (host->quirks &SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 ) host->flags |=SDHCI_AUTO_CMD12 ;
@@ -3221,8 +3237,8 @@ int sdhci_add_host(struct sdhci_host *host)sdhci_init (host,0 ); - ret =request_irq (host->irq, sdhci_irq,IRQF_SHARED , -mmc_hostname (mmc), host); + ret =request_threaded_irq (host->irq, sdhci_irq, sdhci_thread_irq, +IRQF_SHARED ,mmc_hostname (mmc), host);if (ret) {pr_err ("%s: Failed to request IRQ %d: %d\n" ,mmc_hostname (mmc), host->irq, ret);
include/linux/mmc/sdhci.h +2 -0
@@ -177,6 +177,8 @@ struct sdhci_host {unsigned int ocr_avail_mmc;u32 ocr_mask;/* available voltages */ +u32 thread_isr; +wait_queue_head_t buf_ready_int;/* Waitqueue for Buffer Read Ready interrupt */ unsigned int tuning_done;/* Condition flag set when CMD19 succeeds */
Signature · 1 line
1.8.3.1
PATCH 189/222 mmc: sdhci: push card_tasklet into threaded irq handler
In reply to Russell King - ARM LinuxThere's no requirement to have the card tasklet separate now that we have a threaded interrupt handler, so kill this and move the called code into the threaded part of the handler.
--- drivers/mmc/host/sdhci.c | 23 +++++++++-------------- include/linux/mmc/sdhci.h | 3 +-- 2 files changed, 10 insertions(+), 16 deletions(-)
drivers/mmc/host/sdhci.c +9 -14
@@ -2123,15 +2123,6 @@ static const struct mmc_host_ops sdhci_ops = {* * \*****************************************************************************/ -static void sdhci_tasklet_card (unsigned long param) -{ -struct sdhci_host *host = (struct sdhci_host *)param; - -sdhci_card_event (host->mmc); - -mmc_detect_change (host->mmc,msecs_to_jiffies (200 )); -} -static void sdhci_tasklet_finish (unsigned long param) {struct sdhci_host *host;
@@ -2472,7 +2463,10 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)sdhci_writel (host, intmask & (SDHCI_INT_CARD_INSERT |SDHCI_INT_CARD_REMOVE ),SDHCI_INT_STATUS ); -tasklet_schedule (&host->card_tasklet); + + host->thread_isr |= intmask & (SDHCI_INT_CARD_INSERT | +SDHCI_INT_CARD_REMOVE ); + result =IRQ_WAKE_THREAD ; }if (intmask &SDHCI_INT_CMD_MASK )
@@ -2529,6 +2523,11 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id) host->thread_isr =0 ;spin_unlock_irqrestore (&host->lock, flags); +if (isr & (SDHCI_INT_CARD_INSERT |SDHCI_INT_CARD_REMOVE )) { +sdhci_card_event (host->mmc); +mmc_detect_change (host->mmc,msecs_to_jiffies (200 )); + } +if (isr &SDHCI_INT_CARD_INT ) {sdio_run_irqs (host->mmc);
@@ -3219,8 +3218,6 @@ int sdhci_add_host(struct sdhci_host *host)/* * Init tasklets. */ -tasklet_init (&host->card_tasklet, - sdhci_tasklet_card, (unsigned long )host);tasklet_init (&host->finish_tasklet, sdhci_tasklet_finish, (unsigned long )host);
@@ -3285,7 +3282,6 @@ int sdhci_add_host(struct sdhci_host *host)free_irq (host->irq, host);#endif untasklet: -tasklet_kill (&host->card_tasklet);tasklet_kill (&host->finish_tasklet);return ret;
@@ -3329,7 +3325,6 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)del_timer_sync (&host->timer); -tasklet_kill (&host->card_tasklet);tasklet_kill (&host->finish_tasklet);if (host->vmmc) {
include/linux/mmc/sdhci.h +1 -2
@@ -164,8 +164,7 @@ struct sdhci_host {dma_addr_t adma_addr;/* Mapped ADMA descr. table */ dma_addr_t align_addr;/* Mapped bounce buffer */ -struct tasklet_struct card_tasklet;/* Tasklet structures */ -struct tasklet_struct finish_tasklet; +struct tasklet_struct finish_tasklet;/* Tasklet structures */ struct timer_list timer;/* Timer for timeouts */
Signature · 1 line
1.8.3.1
PATCH 190/222 mmc: sdhci: allow sdio interrupts while sdhci runtime suspended
In reply to Russell King - ARM LinuxAllow SDIO interrupts to be received while the SDHCI host is runtime suspended. We do this by leaving the AHB clock enabled while the host is runtime suspended so we can access the SDHCI registers, and so read and raise the SDIO card interrupt.
--- drivers/mmc/host/sdhci-esdhc-imx.c | 12 ++++++++---- drivers/mmc/host/sdhci.c | 7 +++---- drivers/mmc/host/sdhci.h | 5 +++++ 3 files changed, 16 insertions(+), 8 deletions(-)
drivers/mmc/host/sdhci-esdhc-imx.c +8 -4
@@ -1170,8 +1170,10 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev) ret =sdhci_runtime_suspend_host (host); -clk_disable_unprepare (imx_data->clk_per); -clk_disable_unprepare (imx_data->clk_ipg); +if (!sdhci_sdio_irq_enabled (host)) { +clk_disable_unprepare (imx_data->clk_per); +clk_disable_unprepare (imx_data->clk_ipg); + }clk_disable_unprepare (imx_data->clk_ahb);return ret;
@@ -1183,8 +1185,10 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct pltfm_imx_data *imx_data = pltfm_host->priv; -clk_prepare_enable (imx_data->clk_per); -clk_prepare_enable (imx_data->clk_ipg); +if (!sdhci_sdio_irq_enabled (host)) { +clk_prepare_enable (imx_data->clk_per); +clk_prepare_enable (imx_data->clk_ipg); + }clk_prepare_enable (imx_data->clk_ahb);return sdhci_runtime_resume_host (host);
drivers/mmc/host/sdhci.c +3 -4
@@ -1709,8 +1709,7 @@ static int sdhci_get_ro(struct mmc_host *mmc)static void sdhci_enable_sdio_irq_nolock (struct sdhci_host *host,int enable) { -/* SDIO IRQ will be enabled as appropriate in runtime resume */ -if (!(host->flags &SDHCI_DEVICE_DEAD ) || host->runtime_suspended) { +if (!(host->flags &SDHCI_DEVICE_DEAD )) {if (enable)sdhci_unmask_irqs (host,SDHCI_INT_CARD_INT );else
@@ -2421,7 +2420,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)spin_lock (&host->lock); -if (host->runtime_suspended) { +if (host->runtime_suspended && !sdhci_sdio_irq_enabled (host)) {spin_unlock (&host->lock);return IRQ_NONE ; }
@@ -2687,7 +2686,7 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host) }spin_lock_irqsave (&host->lock, flags); -sdhci_mask_irqs (host,SDHCI_INT_ALL_MASK ); +sdhci_mask_irqs (host,SDHCI_INT_ALL_MASK & ~SDHCI_INT_CARD_INT );spin_unlock_irqrestore (&host->lock, flags);synchronize_hardirq (host->irq);
drivers/mmc/host/sdhci.h +5 -0
@@ -397,6 +397,11 @@ extern void sdhci_remove_host(struct sdhci_host *host, int dead);extern void sdhci_send_command (struct sdhci_host *host,struct mmc_command *cmd); +static inline bool sdhci_sdio_irq_enabled (struct sdhci_host *host) +{ +return !!(host->flags &SDHCI_SDIO_IRQ_ENABLED ); +} +#ifdef CONFIG_PM extern int sdhci_suspend_host (struct sdhci_host *host);extern int sdhci_resume_host (struct sdhci_host *host);
Signature · 1 line
1.8.3.1
PATCH 191/222 mmc: sdhci: more efficient interrupt enable register handling
In reply to Russell King - ARM LinuxRather than wasting cycles read-modify-writing the interrupt enable registers, cache the value locally instead.
--- drivers/mmc/host/sdhci.c | 98 +++++++++++++++++++++++------------------------ include/linux/mmc/sdhci.h | 3 ++ 2 files changed, 50 insertions(+), 51 deletions(-)
drivers/mmc/host/sdhci.c +47 -51
@@ -131,27 +131,6 @@ static void sdhci_dumpregs(struct sdhci_host *host)* * \*****************************************************************************/ -static void sdhci_clear_set_irqs (struct sdhci_host *host,u32 clear,u32 set) -{ -u32 ier; - - ier =sdhci_readl (host,SDHCI_INT_ENABLE ); - ier &= ~clear; - ier |= set; -sdhci_writel (host, ier,SDHCI_INT_ENABLE ); -sdhci_writel (host, ier,SDHCI_SIGNAL_ENABLE ); -} - -static void sdhci_unmask_irqs (struct sdhci_host *host,u32 irqs) -{ -sdhci_clear_set_irqs (host,0 , irqs); -} - -static void sdhci_mask_irqs (struct sdhci_host *host,u32 irqs) -{ -sdhci_clear_set_irqs (host, irqs,0 ); -} -static void sdhci_set_card_detection (struct sdhci_host *host,bool enable) {u32 present, irqs;
@@ -165,9 +144,12 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) irqs = present ?SDHCI_INT_CARD_REMOVE :SDHCI_INT_CARD_INSERT ;if (enable) -sdhci_unmask_irqs (host, irqs); + host->ier |= irqs;else -sdhci_mask_irqs (host, irqs); + host->ier &= ~irqs; + +sdhci_writel (host, host->ier,SDHCI_INT_ENABLE ); +sdhci_writel (host, host->ier,SDHCI_SIGNAL_ENABLE ); }static void sdhci_enable_card_detection (struct sdhci_host *host)
@@ -183,17 +165,12 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)static void sdhci_reset (struct sdhci_host *host,u8 mask) {unsigned long timeout; -u32 uninitialized_var (ier ); -if (host->quirks &SDHCI_QUIRK_NO_CARD_NO_RESET ) {if (!(sdhci_readl (host,SDHCI_PRESENT_STATE ) &SDHCI_CARD_PRESENT ))return ; } -if (host->quirks &SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET ) - ier =sdhci_readl (host,SDHCI_INT_ENABLE ); -if (host->ops->platform_reset_enter) host->ops->platform_reset_enter (host, mask);
@@ -224,8 +201,10 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)if (host->ops->platform_reset_exit) host->ops->platform_reset_exit (host, mask); -if (host->quirks &SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET ) -sdhci_clear_set_irqs (host,SDHCI_INT_ALL_MASK , ier); +if (host->quirks &SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET ) { +sdhci_writel (host, host->ier,SDHCI_INT_ENABLE ); +sdhci_writel (host, host->ier,SDHCI_SIGNAL_ENABLE ); + }if (host->flags & (SDHCI_USE_SDMA |SDHCI_USE_ADMA )) {if ((host->ops->enable_dma) && (mask &SDHCI_RESET_ALL ))
@@ -242,11 +221,14 @@ static void sdhci_init(struct sdhci_host *host, int soft)else sdhci_reset (host,SDHCI_RESET_ALL ); -sdhci_clear_set_irqs (host,SDHCI_INT_ALL_MASK , -SDHCI_INT_BUS_POWER |SDHCI_INT_DATA_END_BIT | -SDHCI_INT_DATA_CRC |SDHCI_INT_DATA_TIMEOUT |SDHCI_INT_INDEX | -SDHCI_INT_END_BIT |SDHCI_INT_CRC |SDHCI_INT_TIMEOUT | -SDHCI_INT_DATA_END |SDHCI_INT_RESPONSE ); + host->ier =SDHCI_INT_BUS_POWER |SDHCI_INT_DATA_END_BIT | +SDHCI_INT_DATA_CRC |SDHCI_INT_DATA_TIMEOUT | +SDHCI_INT_INDEX |SDHCI_INT_END_BIT |SDHCI_INT_CRC | +SDHCI_INT_TIMEOUT |SDHCI_INT_DATA_END | +SDHCI_INT_RESPONSE ; + +sdhci_writel (host, host->ier,SDHCI_INT_ENABLE ); +sdhci_writel (host, host->ier,SDHCI_SIGNAL_ENABLE );if (soft) {/* force clock reconfiguration */
@@ -721,9 +703,12 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)u32 dma_irqs =SDHCI_INT_DMA_END |SDHCI_INT_ADMA_ERROR ;if (host->flags &SDHCI_REQ_USE_DMA ) -sdhci_clear_set_irqs (host, pio_irqs, dma_irqs); + host->ier = (host->ier & ~pio_irqs) | dma_irqs;else -sdhci_clear_set_irqs (host, dma_irqs, pio_irqs); + host->ier = (host->ier & ~dma_irqs) | pio_irqs; + +sdhci_writel (host, host->ier,SDHCI_INT_ENABLE ); +sdhci_writel (host, host->ier,SDHCI_SIGNAL_ENABLE ); }static void sdhci_prepare_data (struct sdhci_host *host,struct mmc_command *cmd)
@@ -1711,9 +1696,12 @@ static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable) {if (!(host->flags &SDHCI_DEVICE_DEAD )) {if (enable) -sdhci_unmask_irqs (host,SDHCI_INT_CARD_INT ); + host->ier |=SDHCI_INT_CARD_INT ;else -sdhci_mask_irqs (host,SDHCI_INT_CARD_INT ); + host->ier &= ~SDHCI_INT_CARD_INT ; + +sdhci_writel (host, host->ier,SDHCI_INT_ENABLE ); +sdhci_writel (host, host->ier,SDHCI_SIGNAL_ENABLE );mmiowb (); } }
@@ -1855,7 +1843,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) {struct sdhci_host *host;u16 ctrl; -u32 ier;int tuning_loop_counter =MAX_TUNING_LOOP ;unsigned long timeout;int err =0 ;
@@ -1909,8 +1896,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)* to make sure we don't hit a controller bug, we _only_ * enable Buffer Read Ready interrupt here. */ - ier =sdhci_readl (host,SDHCI_INT_ENABLE ); -sdhci_clear_set_irqs (host, ier,SDHCI_INT_DATA_AVAIL ); +sdhci_writel (host,SDHCI_INT_DATA_AVAIL ,SDHCI_INT_ENABLE ); +sdhci_writel (host,SDHCI_INT_DATA_AVAIL ,SDHCI_SIGNAL_ENABLE );/* * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
@@ -2042,7 +2029,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)if (err && (host->flags &SDHCI_USING_RETUNING_TIMER )) err =0 ; -sdhci_clear_set_irqs (host,SDHCI_INT_DATA_AVAIL , ier); +sdhci_writel (host, host->ier,SDHCI_INT_ENABLE ); +sdhci_writel (host, host->ier,SDHCI_SIGNAL_ENABLE );spin_unlock_irqrestore (&host->lock, flags);sdhci_runtime_pm_put (host);
@@ -2455,10 +2443,12 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)* More testing are needed here to ensure it works * for other platforms though. */ -sdhci_mask_irqs (host, present ?SDHCI_INT_CARD_INSERT : -SDHCI_INT_CARD_REMOVE ); -sdhci_unmask_irqs (host, present ?SDHCI_INT_CARD_REMOVE : -SDHCI_INT_CARD_INSERT ); + host->ier &= ~(SDHCI_INT_CARD_INSERT | +SDHCI_INT_CARD_REMOVE ); + host->ier |= present ?SDHCI_INT_CARD_REMOVE : +SDHCI_INT_CARD_INSERT ; +sdhci_writel (host, host->ier,SDHCI_INT_ENABLE ); +sdhci_writel (host, host->ier,SDHCI_SIGNAL_ENABLE );sdhci_writel (host, intmask & (SDHCI_INT_CARD_INSERT |SDHCI_INT_CARD_REMOVE ),SDHCI_INT_STATUS );
@@ -2587,7 +2577,9 @@ int sdhci_suspend_host(struct sdhci_host *host) }if (!device_may_wakeup (mmc_dev (host->mmc))) { -sdhci_mask_irqs (host,SDHCI_INT_ALL_MASK ); + host->ier =0 ; +sdhci_writel (host,0 ,SDHCI_INT_ENABLE ); +sdhci_writel (host,0 ,SDHCI_SIGNAL_ENABLE );free_irq (host->irq, host); }else {sdhci_enable_irq_wakeups (host);
@@ -2686,7 +2678,9 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host) }spin_lock_irqsave (&host->lock, flags); -sdhci_mask_irqs (host,SDHCI_INT_ALL_MASK & ~SDHCI_INT_CARD_INT ); + host->ier &=SDHCI_INT_CARD_INT ; +sdhci_writel (host, host->ier,SDHCI_INT_ENABLE ); +sdhci_writel (host, host->ier,SDHCI_SIGNAL_ENABLE );spin_unlock_irqrestore (&host->lock, flags);synchronize_hardirq (host->irq);
@@ -3277,7 +3271,8 @@ int sdhci_add_host(struct sdhci_host *host)#ifdef SDHCI_USE_LEDS_CLASS reset:sdhci_reset (host,SDHCI_RESET_ALL ); -sdhci_mask_irqs (host,SDHCI_INT_ALL_MASK ); +sdhci_writel (host,0 ,SDHCI_INT_ENABLE ); +sdhci_writel (host,0 ,SDHCI_SIGNAL_ENABLE );free_irq (host->irq, host);#endif untasklet:
@@ -3319,7 +3314,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)if (!dead)sdhci_reset (host,SDHCI_RESET_ALL ); -sdhci_mask_irqs (host,SDHCI_INT_ALL_MASK ); +sdhci_writel (host,0 ,SDHCI_INT_ENABLE ); +sdhci_writel (host,0 ,SDHCI_SIGNAL_ENABLE );free_irq (host->irq, host);del_timer_sync (&host->timer);
include/linux/mmc/sdhci.h +3 -0
@@ -178,6 +178,9 @@ struct sdhci_host {u32 thread_isr; +/* cached registers */ +u32 ier; +wait_queue_head_t buf_ready_int;/* Waitqueue for Buffer Read Ready interrupt */ unsigned int tuning_done;/* Condition flag set when CMD19 succeeds */
Signature · 1 line
1.8.3.1
PATCH 192/222 mmc: sdhci: plug hole in disabling card detection interrupts
In reply to Russell King - ARM LinuxWhen we disable card detection interrupts, we should disable both the insert and remove interrupts irrespective of the current state - this avoids races between the hardware card detect changing state before we've read that updated state and altered the interrupt mask.
--- drivers/mmc/host/sdhci.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
drivers/mmc/host/sdhci.c +9 -8
@@ -133,20 +133,21 @@ static void sdhci_dumpregs(struct sdhci_host *host)static void sdhci_set_card_detection (struct sdhci_host *host,bool enable) { -u32 present, irqs; +u32 present;if ((host->quirks &SDHCI_QUIRK_BROKEN_CARD_DETECTION ) || (host->mmc->caps &MMC_CAP_NONREMOVABLE ))return ; - present =sdhci_readl (host,SDHCI_PRESENT_STATE ) & -SDHCI_CARD_PRESENT ; - irqs = present ?SDHCI_INT_CARD_REMOVE :SDHCI_INT_CARD_INSERT ; +if (enable) { + present =sdhci_readl (host,SDHCI_PRESENT_STATE ) & +SDHCI_CARD_PRESENT ; -if (enable) - host->ier |= irqs; -else - host->ier &= ~irqs; + host->ier |= present ?SDHCI_INT_CARD_REMOVE : +SDHCI_INT_CARD_INSERT ; + }else { + host->ier &= ~(SDHCI_INT_CARD_REMOVE |SDHCI_INT_CARD_INSERT ); + }sdhci_writel (host, host->ier,SDHCI_INT_ENABLE );sdhci_writel (host, host->ier,SDHCI_SIGNAL_ENABLE );
Signature · 1 line
1.8.3.1
PATCH 193/222 mmc: sdhci: convert generic bus width setup to library function
In reply to Russell King - ARM Linux--- drivers/mmc/host/sdhci-acpi.c | 2 ++ drivers/mmc/host/sdhci-bcm-kona.c | 1 + drivers/mmc/host/sdhci-bcm2835.c | 1 + drivers/mmc/host/sdhci-cns3xxx.c | 1 + drivers/mmc/host/sdhci-dove.c | 1 + drivers/mmc/host/sdhci-esdhc-imx.c | 6 ++--- drivers/mmc/host/sdhci-of-arasan.c | 1 + drivers/mmc/host/sdhci-of-esdhc.c | 6 ++--- drivers/mmc/host/sdhci-of-hlwd.c | 1 + drivers/mmc/host/sdhci-pci.c | 6 ++--- drivers/mmc/host/sdhci-pltfm.c | 1 + drivers/mmc/host/sdhci-pxav2.c | 6 ++--- drivers/mmc/host/sdhci-pxav3.c | 1 + drivers/mmc/host/sdhci-s3c.c | 8 +++---- drivers/mmc/host/sdhci-sirf.c | 1 + drivers/mmc/host/sdhci-spear.c | 2 +- drivers/mmc/host/sdhci-tegra.c | 5 ++--- drivers/mmc/host/sdhci.c | 45 +++++++++++++++++++------------------- drivers/mmc/host/sdhci.h | 5 +++-- 19 files changed, 50 insertions(+), 50 deletions(-)
drivers/mmc/host/sdhci-acpi.c +2 -0
@@ -103,10 +103,12 @@ static void sdhci_acpi_int_hw_reset(struct sdhci_host *host)static const struct sdhci_ops sdhci_acpi_ops_dflt = { .enable_dma = sdhci_acpi_enable_dma, + .set_bus_width = sdhci_set_bus_width, };static const struct sdhci_ops sdhci_acpi_ops_int = { .enable_dma = sdhci_acpi_enable_dma, + .set_bus_width = sdhci_set_bus_width, .hw_reset = sdhci_acpi_int_hw_reset, };
drivers/mmc/host/sdhci-bcm-kona.c +1 -0
@@ -209,6 +209,7 @@ static struct sdhci_ops sdhci_bcm_kona_ops = { .get_max_clock = sdhci_bcm_kona_get_max_clk, .get_timeout_clock = sdhci_bcm_kona_get_timeout_clock, .platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks, + .set_bus_width = sdhci_set_bus_width, .card_event = sdhci_bcm_kona_card_event, };
drivers/mmc/host/sdhci-bcm2835.c +1 -0
@@ -133,6 +133,7 @@ static const struct sdhci_ops bcm2835_sdhci_ops = { .read_b = bcm2835_sdhci_readb, .get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_min_clock = bcm2835_sdhci_get_min_clock, + .set_bus_width = sdhci_set_bus_width, };static const struct sdhci_pltfm_data bcm2835_sdhci_pdata = {
drivers/mmc/host/sdhci-cns3xxx.c +1 -0
@@ -82,6 +82,7 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock)static const struct sdhci_ops sdhci_cns3xxx_ops = { .get_max_clock = sdhci_cns3xxx_get_max_clk, .set_clock = sdhci_cns3xxx_set_clock, + .set_bus_width = sdhci_set_bus_width, };static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
drivers/mmc/host/sdhci-dove.c +1 -0
@@ -86,6 +86,7 @@ static u32 sdhci_dove_readl(struct sdhci_host *host, int reg)static const struct sdhci_ops sdhci_dove_ops = { .read_w = sdhci_dove_readw, .read_l = sdhci_dove_readl, + .set_bus_width = sdhci_set_bus_width, };static const struct sdhci_pltfm_data sdhci_dove_pdata = {
drivers/mmc/host/sdhci-esdhc-imx.c +2 -4
@@ -668,7 +668,7 @@ static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)return -ENOSYS ; } -static int esdhc_pltfm_bus_width (struct sdhci_host *host,int width) +static void esdhc_pltfm_set_bus_width (struct sdhci_host *host,int width) {u32 ctrl;
@@ -686,8 +686,6 @@ static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)esdhc_clrset_le (host,ESDHC_CTRL_BUSWIDTH_MASK , ctrl,SDHCI_HOST_CONTROL ); - -return 0 ; }static void esdhc_prepare_tuning (struct sdhci_host *host,u32 val)
@@ -888,7 +886,7 @@ static struct sdhci_ops sdhci_esdhc_ops = { .get_max_clock = esdhc_pltfm_get_max_clock, .get_min_clock = esdhc_pltfm_get_min_clock, .get_ro = esdhc_pltfm_get_ro, - .platform_bus_width = esdhc_pltfm_bus_width, + .set_bus_width = esdhc_pltfm_set_bus_width, .set_uhs_signaling = esdhc_set_uhs_signaling, };
drivers/mmc/host/sdhci-of-arasan.c +1 -0
@@ -54,6 +54,7 @@ static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host)static struct sdhci_ops sdhci_arasan_ops = { .get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_timeout_clock = sdhci_arasan_get_timeout_clock, + .set_bus_width = sdhci_set_bus_width, };static struct sdhci_pltfm_data sdhci_arasan_pdata = {
drivers/mmc/host/sdhci-of-esdhc.c +2 -4
@@ -269,7 +269,7 @@ static void esdhc_of_platform_init(struct sdhci_host *host) host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ ; } -static int esdhc_pltfm_bus_width (struct sdhci_host *host,int width) +static void esdhc_pltfm_set_bus_width (struct sdhci_host *host,int width) {u32 ctrl;
@@ -289,8 +289,6 @@ static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)clrsetbits_be32 (host->ioaddr +SDHCI_HOST_CONTROL ,ESDHC_CTRL_BUSWIDTH_MASK , ctrl); - -return 0 ; }static const struct sdhci_ops sdhci_esdhc_ops = {
@@ -310,7 +308,7 @@ static const struct sdhci_ops sdhci_esdhc_ops = { .platform_resume = esdhc_of_resume, #endif .adma_workaround = esdhci_of_adma_workaround, - .platform_bus_width = esdhc_pltfm_bus_width, + .set_bus_width = esdhc_pltfm_set_bus_width, }; static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
drivers/mmc/host/sdhci-of-hlwd.c +1 -0
@@ -58,6 +58,7 @@ static const struct sdhci_ops sdhci_hlwd_ops = { .write_l = sdhci_hlwd_writel, .write_w = sdhci_hlwd_writew, .write_b = sdhci_hlwd_writeb, + .set_bus_width = sdhci_set_bus_width, };static const struct sdhci_pltfm_data sdhci_hlwd_pdata = {
drivers/mmc/host/sdhci-pci.c +2 -4
@@ -1031,7 +1031,7 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host)return 0 ; } -static int sdhci_pci_bus_width (struct sdhci_host *host,int width) +static void sdhci_pci_set_bus_width (struct sdhci_host *host,int width) {u8 ctrl;
@@ -1052,8 +1052,6 @@ static int sdhci_pci_bus_width(struct sdhci_host *host, int width) }sdhci_writeb (host, ctrl,SDHCI_HOST_CONTROL ); - -return 0 ; }static void sdhci_pci_gpio_hw_reset (struct sdhci_host *host)
@@ -1081,7 +1079,7 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host)static const struct sdhci_ops sdhci_pci_ops = { .enable_dma = sdhci_pci_enable_dma, - .platform_bus_width = sdhci_pci_bus_width, + .set_bus_width = sdhci_pci_set_bus_width, .hw_reset = sdhci_pci_hw_reset, };
drivers/mmc/host/sdhci-pltfm.c +1 -0
@@ -45,6 +45,7 @@ unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host)EXPORT_SYMBOL_GPL (sdhci_pltfm_clk_get_max_clock);static const struct sdhci_ops sdhci_pltfm_ops = { + .set_bus_width = sdhci_set_bus_width, };#ifdef CONFIG_OF
drivers/mmc/host/sdhci-pxav2.c +2 -4
@@ -88,7 +88,7 @@ static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask) } } -static int pxav2_mmc_set_width (struct sdhci_host *host,int width) +static void pxav2_mmc_set_bus_width (struct sdhci_host *host,int width) {u8 ctrl;u16 tmp;
@@ -107,14 +107,12 @@ static int pxav2_mmc_set_width(struct sdhci_host *host, int width) }writew (tmp, host->ioaddr +SD_CE_ATA_2 );writeb (ctrl, host->ioaddr +SDHCI_HOST_CONTROL ); - -return 0 ; }static const struct sdhci_ops pxav2_sdhci_ops = { .get_max_clock = sdhci_pltfm_clk_get_max_clock, .platform_reset_exit = pxav2_set_private_registers, - .platform_bus_width = pxav2_mmc_set_width, + .set_bus_width = pxav2_mmc_set_bus_width, };#ifdef CONFIG_OF
drivers/mmc/host/sdhci-pxav3.c +1 -0
@@ -227,6 +227,7 @@ static const struct sdhci_ops pxav3_sdhci_ops = { .set_uhs_signaling = pxav3_set_uhs_signaling, .platform_send_init_74_clocks = pxav3_gen_init_74_clocks, .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .set_bus_width = sdhci_set_bus_width, };static struct sdhci_pltfm_data sdhci_pxav3_pdata = {
drivers/mmc/host/sdhci-s3c.c +3 -5
@@ -329,14 +329,14 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) }/** -* sdhci_s3c_platform_bus_width - support 8bit buswidth +* sdhci_s3c_set_bus_width - support 8bit buswidth * @host: The SDHCI host being queried * @width: MMC_BUS_WIDTH_ macro for the bus width being requested * * We have 8-bit width support but is not a v3 controller. * So we add platform_bus_width() and support 8bit width. */ -static int sdhci_s3c_platform_bus_width (struct sdhci_host *host,int width) +static void sdhci_s3c_set_bus_width (struct sdhci_host *host,int width) {u8 ctrl;
@@ -358,15 +358,13 @@ static int sdhci_s3c_platform_bus_width(struct sdhci_host *host, int width) }sdhci_writeb (host, ctrl,SDHCI_HOST_CONTROL ); - -return 0 ; }static struct sdhci_ops sdhci_s3c_ops = { .get_max_clock = sdhci_s3c_get_max_clk, .set_clock = sdhci_s3c_set_clock, .get_min_clock = sdhci_s3c_get_min_clock, - .platform_bus_width = sdhci_s3c_platform_bus_width, + .set_bus_width = sdhci_s3c_set_bus_width, };static void sdhci_s3c_notify_change (struct platform_device *dev,int state)
drivers/mmc/host/sdhci-sirf.c +1 -0
@@ -29,6 +29,7 @@ static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host)static struct sdhci_ops sdhci_sirf_ops = { .get_max_clock = sdhci_sirf_get_max_clk, + .set_bus_width = sdhci_set_bus_width, };static struct sdhci_pltfm_data sdhci_sirf_pdata = {
drivers/mmc/host/sdhci-spear.c +1 -1
@@ -38,7 +38,7 @@ struct spear_sdhci {/* sdhci ops */ static const struct sdhci_ops sdhci_pltfm_ops = { -/* Nothing to do for now. */ + .set_bus_width = sdhci_set_bus_width, };#ifdef CONFIG_OF
drivers/mmc/host/sdhci-tegra.c +2 -3
@@ -127,7 +127,7 @@ static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask) } } -static int tegra_sdhci_buswidth (struct sdhci_host *host,int bus_width) +static void tegra_sdhci_set_bus_width (struct sdhci_host *host,int bus_width) {u32 ctrl;
@@ -144,7 +144,6 @@ static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width) ctrl &= ~SDHCI_CTRL_4BITBUS ; }sdhci_writeb (host, ctrl,SDHCI_HOST_CONTROL ); -return 0 ; }static const struct sdhci_ops tegra_sdhci_ops = {
@@ -152,7 +151,7 @@ static const struct sdhci_ops tegra_sdhci_ops = { .read_l = tegra_sdhci_readl, .read_w = tegra_sdhci_readw, .write_l = tegra_sdhci_writel, - .platform_bus_width = tegra_sdhci_buswidth, + .set_bus_width = tegra_sdhci_set_bus_width, .platform_reset_exit = tegra_sdhci_reset_exit, };
drivers/mmc/host/sdhci.c +22 -23
57 lines not on this page · raw message
drivers/mmc/host/sdhci.h +3 -2
@@ -281,8 +281,7 @@ struct sdhci_ops {unsigned int (*get_max_clock)(struct sdhci_host *host);unsigned int (*get_min_clock)(struct sdhci_host *host);unsigned int (*get_timeout_clock)(struct sdhci_host *host); -int (*platform_bus_width)(struct sdhci_host *host, -int width); +void (*set_bus_width)(struct sdhci_host *host,int width);void (*platform_send_init_74_clocks)(struct sdhci_host *host,u8 power_mode);unsigned int (*get_ro)(struct sdhci_host *host);
@@ -402,6 +401,8 @@ static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host)return !!(host->flags &SDHCI_SDIO_IRQ_ENABLED ); } +void sdhci_set_bus_width (struct sdhci_host *host,int width); +#ifdef CONFIG_PM extern int sdhci_suspend_host (struct sdhci_host *host);extern int sdhci_resume_host (struct sdhci_host *host);
Signature · 1 line
1.8.3.1
PATCH 194/222 mmc: sdhci: convert reset into a library function
In reply to Russell King - ARM LinuxRather than having platform_reset_enter/platform_reset_exit methods, turn the core of the reset handling into a library function which platforms can call at the appropriate moment in their (new) reset method.
--- drivers/mmc/host/sdhci-acpi.c | 2 ++ drivers/mmc/host/sdhci-bcm-kona.c | 1 + drivers/mmc/host/sdhci-bcm2835.c | 1 + drivers/mmc/host/sdhci-cns3xxx.c | 1 + drivers/mmc/host/sdhci-dove.c | 1 + drivers/mmc/host/sdhci-esdhc-imx.c | 1 + drivers/mmc/host/sdhci-of-arasan.c | 1 + drivers/mmc/host/sdhci-of-esdhc.c | 1 + drivers/mmc/host/sdhci-of-hlwd.c | 1 + drivers/mmc/host/sdhci-pci.c | 1 + drivers/mmc/host/sdhci-pltfm.c | 1 + drivers/mmc/host/sdhci-pxav2.c | 6 +++-- drivers/mmc/host/sdhci-pxav3.c | 6 +++-- drivers/mmc/host/sdhci-s3c.c | 1 + drivers/mmc/host/sdhci-sirf.c | 1 + drivers/mmc/host/sdhci-spear.c | 1 + drivers/mmc/host/sdhci-tegra.c | 6 +++-- drivers/mmc/host/sdhci.c | 47 +++++++++++++++++++------------------- drivers/mmc/host/sdhci.h | 4 ++-- 19 files changed, 53 insertions(+), 31 deletions(-)
drivers/mmc/host/sdhci-acpi.c +2 -0
@@ -104,11 +104,13 @@ static void sdhci_acpi_int_hw_reset(struct sdhci_host *host)static const struct sdhci_ops sdhci_acpi_ops_dflt = { .enable_dma = sdhci_acpi_enable_dma, .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, };static const struct sdhci_ops sdhci_acpi_ops_int = { .enable_dma = sdhci_acpi_enable_dma, .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, .hw_reset = sdhci_acpi_int_hw_reset, };
drivers/mmc/host/sdhci-bcm-kona.c +1 -0
@@ -210,6 +210,7 @@ static struct sdhci_ops sdhci_bcm_kona_ops = { .get_timeout_clock = sdhci_bcm_kona_get_timeout_clock, .platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks, .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, .card_event = sdhci_bcm_kona_card_event, };
drivers/mmc/host/sdhci-bcm2835.c +1 -0
@@ -134,6 +134,7 @@ static const struct sdhci_ops bcm2835_sdhci_ops = { .get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_min_clock = bcm2835_sdhci_get_min_clock, .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, };static const struct sdhci_pltfm_data bcm2835_sdhci_pdata = {
drivers/mmc/host/sdhci-cns3xxx.c +1 -0
@@ -83,6 +83,7 @@ static const struct sdhci_ops sdhci_cns3xxx_ops = { .get_max_clock = sdhci_cns3xxx_get_max_clk, .set_clock = sdhci_cns3xxx_set_clock, .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, };static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
drivers/mmc/host/sdhci-dove.c +1 -0
@@ -87,6 +87,7 @@ static const struct sdhci_ops sdhci_dove_ops = { .read_w = sdhci_dove_readw, .read_l = sdhci_dove_readl, .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, };static const struct sdhci_pltfm_data sdhci_dove_pdata = {
drivers/mmc/host/sdhci-esdhc-imx.c +1 -0
@@ -888,6 +888,7 @@ static struct sdhci_ops sdhci_esdhc_ops = { .get_ro = esdhc_pltfm_get_ro, .set_bus_width = esdhc_pltfm_set_bus_width, .set_uhs_signaling = esdhc_set_uhs_signaling, + .reset = sdhci_reset, };static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
drivers/mmc/host/sdhci-of-arasan.c +1 -0
@@ -55,6 +55,7 @@ static struct sdhci_ops sdhci_arasan_ops = { .get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_timeout_clock = sdhci_arasan_get_timeout_clock, .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, };static struct sdhci_pltfm_data sdhci_arasan_pdata = {
drivers/mmc/host/sdhci-of-esdhc.c +1 -0
@@ -309,6 +309,7 @@ static const struct sdhci_ops sdhci_esdhc_ops = {#endif .adma_workaround = esdhci_of_adma_workaround, .set_bus_width = esdhc_pltfm_set_bus_width, + .reset = sdhci_reset, };static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
drivers/mmc/host/sdhci-of-hlwd.c +1 -0
@@ -59,6 +59,7 @@ static const struct sdhci_ops sdhci_hlwd_ops = { .write_w = sdhci_hlwd_writew, .write_b = sdhci_hlwd_writeb, .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, };static const struct sdhci_pltfm_data sdhci_hlwd_pdata = {
drivers/mmc/host/sdhci-pci.c +1 -0
@@ -1080,6 +1080,7 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host)static const struct sdhci_ops sdhci_pci_ops = { .enable_dma = sdhci_pci_enable_dma, .set_bus_width = sdhci_pci_set_bus_width, + .reset = sdhci_reset, .hw_reset = sdhci_pci_hw_reset, };
drivers/mmc/host/sdhci-pltfm.c +1 -0
@@ -46,6 +46,7 @@ EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_max_clock);static const struct sdhci_ops sdhci_pltfm_ops = { .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, };#ifdef CONFIG_OF
drivers/mmc/host/sdhci-pxav2.c +4 -2
@@ -51,11 +51,13 @@#define MMC_CARD 0x1000#define MMC_WIDTH 0x0100 -static void pxav2_set_private_registers (struct sdhci_host *host,u8 mask) +static void pxav2_reset (struct sdhci_host *host,u8 mask) {struct platform_device *pdev =to_platform_device (mmc_dev (host->mmc));struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; +sdhci_reset (host, mask); +if (mask ==SDHCI_RESET_ALL ) {u16 tmp =0 ;
@@ -111,8 +113,8 @@ static void pxav2_mmc_set_bus_width(struct sdhci_host *host, int width)static const struct sdhci_ops pxav2_sdhci_ops = { .get_max_clock = sdhci_pltfm_clk_get_max_clock, - .platform_reset_exit = pxav2_set_private_registers, .set_bus_width = pxav2_mmc_set_bus_width, + .reset = pxav2_reset, };#ifdef CONFIG_OF
drivers/mmc/host/sdhci-pxav3.c +4 -2
@@ -112,11 +112,13 @@ static int mv_conf_mbus_windows(struct platform_device *pdev,return 0 ; } -static void pxav3_set_private_registers (struct sdhci_host *host,u8 mask) +static void pxav3_reset (struct sdhci_host *host,u8 mask) {struct platform_device *pdev =to_platform_device (mmc_dev (host->mmc));struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; +sdhci_reset (host, mask); +if (mask ==SDHCI_RESET_ALL ) {/* * tune timing of read data/command when crc error happen
@@ -223,11 +225,11 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) }static const struct sdhci_ops pxav3_sdhci_ops = { - .platform_reset_exit = pxav3_set_private_registers, .set_uhs_signaling = pxav3_set_uhs_signaling, .platform_send_init_74_clocks = pxav3_gen_init_74_clocks, .get_max_clock = sdhci_pltfm_clk_get_max_clock, .set_bus_width = sdhci_set_bus_width, + .reset = pxav3_reset, };static struct sdhci_pltfm_data sdhci_pxav3_pdata = {
drivers/mmc/host/sdhci-s3c.c +1 -0
@@ -365,6 +365,7 @@ static struct sdhci_ops sdhci_s3c_ops = { .set_clock = sdhci_s3c_set_clock, .get_min_clock = sdhci_s3c_get_min_clock, .set_bus_width = sdhci_s3c_set_bus_width, + .reset = sdhci_reset, };static void sdhci_s3c_notify_change (struct platform_device *dev,int state)
drivers/mmc/host/sdhci-sirf.c +1 -0
@@ -30,6 +30,7 @@ static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host)static struct sdhci_ops sdhci_sirf_ops = { .get_max_clock = sdhci_sirf_get_max_clk, .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, };static struct sdhci_pltfm_data sdhci_sirf_pdata = {
drivers/mmc/host/sdhci-spear.c +1 -0
@@ -39,6 +39,7 @@ struct spear_sdhci {/* sdhci ops */ static const struct sdhci_ops sdhci_pltfm_ops = { .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, };#ifdef CONFIG_OF
drivers/mmc/host/sdhci-tegra.c +4 -2
@@ -108,12 +108,14 @@ static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host)return mmc_gpio_get_ro (host->mmc); } -static void tegra_sdhci_reset_exit (struct sdhci_host *host,u8 mask) +static void tegra_sdhci_reset (struct sdhci_host *host,u8 mask) {struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct sdhci_tegra *tegra_host = pltfm_host->priv;const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; +sdhci_reset (host, mask); +if (!(mask &SDHCI_RESET_ALL ))return ;
@@ -152,7 +154,7 @@ static const struct sdhci_ops tegra_sdhci_ops = { .read_w = tegra_sdhci_readw, .write_l = tegra_sdhci_writel, .set_bus_width = tegra_sdhci_set_bus_width, - .platform_reset_exit = tegra_sdhci_reset_exit, + .reset = tegra_sdhci_reset, };static const struct sdhci_pltfm_data sdhci_tegra20_pdata = {
drivers/mmc/host/sdhci.c +24 -23
111 lines not on this page · raw message
drivers/mmc/host/sdhci.h +2 -2
@@ -285,8 +285,7 @@ struct sdhci_ops {void (*platform_send_init_74_clocks)(struct sdhci_host *host,u8 power_mode);unsigned int (*get_ro)(struct sdhci_host *host); -void (*platform_reset_enter)(struct sdhci_host *host,u8 mask); -void (*platform_reset_exit)(struct sdhci_host *host,u8 mask); +void (*reset)(struct sdhci_host *host,u8 mask);int (*platform_execute_tuning)(struct sdhci_host *host,u32 opcode);int (*set_uhs_signaling)(struct sdhci_host *host,unsigned int uhs);void (*hw_reset)(struct sdhci_host *host);
@@ -402,6 +401,7 @@ static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host) }void sdhci_set_bus_width (struct sdhci_host *host,int width); +void sdhci_reset (struct sdhci_host *host,u8 mask);#ifdef CONFIG_PM extern int sdhci_suspend_host (struct sdhci_host *host);
Signature · 1 line
1.8.3.1
PATCH 195/222 mmc: sdhci: move FSL ESDHC reset handling quirk into esdhc code
In reply to Russell King - ARM LinuxThe Freescale esdhc driver is the only driver which needs the interrupt registers restored after a reset. Move this quirk to be part of the ESDHC driver implementation.
--- drivers/mmc/host/sdhci-esdhc-imx.c | 10 +++++++++- drivers/mmc/host/sdhci-esdhc.h | 3 +-- drivers/mmc/host/sdhci.c | 5 ----- include/linux/mmc/sdhci.h | 2 -- 4 files changed, 10 insertions(+), 10 deletions(-)
drivers/mmc/host/sdhci-esdhc-imx.c +9 -1
@@ -876,6 +876,14 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)return esdhc_change_pinstate (host, uhs); } +static void esdhc_reset (struct sdhci_host *host,u8 mask) +{ +sdhci_reset (host, mask); + +sdhci_writel (host, host->ier,SDHCI_INT_ENABLE ); +sdhci_writel (host, host->ier,SDHCI_SIGNAL_ENABLE ); +} +static struct sdhci_ops sdhci_esdhc_ops = { .read_l = esdhc_readl_le, .read_w = esdhc_readw_le,
@@ -888,7 +896,7 @@ static struct sdhci_ops sdhci_esdhc_ops = { .get_ro = esdhc_pltfm_get_ro, .set_bus_width = esdhc_pltfm_set_bus_width, .set_uhs_signaling = esdhc_set_uhs_signaling, - .reset = sdhci_reset, + .reset = esdhc_reset, };static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
drivers/mmc/host/sdhci-esdhc.h +1 -2
@@ -22,8 +22,7 @@ SDHCI_QUIRK_NO_BUSY_IRQ | \ SDHCI_QUIRK_NONSTANDARD_CLOCK | \ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \ - SDHCI_QUIRK_PIO_NEEDS_DELAY | \ - SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) + SDHCI_QUIRK_PIO_NEEDS_DELAY)#define ESDHC_SYSTEM_CONTROL 0x2c#define ESDHC_CLOCK_MASK 0x0000fff0
drivers/mmc/host/sdhci.c +0 -5
@@ -203,11 +203,6 @@ static void sdhci_do_reset(struct sdhci_host *host, u8 mask) host->ops->reset (host, mask); -if (host->quirks &SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET ) { -sdhci_writel (host, host->ier,SDHCI_INT_ENABLE ); -sdhci_writel (host, host->ier,SDHCI_SIGNAL_ENABLE ); - } -if (host->flags & (SDHCI_USE_SDMA |SDHCI_USE_ADMA )) {if ((host->ops->enable_dma) && (mask &SDHCI_RESET_ALL )) host->ops->enable_dma (host);
include/linux/mmc/sdhci.h +0 -2
@@ -61,8 +61,6 @@ struct sdhci_host {#define SDHCI_QUIRK_NONSTANDARD_CLOCK (1<<17)/* Controller does not like fast PIO transfers */ #define SDHCI_QUIRK_PIO_NEEDS_DELAY (1<<18) -/* Controller losing signal/interrupt enable states after reset */ -#define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET (1<<19)/* Controller has to be forced to use block size of 2048 bytes */ #define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20)/* Controller cannot do multi-block transfers */
Signature · 1 line
1.8.3.1
PATCH 196/222 mmc: sdhci: avoid sync'ing the SG if there's no misalignment
In reply to Russell King - ARM LinuxOn read, we don't need to sync the whole scatterlist and then check whether any segments need copying - if we check first, we avoid potentially expensive cache handling.
--- drivers/mmc/host/sdhci.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci.c +10 -1
@@ -602,6 +602,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host,u8 *align;char *buffer;unsigned long flags; +bool has_unaligned;if (data->flags &MMC_DATA_READ ) direction =DMA_FROM_DEVICE ;
@@ -614,7 +615,15 @@ static void sdhci_adma_table_post(struct sdhci_host *host,dma_unmap_single (mmc_dev (host->mmc), host->align_addr,128 *4 , direction); -if (data->flags &MMC_DATA_READ ) { +/* Do a quick scan of the SG list for any unaligned mappings */ + has_unaligned = false; +for_each_sg (data->sg, sg, host->sg_count, i) +if (sg_dma_address (sg) &3 ) { + has_unaligned = true; +break ; + } + +if (has_unaligned && data->flags &MMC_DATA_READ ) {dma_sync_sg_for_cpu (mmc_dev (host->mmc), data->sg, data->sg_len, direction);
Signature · 1 line
1.8.3.1
PATCH 197/222 mmc: sdhci: convert ADMA descriptors to a coherent allocation
In reply to Russell King - ARM LinuxRather than using the streaming API, use the coherent allocator to provide this memory, thereby eliminating cache flushing of it each time we map and unmap it. This results in a 7.5% increase in transfer speed with a UHS-1 card operating in 3.3v mode at a clock of 49.5MHz.
--- drivers/mmc/host/sdhci.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-)
drivers/mmc/host/sdhci.c +22 -21
@@ -44,6 +44,8 @@#define MAX_TUNING_LOOP 40 +#define ADMA_SIZE ((128 * 2 + 1) * 4) +static unsigned int debug_quirks =0 ;static unsigned int debug_quirks2;
@@ -481,11 +483,6 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,else direction =DMA_TO_DEVICE ; -/* -* The ADMA descriptor table is mapped further down as we -* need to fill it with data first. -*/ - host->align_addr =dma_map_single (mmc_dev (host->mmc), host->align_buffer,128 *4 , direction);if (dma_mapping_error (mmc_dev (host->mmc), host->align_addr))
@@ -546,7 +543,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,* If this triggers then we have a calculation bug * somewhere. :/ */ -WARN_ON ((desc - host->adma_desc) > (128 *2 +1 ) *4 ); +WARN_ON ((desc - host->adma_desc) >ADMA_SIZE ); }if (host->quirks &SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC ) {
@@ -574,17 +571,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, host->align_addr, 128 * 4, direction); } - host->adma_addr =dma_map_single (mmc_dev (host->mmc), - host->adma_desc, (128 *2 +1 ) *4 ,DMA_TO_DEVICE ); -if (dma_mapping_error (mmc_dev (host->mmc), host->adma_addr)) - goto unmap_entries; -BUG_ON (host->adma_addr &0x3 ); -return 0 ; -unmap_entries: -dma_unmap_sg (mmc_dev (host->mmc), data->sg, - data->sg_len, direction); unmap_align:dma_unmap_single (mmc_dev (host->mmc), host->align_addr,128 *4 , direction);
@@ -609,9 +597,6 @@ static void sdhci_adma_table_post(struct sdhci_host *host,else direction =DMA_TO_DEVICE ; -dma_unmap_single (mmc_dev (host->mmc), host->adma_addr, - (128 *2 +1 ) *4 ,DMA_TO_DEVICE ); -dma_unmap_single (mmc_dev (host->mmc), host->align_addr,128 *4 , direction);
@@ -2851,15 +2836,29 @@ int sdhci_add_host(struct sdhci_host *host)* (128) and potentially one alignment transfer for * each of those entries. */ - host->adma_desc =kmalloc ((128 *2 +1 ) *4 ,GFP_KERNEL ); + host->adma_desc =dma_alloc_coherent (mmc_dev (host->mmc), +ADMA_SIZE , &host->adma_addr, +GFP_KERNEL ); host->align_buffer =kmalloc (128 *4 ,GFP_KERNEL );if (!host->adma_desc || !host->align_buffer) { -kfree (host->adma_desc); +dma_free_coherent (mmc_dev (host->mmc),ADMA_SIZE , + host->adma_desc, host->adma_addr);kfree (host->align_buffer);pr_warning ("%s: Unable to allocate ADMA " "buffers. Falling back to standard DMA.\n" ,mmc_hostname (mmc)); host->flags &= ~SDHCI_USE_ADMA ; + host->adma_desc =NULL ; + host->align_buffer =NULL ; + }else if (host->adma_addr &3 ) { +pr_warning ("%s: unable to allocate aligned ADMA descriptor\n" , +mmc_hostname (mmc)); + host->flags &= ~SDHCI_USE_ADMA ; +dma_free_coherent (mmc_dev (host->mmc),ADMA_SIZE , + host->adma_desc, host->adma_addr); +kfree (host->align_buffer); + host->adma_desc =NULL ; + host->align_buffer =NULL ; } }
@@ -3337,7 +3336,9 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)regulator_put (host->vqmmc); } -kfree (host->adma_desc); +if (host->adma_desc) +dma_free_coherent (mmc_dev (host->mmc),ADMA_SIZE , + host->adma_desc, host->adma_addr);kfree (host->align_buffer); host->adma_desc =NULL ;
Signature · 1 line
1.8.3.1
PATCH 198/222 mmc: sdhci: clean up sdhci_update_clock()/sdhci_set_clock()
In reply to Russell King - ARM LinuxOnly one caller to sdhci_set_clock() needs to check whether the requested clock frequency was the same as the currently set frequency, yet we work around this in several other sites via sdhci_update_clock(). Rather than doing this, move those checks out into sdhci_do_set_ios(), which then allows sdhci_update_clock() to be eliminated.
--- drivers/mmc/host/sdhci-cns3xxx.c | 3 --- drivers/mmc/host/sdhci.c | 21 +++++---------------- 2 files changed, 5 insertions(+), 19 deletions(-)
drivers/mmc/host/sdhci-cns3xxx.c +0 -3
@@ -30,9 +30,6 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock)u16 clk;unsigned long timeout; -if (clock == host->clock) -return ; -sdhci_writew (host,0 ,SDHCI_CLOCK_CONTROL );if (clock ==0 )
drivers/mmc/host/sdhci.c +5 -16
@@ -1119,9 +1119,6 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)u16 clk =0 ;unsigned long timeout; -if (clock && clock == host->clock) -return ; - host->mmc->actual_clock =0 ;if (host->ops->set_clock) {
@@ -1228,15 +1225,6 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) host->clock = clock; } -static inline void sdhci_update_clock (struct sdhci_host *host) -{ -unsigned int clock; - - clock = host->clock; - host->clock =0 ; -sdhci_set_clock (host, clock); -} -static int sdhci_set_power (struct sdhci_host *host,unsigned short power) {u8 pwr =0 ;
@@ -1453,7 +1441,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))sdhci_enable_preset_value (host, false); -sdhci_set_clock (host, ios->clock); +if (!ios->clock || ios->clock != host->clock) +sdhci_set_clock (host, ios->clock);if (ios->power_mode ==MMC_POWER_OFF ) vdd_bit =sdhci_set_power (host,-1 );
@@ -1521,7 +1510,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)sdhci_writeb (host, ctrl,SDHCI_HOST_CONTROL );/* Re-enable SD Clock */ -sdhci_update_clock (host); +sdhci_set_clock (host, host->clock); }
@@ -1565,7 +1554,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) }/* Re-enable SD Clock */ -sdhci_update_clock (host); +sdhci_set_clock (host, host->clock); }else sdhci_writeb (host, ctrl,SDHCI_HOST_CONTROL );
@@ -2136,7 +2125,7 @@ static void sdhci_tasklet_finish(unsigned long param)/* Some controllers need this kick or reset won't work here */ if (host->quirks &SDHCI_QUIRK_CLOCK_BEFORE_RESET )/* This is to force an update */ -sdhci_update_clock (host); +sdhci_set_clock (host, host->clock);/* Spec says we should do both at the same time, but Ricoh controllers do not like that. */
Signature · 1 line
1.8.3.1
PATCH 199/222 mmc: sdhci: move setting host->clock into sdhci_do_set_ios()
In reply to Russell King - ARM LinuxWe don't need implementations to do this, since the only time it's necessary is when we change the clock, and the only place that happens is in sdhci_do_set_ios(). So, move it there, and remove it from the iMX platform backend.
--- drivers/mmc/host/sdhci-cns3xxx.c | 4 +--- drivers/mmc/host/sdhci-esdhc-imx.c | 4 +--- drivers/mmc/host/sdhci-of-esdhc.c | 4 +--- drivers/mmc/host/sdhci-s3c.c | 3 --- drivers/mmc/host/sdhci.c | 9 ++++----- 5 files changed, 7 insertions(+), 17 deletions(-)
drivers/mmc/host/sdhci-cns3xxx.c +1 -3
@@ -33,7 +33,7 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock)sdhci_writew (host,0 ,SDHCI_CLOCK_CONTROL );if (clock ==0 ) - goto out; +return ;while (host->max_clk / div > clock) {/*
@@ -72,8 +72,6 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock) clk |=SDHCI_CLOCK_CARD_EN ;sdhci_writew (host, clk,SDHCI_CLOCK_CONTROL ); -out: - host->clock = clock; }static const struct sdhci_ops sdhci_cns3xxx_ops = {
drivers/mmc/host/sdhci-esdhc-imx.c +1 -3
@@ -605,7 +605,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,writel (val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON , host->ioaddr +ESDHC_VENDOR_SPEC ); } - goto out; +return ; }if (esdhc_is_usdhc (imx_data) && !imx_data->is_ddr)
@@ -645,8 +645,6 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, }mdelay (1 ); -out: - host->clock = clock; }static unsigned int esdhc_pltfm_get_ro (struct sdhci_host *host)
drivers/mmc/host/sdhci-of-esdhc.c +1 -3
@@ -205,7 +205,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)u32 temp;if (clock ==0 ) - goto out; +return ;/* Workaround to reduce the clock frequency for p1010 esdhc */ if (of_find_compatible_node (NULL ,NULL ,"fsl,p1010-esdhc" )) {
@@ -238,8 +238,6 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) | (pre_div << ESDHC_PREDIV_SHIFT));sdhci_writel (host, temp,ESDHC_SYSTEM_CONTROL );mdelay (1 ); -out: - host->clock = clock; }#ifdef CONFIG_PM
drivers/mmc/host/sdhci-s3c.c +0 -3
@@ -298,7 +298,6 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)/* If the clock is going off, set to 0 at clock control register */ if (clock ==0 ) {sdhci_writew (host,0 ,SDHCI_CLOCK_CONTROL ); - host->clock = clock;return ; }
@@ -306,8 +305,6 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)clk_set_rate (ourhost->clk_bus[ourhost->cur_clk], clock); - host->clock = clock; - clk =SDHCI_CLOCK_INT_EN ;sdhci_writew (host, clk,SDHCI_CLOCK_CONTROL );
drivers/mmc/host/sdhci.c +4 -5
@@ -1130,7 +1130,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)sdhci_writew (host,0 ,SDHCI_CLOCK_CONTROL );if (clock ==0 ) - goto out; +return ;if (host->version >=SDHCI_SPEC_300 ) { if (sdhci_readw(host, SDHCI_HOST_CONTROL2) &
@@ -1220,9 +1220,6 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) clk |=SDHCI_CLOCK_CARD_EN ;sdhci_writew (host, clk,SDHCI_CLOCK_CONTROL ); - -out: - host->clock = clock; }static int sdhci_set_power (struct sdhci_host *host,unsigned short power)
@@ -1441,8 +1438,10 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))sdhci_enable_preset_value (host, false); -if (!ios->clock || ios->clock != host->clock) +if (!ios->clock || ios->clock != host->clock) {sdhci_set_clock (host, ios->clock); + host->clock = ios->clock; + }if (ios->power_mode ==MMC_POWER_OFF ) vdd_bit =sdhci_set_power (host,-1 );
Signature · 1 line
1.8.3.1
PATCH 200/222 mmc: sdhci: move setting mmc->actual_clock into set_clock handlers
In reply to Russell King - ARM LinuxMove the setting of mmc->actual_clock to zero into the set_clock handlers themselves. This will allow us to clean up the calling logic for the set_clock() method, and turn sdhci_set_clock() into a library function.
--- drivers/mmc/host/sdhci-cns3xxx.c | 2 ++ drivers/mmc/host/sdhci-esdhc-imx.c | 2 ++ drivers/mmc/host/sdhci-of-esdhc.c | 3 ++- drivers/mmc/host/sdhci-s3c.c | 4 ++++ drivers/mmc/host/sdhci.c | 4 ++-- 5 files changed, 12 insertions(+), 3 deletions(-)
drivers/mmc/host/sdhci-cns3xxx.c +2 -0
@@ -30,6 +30,8 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock)u16 clk;unsigned long timeout; + host->mmc->actual_clock =0 ; +sdhci_writew (host,0 ,SDHCI_CLOCK_CONTROL );if (clock ==0 )
drivers/mmc/host/sdhci-esdhc-imx.c +2 -0
@@ -600,6 +600,8 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,u32 temp, val;if (clock ==0 ) { + host->mmc->actual_clock =0 ; +if (esdhc_is_usdhc (imx_data)) { val =readl (host->ioaddr +ESDHC_VENDOR_SPEC ); writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
drivers/mmc/host/sdhci-of-esdhc.c +2 -1
@@ -199,11 +199,12 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)static void esdhc_of_set_clock (struct sdhci_host *host,unsigned int clock) { -int pre_div =2 ;int div =1 ;u32 temp; + host->mmc->actual_clock =0 ; +if (clock ==0 )return ;
drivers/mmc/host/sdhci-s3c.c +4 -0
@@ -161,6 +161,8 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)int src;u32 ctrl; + host->mmc->actual_clock =0 ; +/* don't bother if the clock is going off. */ if (clock ==0 )return ;
@@ -295,6 +297,8 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)unsigned long timeout;u16 clk =0 ; + host->mmc->actual_clock =0 ; +/* If the clock is going off, set to 0 at clock control register */ if (clock ==0 ) {sdhci_writew (host,0 ,SDHCI_CLOCK_CONTROL );
drivers/mmc/host/sdhci.c +2 -2
@@ -1119,14 +1119,14 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)u16 clk =0 ;unsigned long timeout; - host->mmc->actual_clock =0 ; -if (host->ops->set_clock) { host->ops->set_clock (host, clock);if (host->quirks &SDHCI_QUIRK_NONSTANDARD_CLOCK )return ; } + host->mmc->actual_clock =0 ; +sdhci_writew (host,0 ,SDHCI_CLOCK_CONTROL );if (clock ==0 )
Signature · 1 line
1.8.3.1
PATCH 201/222 mmc: sdhci: convert sdhci_set_clock() into a library function
In reply to Russell King - ARM Linux--- drivers/mmc/host/sdhci-acpi.c | 2 ++ drivers/mmc/host/sdhci-bcm-kona.c | 1 + drivers/mmc/host/sdhci-bcm2835.c | 1 + drivers/mmc/host/sdhci-cns3xxx.c | 3 +-- drivers/mmc/host/sdhci-dove.c | 1 + drivers/mmc/host/sdhci-esdhc.h | 1 - drivers/mmc/host/sdhci-of-arasan.c | 1 + drivers/mmc/host/sdhci-of-hlwd.c | 1 + drivers/mmc/host/sdhci-pci.c | 1 + drivers/mmc/host/sdhci-pltfm.c | 1 + drivers/mmc/host/sdhci-pxav2.c | 1 + drivers/mmc/host/sdhci-pxav3.c | 1 + drivers/mmc/host/sdhci-s3c.c | 19 ++++++++++++++----- drivers/mmc/host/sdhci-sirf.c | 1 + drivers/mmc/host/sdhci-spear.c | 1 + drivers/mmc/host/sdhci-tegra.c | 1 + drivers/mmc/host/sdhci.c | 17 ++++++----------- drivers/mmc/host/sdhci.h | 1 + include/linux/mmc/sdhci.h | 2 -- 19 files changed, 36 insertions(+), 21 deletions(-)
drivers/mmc/host/sdhci-acpi.c +2 -0
@@ -102,12 +102,14 @@ static void sdhci_acpi_int_hw_reset(struct sdhci_host *host) }static const struct sdhci_ops sdhci_acpi_ops_dflt = { + .set_clock = sdhci_set_clock, .enable_dma = sdhci_acpi_enable_dma, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, };static const struct sdhci_ops sdhci_acpi_ops_int = { + .set_clock = sdhci_set_clock, .enable_dma = sdhci_acpi_enable_dma, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset,
drivers/mmc/host/sdhci-bcm-kona.c +1 -0
@@ -206,6 +206,7 @@ static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host, }static struct sdhci_ops sdhci_bcm_kona_ops = { + .set_clock = sdhci_set_clock, .get_max_clock = sdhci_bcm_kona_get_max_clk, .get_timeout_clock = sdhci_bcm_kona_get_timeout_clock, .platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks,
drivers/mmc/host/sdhci-bcm2835.c +1 -0
@@ -131,6 +131,7 @@ static const struct sdhci_ops bcm2835_sdhci_ops = { .read_l = bcm2835_sdhci_readl, .read_w = bcm2835_sdhci_readw, .read_b = bcm2835_sdhci_readb, + .set_clock = sdhci_set_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_min_clock = bcm2835_sdhci_get_min_clock, .set_bus_width = sdhci_set_bus_width,
drivers/mmc/host/sdhci-cns3xxx.c +1 -2
@@ -89,8 +89,7 @@ static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |SDHCI_QUIRK_INVERTED_WRITE_PROTECT |SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | -SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | - SDHCI_QUIRK_NONSTANDARD_CLOCK, + SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, };static int sdhci_cns3xxx_probe (struct platform_device *pdev)
drivers/mmc/host/sdhci-dove.c +1 -0
@@ -86,6 +86,7 @@ static u32 sdhci_dove_readl(struct sdhci_host *host, int reg)static const struct sdhci_ops sdhci_dove_ops = { .read_w = sdhci_dove_readw, .read_l = sdhci_dove_readl, + .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, };
drivers/mmc/host/sdhci-esdhc.h +0 -1
@@ -20,7 +20,6 @@#define ESDHC_DEFAULT_QUIRKS (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \ SDHCI_QUIRK_NO_BUSY_IRQ | \ - SDHCI_QUIRK_NONSTANDARD_CLOCK | \ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \ SDHCI_QUIRK_PIO_NEEDS_DELAY)
drivers/mmc/host/sdhci-of-arasan.c +1 -0
@@ -52,6 +52,7 @@ static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host) }static struct sdhci_ops sdhci_arasan_ops = { + .set_clock = sdhci_set_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_timeout_clock = sdhci_arasan_get_timeout_clock, .set_bus_width = sdhci_set_bus_width,
drivers/mmc/host/sdhci-of-hlwd.c +1 -0
@@ -58,6 +58,7 @@ static const struct sdhci_ops sdhci_hlwd_ops = { .write_l = sdhci_hlwd_writel, .write_w = sdhci_hlwd_writew, .write_b = sdhci_hlwd_writeb, + .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, };
drivers/mmc/host/sdhci-pci.c +1 -0
@@ -1078,6 +1078,7 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host) }static const struct sdhci_ops sdhci_pci_ops = { + .set_clock = sdhci_set_clock, .enable_dma = sdhci_pci_enable_dma, .set_bus_width = sdhci_pci_set_bus_width, .reset = sdhci_reset,
drivers/mmc/host/sdhci-pltfm.c +1 -0
@@ -45,6 +45,7 @@ unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host)EXPORT_SYMBOL_GPL (sdhci_pltfm_clk_get_max_clock);static const struct sdhci_ops sdhci_pltfm_ops = { + .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, };
drivers/mmc/host/sdhci-pxav2.c +1 -0
@@ -112,6 +112,7 @@ static void pxav2_mmc_set_bus_width(struct sdhci_host *host, int width) }static const struct sdhci_ops pxav2_sdhci_ops = { + .set_clock = sdhci_set_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock, .set_bus_width = pxav2_mmc_set_bus_width, .reset = pxav2_reset,
drivers/mmc/host/sdhci-pxav3.c +1 -0
@@ -225,6 +225,7 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) }static const struct sdhci_ops pxav3_sdhci_ops = { + .set_clock = sdhci_set_clock, .set_uhs_signaling = pxav3_set_uhs_signaling, .platform_send_init_74_clocks = pxav3_gen_init_74_clocks, .get_max_clock = sdhci_pltfm_clk_get_max_clock,
drivers/mmc/host/sdhci-s3c.c +14 -5
@@ -58,6 +58,8 @@ struct sdhci_s3c {struct clk *clk_io;struct clk *clk_bus[MAX_BUS_CLK ];unsigned long clk_rates[MAX_BUS_CLK ]; + +bool no_divider; };/**
@@ -70,6 +72,7 @@ struct sdhci_s3c {*/ struct sdhci_s3c_drv_data {unsigned int sdhci_quirks; +bool no_divider; };static inline struct sdhci_s3c *to_s3c (struct sdhci_host *host)
@@ -119,7 +122,7 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,* If controller uses a non-standard clock division, find the best clock * speed possible with selected clock source and skip the division. */ -if (ourhost->host->quirks &SDHCI_QUIRK_NONSTANDARD_CLOCK ) { +if (ourhost->no_divider) { rate =clk_round_rate (clksrc, wanted);return wanted - rate; }
@@ -164,8 +167,10 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) host->mmc->actual_clock =0 ;/* don't bother if the clock is going off. */ -if (clock ==0 ) +if (clock ==0 ) { +sdhci_set_clock (host, clock);return ; + }for (src =0 ; src <MAX_BUS_CLK ; src++) { delta =sdhci_s3c_consider_clock (ourhost, src, clock);
@@ -217,6 +222,8 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)if (clock <25 *1000000 ) ctrl |= (S3C_SDHCI_CTRL3_FCSEL3 |S3C_SDHCI_CTRL3_FCSEL2 );writel (ctrl, host->ioaddr +S3C_SDHCI_CONTROL3 ); + +sdhci_set_clock (host, clock); }/**
@@ -606,8 +613,10 @@ static int sdhci_s3c_probe(struct platform_device *pdev)/* Setup quirks for the controller */ host->quirks |=SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC ; host->quirks |=SDHCI_QUIRK_NO_HISPD_BIT ; -if (drv_data) +if (drv_data) { host->quirks |= drv_data->sdhci_quirks; + sc->no_divider = drv_data->no_divider; + }#ifndef CONFIG_MMC_SDHCI_S3C_DMA
@@ -656,7 +665,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)* If controller does not have internal clock divider, * we can use overriding functions instead of default. */ -if (host->quirks &SDHCI_QUIRK_NONSTANDARD_CLOCK ) { +if (sc->no_divider) { sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock; sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock; sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock;
@@ -797,7 +806,7 @@ static const struct dev_pm_ops sdhci_s3c_pmops = {#if defined(CONFIG_CPU_EXYNOS4210 ) || defined(CONFIG_SOC_EXYNOS4212 )static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = { - .sdhci_quirks =SDHCI_QUIRK_NONSTANDARD_CLOCK , + .no_divider = true, };#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)&exynos4_sdhci_drv_data)#else
drivers/mmc/host/sdhci-sirf.c +1 -0
@@ -28,6 +28,7 @@ static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host) }static struct sdhci_ops sdhci_sirf_ops = { + .set_clock = sdhci_set_clock, .get_max_clock = sdhci_sirf_get_max_clk, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset,
drivers/mmc/host/sdhci-spear.c +1 -0
@@ -38,6 +38,7 @@ struct spear_sdhci {/* sdhci ops */ static const struct sdhci_ops sdhci_pltfm_ops = { + .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, };
drivers/mmc/host/sdhci-tegra.c +1 -0
@@ -153,6 +153,7 @@ static const struct sdhci_ops tegra_sdhci_ops = { .read_l = tegra_sdhci_readl, .read_w = tegra_sdhci_readw, .write_l = tegra_sdhci_writel, + .set_clock = sdhci_set_clock, .set_bus_width = tegra_sdhci_set_bus_width, .reset = tegra_sdhci_reset, };
drivers/mmc/host/sdhci.c +6 -11
@@ -1112,19 +1112,13 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)return preset; } -static void sdhci_set_clock (struct sdhci_host *host,unsigned int clock) +void sdhci_set_clock (struct sdhci_host *host,unsigned int clock) {int div =0 ;/* Initialized for compiler warning */ int real_div = div, clk_mul =1 ;u16 clk =0 ;unsigned long timeout; -if (host->ops->set_clock) { - host->ops->set_clock (host, clock); -if (host->quirks &SDHCI_QUIRK_NONSTANDARD_CLOCK ) -return ; - } - host->mmc->actual_clock =0 ;sdhci_writew (host,0 ,SDHCI_CLOCK_CONTROL );
@@ -1221,6 +1215,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) clk |=SDHCI_CLOCK_CARD_EN ;sdhci_writew (host, clk,SDHCI_CLOCK_CONTROL ); } +EXPORT_SYMBOL_GPL (sdhci_set_clock);static int sdhci_set_power (struct sdhci_host *host,unsigned short power) {
@@ -1439,7 +1434,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)sdhci_enable_preset_value (host, false);if (!ios->clock || ios->clock != host->clock) { -sdhci_set_clock (host, ios->clock); + host->ops->set_clock (host, ios->clock); host->clock = ios->clock; }
@@ -1509,7 +1504,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)sdhci_writeb (host, ctrl,SDHCI_HOST_CONTROL );/* Re-enable SD Clock */ -sdhci_set_clock (host, host->clock); + host->ops->set_clock (host, host->clock); }
@@ -1553,7 +1548,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) }/* Re-enable SD Clock */ -sdhci_set_clock (host, host->clock); + host->ops->set_clock (host, host->clock); }else sdhci_writeb (host, ctrl,SDHCI_HOST_CONTROL );
@@ -2124,7 +2119,7 @@ static void sdhci_tasklet_finish(unsigned long param)/* Some controllers need this kick or reset won't work here */ if (host->quirks &SDHCI_QUIRK_CLOCK_BEFORE_RESET )/* This is to force an update */ -sdhci_set_clock (host, host->clock); + host->ops->set_clock (host, host->clock);/* Spec says we should do both at the same time, but Ricoh controllers do not like that. */
drivers/mmc/host/sdhci.h +1 -0
@@ -400,6 +400,7 @@ static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host)return !!(host->flags &SDHCI_SDIO_IRQ_ENABLED ); } +void sdhci_set_clock (struct sdhci_host *host,unsigned int clock);void sdhci_set_bus_width (struct sdhci_host *host,int width);void sdhci_reset (struct sdhci_host *host,u8 mask);
include/linux/mmc/sdhci.h +0 -2
@@ -57,8 +57,6 @@ struct sdhci_host {#define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1<<15)/* Controller reports inverted write-protect state */ #define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1<<16) -/* Controller has nonstandard clock management */ -#define SDHCI_QUIRK_NONSTANDARD_CLOCK (1<<17)/* Controller does not like fast PIO transfers */ #define SDHCI_QUIRK_PIO_NEEDS_DELAY (1<<18)/* Controller has to be forced to use block size of 2048 bytes */
Signature · 1 line
1.8.3.1
PATCH 202/222 mmc: sdhci-esdhc-imx: avoid DMA to kernel stack
In reply to Russell King - ARM Linuxsdhci-esdhc-imx tries to DMA to the kernel stack when tuning the interface, which causes dma-debug to complain. Fix this by kmallocing a buffer to hold the received tuning pattern.
--- drivers/mmc/host/sdhci-esdhc-imx.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-)
drivers/mmc/host/sdhci-esdhc-imx.c +16 -9
@@ -711,13 +711,12 @@ static void esdhc_request_done(struct mmc_request *mrq)complete (&mrq->completion); } -static int esdhc_send_tuning_cmd (struct sdhci_host *host,u32 opcode) +static int esdhc_send_tuning_cmd (struct sdhci_host *host,u32 opcode, +struct scatterlist *sg) {struct mmc_command cmd = {0 };struct mmc_request mrq = {NULL };struct mmc_data data = {0 }; -struct scatterlist sg; -char tuning_pattern[ESDHC_TUNING_BLOCK_PATTERN_LEN ]; cmd.opcode = opcode; cmd.arg =0 ;
@@ -726,11 +725,9 @@ static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode) data.blksz =ESDHC_TUNING_BLOCK_PATTERN_LEN ; data.blocks =1 ; data.flags =MMC_DATA_READ ; - data.sg = &sg; + data.sg = sg; data.sg_len =1 ; -sg_init_one (&sg, tuning_pattern,sizeof (tuning_pattern)); - mrq.cmd = &cmd; mrq.cmd->mrq = &mrq; mrq.data = &data;
@@ -770,13 +767,21 @@ static void esdhc_post_tuning(struct sdhci_host *host)static int esdhc_executing_tuning (struct sdhci_host *host,u32 opcode) { +struct scatterlist sg; +char *tuning_pattern;int min, max, avg, ret; + tuning_pattern =kmalloc (ESDHC_TUNING_BLOCK_PATTERN_LEN ,GFP_KERNEL ); +if (!tuning_pattern) +return -ENOMEM ; + +sg_init_one (&sg, tuning_pattern,ESDHC_TUNING_BLOCK_PATTERN_LEN ); +/* find the mininum delay first which can pass tuning */ min =ESDHC_TUNE_CTRL_MIN ;while (min <ESDHC_TUNE_CTRL_MAX ) {esdhc_prepare_tuning (host, min); -if (!esdhc_send_tuning_cmd (host, opcode)) +if (!esdhc_send_tuning_cmd (host, opcode, &sg))break ; min +=ESDHC_TUNE_CTRL_STEP ; }
@@ -785,7 +790,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) max = min +ESDHC_TUNE_CTRL_STEP ;while (max <ESDHC_TUNE_CTRL_MAX ) {esdhc_prepare_tuning (host, max); -if (esdhc_send_tuning_cmd (host, opcode)) { +if (esdhc_send_tuning_cmd (host, opcode, &sg)) { max -=ESDHC_TUNE_CTRL_STEP ;break ; }
@@ -795,9 +800,11 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)/* use average delay to get the best timing */ avg = (min + max) /2 ;esdhc_prepare_tuning (host, avg); - ret =esdhc_send_tuning_cmd (host, opcode); + ret =esdhc_send_tuning_cmd (host, opcode, &sg);esdhc_post_tuning (host); +kfree (tuning_pattern); +dev_dbg (mmc_dev (host->mmc),"tunning %s at 0x%x ret %d\n" , ret ?"failed" :"passed" , avg, ret);
Signature · 1 line
1.8.3.1
PATCH 203/222 mmc: sdhci-esdhc-imx: comment runtime_pm_get_sync() in esdhc_prepare_tuning()
In reply to Russell King - ARM LinuxIt is far from obvious what this is doing, and it looks like it's an unbalanced runtime_pm_get() call. However, the put is inside sdhci_tasklet_finish(), so it's not unbalanced at all. This should be documented so people know what's going on here. Do so.
--- drivers/mmc/host/sdhci-esdhc-imx.c | 1 + 1 file changed, 1 insertion(+)
drivers/mmc/host/sdhci-esdhc-imx.c +1 -0
@@ -695,6 +695,7 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)/* FIXME: delay a bit for card to be ready for next tuning due to errors */ mdelay (1 ); +/* This is balanced by the runtime put in sdhci_tasklet_finish */ pm_runtime_get_sync (host->mmc->parent); reg =readl (host->ioaddr +ESDHC_MIX_CTRL ); reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL |
Signature · 1 line
1.8.3.1
PATCH 204/222 mmc: sdhci-esdhc-imx: fix lockdep splat upon tuning
In reply to Russell King - ARM Linux=================================
[ INFO: inconsistent lock state ]
3.14.0-rc1+ #490 Not tainted
---------------------------------
inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage.
kworker/u8:0/6 [HC0[0]:SC0[0]:HE1:SE1] takes:
(&(&host->lock)->rlock#2){?.-...}, at: [<c04b57a4>] esdhc_send_tuning_cmd+0x104/0x14c
{IN-HARDIRQ-W} state was registered at:
[<c00652fc>] mark_lock+0x15c/0x6f8 [<c0066354>] __lock_acquire+0xabc/0x1ca0 [<c0067ad8>] lock_acquire+0xa0/0x130 [<c0697a44>] _raw_spin_lock+0x34/0x44 [<c04b0dbc>] sdhci_irq+0x20/0xa40 [<c0071b1c>] handle_irq_event_percpu+0x74/0x284 [<c0071d70>] handle_irq_event+0x44/0x64 [<c0074db8>] handle_fasteoi_irq+0xac/0x140 [<c007147c>] generic_handle_irq+0x28/0x38 [<c000efd4>] handle_IRQ+0x40/0x98 [<c0008584>] gic_handle_irq+0x30/0x64 [<c0013144>] __irq_svc+0x44/0x58 [<c0028fc8>] irq_exit+0xc0/0x120 [<c000efd8>] handle_IRQ+0x44/0x98 [<c0008584>] gic_handle_irq+0x30/0x64 [<c0013144>] __irq_svc+0x44/0x58 [<c068f398>] printk+0x3c/0x44 [<c03191d0>] _regulator_get+0x1b4/0x1e0 [<c031924c>] regulator_get+0x18/0x1c [<c049fbc4>] mmc_add_host+0x30/0x1c0 [<c04b2e10>] sdhci_add_host+0x804/0xbbc [<c04b5318>] sdhci_esdhc_imx_probe+0x380/0x674 [<c036d530>] platform_drv_probe+0x20/0x50 [<c036b948>] driver_probe_device+0x120/0x234 [<c036baf8>] __driver_attach+0x9c/0xa0 [<c036a04c>] bus_for_each_dev+0x5c/0x90 [<c036b418>] driver_attach+0x24/0x28 [<c036b018>] bus_add_driver+0xe4/0x1d8 [<c036c1b0>] driver_register+0x80/0xfc [<c036ce28>] __platform_driver_register+0x50/0x64 [<c093706c>] sdhci_esdhc_imx_driver_init+0x18/0x20 [<c0008834>] do_one_initcall+0x3c/0x164 [<c0901c94>] kernel_init_freeable+0x104/0x1d0 [<c068c45c>] kernel_init+0x10/0x118 [<c000e768>] ret_from_fork+0x14/0x2c irq event stamp: 5933 hardirqs last enabled at (5933): [<c069813c>] _raw_spin_unlock_irqrestore+0x38/0x4c hardirqs last disabled at (5932): [<c0697b04>] _raw_spin_lock_irqsave+0x24/0x60 softirqs last enabled at (5914): [<c0028ba0>] __do_softirq+0x260/0x360 softirqs last disabled at (5909): [<c0028fc8>] irq_exit+0xc0/0x120
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0
----
lock(&(&host->lock)->rlock#2);
<Interrupt>
lock(&(&host->lock)->rlock#2);*** DEADLOCK ***
2 locks held by kworker/u8:0/6:
#0: (kmmcd){.+.+.+}, at: [<c003d890>] process_one_work+0x134/0x4e8
#1: ((&(&host->detect)->work)){+.+.+.}, at: [<c003d890>] process_one_work+0x134/0x4e8
stack backtrace: CPU: 2 PID: 6 Comm: kworker/u8:0 Not tainted 3.14.0-rc1+ #490 Workqueue: kmmcd mmc_rescan Backtrace: [<c00124a0>] (dump_backtrace) from [<c0012640>] (show_stack+0x18/0x1c) [<c0012628>] (show_stack) from [<c069164c>] (dump_stack+0x70/0x8c) [<c06915dc>] (dump_stack) from [<c068f080>] (print_usage_bug+0x274/0x2e4) [<c068ee0c>] (print_usage_bug) from [<c0065774>] (mark_lock+0x5d4/0x6f8) [<c00651a0>] (mark_lock) from [<c0065e6c>] (__lock_acquire+0x5d4/0x1ca0) [<c0065898>] (__lock_acquire) from [<c0067ad8>] (lock_acquire+0xa0/0x130) [<c0067a38>] (lock_acquire) from [<c0697a44>] (_raw_spin_lock+0x34/0x44) [<c0697a10>] (_raw_spin_lock) from [<c04b57a4>] (esdhc_send_tuning_cmd+0x104/0x14c) [<c04b56a0>] (esdhc_send_tuning_cmd) from [<c04b582c>] (esdhc_executing_tuning+0x40/0x100) [<c04b57ec>] (esdhc_executing_tuning) from [<c04afa54>] (sdhci_execute_tuning+0xcc/0x754) [<c04af988>] (sdhci_execute_tuning) from [<c04a4684>] (mmc_sd_init_card+0x65c/0x694) [<c04a4028>] (mmc_sd_init_card) from [<c04a48f0>] (mmc_attach_sd+0xb0/0x184) [<c04a4840>] (mmc_attach_sd) from [<c049eb28>] (mmc_rescan+0x26c/0x2e8) [<c049e8bc>] (mmc_rescan) from [<c003d914>] (process_one_work+0x1b8/0x4e8) [<c003d75c>] (process_one_work) from [<c003e090>] (worker_thread+0x13c/0x3f8) [<c003df54>] (worker_thread) from [<c00449bc>] (kthread+0xcc/0xe8) [<c00448f0>] (kthread) from [<c000e768>] (ret_from_fork+0x14/0x2c)
--- drivers/mmc/host/sdhci-esdhc-imx.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/mmc/host/sdhci-esdhc-imx.c +2 -4
@@ -738,14 +738,12 @@ static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode, mrq.done = esdhc_request_done;init_completion (&(mrq.completion)); -disable_irq (host->irq); -spin_lock (&host->lock); +spin_lock_irq (&host->lock); host->mrq = &mrq;sdhci_send_command (host, mrq.cmd); -spin_unlock (&host->lock); -enable_irq (host->irq); +spin_unlock_irq (&host->lock);wait_for_completion (&mrq.completion);
Signature · 1 line
1.8.3.1
PATCH 205/222 mmc: sdhci: hack up driver to make it more compliant with UHS-1
In reply to Russell King - ARM LinuxPatch suggested by Dong Aisheng <[email protected]>, this avoids additional clock start/stop cycles during the transition to 1.8V signalling mode.
--- drivers/mmc/host/sdhci.c | 12 ------------ 1 file changed, 12 deletions(-)
drivers/mmc/host/sdhci.c +0 -12
@@ -1507,12 +1507,6 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) host->ops->set_clock (host, host->clock); } - -/* Reset SD Clock Enable */ - clk =sdhci_readw (host,SDHCI_CLOCK_CONTROL ); - clk &= ~SDHCI_CLOCK_CARD_EN ; -sdhci_writew (host, clk,SDHCI_CLOCK_CONTROL ); -if (host->ops->set_uhs_signaling) host->ops->set_uhs_signaling (host, ios->timing);else {
@@ -1546,9 +1540,6 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) ios->drv_type = (preset &SDHCI_PRESET_DRV_MASK ) >>SDHCI_PRESET_DRV_SHIFT ; } - -/* Re-enable SD Clock */ - host->ops->set_clock (host, host->clock); }else sdhci_writeb (host, ctrl,SDHCI_HOST_CONTROL );
@@ -1757,9 +1748,6 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, ctrl |=SDHCI_CTRL_VDD_180 ;sdhci_writew (host, ctrl,SDHCI_HOST_CONTROL2 ); -/* Wait for 5ms */ -usleep_range (5000 ,5500 ); -/* 1.8V regulator output should be stable within 5 ms */ ctrl =sdhci_readw (host,SDHCI_HOST_CONTROL2 );if (ctrl &SDHCI_CTRL_VDD_180 )
Signature · 1 line
1.8.3.1
PATCH 206/222 mmc: sdhci: set_uhs_signaling() need not return a value
In reply to Russell King - ARM LinuxThe set_uhs_signaling() method gives the impression that it can fail, but anything returned from the method is entirely ignored by the sdhci driver. So returning failure has no effect.
So, kill the idea that it's possible for this to return an error by removing the returned value.
--- drivers/mmc/host/sdhci-esdhc-imx.c | 4 ++-- drivers/mmc/host/sdhci-pxav3.c | 4 +--- drivers/mmc/host/sdhci.h | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-)
drivers/mmc/host/sdhci-esdhc-imx.c +2 -2
@@ -841,7 +841,7 @@ static int esdhc_change_pinstate(struct sdhci_host *host,return pinctrl_select_state (imx_data->pinctrl, pinctrl); } -static int esdhc_set_uhs_signaling (struct sdhci_host *host,unsigned int uhs) +static void esdhc_set_uhs_signaling (struct sdhci_host *host,unsigned int uhs) {struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct pltfm_imx_data *imx_data = pltfm_host->priv;
@@ -879,7 +879,7 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)break ; } -return esdhc_change_pinstate (host, uhs); +esdhc_change_pinstate (host, uhs); }static void esdhc_reset (struct sdhci_host *host,u8 mask)
drivers/mmc/host/sdhci-pxav3.c +1 -3
@@ -186,7 +186,7 @@ static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode) pxa->power_mode = power_mode; } -static int pxav3_set_uhs_signaling (struct sdhci_host *host,unsigned int uhs) +static void pxav3_set_uhs_signaling (struct sdhci_host *host,unsigned int uhs) {u16 ctrl_2;
@@ -220,8 +220,6 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)dev_dbg (mmc_dev (host->mmc),"%s uhs = %d, ctrl_2 = %04X\n" , __func__, uhs, ctrl_2); - -return 0 ; }static const struct sdhci_ops pxav3_sdhci_ops = {
drivers/mmc/host/sdhci.h +1 -1
@@ -287,7 +287,7 @@ struct sdhci_ops {unsigned int (*get_ro)(struct sdhci_host *host);void (*reset)(struct sdhci_host *host,u8 mask);int (*platform_execute_tuning)(struct sdhci_host *host,u32 opcode); -int (*set_uhs_signaling)(struct sdhci_host *host,unsigned int uhs); +void (*set_uhs_signaling)(struct sdhci_host *host,unsigned int uhs);void (*hw_reset)(struct sdhci_host *host);void (*platform_suspend)(struct sdhci_host *host);void (*platform_resume)(struct sdhci_host *host);
Signature · 1 line
1.8.3.1
PATCH 207/222 mmc: sdhci: convert sdhci_set_uhs_signaling() into a library function
In reply to Russell King - ARM LinuxAdd sdhci_set_uhs_signaling() and always call the set_uhs_signaling method. This avoids quirks being added into sdhci_set_uhs_signaling().
--- drivers/mmc/host/sdhci-acpi.c | 2 ++ drivers/mmc/host/sdhci-bcm-kona.c | 1 + drivers/mmc/host/sdhci-bcm2835.c | 1 + drivers/mmc/host/sdhci-cns3xxx.c | 1 + drivers/mmc/host/sdhci-dove.c | 1 + drivers/mmc/host/sdhci-of-arasan.c | 1 + drivers/mmc/host/sdhci-of-esdhc.c | 1 + drivers/mmc/host/sdhci-of-hlwd.c | 1 + drivers/mmc/host/sdhci-pci.c | 1 + drivers/mmc/host/sdhci-pltfm.c | 1 + drivers/mmc/host/sdhci-pxav2.c | 1 + drivers/mmc/host/sdhci-pxav3.c | 1 + drivers/mmc/host/sdhci-s3c.c | 1 + drivers/mmc/host/sdhci-sirf.c | 1 + drivers/mmc/host/sdhci-spear.c | 1 + drivers/mmc/host/sdhci-tegra.c | 1 + drivers/mmc/host/sdhci.c | 42 +++++++++++++++++++++----------------- drivers/mmc/host/sdhci.h | 1 + 18 files changed, 41 insertions(+), 19 deletions(-)
drivers/mmc/host/sdhci-acpi.c +2 -0
@@ -106,6 +106,7 @@ static const struct sdhci_ops sdhci_acpi_ops_dflt = { .enable_dma = sdhci_acpi_enable_dma, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, };static const struct sdhci_ops sdhci_acpi_ops_int = {
@@ -113,6 +114,7 @@ static const struct sdhci_ops sdhci_acpi_ops_int = { .enable_dma = sdhci_acpi_enable_dma, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, .hw_reset = sdhci_acpi_int_hw_reset, };
drivers/mmc/host/sdhci-bcm-kona.c +1 -0
@@ -212,6 +212,7 @@ static struct sdhci_ops sdhci_bcm_kona_ops = { .platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, .card_event = sdhci_bcm_kona_card_event, };
drivers/mmc/host/sdhci-bcm2835.c +1 -0
@@ -136,6 +136,7 @@ static const struct sdhci_ops bcm2835_sdhci_ops = { .get_min_clock = bcm2835_sdhci_get_min_clock, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, };static const struct sdhci_pltfm_data bcm2835_sdhci_pdata = {
drivers/mmc/host/sdhci-cns3xxx.c +1 -0
@@ -81,6 +81,7 @@ static const struct sdhci_ops sdhci_cns3xxx_ops = { .set_clock = sdhci_cns3xxx_set_clock, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, };static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
drivers/mmc/host/sdhci-dove.c +1 -0
@@ -89,6 +89,7 @@ static const struct sdhci_ops sdhci_dove_ops = { .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, };static const struct sdhci_pltfm_data sdhci_dove_pdata = {
drivers/mmc/host/sdhci-of-arasan.c +1 -0
@@ -57,6 +57,7 @@ static struct sdhci_ops sdhci_arasan_ops = { .get_timeout_clock = sdhci_arasan_get_timeout_clock, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, };static struct sdhci_pltfm_data sdhci_arasan_pdata = {
drivers/mmc/host/sdhci-of-esdhc.c +1 -0
@@ -309,6 +309,7 @@ static const struct sdhci_ops sdhci_esdhc_ops = { .adma_workaround = esdhci_of_adma_workaround, .set_bus_width = esdhc_pltfm_set_bus_width, .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, };static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
drivers/mmc/host/sdhci-of-hlwd.c +1 -0
@@ -61,6 +61,7 @@ static const struct sdhci_ops sdhci_hlwd_ops = { .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, };static const struct sdhci_pltfm_data sdhci_hlwd_pdata = {
drivers/mmc/host/sdhci-pci.c +1 -0
@@ -1082,6 +1082,7 @@ static const struct sdhci_ops sdhci_pci_ops = { .enable_dma = sdhci_pci_enable_dma, .set_bus_width = sdhci_pci_set_bus_width, .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, .hw_reset = sdhci_pci_hw_reset, };
drivers/mmc/host/sdhci-pltfm.c +1 -0
@@ -48,6 +48,7 @@ static const struct sdhci_ops sdhci_pltfm_ops = { .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, };#ifdef CONFIG_OF
drivers/mmc/host/sdhci-pxav2.c +1 -0
@@ -116,6 +116,7 @@ static const struct sdhci_ops pxav2_sdhci_ops = { .get_max_clock = sdhci_pltfm_clk_get_max_clock, .set_bus_width = pxav2_mmc_set_bus_width, .reset = pxav2_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, };#ifdef CONFIG_OF
drivers/mmc/host/sdhci-pxav3.c +1 -0
@@ -229,6 +229,7 @@ static const struct sdhci_ops pxav3_sdhci_ops = { .get_max_clock = sdhci_pltfm_clk_get_max_clock, .set_bus_width = sdhci_set_bus_width, .reset = pxav3_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, };static struct sdhci_pltfm_data sdhci_pxav3_pdata = {
drivers/mmc/host/sdhci-s3c.c +1 -0
@@ -374,6 +374,7 @@ static struct sdhci_ops sdhci_s3c_ops = { .get_min_clock = sdhci_s3c_get_min_clock, .set_bus_width = sdhci_s3c_set_bus_width, .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, };static void sdhci_s3c_notify_change (struct platform_device *dev,int state)
drivers/mmc/host/sdhci-sirf.c +1 -0
@@ -32,6 +32,7 @@ static struct sdhci_ops sdhci_sirf_ops = { .get_max_clock = sdhci_sirf_get_max_clk, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, };static struct sdhci_pltfm_data sdhci_sirf_pdata = {
drivers/mmc/host/sdhci-spear.c +1 -0
@@ -41,6 +41,7 @@ static const struct sdhci_ops sdhci_pltfm_ops = { .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, };#ifdef CONFIG_OF
drivers/mmc/host/sdhci-tegra.c +1 -0
@@ -156,6 +156,7 @@ static const struct sdhci_ops tegra_sdhci_ops = { .set_clock = sdhci_set_clock, .set_bus_width = tegra_sdhci_set_bus_width, .reset = tegra_sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, };static const struct sdhci_pltfm_data sdhci_tegra20_pdata = {
drivers/mmc/host/sdhci.c +23 -19
54 lines not on this page · raw message
drivers/mmc/host/sdhci.h +1 -0
@@ -403,6 +403,7 @@ static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host)void sdhci_set_clock (struct sdhci_host *host,unsigned int clock);void sdhci_set_bus_width (struct sdhci_host *host,int width);void sdhci_reset (struct sdhci_host *host,u8 mask); +void sdhci_set_uhs_signaling (struct sdhci_host *host,unsigned timing);#ifdef CONFIG_PM extern int sdhci_suspend_host (struct sdhci_host *host);
Signature · 1 line
1.8.3.1
PATCH 208/222 mmc: sdhci: cache timing information locally
In reply to Russell King - ARM LinuxRather than reading back the timing information from the registers, cache it locally. This allows implementations to translate the UHS timing by overriding the set_uhs_signaling() method as required without also having to emulate the SDHCI_HOST_CONTROL2 register.
--- drivers/mmc/host/sdhci.c | 23 ++++++++++++----------- include/linux/mmc/sdhci.h | 2 ++ 2 files changed, 14 insertions(+), 11 deletions(-)
drivers/mmc/host/sdhci.c +12 -11
@@ -1083,24 +1083,23 @@ static void sdhci_finish_command(struct sdhci_host *host)static u16 sdhci_get_preset_value (struct sdhci_host *host) { -u16 ctrl, preset =0 ; +u16 preset =0 ; - ctrl =sdhci_readw (host,SDHCI_HOST_CONTROL2 ); - -switch (ctrl &SDHCI_CTRL_UHS_MASK ) { -case SDHCI_CTRL_UHS_SDR12 : +switch (host->timing) { +case MMC_TIMING_UHS_SDR12 : preset =sdhci_readw (host,SDHCI_PRESET_FOR_SDR12 );break ; -case SDHCI_CTRL_UHS_SDR25 : +case MMC_TIMING_UHS_SDR25 : preset =sdhci_readw (host,SDHCI_PRESET_FOR_SDR25 );break ; -case SDHCI_CTRL_UHS_SDR50 : +case MMC_TIMING_UHS_SDR50 : preset =sdhci_readw (host,SDHCI_PRESET_FOR_SDR50 );break ; -case SDHCI_CTRL_UHS_SDR104 : +case MMC_TIMING_UHS_SDR104 : +case MMC_TIMING_MMC_HS200 : preset =sdhci_readw (host,SDHCI_PRESET_FOR_SDR104 );break ; -case SDHCI_CTRL_UHS_DDR50 : +case MMC_TIMING_UHS_DDR50 : preset =sdhci_readw (host,SDHCI_PRESET_FOR_DDR50 );break ;default :
@@ -1530,6 +1529,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) } host->ops->set_uhs_signaling (host, ios->timing); + host->timing = ios->timing; if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) && ((ios->timing == MMC_TIMING_UHS_SDR12) ||
@@ -1828,12 +1828,13 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)* If the Host Controller supports the HS200 mode then the * tuning function has to be executed. */ -if (((ctrl &SDHCI_CTRL_UHS_MASK ) ==SDHCI_CTRL_UHS_SDR50 ) && +if (host->timing ==MMC_TIMING_UHS_SDR50 && (host->flags &SDHCI_SDR50_NEEDS_TUNING || host->flags &SDHCI_SDR104_NEEDS_TUNING )) requires_tuning_nonuhs = true; -if (((ctrl &SDHCI_CTRL_UHS_MASK ) ==SDHCI_CTRL_UHS_SDR104 ) || +if (host->timing ==MMC_TIMING_MMC_HS200 || + host->timing ==MMC_TIMING_UHS_SDR104 || requires_tuning_nonuhs) ctrl |=SDHCI_CTRL_EXEC_TUNING ;else {
include/linux/mmc/sdhci.h +2 -0
@@ -172,6 +172,8 @@ struct sdhci_host {unsigned int ocr_avail_mmc;u32 ocr_mask;/* available voltages */ +unsigned timing;/* Current timing */ +u32 thread_isr;/* cached registers */
Signature · 1 line
1.8.3.1
PATCH 209/222 mmc: sdhci: clean up sdhci_execute_tuning() decision
In reply to Russell King - ARM LinuxClean up the code in sdhci_execute_tuning() so the decision whether to execute tuning is clearer - and despite this reflecting what the original code was doing, it shows that it may not be what the author actually intended.
--- drivers/mmc/host/sdhci.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-)
drivers/mmc/host/sdhci.c +15 -16
@@ -1806,21 +1806,16 @@ static int sdhci_card_busy(struct mmc_host *mmc)static int sdhci_execute_tuning (struct mmc_host *mmc,u32 opcode) { -struct sdhci_host *host; +struct sdhci_host *host =mmc_priv (mmc);u16 ctrl;int tuning_loop_counter =MAX_TUNING_LOOP ;unsigned long timeout;int err =0 ; -bool requires_tuning_nonuhs = false;unsigned long flags; - host =mmc_priv (mmc); -sdhci_runtime_pm_get (host);spin_lock_irqsave (&host->lock, flags); - ctrl =sdhci_readw (host,SDHCI_HOST_CONTROL2 ); -/* * The Host Controller needs tuning only in case of SDR104 mode * and for SDR50 mode when Use Tuning for SDR50 is set in the
@@ -1828,16 +1823,18 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)* If the Host Controller supports the HS200 mode then the * tuning function has to be executed. */ -if (host->timing ==MMC_TIMING_UHS_SDR50 && - (host->flags &SDHCI_SDR50_NEEDS_TUNING || - host->flags &SDHCI_SDR104_NEEDS_TUNING )) - requires_tuning_nonuhs = true; - -if (host->timing ==MMC_TIMING_MMC_HS200 || - host->timing ==MMC_TIMING_UHS_SDR104 || - requires_tuning_nonuhs) - ctrl |=SDHCI_CTRL_EXEC_TUNING ; -else { +switch (host->timing) { +case MMC_TIMING_MMC_HS200 : +case MMC_TIMING_UHS_SDR104 : +break ; + +case MMC_TIMING_UHS_SDR50 : +if (host->flags &SDHCI_SDR50_NEEDS_TUNING || + host->flags &SDHCI_SDR104_NEEDS_TUNING ) +break ; +/* FALLTHROUGH */ + +default :spin_unlock_irqrestore (&host->lock, flags);sdhci_runtime_pm_put (host);return 0 ;
@@ -1850,6 +1847,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)return err; } + ctrl =sdhci_readw (host,SDHCI_HOST_CONTROL2 ); + ctrl |=SDHCI_CTRL_EXEC_TUNING ;sdhci_writew (host, ctrl,SDHCI_HOST_CONTROL2 );/*
Signature · 1 line
1.8.3.1
PATCH 210/222 mmc: sdhci-esdhc-imx: remove emulation of uhs_mode
In reply to Russell King - ARM LinuxWe no longer need to emulate the uhs_mode field of the host control2 register - the main sdhci driver never reads this back to evaluate the current mode as it caches the current mode instead.
--- drivers/mmc/host/sdhci-esdhc-imx.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-)
drivers/mmc/host/sdhci-esdhc-imx.c +3 -14
@@ -160,7 +160,6 @@ struct pltfm_imx_data {MULTIBLK_IN_PROCESS ,/* exact multiblock cmd in process */ WAIT_FOR_INT ,/* sent CMD12, waiting for response INT */ } multiblock_status; -u32 uhs_mode;u32 is_ddr; };
@@ -382,7 +381,6 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg)if (val &ESDHC_MIX_CTRL_SMPCLK_SEL ) ret |=SDHCI_CTRL_TUNED_CLK ; - ret |= (imx_data->uhs_mode &SDHCI_CTRL_UHS_MASK ); ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE ;return ret;
@@ -429,7 +427,6 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)else new_val &= ~ESDHC_VENDOR_SPEC_VSELECT ;writel (new_val, host->ioaddr +ESDHC_VENDOR_SPEC ); - imx_data->uhs_mode = val &SDHCI_CTRL_UHS_MASK ;if (imx_data->socdata->flags &ESDHC_FLAG_MAN_TUNING ) { new_val =readl (host->ioaddr +ESDHC_MIX_CTRL );if (val &SDHCI_CTRL_TUNED_CLK )
@@ -841,28 +838,20 @@ static int esdhc_change_pinstate(struct sdhci_host *host,return pinctrl_select_state (imx_data->pinctrl, pinctrl); } -static void esdhc_set_uhs_signaling (struct sdhci_host *host,unsigned int uhs) +static void esdhc_set_uhs_signaling (struct sdhci_host *host,unsigned timing) {struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct pltfm_imx_data *imx_data = pltfm_host->priv;struct esdhc_platform_data *boarddata = &imx_data->boarddata; -switch (uhs) { +switch (timing) {case MMC_TIMING_UHS_SDR12 : - imx_data->uhs_mode =SDHCI_CTRL_UHS_SDR12 ; -break ;case MMC_TIMING_UHS_SDR25 : - imx_data->uhs_mode =SDHCI_CTRL_UHS_SDR25 ; -break ;case MMC_TIMING_UHS_SDR50 : - imx_data->uhs_mode =SDHCI_CTRL_UHS_SDR50 ; -break ;case MMC_TIMING_UHS_SDR104 :case MMC_TIMING_MMC_HS200 : - imx_data->uhs_mode =SDHCI_CTRL_UHS_SDR104 ;break ;case MMC_TIMING_UHS_DDR50 : - imx_data->uhs_mode =SDHCI_CTRL_UHS_DDR50 ;writel (readl (host->ioaddr +ESDHC_MIX_CTRL ) |ESDHC_MIX_CTRL_DDREN , host->ioaddr +ESDHC_MIX_CTRL );
@@ -879,7 +868,7 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)break ; } -esdhc_change_pinstate (host, uhs); +esdhc_change_pinstate (host, timing); }static void esdhc_reset (struct sdhci_host *host,u8 mask)
Signature · 1 line
1.8.3.1
PATCH 211/222 mmc: sdhci-of-esdhc: remove platform_suspend/platform_resume callbacks
In reply to Russell King - ARM LinuxWe don't need these hooks in order to insert code in these paths, we can just provide our own handlers and call the main sdhci handlers as appropriate.
--- drivers/mmc/host/sdhci-of-esdhc.c | 55 +++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 19 deletions(-)
drivers/mmc/host/sdhci-of-esdhc.c +36 -19
@@ -241,20 +241,6 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)mdelay (1 ); } -#ifdef CONFIG_PM -static u32 esdhc_proctl; -static void esdhc_of_suspend (struct sdhci_host *host) -{ - esdhc_proctl =sdhci_be32bs_readl (host,SDHCI_HOST_CONTROL ); -} - -static void esdhc_of_resume (struct sdhci_host *host) -{ -esdhc_of_enable_dma (host); -sdhci_be32bs_writel (host, esdhc_proctl,SDHCI_HOST_CONTROL ); -} -#endif -static void esdhc_of_platform_init (struct sdhci_host *host) {u32 vvn;
@@ -302,16 +288,47 @@ static const struct sdhci_ops sdhci_esdhc_ops = { .get_max_clock = esdhc_of_get_max_clock, .get_min_clock = esdhc_of_get_min_clock, .platform_init = esdhc_of_platform_init, -#ifdef CONFIG_PM - .platform_suspend = esdhc_of_suspend, - .platform_resume = esdhc_of_resume, -#endif .adma_workaround = esdhci_of_adma_workaround, .set_bus_width = esdhc_pltfm_set_bus_width, .reset = sdhci_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, }; +#ifdef CONFIG_PM + +static u32 esdhc_proctl; +static int esdhc_of_suspend (struct device *dev) +{ +struct sdhci_host *host =dev_get_drvdata (dev); + + esdhc_proctl =sdhci_be32bs_readl (host,SDHCI_HOST_CONTROL ); + +return sdhci_suspend_host (host); +} + +static void esdhc_of_resume (device *dev) +{ +struct sdhci_host *host =dev_get_drvdata (dev); +int ret =sdhci_resume_host (host); + +if (ret ==0 ) { +/* Isn't this already done by sdhci_resume_host() ? --rmk */ +esdhc_of_enable_dma (host); +sdhci_be32bs_writel (host, esdhc_proctl,SDHCI_HOST_CONTROL ); + } + +return ret; +} + +static const struct dev_pm_ops esdhc_pmops = { + .suspend = esdhci_of_suspend, + .resume = esdhci_of_resume, +}; +#define ESDHC_PMOPS (&esdhc_pmops) +#else +#define ESDHC_PMOPS NULL +#endif +static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {/* * card detection could be handled via GPIO
@@ -373,7 +390,7 @@ static struct platform_driver sdhci_esdhc_driver = { .name = "sdhci-esdhc", .owner = THIS_MODULE, .of_match_table = sdhci_esdhc_of_match, - .pm = SDHCI_PLTFM_PMOPS, + .pm = ESDHC_PMOPS, }, .probe = sdhci_esdhc_probe, .remove = sdhci_esdhc_remove,
Signature · 1 line
1.8.3.1
PATCH 212/222 mmc: sdhci: remove platform_suspend/platform_resume callbacks
In reply to Russell King - ARM LinuxThe only user (sdhci-of-esdhc) no longer uses these callbacks, so lets remove them to discourage any further use.
--- drivers/mmc/host/sdhci.c | 6 ------ drivers/mmc/host/sdhci.h | 2 -- 2 files changed, 8 deletions(-)
drivers/mmc/host/sdhci.c +0 -6
@@ -2530,9 +2530,6 @@ EXPORT_SYMBOL_GPL(sdhci_disable_irq_wakeups);int sdhci_suspend_host (struct sdhci_host *host) { -if (host->ops->platform_suspend) - host->ops->platform_suspend (host); -sdhci_disable_card_detection (host);/* Disable tuning since we are suspending */
@@ -2589,9 +2586,6 @@ int sdhci_resume_host(struct sdhci_host *host)sdhci_enable_card_detection (host); -if (host->ops->platform_resume) - host->ops->platform_resume (host); -/* Set the re-tuning expiration flag */ if (host->flags &SDHCI_USING_RETUNING_TIMER ) host->flags |=SDHCI_NEEDS_RETUNING ;
drivers/mmc/host/sdhci.h +0 -2
@@ -289,8 +289,6 @@ struct sdhci_ops {int (*platform_execute_tuning)(struct sdhci_host *host,u32 opcode);void (*set_uhs_signaling)(struct sdhci_host *host,unsigned int uhs);void (*hw_reset)(struct sdhci_host *host); -void (*platform_suspend)(struct sdhci_host *host); -void (*platform_resume)(struct sdhci_host *host);void (*adma_workaround)(struct sdhci_host *host,u32 intmask);void (*platform_init)(struct sdhci_host *host);void (*card_event)(struct sdhci_host *host);
Signature · 1 line
1.8.3.1
PATCH 213/222 mmc: sdhci-tegra: get rid of special PRESENT_STATE register handling
In reply to Russell King - ARM Linuxsdhci-tegra provides a get_ro method, which overrides the checking of the write protect bit in the PRESENT_STATE register in sdhci.c:
if (host->flags & SDHCI_DEVICE_DEAD)
is_readonly = 0;
else if (host->ops->get_ro)
is_readonly = host->ops->get_ro(host);
else
is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE)
& SDHCI_WRITE_PROTECT);This means it's pointless detecting accesses to this register and manually setting the SDHCI_WRITE_PROTECT as it has no effect.
This means that the whole of tegra_sdhci_readl() can be removed and we can use the builtin sdhci readl functionality here.
--- drivers/mmc/host/sdhci-tegra.c | 14 -------------- 1 file changed, 14 deletions(-)
drivers/mmc/host/sdhci-tegra.c +0 -14
@@ -48,19 +48,6 @@ struct sdhci_tegra {int power_gpio; }; -static u32 tegra_sdhci_readl (struct sdhci_host *host,int reg) -{ -u32 val; - -if (unlikely (reg ==SDHCI_PRESENT_STATE )) { -/* Use wp_gpio here instead? */ - val =readl (host->ioaddr + reg); -return val |SDHCI_WRITE_PROTECT ; - } - -return readl (host->ioaddr + reg); -} -static u16 tegra_sdhci_readw (struct sdhci_host *host,int reg) {struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);
@@ -150,7 +137,6 @@ static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width)static const struct sdhci_ops tegra_sdhci_ops = { .get_ro = tegra_sdhci_get_ro, - .read_l = tegra_sdhci_readl, .read_w = tegra_sdhci_readw, .write_l = tegra_sdhci_writel, .set_clock = sdhci_set_clock,
Signature · 1 line
1.8.3.1
PATCH 214/222 mmc: sdhci: move regulator handling into sdhci_set_power()
In reply to Russell King - ARM LinuxMove the regulator handling into sdhci_set_power() rather than being in sdhci_do_set_ios(). This wraps all power control up into this function.
--- drivers/mmc/host/sdhci.c | 72 +++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 37 deletions(-)
drivers/mmc/host/sdhci.c +35 -37
@@ -1216,7 +1216,7 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) }EXPORT_SYMBOL_GPL (sdhci_set_clock); -static int sdhci_set_power (struct sdhci_host *host,unsigned short power) +static void sdhci_set_power (struct sdhci_host *host,unsigned short power) {u8 pwr =0 ;
@@ -1239,7 +1239,7 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power) }if (host->pwr == pwr) -return -1 ; +return ; host->pwr = pwr;
@@ -1247,38 +1247,43 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)sdhci_writeb (host,0 ,SDHCI_POWER_CONTROL );if (host->quirks2 &SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON )sdhci_runtime_pm_bus_off (host); -return 0 ; - } - -/* -* Spec says that we should clear the power reg before setting -* a new value. Some controllers don't seem to like this though. -*/ -if (!(host->quirks &SDHCI_QUIRK_SINGLE_POWER_WRITE )) -sdhci_writeb (host,0 ,SDHCI_POWER_CONTROL ); + power =0 ; + }else { +/* +* Spec says that we should clear the power reg before setting +* a new value. Some controllers don't seem to like this though. +*/ +if (!(host->quirks &SDHCI_QUIRK_SINGLE_POWER_WRITE )) +sdhci_writeb (host,0 ,SDHCI_POWER_CONTROL ); -/* -* At least the Marvell CaFe chip gets confused if we set the voltage -* and set turn on power at the same time, so set the voltage first. -*/ -if (host->quirks &SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER ) -sdhci_writeb (host, pwr,SDHCI_POWER_CONTROL ); +/* +* At least the Marvell CaFe chip gets confused if we set the +* voltage and set turn on power at the same time, so set the +* voltage first. +*/ +if (host->quirks &SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER ) +sdhci_writeb (host, pwr,SDHCI_POWER_CONTROL ); - pwr |=SDHCI_POWER_ON ; + pwr |=SDHCI_POWER_ON ; -sdhci_writeb (host, pwr,SDHCI_POWER_CONTROL ); +sdhci_writeb (host, pwr,SDHCI_POWER_CONTROL ); -if (host->quirks2 &SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON ) -sdhci_runtime_pm_bus_on (host); +if (host->quirks2 &SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON ) +sdhci_runtime_pm_bus_on (host); -/* -* Some controllers need an extra 10ms delay of 10ms before they -* can apply clock after applying power -*/ -if (host->quirks &SDHCI_QUIRK_DELAY_AFTER_POWER ) -mdelay (10 ); +/* +* Some controllers need an extra 10ms delay of 10ms before +* they can apply clock after applying power +*/ +if (host->quirks &SDHCI_QUIRK_DELAY_AFTER_POWER ) +mdelay (10 ); + } -return power; +if (host->vmmc) { +spin_unlock_irq (&host->lock); +mmc_regulator_set_ocr (host->mmc, host->vmmc, power); +spin_lock_irq (&host->lock); + } }/*****************************************************************************\
@@ -1428,7 +1433,6 @@ EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);static void sdhci_do_set_ios (struct sdhci_host *host,struct mmc_ios *ios) {unsigned long flags; -int vdd_bit =-1 ;u8 ctrl;spin_lock_irqsave (&host->lock, flags);
@@ -1460,15 +1464,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) }if (ios->power_mode ==MMC_POWER_OFF ) - vdd_bit =sdhci_set_power (host,-1 ); +sdhci_set_power (host,-1 );else - vdd_bit =sdhci_set_power (host, ios->vdd); - -if (host->vmmc && vdd_bit !=-1 ) { -spin_unlock_irqrestore (&host->lock, flags); -mmc_regulator_set_ocr (host->mmc, host->vmmc, vdd_bit); -spin_lock_irqsave (&host->lock, flags); - } +sdhci_set_power (host, ios->vdd);if (host->ops->platform_send_init_74_clocks) host->ops->platform_send_init_74_clocks (host, ios->power_mode);
Signature · 1 line
1.8.3.1
PATCH 215/222 mmc: sdhci: move remaining power handling into sdhci_set_power()
In reply to Russell King - ARM LinuxMove the remaining parts of the power handling in sdhci_do_set_ios() into sdhci_set_power().
--- drivers/mmc/host/sdhci.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-)
drivers/mmc/host/sdhci.c +7 -9
@@ -1216,12 +1216,13 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) }EXPORT_SYMBOL_GPL (sdhci_set_clock); -static void sdhci_set_power (struct sdhci_host *host,unsigned short power) +static void sdhci_set_power (struct sdhci_host *host,unsigned char mode, +unsigned short vdd) {u8 pwr =0 ; -if (power != (unsigned short )-1 ) { -switch (1 << power) { +if (mode !=MMC_POWER_OFF ) { +switch (1 << vdd) {case MMC_VDD_165_195 : pwr =SDHCI_POWER_180 ;break ;
@@ -1247,7 +1248,7 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)sdhci_writeb (host,0 ,SDHCI_POWER_CONTROL );if (host->quirks2 &SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON )sdhci_runtime_pm_bus_off (host); - power =0 ; + vdd =0 ; }else {/* * Spec says that we should clear the power reg before setting
@@ -1281,7 +1282,7 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)if (host->vmmc) {spin_unlock_irq (&host->lock); -mmc_regulator_set_ocr (host->mmc, host->vmmc, power); +mmc_regulator_set_ocr (host->mmc, host->vmmc, vdd);spin_lock_irq (&host->lock); } }
@@ -1463,10 +1464,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) host->clock = ios->clock; } -if (ios->power_mode ==MMC_POWER_OFF ) -sdhci_set_power (host,-1 ); -else -sdhci_set_power (host, ios->vdd); +sdhci_set_power (host, ios->power_mode, ios->vdd);if (host->ops->platform_send_init_74_clocks) host->ops->platform_send_init_74_clocks (host, ios->power_mode);
Signature · 1 line
1.8.3.1
PATCH 216/222 mmc: sdhci: track whether preset mode is currently enabled in hardware
In reply to Russell King - ARM LinuxTrack whether preset mode is currently enabled in hardware, and use that when making decisions elsewhere in the code rather than reading the register and checking the bit.
--- drivers/mmc/host/sdhci.c | 44 ++++++++++++++++++++++++++------------------ include/linux/mmc/sdhci.h | 1 + 2 files changed, 27 insertions(+), 18 deletions(-)
drivers/mmc/host/sdhci.c +26 -18
@@ -205,9 +205,14 @@ static void sdhci_do_reset(struct sdhci_host *host, u8 mask) host->ops->reset (host, mask); -if (host->flags & (SDHCI_USE_SDMA |SDHCI_USE_ADMA )) { -if ((host->ops->enable_dma) && (mask &SDHCI_RESET_ALL )) - host->ops->enable_dma (host); +if (mask &SDHCI_RESET_ALL ) { +if (host->flags & (SDHCI_USE_SDMA |SDHCI_USE_ADMA )) { +if (host->ops->enable_dma) + host->ops->enable_dma (host); + } + +/* Resetting the controller clears many */ + host->preset_enabled = false; } }
@@ -1126,8 +1131,7 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)return ;if (host->version >=SDHCI_SPEC_300 ) { -if (sdhci_readw (host,SDHCI_HOST_CONTROL2 ) & -SDHCI_CTRL_PRESET_VAL_ENABLE ) { +if (host->preset_enabled) {u16 pre_val; clk =sdhci_readw (host,SDHCI_CLOCK_CONTROL );
@@ -1491,13 +1495,13 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) (ios->timing == MMC_TIMING_UHS_SDR25)) ctrl |=SDHCI_CTRL_HISPD ; - ctrl_2 =sdhci_readw (host,SDHCI_HOST_CONTROL2 ); -if (!(ctrl_2 &SDHCI_CTRL_PRESET_VAL_ENABLE )) { +if (!host->preset_enabled) {sdhci_writeb (host, ctrl,SDHCI_HOST_CONTROL );/* * We only need to set Driver Strength if the * preset value enable is not set. */ + ctrl_2 =sdhci_readw (host,SDHCI_HOST_CONTROL2 ); ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK ;if (ios->drv_type ==MMC_SET_DRIVER_TYPE_A ) ctrl_2 |=SDHCI_CTRL_DRV_TYPE_A ;
@@ -2001,26 +2005,30 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)static void sdhci_enable_preset_value (struct sdhci_host *host,bool enable) { -u16 ctrl; -/* Host Controller v3.00 defines preset value registers */ if (host->version <SDHCI_SPEC_300 )return ; - ctrl =sdhci_readw (host,SDHCI_HOST_CONTROL2 ); -/* * We only enable or disable Preset Value if they are not already * enabled or disabled respectively. Otherwise, we bail out. */ -if (enable && !(ctrl &SDHCI_CTRL_PRESET_VAL_ENABLE )) { - ctrl |=SDHCI_CTRL_PRESET_VAL_ENABLE ; -sdhci_writew (host, ctrl,SDHCI_HOST_CONTROL2 ); - host->flags |=SDHCI_PV_ENABLED ; - }else if (!enable && (ctrl &SDHCI_CTRL_PRESET_VAL_ENABLE )) { - ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE ; +if (host->preset_enabled != enable) { +u16 ctrl =sdhci_readw (host,SDHCI_HOST_CONTROL2 ); + +if (enable) + ctrl |=SDHCI_CTRL_PRESET_VAL_ENABLE ; +else + ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE ; +sdhci_writew (host, ctrl,SDHCI_HOST_CONTROL2 ); - host->flags &= ~SDHCI_PV_ENABLED ; + +if (enable) + host->flags |=SDHCI_PV_ENABLED ; +else + host->flags &= ~SDHCI_PV_ENABLED ; + + host->preset_enabled = enable; } }
include/linux/mmc/sdhci.h +1 -0
@@ -143,6 +143,7 @@ struct sdhci_host {bool runtime_suspended;/* Host is runtime suspended */ bool bus_on;/* Bus power prevents runtime suspend */ +bool preset_enabled;/* Preset is enabled */ struct mmc_request *mrq;/* Current request */ struct mmc_command *cmd;/* Current command */
Signature · 1 line
1.8.3.1
PATCH 217/222 mmc: sdhci: fix SDHCI dependencies
In reply to Russell King - ARM Linux--- drivers/mmc/host/Kconfig | 63 ++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 31 deletions(-)
drivers/mmc/host/Kconfig +32 -31
@@ -25,8 +25,7 @@ config MMC_PXA If unsure, say N. config MMC_SDHCI - tristate "Secure Digital Host Controller Interface support" - depends on HAS_DMA + tristate help This selects the generic Secure Digital Host Controller Interface. It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
@@ -59,7 +58,8 @@ config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER config MMC_SDHCI_PCI tristate "SDHCI support on PCI bus" - depends on MMC_SDHCI && PCI + depends on PCI && HAS_DMA + select MMC_SDHCI help This selects the PCI Secure Digital Host Controller Interface. Most controllers found today are PCI devices.
@@ -83,7 +83,8 @@ config MMC_RICOH_MMC config MMC_SDHCI_ACPI tristate "SDHCI support for ACPI enumerated SDHCI controllers" - depends on MMC_SDHCI && ACPI + depends on ACPI && HAS_DMA + select MMC_SDHCI help This selects support for ACPI enumerated SDHCI controllers, identified by ACPI Compatibility ID PNP0D40 or specific
@@ -94,8 +95,8 @@ config MMC_SDHCI_ACPI If unsure, say N. config MMC_SDHCI_PLTFM - tristate "SDHCI platform and OF driver helper" - depends on MMC_SDHCI + tristate + select MMC_SDHCI help This selects the common helper functions support for Secure Digital Host Controller Interface based platform and OF drivers.
@@ -106,8 +107,8 @@ config MMC_SDHCI_PLTFM config MMC_SDHCI_OF_ARASAN tristate "SDHCI OF support for the Arasan SDHCI controllers" - depends on MMC_SDHCI_PLTFM - depends on OF + depends on OF && HAS_DMA + select MMC_SDHCI_PLTFM help This selects the Arasan Secure Digital Host Controller Interface (SDHCI). This hardware is found e.g. in Xilinx' Zynq SoC.
@@ -118,9 +119,9 @@ config MMC_SDHCI_OF_ARASAN config MMC_SDHCI_OF_ESDHC tristate "SDHCI OF support for the Freescale eSDHC controller" - depends on MMC_SDHCI_PLTFM - depends on PPC_OF + depends on PPC_OF && HAS_DMA select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER + select MMC_SDHCI_PLTFM help This selects the Freescale eSDHC controller support.
@@ -130,9 +131,9 @@ config MMC_SDHCI_OF_ESDHC config MMC_SDHCI_OF_HLWD tristate "SDHCI OF support for the Nintendo Wii SDHCI controllers" - depends on MMC_SDHCI_PLTFM - depends on PPC_OF + depends on PPC_OF && HAS_DMA select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER + select MMC_SDHCI_PLTFM help This selects the Secure Digital Host Controller Interface (SDHCI) found in the "Hollywood" chipset of the Nintendo Wii video game
@@ -144,8 +145,8 @@ config MMC_SDHCI_OF_HLWD config MMC_SDHCI_CNS3XXX tristate "SDHCI support on the Cavium Networks CNS3xxx SoC" - depends on ARCH_CNS3XXX - depends on MMC_SDHCI_PLTFM + depends on ARCH_CNS3XXX && HAS_DMA + select MMC_SDHCI_PLTFM help This selects the SDHCI support for CNS3xxx System-on-Chip devices.
@@ -155,9 +156,9 @@ config MMC_SDHCI_CNS3XXX config MMC_SDHCI_ESDHC_IMX tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller" - depends on ARCH_MXC - depends on MMC_SDHCI_PLTFM + depends on ARCH_MXC && HAS_DMA select MMC_SDHCI_IO_ACCESSORS + select MMC_SDHCI_PLTFM help This selects the Freescale eSDHC/uSDHC controller support found on i.MX25, i.MX35 i.MX5x and i.MX6x.
@@ -168,9 +169,9 @@ config MMC_SDHCI_ESDHC_IMX config MMC_SDHCI_DOVE tristate "SDHCI support on Marvell's Dove SoC" - depends on ARCH_DOVE - depends on MMC_SDHCI_PLTFM + depends on ARCH_DOVE && HAS_DMA select MMC_SDHCI_IO_ACCESSORS + select MMC_SDHCI_PLTFM help This selects the Secure Digital Host Controller Interface in Marvell's Dove SoC.
@@ -181,9 +182,9 @@ config MMC_SDHCI_DOVE config MMC_SDHCI_TEGRA tristate "SDHCI platform support for the Tegra SD/MMC Controller" - depends on ARCH_TEGRA - depends on MMC_SDHCI_PLTFM + depends on ARCH_TEGRA && HAS_DMA select MMC_SDHCI_IO_ACCESSORS + select MMC_SDHCI_PLTFM help This selects the Tegra SD/MMC controller. If you have a Tegra platform with SD or MMC devices, say Y or M here.
@@ -192,7 +193,8 @@ config MMC_SDHCI_TEGRA config MMC_SDHCI_S3C tristate "SDHCI support on Samsung S3C SoC" - depends on MMC_SDHCI && PLAT_SAMSUNG + depends on PLAT_SAMSUNG && HAS_DMA + select MMC_SDHCI help This selects the Secure Digital Host Controller Interface (SDHCI) often referrered to as the HSMMC block in some of the Samsung S3C
@@ -204,8 +206,8 @@ config MMC_SDHCI_S3C config MMC_SDHCI_SIRF tristate "SDHCI support on CSR SiRFprimaII and SiRFmarco SoCs" - depends on ARCH_SIRF - depends on MMC_SDHCI_PLTFM + depends on ARCH_SIRF && HAS_DMA + select MMC_SDHCI_PLTFM help This selects the SDHCI support for SiRF System-on-Chip devices.
@@ -215,8 +217,7 @@ config MMC_SDHCI_SIRF config MMC_SDHCI_PXAV3 tristate "Marvell MMP2 SD Host Controller support (PXAV3)" - depends on CLKDEV_LOOKUP - select MMC_SDHCI + depends on CLKDEV_LOOKUP && HAS_DMA select MMC_SDHCI_PLTFM default CPU_MMP2 help
@@ -228,8 +229,7 @@ config MMC_SDHCI_PXAV3 config MMC_SDHCI_PXAV2 tristate "Marvell PXA9XX SD Host Controller support (PXAV2)" - depends on CLKDEV_LOOKUP - select MMC_SDHCI + depends on CLKDEV_LOOKUP && HAS_DMA select MMC_SDHCI_PLTFM default CPU_PXA910 help
@@ -241,7 +241,8 @@ config MMC_SDHCI_PXAV2 config MMC_SDHCI_SPEAR tristate "SDHCI support on ST SPEAr platform" - depends on MMC_SDHCI && PLAT_SPEAR + depends on PLAT_SPEAR && HAS_DMA + select MMC_SDHCI help This selects the Secure Digital Host Controller Interface (SDHCI) often referrered to as the HSMMC block in some of the ST SPEAR range
@@ -263,7 +264,7 @@ config MMC_SDHCI_S3C_DMA config MMC_SDHCI_BCM_KONA tristate "SDHCI support on Broadcom KONA platform" - depends on ARCH_BCM_MOBILE + depends on ARCH_BCM_MOBILE && HAS_DMA select MMC_SDHCI_PLTFM help This selects the Broadcom Kona Secure Digital Host Controller
@@ -274,9 +275,9 @@ config MMC_SDHCI_BCM_KONA config MMC_SDHCI_BCM2835 tristate "SDHCI platform support for the BCM2835 SD/MMC Controller" - depends on ARCH_BCM2835 - depends on MMC_SDHCI_PLTFM + depends on ARCH_BCM2835 && HAS_DMA select MMC_SDHCI_IO_ACCESSORS + select MMC_SDHCI_PLTFM help This selects the BCM2835 SD/MMC controller. If you have a BCM2835 platform with SD or MMC devices, say Y or M here.
Signature · 1 line
1.8.3.1
PATCH 218/222 mmc: add support for power-on sequencing through DT
In reply to Russell King - ARM LinuxFrom: Olof Johansson <[email protected]>
To: linux-arm-kernel at lists.infradead.org
This patch enables support for power-on sequencing of SDIO peripherals through DT.
In general, it's quite common that wifi modules and other similar peripherals have several signals in addition to the SDIO interface that needs wiggling before the module will power on. It's common to have a reference clock, one or several power rails and one or several lines for reset/enable type functions.
The binding as written today introduces a number of reset gpios, a regulator and a clock specifier. The code will handle up to 2 gpio reset lines, but it's trivial to increase to more than that if needed at some point.
Implementation-wise, the MMC core has been changed to handle this during host power up, before the host interface is powered on. I have not yet implemented the power-down side, I wanted people to have a chance for reporting back w.r.t. issues (or comments on the bindings) first.
I have not tested the regulator portion, since the system and module I'm working on doesn't need one (Samsung Chromebook with Marvell 8797-based wifi). Testing of those portions (and reporting back) would be appreciated.
--- Documentation/devicetree/bindings/mmc/mmc.txt | 11 +++++++ drivers/mmc/core/core.c | 42 +++++++++++++++++++++++++++ drivers/mmc/core/host.c | 30 ++++++++++++++++++- include/linux/mmc/host.h | 5 ++++ 4 files changed, 87 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/mmc/mmc.txt +11 -0
@@ -5,6 +5,8 @@ these definitions. Interpreted by the OF core: - reg: Registers location and length. - interrupts: Interrupts used by the MMC controller. +- clocks: Clocks needed for the host controller, if any. +- clock-names: Goes with clocks above. Card detection: If no property below is supplied, host native card detect is used.
@@ -39,6 +41,15 @@ If no property below is supplied, host native card detect is used. - mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported - mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported +Card power and reset control: +The following properties can be specified for cases where the MMC +peripheral needs additional reset, regulator and clock lines. It is for +example common for WiFi/BT adapters to have these separate from the main +MMC bus: + - card-reset-gpios: Specify GPIOs for card reset (reset active low) + - card-external-vcc-supply: Regulator to drive (independent) card VCC + - clock with name "card_ext_clock": External clock provided to the card + *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line polarity properties, we have to fix the meaning of the "normal" and "inverted" line levels. We choose to follow the SDHCI standard, which specifies both those
drivers/mmc/core/core.c +42 -0
65 lines not on this page · raw message
drivers/mmc/core/host.c +29 -1
@@ -12,14 +12,18 @@* MMC host class device management */ +#include <linux/kernel.h> +#include <linux/clk.h> #include <linux/device.h> #include <linux/err.h> +#include <linux/gpio/consumer.h> #include <linux/idr.h> #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/pagemap.h> #include <linux/export.h> #include <linux/leds.h> +#include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/suspend.h>
@@ -312,7 +316,7 @@ int mmc_of_parse(struct mmc_host *host)u32 bus_width;bool explicit_inv_wp, gpio_inv_wp = false;enum of_gpio_flags flags; -int len, ret, gpio; +int i, len, ret, gpio;if (!host->parent || !host->parent->of_node)return 0 ;
@@ -415,6 +419,30 @@ int mmc_of_parse(struct mmc_host *host)if (explicit_inv_wp ^ gpio_inv_wp) host->caps2 |=MMC_CAP2_RO_ACTIVE_HIGH ; +/* Parse card power/reset/clock control */ +if (of_find_property (np,"card-reset-gpios" ,NULL )) { +struct gpio_desc *gpd; +for (i =0 ; i <ARRAY_SIZE (host->card_reset_gpios); i++) { + gpd =devm_gpiod_get_index (host->parent,"card-reset" , i); +if (IS_ERR (gpd)) +break ; +gpiod_direction_output (gpd,0 ); + host->card_reset_gpios[i] = gpd; + } + + gpd =devm_gpiod_get_index (host->parent,"card-reset" ,ARRAY_SIZE (host->card_reset_gpios)); +if (!IS_ERR (gpd)) { +dev_warn (host->parent,"More reset gpios than we can handle" ); +gpiod_put (gpd); + } + } + + host->card_clk =of_clk_get_by_name (np,"card_ext_clock" ); +if (IS_ERR (host->card_clk)) + host->card_clk =NULL ; + + host->card_regulator =regulator_get (host->parent,"card-external-vcc" ); +if (of_find_property (np,"cap-sd-highspeed" , &len)) host->caps |=MMC_CAP_SD_HIGHSPEED ;if (of_find_property (np,"cap-mmc-highspeed" , &len))
include/linux/mmc/host.h +5 -0
@@ -294,6 +294,11 @@ struct mmc_host {unsigned long clkgate_delay;#endif +/* card specific properties to deal with power and reset */ +struct regulator *card_regulator;/* External VCC needed by the card */ +struct gpio_desc *card_reset_gpios[2 ];/* External resets, active low */ +struct clk *card_clk;/* External clock needed by the card */ +/* host specific block data */ unsigned int max_seg_size;/* see blk_queue_max_segment_size */ unsigned short max_segs;/* see blk_queue_max_segments */
Signature · 1 line
1.8.3.1
PATCH 219/222 mmc: dw_mmc: call mmc_of_parse to fill in common options
In reply to Russell King - ARM LinuxFrom: Olof Johansson <[email protected]>
To: linux-arm-kernel at lists.infradead.org
The shared of parse function fills in common options for capabilities, etc, but it needs to be called from each driver that wants to make use of it. dw_mmc was missing the call.
--- drivers/mmc/host/dw_mmc.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/mmc/host/dw_mmc.c +2 -0
@@ -2140,6 +2140,8 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)if (!mmc)return -ENOMEM ; +mmc_of_parse (mmc); + slot =mmc_priv (mmc); slot->id = id; slot->mmc = mmc;
Signature · 1 line
1.8.3.1
PATCH 220/222 mmc: fix power-on sequencing for esdhc-imx driver
In reply to Russell King - ARM LinuxThere's no reason that this can't be applied to all MMC interfaces as it's all core code, so tie this into the core rather than it being optional for each host.
--- drivers/mmc/core/host.c | 90 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 25 deletions(-)
drivers/mmc/core/host.c +65 -25
@@ -316,7 +316,7 @@ int mmc_of_parse(struct mmc_host *host)u32 bus_width;bool explicit_inv_wp, gpio_inv_wp = false;enum of_gpio_flags flags; -int i, len, ret, gpio; +int len, ret, gpio;if (!host->parent || !host->parent->of_node)return 0 ;
@@ -419,30 +419,6 @@ int mmc_of_parse(struct mmc_host *host)if (explicit_inv_wp ^ gpio_inv_wp) host->caps2 |=MMC_CAP2_RO_ACTIVE_HIGH ; -/* Parse card power/reset/clock control */ -if (of_find_property (np,"card-reset-gpios" ,NULL )) { -struct gpio_desc *gpd; -for (i =0 ; i <ARRAY_SIZE (host->card_reset_gpios); i++) { - gpd =devm_gpiod_get_index (host->parent,"card-reset" , i); -if (IS_ERR (gpd)) -break ; -gpiod_direction_output (gpd,0 ); - host->card_reset_gpios[i] = gpd; - } - - gpd =devm_gpiod_get_index (host->parent,"card-reset" ,ARRAY_SIZE (host->card_reset_gpios)); -if (!IS_ERR (gpd)) { -dev_warn (host->parent,"More reset gpios than we can handle" ); -gpiod_put (gpd); - } - } - - host->card_clk =of_clk_get_by_name (np,"card_ext_clock" ); -if (IS_ERR (host->card_clk)) - host->card_clk =NULL ; - - host->card_regulator =regulator_get (host->parent,"card-external-vcc" ); -if (of_find_property (np,"cap-sd-highspeed" , &len)) host->caps |=MMC_CAP_SD_HIGHSPEED ;if (of_find_property (np,"cap-mmc-highspeed" , &len))
@@ -485,6 +461,66 @@ int mmc_of_parse(struct mmc_host *host)EXPORT_SYMBOL (mmc_of_parse); +static int mmc_of_parse_child (struct mmc_host *host) +{ +struct device_node *np; +struct clk *clk; +int i; + +if (!host->parent || !host->parent->of_node) +return 0 ; + + np = host->parent->of_node; + + host->card_regulator =regulator_get (host->parent,"card-external-vcc" ); +if (IS_ERR (host->card_regulator)) { +if (PTR_ERR (host->card_regulator) == -EPROBE_DEFER ) +return PTR_ERR (host->card_regulator); + host->card_regulator =NULL ; + } + +/* Parse card power/reset/clock control */ +if (of_find_property (np,"card-reset-gpios" ,NULL )) { +struct gpio_desc *gpd; +int level =0 ; + +/* +* If the regulator is enabled, then we can hold the +* card in reset with an active high resets. Otherwise, +* hold the resets low. +*/ +if (host->card_regulator &®ulator_is_enabled (host->card_regulator)) + level =1 ; + +for (i =0 ; i <ARRAY_SIZE (host->card_reset_gpios); i++) { + gpd =devm_gpiod_get_index (host->parent,"card-reset" , i); +if (IS_ERR (gpd)) { +if (PTR_ERR (gpd) == -EPROBE_DEFER ) +return PTR_ERR (gpd); +break ; + } +gpiod_direction_output (gpd,gpiod_is_active_low (gpd) | level); + host->card_reset_gpios[i] = gpd; + } + + gpd =devm_gpiod_get_index (host->parent,"card-reset" ,ARRAY_SIZE (host->card_reset_gpios)); +if (!IS_ERR (gpd)) { +dev_warn (host->parent,"More reset gpios than we can handle" ); +gpiod_put (gpd); + } + } + + clk =of_clk_get_by_name (np,"card_ext_clock" ); +if (IS_ERR (clk)) { +if (PTR_ERR (clk) == -EPROBE_DEFER ) +return PTR_ERR (clk); + clk =NULL ; + } + host->card_clk = clk; + +return 0 ; +} +/** * mmc_alloc_host - initialise the per-host structure. * @extra: sizeof private data structure
@@ -564,6 +600,10 @@ int mmc_add_host(struct mmc_host *host) {int err; + err =mmc_of_parse_child (host); +if (err) +return err; +WARN_ON ((host->caps &MMC_CAP_SDIO_IRQ ) && !host->ops->enable_sdio_irq);
Signature · 1 line
1.8.3.1
PATCH 221/222 ARM: cubox-i: add support for SD UHS-1 cards
In reply to Russell King - ARM Linux--- arch/arm/boot/dts/imx6qdl-cubox-i.dtsi | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-)
arch/arm/boot/dts/imx6qdl-cubox-i.dtsi +25 -1
@@ -111,6 +111,28 @@ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 >; }; + + pinctrl_cubox_i_usdhc2_100mhz: cubox-i-usdhc2-100mhz { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170b9 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100b9 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170b9 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170b9 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170b9 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130b9 + >; + }; + + pinctrl_cubox_i_usdhc2_200mhz: cubox-i-usdhc2-200mhz { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170f9 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100f9 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170f9 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170f9 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170f9 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130f9 + >; + }; }; };
@@ -131,8 +153,10 @@ }; &usdhc2 { - pinctrl-names = "default"; + pinctrl-names = "default", "state_100mhz", "state_200mhz"; pinctrl-0 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2>; + pinctrl-1 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2_100mhz>; + pinctrl-2 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2_200mhz>; vmmc-supply = <®_3p3v>; cd-gpios = <&gpio1 4 0>; status = "okay";
Signature · 1 line
1.8.3.1
PATCH 222/222 ARM: cubox-i: add support for Wifi/BT
In reply to Russell King - ARM Linux--- arch/arm/boot/dts/imx6qdl-cubox-i.dtsi | 8 +++ arch/arm/boot/dts/imx6qdl-microsom.dtsi | 98 +++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+)
arch/arm/boot/dts/imx6qdl-cubox-i.dtsi +8 -0
@@ -152,6 +152,14 @@ status = "okay"; }; +&uart4 { + status = "okay"; +}; + +&usdhc1 { + status = "okay"; +}; + &usdhc2 { pinctrl-names = "default", "state_100mhz", "state_200mhz"; pinctrl-0 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2>;
arch/arm/boot/dts/imx6qdl-microsom.dtsi +98 -0
126 lines not on this page · raw message
Signature · 1 line
1.8.3.1
cover The *Full* Cubox-i series
In reply to Russell King - ARM LinuxQuoted 8 lines · Russell King - ARM Linux
So that people can see what kind of a patch nightmare I'm in, and hopefully start being more co-operative towards getting patches into mainline, here is the *full* patch set for CuBox-i support that I'm presently sitting on.
Anything that can be done to make this easier would be very helpful, so I'm not spending lots of time tweaking some random patch and then having to remerge all these different sub-series.
Do you happen to have a branch that I can pull to test this on Tegra? Is there anything that I should be paying special attention to when testing?
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140425/1a66ff1c/attachment.sig>
cover The *Full* Cubox-i series
Quoted 6 lines · Thierry Reding
Quoted 5 lines · Russell King - ARM Linux
So that people can see what kind of a patch nightmare I'm in, and hopefully start being more co-operative towards getting patches into mainline, here is the *full* patch set for CuBox-i support that I'm presently sitting on.
Quoted 7 lines
Quoted 3 lines
Anything that can be done to make this easier would be very helpful, so I'm not spending lots of time tweaking some random patch and then having to remerge all these different sub-series.
Do you happen to have a branch that I can pull to test this on Tegra? Is there anything that I should be paying special attention to when testing?
One of the issues I'm _most_ concerned about is the L2C code. I only have a very limited number of platforms I can test that stuff out on.
The L2C code that I've now dumped into linux-next is there in an attempt to get more testing coverage, and it has resulted in that - Kevin's boot test revealed that it breaks on a Broadcom platform. I'm hoping Kevin will investigate further as per my emails, but I've no idea at the moment whether that's going to happen or not. I can't do it because I don't have access to any Broadcom hardware, neither do I have much idea as to its cause.
This is one of the big problems of the arm-soc automatic testing. It's all very well setting up some automatic testing facility, but it's utterly useless if you can't get at information needed to debug issues that it reports.
I know that various patches in there need squashing together or deleting (eg, whether we enable the power management via DT, or whether we always enable it) depending on the results of testing...
I'm at the end of knowing what to do with any of that stuff right now. The way I'm currently feeling, I might just as well delete the entire L2 cache changes branch because I'm *not* getting the support needed to make progress with it.
The same is true of the mmc stuff. It's a big patch set, and it's conflicting with other people's changes. That patch set is over two months old now, and it's received very little in the way of testing so far...
And as you can see from this patch set, I also have a whole load of changes to the Freescale FEC driver which haven't yet been properly posted (and as I found out yesterday from one of DaveM's review comments for a different driver, it already requires some changes.)
What I would like to do is to get some of these patches into a "finished" state (iow, reviewed and tested) and properly queued up for the next merge window so I don't have to mess around with soo many in-flux patches, as I have been for the last two to three months.
At the moment, the rate at which I seem to be able to get patches into the mainline kernel is down around 40 per cycle (basically the imx-drm debacle), which is piss poor when dealing with such a big backlog - a backlog which has taken just four months to build up.
Signature · 2 lines
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly improving, and getting towards what was expected from it.
cover The *Full* Cubox-i series
Quoted 14 lines · Russell King - ARM Linux
Quoted 13 lines · Thierry Reding
Quoted 8 lines · Russell King - ARM Linux
So that people can see what kind of a patch nightmare I'm in, and hopefully start being more co-operative towards getting patches into mainline, here is the *full* patch set for CuBox-i support that I'm presently sitting on.
Anything that can be done to make this easier would be very helpful, so I'm not spending lots of time tweaking some random patch and then having to remerge all these different sub-series.
Do you happen to have a branch that I can pull to test this on Tegra? Is there anything that I should be paying special attention to when testing?
[...]
Quoted 4 lines
What I would like to do is to get some of these patches into a "finished" state (iow, reviewed and tested) and properly queued up for the next merge window so I don't have to mess around with soo many in-flux patches, as I have been for the last two to three months.
Okay. I don't have access to a whole lot of hardware myself. It's really just a couple of Tegra boards, but I can still at least run the patches and report back if (or not) there's any breakage and help debug from there.
But I'm somewhat reluctant to go pick up 222 patches from my inbox manually if there's a branch available somewhere that I can pick up more easily.
Quoted 4 lines
At the moment, the rate at which I seem to be able to get patches into the mainline kernel is down around 40 per cycle (basically the imx-drm debacle), which is piss poor when dealing with such a big backlog - a backlog which has taken just four months to build up.
I've been through some of that same myself. Hence my offer to help.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140425/aadfc6da/attachment.sig>
cover The *Full* Cubox-i series
Quoted 8 lines · Thierry Reding
Okay. I don't have access to a whole lot of hardware myself. It's really just a couple of Tegra boards, but I can still at least run the patches and report back if (or not) there's any breakage and help debug from there.
But I'm somewhat reluctant to go pick up 222 patches from my inbox manually if there's a branch available somewhere that I can pick up more easily.
Let me re-merge for the changes which just happened to the MMC branch and I'll push this stuff out.
Thanks for the offer to help, much appreciated.
Signature · 2 lines
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly improving, and getting towards what was expected from it.
cover The *Full* Cubox-i series
In reply to Russell King - ARM LinuxQuoted 15 lines · Russell King - ARM Linux
Quoted 6 lines · Thierry Reding
Quoted 5 lines · Russell King - ARM Linux
So that people can see what kind of a patch nightmare I'm in, and hopefully start being more co-operative towards getting patches into mainline, here is the *full* patch set for CuBox-i support that I'm presently sitting on.
Quoted 7 lines
Quoted 3 lines
Anything that can be done to make this easier would be very helpful, so I'm not spending lots of time tweaking some random patch and then having to remerge all these different sub-series.
Do you happen to have a branch that I can pull to test this on Tegra? Is there anything that I should be paying special attention to when testing?
Quoted 8 lines
One of the issues I'm _most_ concerned about is the L2C code. I only have a very limited number of platforms I can test that stuff out on.
The L2C code that I've now dumped into linux-next is there in an attempt to get more testing coverage, and it has resulted in that - Kevin's boot test revealed that it breaks on a Broadcom platform. I'm hoping Kevin will investigate further as per my emails, but I've no idea at the moment whether that's going to happen or not.
Yes, it is happening. Actually Matt Porter (co-maintainer of BCM SoC support) has reproduced it and is looking into it since he has access to HW details/docs that I do not. However, both of us will be at ELC next week, so there might not be much progress immediately.
Kevin