[PATCH 07/13] drm: bridge/dw_hdmi: introduce interface to setting sample rate
Hi Russell, å¨ 2015/5/9 18:26, Russell King åé: > Introduce dw_hdmi_set_sample_rate(), which allows us to configure the > audio sample rate, setting the CTS/N values appropriately. > > Signed-off-by: Russell King Test on RK3288 platform, it works wells (like patch 03/13 reply) Test-by: Yakir Yang > --- > drivers/gpu/drm/bridge/dw_hdmi.c | 10 ++ > include/drm/bridge/dw_hdmi.h | 5 + > 2 files changed, 15 insertions(+) > > diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c > b/drivers/gpu/drm/bridge/dw_hdmi.c > index 75728ba552d0..0369fab5c695 100644 > --- a/drivers/gpu/drm/bridge/dw_hdmi.c > +++ b/drivers/gpu/drm/bridge/dw_hdmi.c > @@ -366,6 +366,16 @@ static void > hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi) > mutex_unlock(&hdmi->audio_mutex); > } > > +void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate) > +{ > + mutex_lock(&hdmi->audio_mutex); > + hdmi->sample_rate = rate; > + hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock, > + hdmi->sample_rate, hdmi->ratio); > + mutex_unlock(&hdmi->audio_mutex); > +} > +EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_rate); > + > /* >* this submodule is responsible for the video data synchronization. >* for example, for RGB 4:4:4 input, the data map is defined as > diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h > index de13bfc35634..763af51e1d60 100644 > --- a/include/drm/bridge/dw_hdmi.h > +++ b/include/drm/bridge/dw_hdmi.h > @@ -12,6 +12,8 @@ > > #include > > +struct dw_hdmi; > + > enum { > DW_HDMI_RES_8, > DW_HDMI_RES_10, > @@ -59,4 +61,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master, >void *data, struct drm_encoder *encoder, >struct resource *iores, int irq, >const struct dw_hdmi_plat_data *plat_data); > + > +void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate); > + > #endif /* __IMX_HDMI_H__ */
[PATCH 08/13] drm: bridge/dw_hdmi: introduce interfaces to enable and disable audio
Hi Russell, å¨ 2015/5/9 18:26, Russell King åé: > iMX6 devices suffer from an errata (ERR005174) where the audio FIFO can > be emptied while it is partially full, resulting in misalignment of the > audio samples. > > To prevent this, the errata workaround recommends writing N as zero > until the audio FIFO has been loaded by DMA. Writing N=0 prevents the > HDMI bridge from reading from the audio FIFO, effectively disabling > audio. > > This means we need to provide the audio driver with a pair of functions > to enable/disable audio. These are dw_hdmi_audio_enable() and > dw_hdmi_audio_disable(). > > A spinlock is introduced to ensure that setting the CTS/N values can't > race, ensuring that the audio driver calling the enable/disable > functions (which are called in an atomic context) can't race with a > modeset. > > Signed-off-by: Russell King Test on RK3288 platform, it works wells. Previously I use to switch off the i2s audio clock, for now seems it is not necessary. Test-by: Yakir Yang Thanks, Yakir Yang > --- > drivers/gpu/drm/bridge/dw_hdmi.c | 34 +- > include/drm/bridge/dw_hdmi.h | 2 ++ > 2 files changed, 35 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c > b/drivers/gpu/drm/bridge/dw_hdmi.c > index 0369fab5c695..adda3a988f36 100644 > --- a/drivers/gpu/drm/bridge/dw_hdmi.c > +++ b/drivers/gpu/drm/bridge/dw_hdmi.c > @@ -18,6 +18,7 @@ > #include > #include > #include > +#include > > #include > #include > @@ -124,8 +125,12 @@ struct dw_hdmi { > struct i2c_adapter *ddc; > void __iomem *regs; > > + spinlock_t audio_lock; > struct mutex audio_mutex; > unsigned int sample_rate; > + unsigned int audio_cts; > + unsigned int audio_n; > + bool audio_enable; > int ratio; > > void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); > @@ -347,7 +352,11 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi > *hdmi, > dev_dbg(hdmi->dev, "%s: samplerate=%ukHz ratio=%d pixelclk=%luMHz N=%d > cts=%d\n", > __func__, sample_rate, ratio, pixel_clk, n, cts); > > - hdmi_set_cts_n(hdmi, cts, n); > + spin_lock_irq(&hdmi->audio_lock); > + hdmi->audio_n = n; > + hdmi->audio_cts = cts; > + hdmi_set_cts_n(hdmi, cts, hdmi->audio_enable ? n : 0); > + spin_unlock_irq(&hdmi->audio_lock); > } > > static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi) > @@ -376,6 +385,28 @@ void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, > unsigned int rate) > } > EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_rate); > > +void dw_hdmi_audio_enable(struct dw_hdmi *hdmi) > +{ > + unsigned long flags; > + > + spin_lock_irqsave(&hdmi->audio_lock, flags); > + hdmi->audio_enable = true; > + hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n); > + spin_unlock_irqrestore(&hdmi->audio_lock, flags); > +} > +EXPORT_SYMBOL_GPL(dw_hdmi_audio_enable); > + > +void dw_hdmi_audio_disable(struct dw_hdmi *hdmi) > +{ > + unsigned long flags; > + > + spin_lock_irqsave(&hdmi->audio_lock, flags); > + hdmi->audio_enable = false; > + hdmi_set_cts_n(hdmi, hdmi->audio_cts, 0); > + spin_unlock_irqrestore(&hdmi->audio_lock, flags); > +} > +EXPORT_SYMBOL_GPL(dw_hdmi_audio_disable); > + > /* >* this submodule is responsible for the video data synchronization. >* for example, for RGB 4:4:4 input, the data map is defined as > @@ -1578,6 +1609,7 @@ int dw_hdmi_bind(struct device *dev, struct device > *master, > hdmi->encoder = encoder; > > mutex_init(&hdmi->audio_mutex); > + spin_lock_init(&hdmi->audio_lock); > > of_property_read_u32(np, "reg-io-width", &val); > > diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h > index 763af51e1d60..bae79f3c4d28 100644 > --- a/include/drm/bridge/dw_hdmi.h > +++ b/include/drm/bridge/dw_hdmi.h > @@ -63,5 +63,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master, >const struct dw_hdmi_plat_data *plat_data); > > void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate); > +void dw_hdmi_audio_enable(struct dw_hdmi *hdmi); > +void dw_hdmi_audio_disable(struct dw_hdmi *hdmi); > > #endif /* __IMX_HDMI_H__ */
[PATCH 02/13] drm: bridge/dw_hdmi: clean up phy configuration
Hi Russell, å¨ 2015/5/9 18:26, Russell King åé: > The phy configuration is dependent on the SoC, and we look up values for > some of the registers in SoC specific data. However, we had partially > programmed the phy before we had successfully looked up the clock rate. > Also, we were only checking that we had a valid configuration for the > currctrl register. > > Move all these lookups to the start of this function instead, so we can > check that all lookups were successful before beginning to program the > phy. > > Signed-off-by: Russell King Test on RK3288 platform, it works wells :-) Test-by: Best regards, Yakir Yang > --- > drivers/gpu/drm/bridge/dw_hdmi.c | 68 > +--- > 1 file changed, 35 insertions(+), 33 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c > b/drivers/gpu/drm/bridge/dw_hdmi.c > index 3494391e4199..23ea8c5c85b6 100644 > --- a/drivers/gpu/drm/bridge/dw_hdmi.c > +++ b/drivers/gpu/drm/bridge/dw_hdmi.c > @@ -753,12 +753,12 @@ static void dw_hdmi_phy_sel_interface_control(struct > dw_hdmi *hdmi, u8 enable) > static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, > unsigned char res, int cscon) > { > - unsigned res_idx, i; > + unsigned res_idx; > u8 val, msec; > - const struct dw_hdmi_plat_data *plat_data = hdmi->plat_data; > - const struct dw_hdmi_mpll_config *mpll_config = plat_data->mpll_cfg; > - const struct dw_hdmi_curr_ctrl *curr_ctrl = plat_data->cur_ctr; > - const struct dw_hdmi_phy_config *phy_config = plat_data->phy_config; > + const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; > + const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg; > + const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr; > + const struct dw_hdmi_phy_config *phy_config = pdata->phy_config; > > if (prep) > return -EINVAL; > @@ -778,6 +778,30 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, > unsigned char prep, > return -EINVAL; > } > > + /* PLL/MPLL Cfg - always match on final entry */ > + for (; mpll_config->mpixelclock != ~0UL; mpll_config++) > + if (hdmi->hdmi_data.video_mode.mpixelclock <= > + mpll_config->mpixelclock) > + break; > + > + for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++) > + if (hdmi->hdmi_data.video_mode.mpixelclock <= > + curr_ctrl->mpixelclock) > + break; > + > + for (; phy_config->mpixelclock != ~0UL; phy_config++) > + if (hdmi->hdmi_data.video_mode.mpixelclock <= > + phy_config->mpixelclock) > + break; > + > + if (mpll_config->mpixelclock == ~0UL || > + curr_ctrl->mpixelclock == ~0UL || > + phy_config->mpixelclock == ~0UL) { > + dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n", > + hdmi->hdmi_data.video_mode.mpixelclock); > + return -EINVAL; > + } > + > /* Enable csc path */ > if (cscon) > val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH; > @@ -803,40 +827,18 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, > unsigned char prep, > HDMI_PHY_I2CM_SLAVE_ADDR); > hdmi_phy_test_clear(hdmi, 0); > > - /* PLL/MPLL Cfg - always match on final entry */ > - for (i = 0; mpll_config[i].mpixelclock != (~0UL); i++) > - if (hdmi->hdmi_data.video_mode.mpixelclock <= > - mpll_config[i].mpixelclock) > - break; > - > - hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06); > - hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15); > - > - for (i = 0; curr_ctrl[i].mpixelclock != (~0UL); i++) > - if (hdmi->hdmi_data.video_mode.mpixelclock <= > - curr_ctrl[i].mpixelclock) > - break; > - > - if (curr_ctrl[i].mpixelclock == (~0UL)) { > - dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n", > - hdmi->hdmi_data.video_mode.mpixelclock); > - return -EINVAL; > - } > + hdmi_phy_i2c_write(hdmi, mpll_config->res[res_idx].cpce, 0x06); > + hdmi_phy_i2c_write(hdmi, mpll_config->res[res_idx].gmp, 0x15); > > /* CURRCTRL */ > - hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10); > + hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[res_idx], 0x10); >
[PATCH 03/13] drm: bridge/dw_hdmi: clean up hdmi_set_clk_regenerator()
Hi Russell, å¨ 2015/5/9 18:26, Russell King åé: > Clean up hdmi_set_clk_regenerator() by allowing it to take the audio > sample rate and ratio directly, rather than hiding it inside the > function. Raise the unsupported pixel clock/sample rate message from > debug to error level as this results in audio not working correctly. > > Signed-off-by: Russell King Test on RK3288 platform, it works wells while do not need clear the ncts_atomic_write bit in aud_n3, so no need more code it's find. Test-by: Best regards, Yakir Yang > --- > drivers/gpu/drm/bridge/dw_hdmi.c | 32 +++- > 1 file changed, 15 insertions(+), 17 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c > b/drivers/gpu/drm/bridge/dw_hdmi.c > index 23ea8c5c85b6..75099b80ca7e 100644 > --- a/drivers/gpu/drm/bridge/dw_hdmi.c > +++ b/drivers/gpu/drm/bridge/dw_hdmi.c > @@ -335,39 +335,37 @@ static unsigned int hdmi_compute_cts(unsigned int freq, > unsigned long pixel_clk, > } > > static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi, > - unsigned long pixel_clk) > + unsigned long pixel_clk, unsigned int sample_rate, unsigned int ratio) > { > - unsigned int clk_n, clk_cts; > + unsigned int n, cts; > > - clk_n = hdmi_compute_n(hdmi->sample_rate, pixel_clk, > -hdmi->ratio); > - clk_cts = hdmi_compute_cts(hdmi->sample_rate, pixel_clk, > -hdmi->ratio); > - > - if (!clk_cts) { > - dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n", > - __func__, pixel_clk); > - return; > + n = hdmi_compute_n(sample_rate, pixel_clk, ratio); > + cts = hdmi_compute_cts(sample_rate, pixel_clk, ratio); > + if (!cts) { > + dev_err(hdmi->dev, > + "%s: pixel clock/sample rate not supported: %luMHz / > %ukHz\n", > + __func__, pixel_clk, sample_rate); > } > > - dev_dbg(hdmi->dev, "%s: samplerate=%d ratio=%d pixelclk=%lu N=%d > cts=%d\n", > - __func__, hdmi->sample_rate, hdmi->ratio, > - pixel_clk, clk_n, clk_cts); > + dev_dbg(hdmi->dev, "%s: samplerate=%ukHz ratio=%d pixelclk=%luMHz N=%d > cts=%d\n", > + __func__, sample_rate, ratio, pixel_clk, n, cts); > > - hdmi_set_cts_n(hdmi, clk_cts, clk_n); > + hdmi_set_cts_n(hdmi, cts, n); > } > > static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi) > { > mutex_lock(&hdmi->audio_mutex); > - hdmi_set_clk_regenerator(hdmi, 7425); > + hdmi_set_clk_regenerator(hdmi, 7425, hdmi->sample_rate, > + hdmi->ratio); > mutex_unlock(&hdmi->audio_mutex); > } > > static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi) > { > mutex_lock(&hdmi->audio_mutex); > - hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock); > + hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock, > + hdmi->sample_rate, hdmi->ratio); > mutex_unlock(&hdmi->audio_mutex); > } >
[RESEND PATCH v1 2/2] drm: bridge/dw_hdmi-i2s-audio: add audio driver
Hi Paul, å¨ 2015/5/25 16:24, Paul Bolle åé: > Just a nit: a license mismatch. > > On Fri, 2015-05-22 at 10:14 -0500, Yakir Yang wrote: >> --- /dev/null >> +++ b/drivers/gpu/drm/bridge/dw_hdmi-i2s-audio.c >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License version 2 as >> + * published by the Free Software Foundation. > This states the license is GPL v2. > >> +MODULE_LICENSE("GPL"); > And, according to include/linux/module.h, this states the license is GPL > v2 or later. So I think that either the comment at the top of this file > or the ident used in the MODULE_LICENSE() macro should change. Thanks for your catch, got it :-) Yakir Yang > > Paul Bolle > > > >
[PATCH v2 1/3] drm: bridge/dw_hdmi: fixed codec style
On 2015å¹´03æ09æ¥ 14:48, Joe Perches wrote: > On Sun, 2015-03-08 at 21:48 -0700, Joe Perches wrote: > >> Shouldn't all of these be static? > Don't mind me. These shouldn't be static. > > I was a bit mislead by the commit message. > > I think it'd be better not to put patch-like > + and - lines in the commit description. > > cheers, Joe > > Okay, I will delete it from commit message. Thanks for reply :) >
[PATCH v2 1/3] drm: bridge/dw_hdmi: fixed codec style
On 2015å¹´03æ09æ¥ 15:05, Daniel Kurtz wrote: > On Mon, Mar 9, 2015 at 12:42 PM, Yakir Yang wrote: >> - const struct dw_hdmi_mpll_config *mpll_config = >> -hdmi->plat_data->mpll_cfg; >> - const struct dw_hdmi_curr_ctrl *curr_ctrl = hdmi->plat_data->cur_ctr; >> - const struct dw_hdmi_sym_term *sym_term = hdmi->plat_data->sym_term; >> >> + const struct dw_hdmi_plat_data *plat_data = hdmi->plat_data; >> + const struct dw_hdmi_mpll_config *mpll_config = plat_data->mpll_cfg; >> + const struct dw_hdmi_curr_ctrl *curr_ctrl = plat_data->cur_ctr; >> + const struct dw_hdmi_sym_term *sym_term = plat_data->sym_term; >> >> Signed-off-by: Yakir Yang > I agree with Joe Perches that this commit message is not very clear. > It should summarize what the patches is doing and why, not just be a > copy of the change. > e.g., "Using a local struct pointer to reduce one level of indirection > makes the code slightly more readable." > > , but otherwise this is: > Reviewed-by: Daniel Kurtz Okay, I will correct it now. Thanks for your reivew :) >> --- >> >> Changes in v2: None >> >> drivers/gpu/drm/bridge/dw_hdmi.c | 8 >> 1 file changed, 4 insertions(+), 4 deletions(-) >> >> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c >> b/drivers/gpu/drm/bridge/dw_hdmi.c >> index 9ffc257..b9d8d8a 100644 >> --- a/drivers/gpu/drm/bridge/dw_hdmi.c >> +++ b/drivers/gpu/drm/bridge/dw_hdmi.c >> @@ -900,10 +900,10 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, >> unsigned char prep, >> { >> unsigned res_idx, i; >> u8 val, msec; >> - const struct dw_hdmi_mpll_config *mpll_config = >> - hdmi->plat_data->mpll_cfg; >> - const struct dw_hdmi_curr_ctrl *curr_ctrl = hdmi->plat_data->cur_ctr; >> - const struct dw_hdmi_sym_term *sym_term = hdmi->plat_data->sym_term; >> + const struct dw_hdmi_plat_data *plat_data = hdmi->plat_data; >> + const struct dw_hdmi_mpll_config *mpll_config = plat_data->mpll_cfg; >> + const struct dw_hdmi_curr_ctrl *curr_ctrl = plat_data->cur_ctr; >> + const struct dw_hdmi_sym_term *sym_term = plat_data->sym_term; >> >> if (prep) >> return -EINVAL; >> -- >> 2.1.2 >> >> >> >> ___ >> Linux-rockchip mailing list >> Linux-rockchip at lists.infradead.org >> http://lists.infradead.org/mailman/listinfo/linux-rockchip > >
[PATCH v4 02/15] drm: bridge/dw_hdmi: wrap irq control in fucntions
Hi Philipp, On 2015å¹´03æ12æ¥ 18:24, Philipp Zabel wrote: > Hi Yakir, > > Am Samstag, den 28.02.2015, 21:28 -0500 schrieb Yakir Yang: >> Wrap irq control in functions, and then we can call in >> dw_hdmi_bind/dw_hdmi_unbind/dw_hdmi_resume/dw_hdmi_suspend >> functions. >> >> Signed-off-by: Yakir Yang > [...] Sorry, I can not understand this comment. could you please talk more detail about this one. Thank you very much :) >> @@ -1702,17 +1722,8 @@ EXPORT_SYMBOL_GPL(dw_hdmi_unbind); >> int dw_hdmi_suspend(struct device *dev) >> { >> struct dw_hdmi *hdmi = dev_get_drvdata(dev); >> -u8 ih_mute; >> - >> -/* Disable all interrupts */ >> -hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0); >> - >> - /* Disable top level interrupt bits in HDMI block */ >> -ih_mute = hdmi_readb(hdmi, HDMI_IH_MUTE) | >> - HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT | >> - HDMI_IH_MUTE_MUTE_ALL_INTERRUPT; >> >> -hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE); >> +hdmi_mute_interrupts(hdmi); >> >> return 0; >> } >> @@ -1722,19 +1733,7 @@ int dw_hdmi_resume(struct device *dev) >> { >> struct dw_hdmi *hdmi = dev_get_drvdata(dev); >> >> -/* >> - * Configure registers related to HDMI interrupt >> - * generation before registering IRQ. >> - */ >> -hdmi_writeb(hdmi, HDMI_PHY_HPD, HDMI_PHY_POL0); >> - >> -/* Clear Hotplug interrupts */ >> -hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0); >> - >> -dw_hdmi_fb_registered(hdmi); >> - >> -/* Unmute interrupts */ >> -hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0); >> +hdmi_unmute_interrupts(hdmi); >> >> return 0; >> } > Here you remove code added in the previous patch. > It would be better to just apply patch 2 first and then rebase patch 1 > on top of it. Thanks, I will reorder patch 1 & patch 2, in next vesion :) > regards > Philipp regards :) Yakir > > > >
[PATCH v4 04/15] drm: bridge/dw_hdmi: add identification registers parse and record
Hi philipp, On 2015å¹´03æ12æ¥ 18:29, Philipp Zabel wrote: > Am Samstag, den 28.02.2015, 21:35 -0500 schrieb Yakir Yang: >> By parsing the identification registers we can know what functions >> are present on the hdmi ip. >> >> Signed-off-by: Yakir Yang >> --- >> Changes in v4: >> -Correct phy_type assignment bug >> >> Changes in v3: >> - Add ID registers parse and record >> >> Changes in v2: None >> >> drivers/gpu/drm/bridge/dw_hdmi.c | 59 >> >> drivers/gpu/drm/bridge/dw_hdmi.h | 23 >> 2 files changed, 82 insertions(+) >> >> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c >> b/drivers/gpu/drm/bridge/dw_hdmi.c >> index 08f10da..937beed 100644 >> --- a/drivers/gpu/drm/bridge/dw_hdmi.c >> +++ b/drivers/gpu/drm/bridge/dw_hdmi.c >> @@ -79,6 +79,23 @@ static const u16 csc_coeff_rgb_in_eitu709[3][4] = { >> { 0x6756, 0x78ab, 0x2000, 0x0200 } >> }; >> >> +struct hdmi_id { >> +u8 design; >> +u8 revision; >> + >> +bool prepen; >> +bool audspdif; >> +bool audi2s; >> +bool hdmi14; >> +bool csc; >> +bool hdcp; >> +bool hdmi20; >> +bool confapb; >> +bool ahbauddma; >> +bool gpaud; >> +u8 phy_type; >> +}; >> >> struct hdmi_vmode { >> bool mdvi; >> bool mhsyncpolarity; >> @@ -111,6 +128,8 @@ struct dw_hdmi { >> struct clk *isfr_clk; >> struct clk *iahb_clk; >> >> +struct hdmi_id id; >> + >> struct hdmi_data_info hdmi_data; >> const struct dw_hdmi_plat_data *plat_data; >> >> @@ -1259,6 +1278,36 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct >> drm_display_mode *mode) >> return 0; >> } >> >> +static void hdmi_parse_id(struct dw_hdmi *hdmi) >> +{ >> +u8 config0_id, config1_id, config2_id, config3_id; >> + >> +config0_id = hdmi_readb(hdmi, HDMI_CONFIG0_ID); >> +config1_id = hdmi_readb(hdmi, HDMI_CONFIG1_ID); >> +config2_id = hdmi_readb(hdmi, HDMI_CONFIG2_ID); >> +config3_id = hdmi_readb(hdmi, HDMI_CONFIG3_ID); >> + >> +hdmi->id.prepen = config0_id & HDMI_CONFIG0_ID_PREPEN ? true : false; >> +hdmi->id.audi2s = config0_id & HDMI_CONFIG0_ID_AUDI2S ? true : false; >> +hdmi->id.hdmi14 = config0_id & HDMI_CONFIG0_ID_HDMI14 ? true : false; >> +hdmi->id.hdcp = config0_id & HDMI_CONFIG0_ID_HDCP ? true : false; >> +hdmi->id.csc = config0_id & HDMI_CONFIG0_ID_CSC ? true : false; >> +hdmi->id.audspdif = config0_id & HDMI_CONFIG0_ID_AUDSPDIF ? >> +true : false; >> + >> +hdmi->id.confapb = config1_id & HDMI_CONFIG1_ID_CONFAPB ? true : false; >> +hdmi->id.hdmi20 = config1_id & HDMI_CONFIG1_ID_HDMI20 ? true : false; >> + >> +hdmi->id.phy_type = config2_id; >> + >> +hdmi->id.gpaud = config3_id & HDMI_CONFIG3_ID_GPAUD ? true : false; >> +hdmi->id.ahbauddma = config3_id & HDMI_CONFIG3_ID_AHBAUDDMA ? >> + true : false; >> + >> +hdmi->id.design = hdmi_readb(hdmi, HDMI_DESIGN_ID); >> +hdmi->id.revision = hdmi_readb(hdmi, HDMI_REVISION_ID); >> +} > What is the purpose of creating a copy of all the feature bits? As far > as I can tell you are only ever using hdmi_id.design afterwards. Yeah, you are right. Seems hdmi audio have long long way to go. As for now, we just need hdmi_id.design to separate registers. Agree, I will simplify it in next verison. > > > regards > Philipp regards :) Yakir > > > -- next part -- An HTML attachment was scrubbed... URL: <http://lists.freedesktop.org/archives/dri-devel/attachments/20150312/5bb11ffe/attachment-0001.html>
[PATCH v4 02/15] drm: bridge/dw_hdmi: wrap irq control in fucntions
Hi Philipp, On 2015å¹´03æ12æ¥ 22:41, Philipp Zabel wrote: > Hi Yakir, > > Am Donnerstag, den 12.03.2015, 22:31 +0800 schrieb yakir: >> Hi Philipp, >> >> On 2015å¹´03æ12æ¥ 18:24, Philipp Zabel wrote: >>> Hi Yakir, >>> >>> Am Samstag, den 28.02.2015, 21:28 -0500 schrieb Yakir Yang: >>>> Wrap irq control in functions, and then we can call in >>>> dw_hdmi_bind/dw_hdmi_unbind/dw_hdmi_resume/dw_hdmi_suspend >>>> functions. >>>> >>>> Signed-off-by: Yakir Yang >>> [...] >> Sorry, I can not understand this comment. could you please talk more >> detail about this one. >> >> Thank you very much :) > I use "[...]" as a sign that I removed parts from the quoted email, like > this: > > [...] Okay, thanks for your explanation :) >>> Here you remove code added in the previous patch. >>> It would be better to just apply patch 2 first and then rebase patch 1 >>> on top of it. >> Thanks, I will reorder patch 1 & patch 2, in next vesion :) > regards > Philipp > regards :) Yakir > > -- next part -- An HTML attachment was scrubbed... URL: <http://lists.freedesktop.org/archives/dri-devel/attachments/20150312/0b590faf/attachment-0001.html>
[PATCH v4 03/15] drm: rockchip/dw_hdmi_rockchip: add resume/suspend support
Hi Philipp, On 2015å¹´03æ12æ¥ 18:24, Philipp Zabel wrote: > Am Samstag, den 28.02.2015, 21:32 -0500 schrieb Yakir Yang: >> Signed-off-by: Yakir Yang >> --- >> Changes in v4: None >> Changes in v3: >> - Setting the .pm member instead of suspend/resume >> >> Changes in v2: >> - Add suspend/resume support for dw_hdmi_rockchip driver >> >> drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 16 >> 1 file changed, 16 insertions(+) >> >> diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c >> b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c >> index d236faa..fc1d02e 100644 >> --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c >> +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c >> @@ -323,11 +323,27 @@ static int dw_hdmi_rockchip_remove(struct >> platform_device *pdev) >> return 0; >> } >> >> +static int dw_hdmi_rockchip_suspend(struct device *dev) >> +{ >> +return dw_hdmi_suspend(dev); >> +} >> + >> +static int dw_hdmi_rockchip_resume(struct device *dev) >> +{ >> +return dw_hdmi_resume(dev); >> +} > You could just skip dw_hdmi_rockchip_suspend/resume and > set .suspend/.resume in dw_hdmi_rockchip_pm directly to > dw_hdmi_suspend/resume. > Okay, sounds good, I will adjust it in next version. Thanks :) >> +static const struct dev_pm_ops dw_hdmi_rockchip_pm = { >> +.resume = dw_hdmi_rockchip_resume, >> +.suspend = dw_hdmi_rockchip_suspend, >> +}; >> + >> static struct platform_driver dw_hdmi_rockchip_pltfm_driver = { >> .probe = dw_hdmi_rockchip_probe, >> .remove = dw_hdmi_rockchip_remove, >> .driver = { >> .name = "dwhdmi-rockchip", >> +.pm = &dw_hdmi_rockchip_pm, >> .of_match_table = dw_hdmi_rockchip_dt_ids, >> }, >> }; > regards > Philipp > regards :) Yakir > >
[PATCH v4 14/15] ASoC: rockchip/rockchip-hdmi-audio: add sound driver for hdmi audio
Hi Mark, On 2015å¹´03æ27æ¥ 02:16, Mark Brown wrote: > On Sat, Feb 28, 2015 at 10:04:30PM -0500, Yakir Yang wrote: > >> +ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt); >> +if (ret < 0) { >> +dev_err(cpu_dai->dev, "failed to set cpu_dai fmt.\n"); >> +return ret; >> +} > You've already set this in the dai_link, no need to do it again. Okay, correct it in next v5. > + dev_info(&pdev->dev, "hdmi audio init success.\n"); > Please remove noisy prints like this. Okay, turn it to dev_debug(...) >> +free_cpu_of_node: >> +hdmi_audio_dai.cpu_of_node = NULL; >> +hdmi_audio_dai.platform_of_node = NULL; >> +free_priv_data: >> +snd_soc_card_set_drvdata(card, NULL); >> +platform_set_drvdata(pdev, NULL); >> +card->dev = NULL; > If any of these assignments is doing anything there's a problem with the > code. > Yes, when probe failed, program will goto this code. >> +{ >> +struct snd_soc_card *card = platform_get_drvdata(pdev); >> + >> +snd_soc_unregister_card(card); > devm_snd_soc_register_card() and you can remove this function entirely. do you mean that when I take devm_snd_soc_register_card() to register card, then I do not need unregister card any more(destroy with device) ? > >> +static const struct of_device_id rockchip_hdmi_audio_of_match[] = { >> +{ .compatible = "rockchip,rk3288-hdmi-audio", }, >> +{}, >> +}; > There is no documentation for this binding, binding documentation is > mandatory. Based on the compatible string this looks like it's specific > to the SoC rather than a design for a board - is the whole card part of > the SoC? It's my fault, cause the dts patch have not CC you, I will correct it in next v5 Thanks :) Yakir
[PATCH RFC 02/11] drm: bridge/dw_hdmi: use drm_hdmi_avi_infoframe_from_display_mode()
Hi Russell, å¨ 2015/3/31 19:57, Russell King - ARM Linux åé: > On Tue, Mar 31, 2015 at 05:02:20AM -0400, Yang Kuankuan wrote: >> Besides, as you are going an dw_hdmi cleanups, I want to point another bugs >> that relate to the HDMI CTS test. There are somethings wrong with General >> Control Pack, as for now the encoder color depth is 8-bit packing mode, >> so the color depth only support 24 bits per pixel video, In this case the >> CD filed in GCP should set to "Color Depth Not indicated". > I'm not sure I follow. > > According to the iMX6 documentation, setting the CD field to either > or 0100 indicates that the color depth is 24 bits per pixel, 8 bits per > component, 8 bit packing mode - there's no documented difference between > these. Yeah, that is the point. Though there's no designedware datasheet difference between "b" & 0100b" in vp_pr_cd, but I think the color_depth in vp_pr_cd register are mapping to CD0-CD3 filed in GCP packet, and acutally "b" & "0100b" are differnent in CD filed ("b Color Depth not indicated" & "0100b 24 bit per pixel"). If the CD filed is non-zero, that indicate we are support depth color mode(but I think the depth color mode need at least 36bpp). Besides as the HDMI Specification descripte, "/If the Sink dose not receive a GCP with non-zero CD from more than 4 consecutive video// //fields, it should exit deep color mode and reverting to 24-bit color/"(24-bit color is default). In the end I think if we only output 24-bit color, we should make the CD field to zero :) > Are you saying that you wish to pass something other than 24 bpp video > to your HDMI encoder? > >> In the end we should keep the *csc_color_depth(HDMI_CSC_SCALE)* & >> *color_depth(HDMI_VP_PR_CD)* to zero, code should modify like this GCP >> would test pass: > >From what you're describing, you want CD field = 0 and CSC_SCALE = 0. > It looks like hdmi_video_packetize() will set the CD field to zero if > hdmi_data.enc_color_depth = 0, but that would cause hdmi_video_sample() > and hdmi_video_csc() to fail. Maybe those two functions should be fixed > to accept a color depth of zero, and maybe you need to set > enc_color_depth to 0? > > Interestingly, HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP is defined to be > zero, but again, in the iMX6 data, it could take a value of either > 0x00 or 0x40. I think hdmi_video_csc() should set this to 0x40 if > hdmi_data.enc_color_depth = 0, and 0x40 for hdmi_data.enc_color_depth = 8. Agree! If we only output 24-bit color, we should let the hdmi_data.enc_color_depth = 0, and hdmi_video_csc() & hdmi_video_packetize() should handle the "enc_color_depth = 0". Best regards. Yakir Yang -- next part -- An HTML attachment was scrubbed... URL: <http://lists.freedesktop.org/archives/dri-devel/attachments/20150401/f7bfb8ee/attachment-0001.html>
[PATCH RFC 01/11] drm: bridge/dw_hdmi: clean up hdmi_set_clk_regenerator()
Hi Rusell, å¨ 2015/3/31 18:35, Russell King - ARM Linux åé: > On Tue, Mar 31, 2015 at 02:55:53AM -0400, Yang Kuankuan wrote: >> Hi Russell, >> >> I'm okay with this change, and also I am preparing that collect N/CTS >> setting to an array, like this : >> >> struct n_cts { >> unsigned int cts; >> unsigned int n; >> }; >> >> struct tmds_n_cts { >> unsigned long tmds; >> /* 1 entry each for 32KHz, 44.1KHz, and 48KHz */ >> struct n_cts n_cts[3]; >> }; >> >> static const struct tmds_n_cts n_cts_table[] = { >> { 25175000, {{ 28125, 4576}, { 31250, 7007}, { 25175, 6144} } }, >> } > I think this is something which should be a common helper rather than > being specific to the driver. I believe these are the standard values > for coherent audio/video clocks which can be found in the HDMI > specifications. Such a helper should document that it is only for > use when the audio and video clocks are coherent. Yep, it will be logical to add the n/cts calcu to a common helper. And actually the HDMI specifications have give the Revommended N and Expected CTS values for several standard TMDS clock rates(25.2/1.001 ...). > > (The HDMI spec gives alternative N values for use with auto-CTS value > generation for non-coherent clocks.) > > I'd also prefer the lookup to use the same units as the drm_display_mode > video clock specification, which is kHz, so we can eventually kill the > needless *1000 in dw_hdmi. > > One of the issues with using a common helper is that the common helper > would include the 1.001 clocks, which are allegedly unsupported by the > FSL iMX6 implementation, and, if proven that they don't work, we would > need some way to disable audio for those devices. Okay, but rockchip platform can handle the 1.001 clocks, so maybe we can call some valid function from dw_hdmi-imx & dw_hdmi-rockchip to mark the effective clock that platform support ? >> But I am confused by the "hdmi->ratio", this variable was modify to >> 100 in bind funciton, then nowhere would change it again. In this >> case "hdmi->ratio" seems an unused variable, can we remove it ? > I guess the FSL sources should be checked to find out what the intended > use for that was, and we then need to decide whether to keep it (and > implement it) or remove it. Need FSL ack... Best regards. Yakir Yang
[PATCH v3 2/3] drm: bridge/dw_hdmi_rockchip: improve hdmi eye-diagram test
Hi Russell, å¨ 2015/4/1 0:57, Russell King - ARM Linux åé: > On Mon, Mar 09, 2015 at 05:43:19PM +0800, Yakir Yang wrote: >> As for 1920x1080 display resolution, we should turn on the >> Transmitter Trailer-B. >> >> Signed-off-by: Yakir Yang >> --- > BTW, one of: > > drm/rockchip: dw_hdmi-rockchip: ... > drm/rockchip: dw_hdmi: ... > drm: rockchip: dw_hdmi-rockchip: ... > drm: rockchip: dw_hdmi: ... > drm: rockchip/dw_hdmi-rockchip: ... > drm: rockchip/dw_hdmi: ... > > might be a better subject line for patches which only touch the rockchip > part of this driver. I'd also suggest one of: Okay, I choose the "drm: rockchip/dw_hdmi-rockchip: ...", improve in v4 Thanks Yakir Yang > drm/imx: dw_hdmi-imx: ... > drm/imx: dw_hdmi: ... > drm: imx: dw_hdmi-imx: ... > drm: imx: dw_hdmi: ... > drm: imx/dw_hdmi-imx: ... > drm: imx/dw_hdmi: ... > > for iMX-only patches. It doesn't really mater which as we already have > a mixture of these formats already. >
[PATCH v3 0/3] Improve eye-diagram & single-ended test for rk3288 hdmi
Hi Russell, å¨ 2015/4/1 0:25, Russell King - ARM Linux åé: > On Mon, Mar 09, 2015 at 05:42:21PM +0800, Yakir Yang wrote: >> RK3288 hdmi eye-diagram test would fail when pixel clock is 148.5MHz, >> and single-ended test would failed when display mode is 74.25MHz. > Has anyone reviewed these changes yet? I don't see any replies, nor > are they in David's git tree. To me, they look mostly fine - the only > issue I get is that the final patch doesn't apply cleanly to dw_hdmi.h > since they're generated against a tree which has audio support merged. > I also see no regressions on iMX6, so I think they can be merged. > > Unless anyone has any objections, I'll add these to my queue for David. > > Thanks. Wooh, thanks, I will send v4 now to improve the "drm: dw_hdmi/dw_hdmi-rockchip". Best regards, Yakir Yang
[PATCH RFC 09/11] sound/core: add IEC958 channel status helper
Hi Russell, å¨ 2015/3/31 17:13, Russell King - ARM Linux åé: > On Tue, Mar 31, 2015 at 04:30:39AM -0400, Yang Kuankuan wrote: >>> + cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; >>> + cs[1] = IEC958_AES1_CON_GENERAL; >>> + cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC; >>> + cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | fs; >>> + >> Pretty good, also suitable to rockchip platform, but why not add the >> "IEC958_AES2_CON_CHANNEL_MASK" & "IEC958_AES2_CON_WORDLEN" ? >> >> Seems sample frequency & channle number & word length are the basic >> message :) > I was debating about the word length, and that's something I'll add > later to it - but only if length shows that we have the 5th byte > available in the buffer. Most users seem to only use the first four > bytes. > > As for the channel number, this is intentionally left to the driver - > most cases I've found either the driver isn't interested, or where > they are interested (the only case I know of is my dw_hdmi ahb audio > driver), it's more appropriate to generate a baseline channel status, > and let the driver iterate over the channels adding the appropriate > channel number in. Okay, agree with you to keep baseline channel status, but seems dw_hdmi i2s audio are interested in channle number (to fill in schnl resigeters). Best regards. Yakir Yang
[PATCH] drm: bridge/dw_hdmi: Return num_modes in dw_hdmi_connector_get_modes
Doug, å¨ 2015/6/5 2:04, Doug Anderson åé: > The dw_hdmi_connector_get_modes() function accidentally forgets to > return the number of modes it added, although it has this information > stored in a local variable. Let's fix that. > > Without this fix, drm_helper_probe_single_connector_modes_merge_bits() > could get confused and always call drm_add_modes_noedid(). That's not > right. > > Signed-off-by: Doug Anderson Test-by: Yakir Yang Thanks for your patch, it looks good to me. I And I test it on my 1080p TV, found that the 800x600 at 56Hz resolution which don't indicate in edid would no longer report, that is right :) 3331connectedHDMI-A510x2901731 modes: name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot) 800x600 60 800 840 968 1056 600 601 605 628 flags: phsync, pvsync; type: driver 800x600 56 800 824 896 1024 600 601 603 625 flags: phsync, pvsync; type: driver 640x480 60 640 656 752 800 480 490 492 525 flags: nhsync, nvsync; type: driver 640x480 60 640 656 752 800 480 489 492 525 flags: nhsync, nvsync; type: driver First detailed timing is preferred timing Established timings supported: 720x400 at 70Hz 640x480 at 60Hz 640x480 at 75Hz 800x600 at 60Hz 800x600 at 75Hz 1024x768 at 60Hz 1024x768 at 75Hz 1280x1024 at 75Hz Standard timings supported: 1152x864 at 75Hz 1280x1024 at 60Hz 1920x1080 at 60Hz Thanks ! - Yakir > --- > drivers/gpu/drm/bridge/dw_hdmi.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c > b/drivers/gpu/drm/bridge/dw_hdmi.c > index 594f84c..816d104 100644 > --- a/drivers/gpu/drm/bridge/dw_hdmi.c > +++ b/drivers/gpu/drm/bridge/dw_hdmi.c > @@ -1395,7 +1395,7 @@ static int dw_hdmi_connector_get_modes(struct > drm_connector *connector) > struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, >connector); > struct edid *edid; > - int ret; > + int ret = 0; > > if (!hdmi->ddc) > return 0; > @@ -1412,7 +1412,7 @@ static int dw_hdmi_connector_get_modes(struct > drm_connector *connector) > dev_dbg(hdmi->dev, "failed to get edid\n"); > } > > - return 0; > + return ret; > } > > static enum drm_mode_status -- next part -- An HTML attachment was scrubbed... URL: <http://lists.freedesktop.org/archives/dri-devel/attachments/20150605/4f01257f/attachment.html>
[PATCH v3 05/15] drm: bridge/dw_hdmi: combine hdmi_set_clock_regenerator_n() and hdmi_regenerate_cts()
On 02/05/2015 11:54 PM, Daniel Kurtz wrote: > On Tue, Feb 3, 2015 at 11:12 PM, Yakir Yang wrote: >> Signed-off-by: Yakir Yang > Reviewed-by: Daniel Kurtz Okay, add in next verson4. Thanks. : ) > >> --- >> Changes in v3: >> - Combine hdmi_set_clock_regenerator_n() and hdmi_regenerate_cts() >> >> Changes in v2: None >> >> drivers/gpu/drm/bridge/dw_hdmi.c | 16 ++-- >> 1 file changed, 6 insertions(+), 10 deletions(-) >> >> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c >> b/drivers/gpu/drm/bridge/dw_hdmi.c >> index 7b5b664..262163f 100644 >> --- a/drivers/gpu/drm/bridge/dw_hdmi.c >> +++ b/drivers/gpu/drm/bridge/dw_hdmi.c >> @@ -196,19 +196,16 @@ static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 >> data, unsigned int reg, >> hdmi_modb(hdmi, data << shift, mask, reg); >> } >> >> -static void hdmi_set_clock_regenerator_n(struct dw_hdmi *hdmi, >> -unsigned int value) >> +static void hdmi_set_clock_regenerator(struct dw_hdmi *hdmi, >> + unsigned int n, unsigned int cts) >> { >> - hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1); >> - hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2); >> - hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3); >> + hdmi_writeb(hdmi, n & 0xff, HDMI_AUD_N1); >> + hdmi_writeb(hdmi, (n >> 8) & 0xff, HDMI_AUD_N2); >> + hdmi_writeb(hdmi, (n >> 16) & 0x0f, HDMI_AUD_N3); >> >> /* nshift factor = 0 */ >> hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3); >> -} >> >> -static void hdmi_regenerate_cts(struct dw_hdmi *hdmi, unsigned int cts) >> -{ >> /* Must be set/cleared first */ >> hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); >> >> @@ -374,8 +371,7 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi >> *hdmi, >> __func__, hdmi->sample_rate, hdmi->ratio, >> pixel_clk, clk_n, clk_cts); >> >> - hdmi_set_clock_regenerator_n(hdmi, clk_n); >> - hdmi_regenerate_cts(hdmi, clk_cts); >> + hdmi_set_clock_regenerator(hdmi, clk_n, clk_cts); >> } >> >> static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi) >> -- >> 2.1.2 >> >> > >
[PATCH v3 04/15] drm: bridge/dw_hdmi: add indentification registers parse and record
On 02/05/2015 11:46 PM, Daniel Kurtz wrote: > On Tue, Feb 3, 2015 at 11:11 PM, Yakir Yang wrote: >> By parsing the indentification registers we can know what functions >> are present on the hdmi ip. >> >> Signed-off-by: Yakir Yang >> --- >> Changes in v3: >> - Add ID registers parse and record >> >> Changes in v2: None >> >> drivers/gpu/drm/bridge/dw_hdmi.c | 59 >> >> drivers/gpu/drm/bridge/dw_hdmi.h | 23 >> 2 files changed, 82 insertions(+) >> >> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c >> b/drivers/gpu/drm/bridge/dw_hdmi.c >> index 08f10da..7b5b664 100644 >> --- a/drivers/gpu/drm/bridge/dw_hdmi.c >> +++ b/drivers/gpu/drm/bridge/dw_hdmi.c >> @@ -79,6 +79,23 @@ static const u16 csc_coeff_rgb_in_eitu709[3][4] = { >> { 0x6756, 0x78ab, 0x2000, 0x0200 } >> }; >> >> +struct hdmi_id { >> + u8 design; >> + u8 revision; >> + >> + bool prepen; >> + bool audspdif; >> + bool audi2s; >> + bool hdmi14; >> + bool csc; >> + bool hdcp; >> + bool hdmi20; >> + bool confapb; >> + bool ahbauddma; >> + bool gpaud; >> + u8 phy_type; >> +}; >> + >> struct hdmi_vmode { >> bool mdvi; >> bool mhsyncpolarity; >> @@ -111,6 +128,8 @@ struct dw_hdmi { >> struct clk *isfr_clk; >> struct clk *iahb_clk; >> >> + struct hdmi_id id; >> + >> struct hdmi_data_info hdmi_data; >> const struct dw_hdmi_plat_data *plat_data; >> >> @@ -1259,6 +1278,36 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct >> drm_display_mode *mode) >> return 0; >> } >> >> +static void hdmi_parse_id(struct dw_hdmi *hdmi) >> +{ >> + u8 config0_id, config1_id, config2_id, config3_id; >> + >> + config0_id = hdmi_readb(hdmi, HDMI_CONFIG0_ID); >> + config1_id = hdmi_readb(hdmi, HDMI_CONFIG1_ID); >> + config2_id = hdmi_readb(hdmi, HDMI_CONFIG2_ID); >> + config3_id = hdmi_readb(hdmi, HDMI_CONFIG3_ID); >> + >> + hdmi->id.prepen = config0_id & HDMI_CONFIG0_ID_PREPEN ? true : false; > These could all be "!!(A & B)", but perhaps that is just a matter of > personal preference. Okay, "!!(A & B)" looks good, I will modify it. Thanks. : ) >> + hdmi->id.audi2s = config0_id & HDMI_CONFIG0_ID_AUDI2S ? true : false; >> + hdmi->id.hdmi14 = config0_id & HDMI_CONFIG0_ID_HDMI14 ? true : false; >> + hdmi->id.hdcp = config0_id & HDMI_CONFIG0_ID_HDCP ? true : false; >> + hdmi->id.csc = config0_id & HDMI_CONFIG0_ID_CSC ? true : false; >> + hdmi->id.audspdif = config0_id & HDMI_CONFIG0_ID_AUDSPDIF ? >> + true : false; >> + >> + hdmi->id.confapb = config1_id & HDMI_CONFIG1_ID_CONFAPB ? true : >> false; >> + hdmi->id.hdmi20 = config1_id & HDMI_CONFIG1_ID_HDMI20 ? true : false; >> + >> + hdmi->id.phy_type = config2_id & HDMI_CONFIG2_ID; > HDMI_CONFIG2_ID is a register offset, not a mask. Thanks, I will correct it. >> + >> + hdmi->id.gpaud = config3_id & HDMI_CONFIG3_ID_GPAUD ? true : false; >> + hdmi->id.ahbauddma = config3_id & HDMI_CONFIG3_ID_AHBAUDDMA ? >> +true : false; >> + >> + hdmi->id.design = hdmi_readb(hdmi, HDMI_DESIGN_ID); >> + hdmi->id.revision = hdmi_readb(hdmi, HDMI_REVISION_ID); >> +} >> + >> /* Wait until we are registered to enable interrupts */ >> static int dw_hdmi_fb_registered(struct dw_hdmi *hdmi) >> { >> @@ -1670,6 +1719,16 @@ int dw_hdmi_bind(struct device *dev, struct device >> *master, >> hdmi_readb(hdmi, HDMI_PRODUCT_ID0), >> hdmi_readb(hdmi, HDMI_PRODUCT_ID1)); >> >> + /* Config IDs */ >> + dev_info(dev, >> +"Detected HDMI config_id 0x%x:0x%x:0x%x:0x%x\n", >> +hdmi_readb(hdmi, HDMI_CONFIG0_ID), >> +hdmi_readb(hdmi, HDMI_CONFIG1_ID), >> +hdmi_readb(hdmi, HDMI_CONFIG2_ID), >> +hdmi_readb(hdmi, HDMI_CONFIG3_ID)); >> + >> + hdmi_parse_id(hdmi); > It seems a bit silly to read the regs once to print them, and then > again in hdmi_parse_id(). > Perhaps move the dev_info
[PATCH] drm/analogix_dp: Ensure the panel is properly prepared/unprepared
Sean, On 07/30/2016 03:16 AM, Sean Paul wrote: > Instead of just preparing the panel on bind, actually prepare/unprepare > during modeset/disable. The panel must be prepared in order to read hpd > status, so we need to refcount the prepares in order to ensure we don't > accidentally turn the panel off at the wrong time. > > Signed-off-by: Sean Paul > --- > > > Hi Yakir, > This is what I was talking about upthread. I've tested it and it seems to be > working. > > What do you think? Thanks for your patch, and it works. But I have introduced two questions, and I haven't found a way to fixed them. > Sean > > > > drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 48 +- > 1 file changed, 37 insertions(+), 11 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > index 32715da..7b764a4 100644 > --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > @@ -960,11 +960,27 @@ enum drm_connector_status > analogix_dp_detect(struct drm_connector *connector, bool force) > { > struct analogix_dp_device *dp = to_dp(connector); > + enum drm_connector_status status = connector_status_disconnected; > + int ret; > > - if (analogix_dp_detect_hpd(dp)) > - return connector_status_disconnected; > + if (dp->plat_data->panel && dp->dpms_mode != DRM_MODE_DPMS_ON) { > + ret = drm_panel_prepare(dp->plat_data->panel); > + if (ret) { > + DRM_ERROR("failed to setup panel (%d)\n", ret); > + return connector_status_disconnected; > + } > + } > + > + if (!analogix_dp_detect_hpd(dp)) > + status = connector_status_connected; > + > + if (dp->plat_data->panel && dp->dpms_mode != DRM_MODE_DPMS_ON) { > + ret = drm_panel_unprepare(dp->plat_data->panel); > + if (ret) > + DRM_ERROR("failed to setup the panel ret = %d\n", ret); > + } > > - return connector_status_connected; > + return status; 1. Panel would flicker at system boot time. Your patch would flash the panel power in connector->detect() function when dp->dpms_mode isn't DRM_MODE_DPMS_OFF. So when userspace keep detect the connector status in boot time, we could see panel would flicker (light up for a while, and turn off again, and keep loop for several time). I have copied some kernel logs: [ 11.065267] YKK - analogix_dp_detect:1052 [ 11.729596] YKK - analogix_dp_get_modes:1016 [ 11.737608] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 11.749229] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 11.760799] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 13.315962] YKK - analogix_dp_detect:1052 [ 13.984702] YKK - analogix_dp_get_modes:1016 [ 13.992977] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 14.004414] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 14.015842] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 14.183109] YKK - analogix_dp_bridge_pre_enable:1147 [ 14.306301] rockchip-dp ff97.edp: Link Training Clock Recovery success [ 14.319130] rockchip-dp ff97.edp: Link Training success! [ 14.326388] rockchip-dp ff97.edp: wait SYS_CTL_2. [ 14.437247] rockchip-dp ff97.edp: Timeout of video streamclk ok [ 14.443585] rockchip-dp ff97.edp: unable to config video > } > > static void analogix_dp_connector_destroy(struct drm_connector *connector) > @@ -1035,6 +1051,18 @@ static int analogix_dp_bridge_attach(struct drm_bridge > *bridge) > return 0; > } > > +static void analogix_dp_bridge_pre_enable(struct drm_bridge *bridge) > +{ > + struct analogix_dp_device *dp = bridge->driver_private; > + int ret; > + > + if (dp->plat_data->panel) { > + ret = drm_panel_prepare(dp->plat_data->panel); > + if (ret) > + DRM_ERROR("failed to setup the panel ret = %d\n", ret); > + } 2. Driver would failed to read EDID in some case. Panel would only be powered up in bridge->pre_enable() function which later than connector->get_modes() function, and this would caused DPCD transfer failed in analogix_dp_handle_edid(). This seem won't caused too big issue, cause userspace would
[PATCH v14 0/17] Add Analogix Core Display Port Driver
On 07/29/2016 04:38 PM, Tomeu Vizoso wrote: > On 5 April 2016 at 04:06, Yakir Yang wrote: >> Hi Daniel, >> >> >> On 03/31/2016 06:15 PM, Daniel Vetter wrote: >>> On Mon, Feb 15, 2016 at 07:08:05PM +0800, Yakir Yang wrote: >>>> Hi all, >>>> >>>> The Samsung Exynos eDP controller and Rockchip RK3288 eDP controller >>>> share the same IP, so a lot of parts can be re-used. I split the common >>>> code into bridge directory, then rk3288 and exynos only need to keep >>>> some platform code. Cause I can't find the exact IP name of exynos dp >>>> controller, so I decide to name dp core driver with "analogix" which I >>>> find in rk3288 eDP TRM >>>> >>>> But there are still three light registers setting different between >>>> exynos and rk3288. >>>> 1. RK3288 have five special pll registers which not indicate in exynos >>>> dp controller. >>>> 2. The address of DP_PHY_PD(dp phy power manager register) are different >>>> between rk3288 and exynos. >>>> 3. Rk3288 and exynos have different setting with AUX_HW_RETRY_CTL(dp >>>> debug >>>> register). >>>> >>>> Due to Mark Yao have introduced the ATOMIC support to Rockchip drm, so >>>> it's >>>> okay to use the ATOMIC helpers functions in connector_funcs. No need to >>>> splict >>>> the connector init to platform driver anymore, and this is the biggest >>>> change >>>> since version 11. >>>> >>>> This v14 didn't have lots of new changes which seems not the correct time >>>> to >>>> upgrade the version number, but I have changed ordering of patches >>>> (adding 2 >>>> more, and removing 2 out). Especially to prevent confusing people, so I >>>> updated >>>> the whole series. >>> So I'm jumping into this part way late, but just noticed (well Thierry >>> pointed this out to me) that the exynos dp driver reinvents all the dp and >>> dp-aux helpers we already. That's somewhat okish for a private driver (and >>> exynos has a reputation for that kind of stuff), but imo not ok for a >>> shared driver. >>> >>> Not saying this should block merging this patch, but it really needs to be >>> addressed. All the dp aux and edid read code in the current >>> exynos_dp_core/reg.c files needs to be replaced with dp helpers and the >>> core i2c edid reading code. >>> >>> Who's going to sign up to do this? >> >> Volunteer to that, after finish this thread, I would send new series to >> switch to take use of dp helper. > Hi Yakir, > > do you have plans to do this work in the short term? If not, I can tackle it. Wow, that would be great if you like to tackle it :-D I always keep this in my mind, but haven't found an chance to finish it. I would like to sit in your Cc list when you post them out ;) Best Regards, - Yakir > Regards, > > Tomeu > >> :-D >> - Yakir >> >> >>> -Daniel >>> >>>> Thanks, >>>> - Yakir >>>> >>>> >>>> Changes in v14: >>>> - Rebase the new changes in imx-dp driver >>>> - Split up this patch into 3 parts, make this easy to review (Heiko) >>>> - Remove the Rockchip DP PHY to an separate thread (Heiko) >>>> https://patchwork.kernel.org/patch/8312701/ >>>> >>>> Changes in v13: >>>> - Use .enable instead of preprare/commit in encoder_helper_funcs (Heiko) >>>> - Fix the missing parameters with drm_encoder_init() helper function. >>>> (Heiko) >>>> >>>> Changes in v12: >>>> - Move the connector init to analogix_dp driver, and using ATOMIC helper >>>> (Heiko) >>>> - Add the ack from Jingoo >>>> - Remove the enum link_rate_type struct, using the marcos in >>>> drm_dp_helper.h (Jingoo) >>>> >>>> Changes in v11: >>>> - Uses tabs to fix the indentation issues in analogix_dp_core.h (Heiko) >>>> - Rename the "analogix,need-force-hpd" to common 'force-hpd' (Rob) >>>> - Add the ack from Rob Herring >>>> - Revert parts of Gustavo Padovan's changes in commit: >>>> drm/exynos: do not start enabling DP at bind() phase >>>> Add dp phy poweron function in bind time. >>>> - Move the panel prepare from get_m
[PATCH 1/3] drm/rockchip: inno_hdmi: add audio support
Hi Mark & Heiko, Ping.. Thanks, - Yakir On 06/15/2016 09:28 PM, Yakir Yang wrote: > Using the common hdmi-codec driver to support hdmi audio function. > > Signed-off-by: Yakir Yang > --- > drivers/gpu/drm/rockchip/inno_hdmi.c | 237 > ++- > drivers/gpu/drm/rockchip/inno_hdmi.h | 2 + > 2 files changed, 237 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c > b/drivers/gpu/drm/rockchip/inno_hdmi.c > index f8b4feb..c31dc07 100644 > --- a/drivers/gpu/drm/rockchip/inno_hdmi.c > +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c > @@ -29,6 +29,8 @@ > #include > #include > > +#include > + > #include "rockchip_drm_drv.h" > #include "rockchip_drm_vop.h" > > @@ -36,6 +38,12 @@ > > #define to_inno_hdmi(x) container_of(x, struct inno_hdmi, x) > > +struct audio_info { > + int sample_rate; > + int channels; > + int sample_width; > +}; > + > struct hdmi_data_info { > int vic; > bool sink_is_hdmi; > @@ -71,6 +79,9 @@ struct inno_hdmi { > > unsigned int tmds_rate; > > + struct platform_device *audio_pdev; > + bool audio_enable; > + > struct hdmi_data_info hdmi_data; > struct drm_display_mode previous_mode; > }; > @@ -306,6 +317,57 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi > *hdmi, > return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AVI, 0, 0, 0); > } > > +static int inno_hdmi_config_audio_aai(struct inno_hdmi *hdmi, > + struct audio_info *audio) > +{ > + struct hdmi_audio_infoframe *faudio; > + union hdmi_infoframe frame; > + int rc; > + > + rc = hdmi_audio_infoframe_init(&frame.audio); > + faudio = (struct hdmi_audio_infoframe *)&frame; > + > + faudio->channels = audio->channels; > + > + switch (audio->sample_width) { > + case 16: > + faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_16; > + break; > + case 20: > + faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_20; > + break; > + case 24: > + faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_24; > + break; > + } > + > + switch (audio->sample_rate) { > + case 32000: > + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_32000; > + break; > + case 44100: > + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_44100; > + break; > + case 48000: > + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_48000; > + break; > + case 88200: > + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_88200; > + break; > + case 96000: > + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_96000; > + break; > + case 176400: > + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_176400; > + break; > + case 192000: > + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_192000; > + break; > + } > + > + return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AAI, 0, 0, 0); > +} > + > static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) > { > struct hdmi_data_info *data = &hdmi->hdmi_data; > @@ -478,8 +540,9 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, > inno_hdmi_i2c_init(hdmi); > > /* Unmute video and audio output */ > - hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, > - v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0)); > + hdmi_modb(hdmi, HDMI_AV_MUTE, m_VIDEO_BLACK, v_VIDEO_MUTE(0)); > + if (hdmi->audio_enable) > + hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE, v_AUDIO_MUTE(0)); > > return 0; > } > @@ -616,6 +679,174 @@ static struct drm_connector_helper_funcs > inno_hdmi_connector_helper_funcs = { > .best_encoder = inno_hdmi_connector_best_encoder, > }; > > +int inno_hdmi_audio_config_set(struct inno_hdmi *hdmi, struct audio_info > *audio) > +{ > + int rate, N, channel; > + > + if (audio->channels < 3) > + channel = I2S_CHANNEL_1_2; > + else if (audio->channels < 5) > + channel = I2S_CHANNEL_3_4; > + else if (audio->channels < 7) > + channel = I2S_CHANNEL_5_6; > + else > + channel = I2S_CHANNEL_7_8; > + > + switch (audio->sample_rate)
[PATCH 1/3] drm/rockchip: inno_hdmi: add audio support
Mark, Got it, would rebase soonest :-) Thanks, - Yakir On 08/04/2016 10:01 AM, Mark yao wrote: > Hi Yakir > > After apply your patch, I got following warning messge: > > drivers/gpu/drm/rockchip/inno_hdmi.c:818:2: warning: initialization > from incompatible pointer type [enabled by default] > drivers/gpu/drm/rockchip/inno_hdmi.c:818:2: warning: (near > initialization for 'audio_codec_ops.hw_params') [enabled by default] > drivers/gpu/drm/rockchip/inno_hdmi.c:819:2: warning: initialization > from incompatible pointer type [enabled by default] > drivers/gpu/drm/rockchip/inno_hdmi.c:819:2: warning: (near > initialization for 'audio_codec_ops.audio_shutdown') [enabled by default] > drivers/gpu/drm/rockchip/inno_hdmi.c:820:2: warning: initialization > from incompatible pointer type [enabled by default] > drivers/gpu/drm/rockchip/inno_hdmi.c:820:2: warning: (near > initialization for 'audio_codec_ops.digital_mute') [enabled by default] > drivers/gpu/drm/rockchip/inno_hdmi.c:821:2: warning: initialization > from incompatible pointer type [enabled by default] > drivers/gpu/drm/rockchip/inno_hdmi.c:821:2: warning: (near > initialization for 'audio_codec_ops.get_eld') [enabled by default] > > since the commit "efc9194 ASoC: hdmi-codec: callback function will be > called with private data", > the hdmi_codec_ops had some changes. > Can you rebase your patch to the newest kernel? > > Thanks. > On 2016å¹´06æ15æ¥ 21:28, Yakir Yang wrote: >> Using the common hdmi-codec driver to support hdmi audio function. >> >> Signed-off-by: Yakir Yang >> --- >> drivers/gpu/drm/rockchip/inno_hdmi.c | 237 >> ++- >> drivers/gpu/drm/rockchip/inno_hdmi.h | 2 + >> 2 files changed, 237 insertions(+), 2 deletions(-) >> >> diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c >> b/drivers/gpu/drm/rockchip/inno_hdmi.c >> index f8b4feb..c31dc07 100644 >> --- a/drivers/gpu/drm/rockchip/inno_hdmi.c >> +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c >> @@ -29,6 +29,8 @@ >> #include >> #include >> +#include >> + >> #include "rockchip_drm_drv.h" >> #include "rockchip_drm_vop.h" >> @@ -36,6 +38,12 @@ >> #define to_inno_hdmi(x)container_of(x, struct inno_hdmi, x) >> +struct audio_info { >> +int sample_rate; >> +int channels; >> +int sample_width; >> +}; >> + >> struct hdmi_data_info { >> int vic; >> bool sink_is_hdmi; >> @@ -71,6 +79,9 @@ struct inno_hdmi { >> unsigned int tmds_rate; >> +struct platform_device *audio_pdev; >> +bool audio_enable; >> + >> struct hdmi_data_infohdmi_data; >> struct drm_display_mode previous_mode; >> }; >> @@ -306,6 +317,57 @@ static int inno_hdmi_config_video_avi(struct >> inno_hdmi *hdmi, >> return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AVI, >> 0, 0, 0); >> } >> +static int inno_hdmi_config_audio_aai(struct inno_hdmi *hdmi, >> + struct audio_info *audio) >> +{ >> +struct hdmi_audio_infoframe *faudio; >> +union hdmi_infoframe frame; >> +int rc; >> + >> +rc = hdmi_audio_infoframe_init(&frame.audio); >> +faudio = (struct hdmi_audio_infoframe *)&frame; >> + >> +faudio->channels = audio->channels; >> + >> +switch (audio->sample_width) { >> +case 16: >> +faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_16; >> +break; >> +case 20: >> +faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_20; >> +break; >> +case 24: >> +faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_24; >> +break; >> +} >> + >> +switch (audio->sample_rate) { >> +case 32000: >> +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_32000; >> +break; >> +case 44100: >> +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_44100; >> +break; >> +case 48000: >> +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_48000; >> +break; >> +case 88200: >> +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_88200; >> +break; >> +case 96000: >> +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_96000; >> +break; >> +case 176400: >> +faudio->sample_frequency = HDMI_AUDIO
[PATCH] drm/bridge: analogix_dp: Remove duplicated code
Tomeu, Nice job ! Have a few nits bellow. ;) On 08/04/2016 02:23 PM, Tomeu Vizoso wrote: > Remove code for reading the EDID and DPCD fields and use the helpers > instead. > > Besides the obvious code reduction, other helpers are being added to the > core that could be used in this driver and will be good to be able to > use them instead of duplicating them. > > Signed-off-by: Tomeu Vizoso > Cc: Javier Martinez Canillas > Cc: Mika Kahola > Cc: Yakir Yang > Cc: Daniel Vetter > --- > drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 390 > +++-- > drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 39 +-- > drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 324 - > 3 files changed, 201 insertions(+), 552 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > index 32715daf73cb..c81cb37e56b6 100644 > --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > @@ -31,6 +31,7 @@ > #include > > #include "analogix_dp_core.h" > +#include "analogix_dp_reg.h" > > #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) > > @@ -97,150 +98,21 @@ static int analogix_dp_detect_hpd(struct > analogix_dp_device *dp) > return 0; > } > > -static unsigned char analogix_dp_calc_edid_check_sum(unsigned char > *edid_data) > -{ > - int i; > - unsigned char sum = 0; > - > - for (i = 0; i < EDID_BLOCK_LENGTH; i++) > - sum = sum + edid_data[i]; > - > - return sum; > -} > - > -static int analogix_dp_read_edid(struct analogix_dp_device *dp) > -{ > - unsigned char *edid = dp->edid; > - unsigned int extend_block = 0; > - unsigned char sum; > - unsigned char test_vector; > - int retval; > - > - /* > - * EDID device address is 0x50. > - * However, if necessary, you must have set upper address > - * into E-EDID in I2C device, 0x30. > - */ > - > - /* Read Extension Flag, Number of 128-byte EDID extension blocks */ > - retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, > - EDID_EXTENSION_FLAG, > - &extend_block); > - if (retval) > - return retval; > - > - if (extend_block > 0) { > - dev_dbg(dp->dev, "EDID data includes a single extension!\n"); > - > - /* Read EDID data */ > - retval = analogix_dp_read_bytes_from_i2c(dp, > - I2C_EDID_DEVICE_ADDR, > - EDID_HEADER_PATTERN, > - EDID_BLOCK_LENGTH, > - &edid[EDID_HEADER_PATTERN]); > - if (retval != 0) { > - dev_err(dp->dev, "EDID Read failed!\n"); > - return -EIO; > - } > - sum = analogix_dp_calc_edid_check_sum(edid); > - if (sum != 0) { > - dev_err(dp->dev, "EDID bad checksum!\n"); > - return -EIO; > - } > - > - /* Read additional EDID data */ > - retval = analogix_dp_read_bytes_from_i2c(dp, > - I2C_EDID_DEVICE_ADDR, > - EDID_BLOCK_LENGTH, > - EDID_BLOCK_LENGTH, > - &edid[EDID_BLOCK_LENGTH]); > - if (retval != 0) { > - dev_err(dp->dev, "EDID Read failed!\n"); > - return -EIO; > - } > - sum = analogix_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]); > - if (sum != 0) { > - dev_err(dp->dev, "EDID bad checksum!\n"); > - return -EIO; > - } > - > - analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, > - &test_vector); > - if (test_vector & DP_TEST_LINK_EDID_READ) { > - analogix_dp_write_byte_to_dpcd(dp, > - DP_TEST_EDID_CHECKSUM, > - edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); > - analogix_dp_write_byte_to_dpcd(dp, > - DP_TEST_RESPONSE, > - DP_TEST_EDID_CHECKSUM_WRITE); > -
[PATCH] drm/bridge: analogix_dp: Remove duplicated code
Tomeu, o_O Ignore my previous email, seems I make a mistaken about the email format, and mess up the patch format. I have move my previous comments to this one :-) On 08/04/2016 02:23 PM, Tomeu Vizoso wrote: > Remove code for reading the EDID and DPCD fields and use the helpers > instead. > > Besides the obvious code reduction, other helpers are being added to the > core that could be used in this driver and will be good to be able to > use them instead of duplicating them. > > Signed-off-by: Tomeu Vizoso > Cc: Javier Martinez Canillas > Cc: Mika Kahola > Cc: Yakir Yang > Cc: Daniel Vetter > --- > drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 390 > +++-- > drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 39 +-- > drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 324 - > 3 files changed, 201 insertions(+), 552 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > index 32715daf73cb..c81cb37e56b6 100644 > --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > @@ -31,6 +31,7 @@ > #include > > #include "analogix_dp_core.h" > +#include "analogix_dp_reg.h" > > #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) > > @@ -97,150 +98,21 @@ static int analogix_dp_detect_hpd(struct > analogix_dp_device *dp) > return 0; > } > > -static unsigned char analogix_dp_calc_edid_check_sum(unsigned char > *edid_data) > -{ > - int i; > - unsigned char sum = 0; > - > - for (i = 0; i < EDID_BLOCK_LENGTH; i++) > - sum = sum + edid_data[i]; > - > - return sum; > -} > - > -static int analogix_dp_read_edid(struct analogix_dp_device *dp) > -{ > - unsigned char *edid = dp->edid; > - unsigned int extend_block = 0; > - unsigned char sum; > - unsigned char test_vector; > - int retval; > - > - /* > - * EDID device address is 0x50. > - * However, if necessary, you must have set upper address > - * into E-EDID in I2C device, 0x30. > - */ > - > - /* Read Extension Flag, Number of 128-byte EDID extension blocks */ > - retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, > - EDID_EXTENSION_FLAG, > - &extend_block); > - if (retval) > - return retval; > - > - if (extend_block > 0) { > - dev_dbg(dp->dev, "EDID data includes a single extension!\n"); > - > - /* Read EDID data */ > - retval = analogix_dp_read_bytes_from_i2c(dp, > - I2C_EDID_DEVICE_ADDR, > - EDID_HEADER_PATTERN, > - EDID_BLOCK_LENGTH, > - &edid[EDID_HEADER_PATTERN]); > - if (retval != 0) { > - dev_err(dp->dev, "EDID Read failed!\n"); > - return -EIO; > - } > - sum = analogix_dp_calc_edid_check_sum(edid); > - if (sum != 0) { > - dev_err(dp->dev, "EDID bad checksum!\n"); > - return -EIO; > - } > - > - /* Read additional EDID data */ > - retval = analogix_dp_read_bytes_from_i2c(dp, > - I2C_EDID_DEVICE_ADDR, > - EDID_BLOCK_LENGTH, > - EDID_BLOCK_LENGTH, > - &edid[EDID_BLOCK_LENGTH]); > - if (retval != 0) { > - dev_err(dp->dev, "EDID Read failed!\n"); > - return -EIO; > - } > - sum = analogix_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]); > - if (sum != 0) { > - dev_err(dp->dev, "EDID bad checksum!\n"); > - return -EIO; > - } > - > - analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, > - &test_vector); > - if (test_vector & DP_TEST_LINK_EDID_READ) { > - analogix_dp_write_byte_to_dpcd(dp, > - DP_TEST_EDID_CHECKSUM, > - edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); > - analogix_dp_write_byte_to_dpcd(dp, > -
[PATCH] drm/bridge: analogix_dp: Remove duplicated code v2
+ Archit Tomeu, Thanks for the update :-) But you have missed three tiny align problems, please see my inline notes, wish you could fix them. After that this patch looks good to me, so: Reviewed-by: Yakir Yang I guess this patch should go through Archit's drm_bridge tree, so I added him into the CC list. - Yakir On 08/05/2016 08:59 PM, Tomeu Vizoso wrote: > Remove code for reading the EDID and DPCD fields and use the helpers > instead. > > Besides the obvious code reduction, other helpers are being added to the > core that could be used in this driver and will be good to be able to > use them instead of duplicating them. > > Signed-off-by: Tomeu Vizoso > Tested-by: Javier Martinez Canillas > Tested-by: Sean Paul > Cc: Javier Martinez Canillas > Cc: Mika Kahola > Cc: Yakir Yang > Cc: Daniel Vetter > > v2: > - A bunch of good fixes from Sean and Yakir > - Moved the transfer function to analogix_dp_reg.c > - Removed reference to the EDID from the dp struct > --- > drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 263 > drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 40 +- > drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 451 > ++--- > 3 files changed, 204 insertions(+), 550 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > index 32715daf73cb..624fc4f44450 100644 > --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > @@ -31,6 +31,7 @@ > #include > > #include "analogix_dp_core.h" > +#include "analogix_dp_reg.h" > > #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) > > @@ -97,150 +98,21 @@ static int analogix_dp_detect_hpd(struct > analogix_dp_device *dp) > return 0; > } > > -static unsigned char analogix_dp_calc_edid_check_sum(unsigned char > *edid_data) > -{ > - int i; > - unsigned char sum = 0; > - > - for (i = 0; i < EDID_BLOCK_LENGTH; i++) > - sum = sum + edid_data[i]; > - > - return sum; > -} > - > -static int analogix_dp_read_edid(struct analogix_dp_device *dp) > -{ > - unsigned char *edid = dp->edid; > - unsigned int extend_block = 0; > - unsigned char sum; > - unsigned char test_vector; > - int retval; > - > - /* > - * EDID device address is 0x50. > - * However, if necessary, you must have set upper address > - * into E-EDID in I2C device, 0x30. > - */ > - > - /* Read Extension Flag, Number of 128-byte EDID extension blocks */ > - retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, > - EDID_EXTENSION_FLAG, > - &extend_block); > - if (retval) > - return retval; > - > - if (extend_block > 0) { > - dev_dbg(dp->dev, "EDID data includes a single extension!\n"); > - > - /* Read EDID data */ > - retval = analogix_dp_read_bytes_from_i2c(dp, > - I2C_EDID_DEVICE_ADDR, > - EDID_HEADER_PATTERN, > - EDID_BLOCK_LENGTH, > - &edid[EDID_HEADER_PATTERN]); > - if (retval != 0) { > - dev_err(dp->dev, "EDID Read failed!\n"); > - return -EIO; > - } > - sum = analogix_dp_calc_edid_check_sum(edid); > - if (sum != 0) { > - dev_err(dp->dev, "EDID bad checksum!\n"); > - return -EIO; > - } > - > - /* Read additional EDID data */ > - retval = analogix_dp_read_bytes_from_i2c(dp, > - I2C_EDID_DEVICE_ADDR, > - EDID_BLOCK_LENGTH, > - EDID_BLOCK_LENGTH, > - &edid[EDID_BLOCK_LENGTH]); > - if (retval != 0) { > - dev_err(dp->dev, "EDID Read failed!\n"); > - return -EIO; > - } > - sum = analogix_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]); > - if (sum != 0) { > - dev_err(dp->dev, "EDID bad checksum!\n"); > - return -EIO; > - } > - > - analogix_dp_read_
[PATCH v2] drm/bridge: analogix_dp: Ensure the panel is properly prepared/unprepared
+ Archit On 08/09/2016 02:53 AM, Sean Paul wrote: > Instead of just preparing the panel on bind, actually prepare/unprepare > during modeset/disable. The panel must be prepared in order to read hpd > status and edid, so we need to keep state around the prepares in order > to ensure we don't accidentally turn the panel off at the wrong time. > > Signed-off-by: Sean Paul Reviewed-by: Yakir Yang And I also tested this patch on RK3399 Kevin board, panel works rightly, so: Tested-by: Yakir Yang Also add Archit into CC list, guess this patch should go through his drm_bridge's tree. Thanks, - Yakir > --- > > Changes in v2: > - Added panel_is_modeset state/lock to avoid racing detect with modeset > (marcheu) > - Added prepare/unprepare in .get_modes (yakir) > > drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 101 > ++--- > drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 3 + > 2 files changed, 93 insertions(+), 11 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > index 32715da..47c449a 100644 > --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > @@ -923,11 +923,63 @@ static void analogix_dp_commit(struct > analogix_dp_device *dp) > analogix_dp_start_video(dp); > } > > +/* > + * This function is a bit of a catch-all for panel preparation, hopefully > + * simplifying the logic of functions that need to prepare/unprepare the > panel > + * below. > + * > + * If @prepare is true, this function will prepare the panel. Conversely, if > it > + * is false, the panel will be unprepared. > + * > + * If @is_modeset_prepare is true, the function will disregard the current > state > + * of the panel and either prepare/unprepare the panel based on @prepare. > Once > + * it finishes, it will update dp->panel_is_modeset to reflect the current > state > + * of the panel. > + */ > +static int analogix_dp_prepare_panel(struct analogix_dp_device *dp, > + bool prepare, bool is_modeset_prepare) > +{ > + int ret = 0; > + > + if (!dp->plat_data->panel) > + return 0; > + > + mutex_lock(&dp->panel_lock); > + > + /* > + * Exit early if this is a temporary prepare/unprepare and we're already > + * modeset (since we neither want to prepare twice or unprepare early). > + */ > + if (dp->panel_is_modeset && !is_modeset_prepare) > + goto out; > + > + if (prepare) > + ret = drm_panel_prepare(dp->plat_data->panel); > + else > + ret = drm_panel_unprepare(dp->plat_data->panel); > + > + if (ret) > + goto out; > + > + if (is_modeset_prepare) > + dp->panel_is_modeset = prepare; > + > +out: > + mutex_unlock(&dp->panel_lock); > + return ret; > +} > + > int analogix_dp_get_modes(struct drm_connector *connector) > { > struct analogix_dp_device *dp = to_dp(connector); > struct edid *edid = (struct edid *)dp->edid; > - int num_modes = 0; > + int ret, num_modes = 0; > + > + ret = analogix_dp_prepare_panel(dp, true, false); > + if (ret) { > + DRM_ERROR("Failed to prepare panel (%d)\n", ret); > + return 0; > + } > > if (analogix_dp_handle_edid(dp) == 0) { > drm_mode_connector_update_edid_property(&dp->connector, edid); > @@ -940,6 +992,10 @@ int analogix_dp_get_modes(struct drm_connector > *connector) > if (dp->plat_data->get_modes) > num_modes += dp->plat_data->get_modes(dp->plat_data, connector); > > + ret = analogix_dp_prepare_panel(dp, false, false); > + if (ret) > + DRM_ERROR("Failed to unprepare panel (%d)\n", ret); > + > return num_modes; > } > > @@ -960,11 +1016,23 @@ enum drm_connector_status > analogix_dp_detect(struct drm_connector *connector, bool force) > { > struct analogix_dp_device *dp = to_dp(connector); > + enum drm_connector_status status = connector_status_disconnected; > + int ret; > > - if (analogix_dp_detect_hpd(dp)) > + ret = analogix_dp_prepare_panel(dp, true, false); > + if (ret) { > + DRM_ERROR("Failed to prepare panel (%d)\n", ret); > return connector_status_disconnected; > + } > + > + if (!analogix_dp_detect_hpd(dp)) > + status = connector_status_connected; >
[PATCH] drm/rockchip: Properly adjust to a true clock in adjusted_mode
Sean, On 08/09/2016 03:29 AM, Sean Paul wrote: > From: Douglas Anderson > > When fixing up the clock in vop_crtc_mode_fixup() we're not doing it > quite correctly. Specifically if we've got the true clock 26667 Hz, > we'll perform this calculation: > 26667 / 1000 => 26 > > Later when we try to set the clock we'll do clk_set_rate(26 * > 1000). The common clock framework won't actually pick the proper clock > in this case since it always wants clocks <= the specified one. > > Let's solve this by using DIV_ROUND_UP. > > Signed-off-by: Douglas Anderson > Signed-off-by: Sean Paul After discuss with Zheng Xing (Rockchip clock contributor), we think this patch looks good, so: Reviewed-by: Yakir Yang > --- > drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > index 31744fe..1bbffaf 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > @@ -891,7 +891,8 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, > struct vop *vop = to_vop(crtc); > > adjusted_mode->clock = > - clk_round_rate(vop->dclk, mode->clock * 1000) / 1000; > + DIV_ROUND_UP(clk_round_rate(vop->dclk, mode->clock * 1000), > + 1000); > > return true; > }
[PATCH v2 1/6] drm/rockchip: Convert psr_list_mutex to spinlock and use it
On 08/17/2016 09:11 AM, Sean Paul wrote: > This patch converts the psr_list_mutex to a spinlock and locks > all access to psr_list to avoid races (however unlikely they > were). > > Signed-off-by: Sean Paul Reviewed-by: Yakir Yang > --- > > Changes in v2: > - Rebased on > https://cgit.freedesktop.org/~seanpaul/dogwood/log/?h=for-next > > drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- > drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 2 +- > drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 25 ++--- > 3 files changed, 20 insertions(+), 9 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c > b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c > index b43fe5d9..76eaf1d 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c > @@ -157,7 +157,7 @@ static int rockchip_drm_bind(struct device *dev) > drm_dev->dev_private = private; > > INIT_LIST_HEAD(&private->psr_list); > - mutex_init(&private->psr_list_mutex); > + spin_lock_init(&private->psr_list_lock); > > drm_mode_config_init(drm_dev); > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h > b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h > index 9c34c9e..5c69845 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h > @@ -63,7 +63,7 @@ struct rockchip_drm_private { > struct drm_atomic_state *state; > > struct list_head psr_list; > - struct mutex psr_list_mutex; > + spinlock_t psr_list_lock; > }; > > int rockchip_register_crtc_funcs(struct drm_crtc *crtc, > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > index a6d3bd25..bd25273 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > @@ -45,12 +45,18 @@ static struct psr_drv *find_psr_by_crtc(struct drm_crtc > *crtc) > { > struct rockchip_drm_private *drm_drv = crtc->dev->dev_private; > struct psr_drv *psr; > + unsigned long flags; > > - list_for_each_entry(psr, &drm_drv->psr_list, list) > + spin_lock_irqsave(&drm_drv->psr_list_lock, flags); > + list_for_each_entry(psr, &drm_drv->psr_list, list) { > if (psr->encoder->crtc == crtc) > - return psr; > + goto out; > + } > + psr = ERR_PTR(-ENODEV); > > - return ERR_PTR(-ENODEV); > +out: > + spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags); > + return psr; > } > > static void psr_state_work(struct work_struct *work) > @@ -173,7 +179,9 @@ void rockchip_drm_psr_flush(struct drm_device *dev) > { > struct rockchip_drm_private *drm_drv = dev->dev_private; > struct psr_drv *psr; > + unsigned long flags; > > + spin_lock_irqsave(&drm_drv->psr_list_lock, flags); > list_for_each_entry(psr, &drm_drv->psr_list, list) { > if (psr->request_state == PSR_DISABLE) > continue; > @@ -183,6 +191,7 @@ void rockchip_drm_psr_flush(struct drm_device *dev) > > psr_set_state(psr, PSR_FLUSH); > } > + spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags); > } > EXPORT_SYMBOL(rockchip_drm_psr_flush); > > @@ -199,6 +208,7 @@ int rockchip_drm_psr_register(struct drm_encoder *encoder, > { > struct rockchip_drm_private *drm_drv = encoder->dev->dev_private; > struct psr_drv *psr; > + unsigned long flags; > > if (!encoder || !psr_set) > return -EINVAL; > @@ -215,9 +225,9 @@ int rockchip_drm_psr_register(struct drm_encoder *encoder, > psr->encoder = encoder; > psr->set = psr_set; > > - mutex_lock(&drm_drv->psr_list_mutex); > + spin_lock_irqsave(&drm_drv->psr_list_lock, flags); > list_add_tail(&psr->list, &drm_drv->psr_list); > - mutex_unlock(&drm_drv->psr_list_mutex); > + spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags); > > return 0; > } > @@ -235,8 +245,9 @@ void rockchip_drm_psr_unregister(struct drm_encoder > *encoder) > { > struct rockchip_drm_private *drm_drv = encoder->dev->dev_private; > struct psr_drv *psr, *n; > + unsigned long flags; > > - mutex_lock(&drm_drv->psr_list_mutex); > + spin_lock_irqsave(&drm_drv->psr_list_lock, flags); > list_for_each_entry_safe(psr, n, &drm_drv->psr_list, list) { > if (psr->encoder == encoder) { > del_timer(&psr->flush_timer); > @@ -244,6 +255,6 @@ void rockchip_drm_psr_unregister(struct drm_encoder > *encoder) > kfree(psr); > } > } > - mutex_unlock(&drm_drv->psr_list_mutex); > + spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags); > } > EXPORT_SYMBOL(rockchip_drm_psr_unregister);
[PATCH v2 2/6] drm/rockchip: Don't use a delayed worker for psr state changes
On 08/17/2016 09:11 AM, Sean Paul wrote: > The delayed worker isn't needed and is racey. Remove it and do > the state change in line. > > Signed-off-by: Sean Paul Reviewed-by: Yakir Yang Tested-by: Yakir Yang > --- > > Changes in v2: > - Rebased on > https://cgit.freedesktop.org/~seanpaul/dogwood/log/?h=for-next > > drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 38 > - > 1 file changed, 10 insertions(+), 28 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > index bd25273..4c645d7 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > @@ -19,7 +19,6 @@ > #include "rockchip_drm_psr.h" > > #define PSR_FLUSH_TIMEOUT msecs_to_jiffies(3000) /* 3 seconds */ > -#define PSR_SET_DELAY_TIME msecs_to_jiffies(10) > > enum psr_state { > PSR_FLUSH, > @@ -31,11 +30,8 @@ struct psr_drv { > struct list_headlist; > struct drm_encoder *encoder; > > - enum psr_state request_state; > enum psr_state state; > > - struct delayed_work state_work; > - > struct timer_list flush_timer; > > void (*set)(struct drm_encoder *encoder, bool enable); > @@ -59,11 +55,8 @@ out: > return psr; > } > > -static void psr_state_work(struct work_struct *work) > +static void psr_set_state(struct psr_drv *psr, enum psr_state state) > { > - struct psr_drv *psr = container_of(work, typeof(*psr), state_work.work); > - enum psr_state request_state = psr->request_state; > - > /* >* Allowed finite state machine: >* > @@ -75,24 +68,22 @@ static void psr_state_work(struct work_struct *work) >*/ > > /* Forbid no state change */ > - if (request_state == psr->state) > + if (state == psr->state) > return; > > /* Forbid DISABLE change to FLUSH */ > - if (request_state == PSR_FLUSH && psr->state == PSR_DISABLE) > + if (state == PSR_FLUSH && psr->state == PSR_DISABLE) > return; > > + /* Only wrote in this work, no need lock protection */ > + psr->state = state; > + > /* Allow but no need hardware change, just need assign the state */ > - if (request_state == PSR_DISABLE && psr->state == PSR_FLUSH) { > - psr->state = request_state; > + if (state == PSR_DISABLE && psr->state == PSR_FLUSH) > return; > - } > - > - /* Only wrote in this work, no need lock protection */ > - psr->state = request_state; > > /* Refact to hardware state change */ > - switch (request_state) { > + switch (psr->state) { > case PSR_ENABLE: > psr->set(psr->encoder, true); > break; > @@ -104,13 +95,6 @@ static void psr_state_work(struct work_struct *work) > } > } > > -static void psr_set_state(struct psr_drv *psr, enum psr_state state) > -{ > - psr->request_state = state; > - > - schedule_delayed_work(&psr->state_work, PSR_SET_DELAY_TIME); > -} > - > static void psr_flush_handler(unsigned long data) > { > struct psr_drv *psr = (struct psr_drv *)data; > @@ -119,7 +103,7 @@ static void psr_flush_handler(unsigned long data) > return; > > /* State changed between flush time, then keep it */ > - if (psr->request_state != PSR_FLUSH) > + if (psr->state != PSR_FLUSH) > return; > > psr_set_state(psr, PSR_ENABLE); > @@ -183,7 +167,7 @@ void rockchip_drm_psr_flush(struct drm_device *dev) > > spin_lock_irqsave(&drm_drv->psr_list_lock, flags); > list_for_each_entry(psr, &drm_drv->psr_list, list) { > - if (psr->request_state == PSR_DISABLE) > + if (psr->state == PSR_DISABLE) > continue; > > mod_timer(&psr->flush_timer, > @@ -219,8 +203,6 @@ int rockchip_drm_psr_register(struct drm_encoder *encoder, > > setup_timer(&psr->flush_timer, psr_flush_handler, (unsigned long)psr); > > - INIT_DELAYED_WORK(&psr->state_work, psr_state_work); > - > psr->state = PSR_DISABLE; > psr->encoder = encoder; > psr->set = psr_set;
[PATCH v2 3/6] drm/rockchip: Use a spinlock to protect psr state
On 08/17/2016 09:11 AM, Sean Paul wrote: > The handling of psr state is racey, shore that up with > a per-psr driver lock. > > Signed-off-by: Sean Paul Reviewed-by: Yakir Yang > --- > > Changes in v2: > - Rebased on > https://cgit.freedesktop.org/~seanpaul/dogwood/log/?h=for-next > > drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 26 +- > 1 file changed, 17 insertions(+), 9 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > index 4c645d7..5bd54f2 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > @@ -30,6 +30,7 @@ struct psr_drv { > struct list_headlist; > struct drm_encoder *encoder; > > + spinlock_t lock; > enum psr_state state; > > struct timer_list flush_timer; > @@ -55,7 +56,7 @@ out: > return psr; > } > > -static void psr_set_state(struct psr_drv *psr, enum psr_state state) > +static void psr_set_state_locked(struct psr_drv *psr, enum psr_state state) > { > /* >* Allowed finite state machine: > @@ -75,7 +76,6 @@ static void psr_set_state(struct psr_drv *psr, enum > psr_state state) > if (state == PSR_FLUSH && psr->state == PSR_DISABLE) > return; > > - /* Only wrote in this work, no need lock protection */ > psr->state = state; > > /* Allow but no need hardware change, just need assign the state */ > @@ -95,18 +95,28 @@ static void psr_set_state(struct psr_drv *psr, enum > psr_state state) > } > } > > +static void psr_set_state(struct psr_drv *psr, enum psr_state state) > +{ > + unsigned long flags; > + > + spin_lock_irqsave(&psr->lock, flags); > + psr_set_state_locked(psr, state); > + spin_unlock_irqrestore(&psr->lock, flags); > +} > + > static void psr_flush_handler(unsigned long data) > { > struct psr_drv *psr = (struct psr_drv *)data; > + unsigned long flags; > > if (!psr) > return; > > /* State changed between flush time, then keep it */ > - if (psr->state != PSR_FLUSH) > - return; > - > - psr_set_state(psr, PSR_ENABLE); > + spin_lock_irqsave(&psr->lock, flags); > + if (psr->state == PSR_FLUSH) > + psr_set_state_locked(psr, PSR_ENABLE); > + spin_unlock_irqrestore(&psr->lock, flags); > } > > /** > @@ -167,9 +177,6 @@ void rockchip_drm_psr_flush(struct drm_device *dev) > > spin_lock_irqsave(&drm_drv->psr_list_lock, flags); > list_for_each_entry(psr, &drm_drv->psr_list, list) { > - if (psr->state == PSR_DISABLE) > - continue; > - > mod_timer(&psr->flush_timer, > round_jiffies_up(jiffies + PSR_FLUSH_TIMEOUT)); > > @@ -202,6 +209,7 @@ int rockchip_drm_psr_register(struct drm_encoder *encoder, > return -ENOMEM; > > setup_timer(&psr->flush_timer, psr_flush_handler, (unsigned long)psr); > + spin_lock_init(&psr->lock); > > psr->state = PSR_DISABLE; > psr->encoder = encoder;
[PATCH v2 4/6] drm/rockchip: A couple small fixes to psr
On 08/17/2016 09:11 AM, Sean Paul wrote: > A few things that need tidying up, no functional changes. > > Signed-off-by: Sean Paul Reviewed-by: Yakir Yang > --- > > Changes in v2: > - Introduced > > drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 19 +++ > 1 file changed, 7 insertions(+), 12 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > index 5bd54f2..c6ac5d0 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > @@ -62,27 +62,25 @@ static void psr_set_state_locked(struct psr_drv *psr, > enum psr_state state) >* Allowed finite state machine: >* >* PSR_ENABLE < = = = = = > PSR_FLUSH > - * | ^| > - * | || > - * v || > + * | ^| > + * | || > + * v || >* PSR_DISABLE < - - - - - - - - - >*/ > - > - /* Forbid no state change */ > if (state == psr->state) > return; > > - /* Forbid DISABLE change to FLUSH */ > + /* Requesting a flush when disabled is a noop */ > if (state == PSR_FLUSH && psr->state == PSR_DISABLE) > return; > > psr->state = state; > > - /* Allow but no need hardware change, just need assign the state */ > + /* Already disabled in flush, change the state, but not the hardware */ > if (state == PSR_DISABLE && psr->state == PSR_FLUSH) > return; > > - /* Refact to hardware state change */ > + /* Actually commit the state change to hardware */ > switch (psr->state) { > case PSR_ENABLE: > psr->set(psr->encoder, true); > @@ -109,10 +107,7 @@ static void psr_flush_handler(unsigned long data) > struct psr_drv *psr = (struct psr_drv *)data; > unsigned long flags; > > - if (!psr) > - return; > - > - /* State changed between flush time, then keep it */ > + /* If the state has changed since we initiated the flush, do nothing */ > spin_lock_irqsave(&psr->lock, flags); > if (psr->state == PSR_FLUSH) > psr_set_state_locked(psr, PSR_ENABLE);
[PATCH v2 5/6] drm/rockchip: Improve analogix-dp psr handling
On 08/17/2016 09:11 AM, Sean Paul wrote: > Remove the delayed worker, opting instead for the non-delayed > variety. Also introduce a lock to ensure we don't have races > with the worker and psr_state. Finally, cancel and wait for > the worker to finish when disabling the bridge. > > Signed-off-by: Sean Paul Reviewed-by: Yakir Yang > --- > > Changes in v2: > - Rebased on > https://cgit.freedesktop.org/~seanpaul/dogwood/log/?h=for-next > > drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 19 ++- > 1 file changed, 14 insertions(+), 5 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c > b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c > index d6d0751..439b933 100644 > --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c > +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c > @@ -42,7 +42,6 @@ > > #define HIWORD_UPDATE(val, mask)(val | (mask) << 16) > > -#define PSR_SET_DELAY_TIME msecs_to_jiffies(10) > #define PSR_WAIT_LINE_FLAG_TIMEOUT_MS 100 > > #define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm) > @@ -72,7 +71,8 @@ struct rockchip_dp_device { > struct regmap*grf; > struct reset_control *rst; > > - struct delayed_work psr_work; > + struct work_struct psr_work; > + spinlock_t psr_lock; > unsigned int psr_state; > > const struct rockchip_dp_chip_data *data; > @@ -83,25 +83,29 @@ struct rockchip_dp_device { > static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled) > { > struct rockchip_dp_device *dp = to_dp(encoder); > + unsigned long flags; > > dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit"); > > + spin_lock_irqsave(&dp->psr_lock, flags); > if (enabled) > dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE; > else > dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; > > - schedule_delayed_work(&dp->psr_work, PSR_SET_DELAY_TIME); > + schedule_work(&dp->psr_work); > + spin_unlock_irqrestore(&dp->psr_lock, flags); > } > > static void analogix_dp_psr_work(struct work_struct *work) > { > struct rockchip_dp_device *dp = > - container_of(work, typeof(*dp), psr_work.work); > + container_of(work, typeof(*dp), psr_work); > struct drm_crtc *crtc = dp->encoder.crtc; > int psr_state = dp->psr_state; > int vact_end; > int ret; > + unsigned long flags; > > if (!crtc) > return; > @@ -115,10 +119,12 @@ static void analogix_dp_psr_work(struct work_struct > *work) > return; > } > > + spin_lock_irqsave(&dp->psr_lock, flags); > if (psr_state == EDP_VSC_PSR_STATE_ACTIVE) > analogix_dp_enable_psr(dp->dev); > else > analogix_dp_disable_psr(dp->dev); > + spin_unlock_irqrestore(&dp->psr_lock, flags); > } > > static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) > @@ -135,6 +141,8 @@ static int rockchip_dp_poweron(struct > analogix_dp_plat_data *plat_data) > struct rockchip_dp_device *dp = to_dp(plat_data); > int ret; > > + cancel_work_sync(&dp->psr_work); > + > ret = clk_prepare_enable(dp->pclk); > if (ret < 0) { > dev_err(dp->dev, "failed to enable pclk %d\n", ret); > @@ -390,8 +398,9 @@ static int rockchip_dp_bind(struct device *dev, struct > device *master, > dp->plat_data.power_off = rockchip_dp_powerdown; > dp->plat_data.get_modes = rockchip_dp_get_modes; > > + spin_lock_init(&dp->psr_lock); > dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; > - INIT_DELAYED_WORK(&dp->psr_work, analogix_dp_psr_work); > + INIT_WORK(&dp->psr_work, analogix_dp_psr_work); > > rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set); >
[PATCH v2 0/6] drm/rockchip: Some patches to update the PSR series
Sean, Thanks a lot for your good fixes. I have reviewed most of them, and all looks good to me. But I got a question for merging things. My PSR patch set still under reviewing, haven't been picked up Mark or other maintainers. Feel a little bit embarrassed, how could we handle this situation ? - Yakir On 08/17/2016 09:11 AM, Sean Paul wrote: > This is a follow-on set to Yakir's original PSR set here: > https://lkml.org/lkml/2016/7/24/34 > and applies to the for-next branch at: > https://cgit.freedesktop.org/~seanpaul/dogwood > > There are a few issues with the code that needed to be > shored up. > (1) The use of mutexes instead of spinlocks caused issues calling the > psr functions from vblank_enable/disable. > (2) The proliferation of workers due to (1) > (3) A bunch of races due to (2) > (4) vblank is not enabled unless an event is requested, this breaks > a lot of things, but most noticeable was cursor. > > Changes in v2: > - Rebased on https://cgit.freedesktop.org/~seanpaul/dogwood > instead of random on-list patches (some of which had drifted) > - Added the "small fixes" patch to catch some nits > > > Sean Paul (6): >drm/rockchip: Convert psr_list_mutex to spinlock and use it >drm/rockchip: Don't use a delayed worker for psr state changes >drm/rockchip: Use a spinlock to protect psr state >drm/rockchip: A couple small fixes to psr >drm/rockchip: Improve analogix-dp psr handling >drm/rockchip: Enable vblank without event > > drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 19 -- > drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- > drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 2 +- > drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 90 > - > drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 15 +++-- > 5 files changed, 69 insertions(+), 59 deletions(-) >
[PATCH v2 0/6] drm/rockchip: Some patches to update the PSR series
Sean, On 08/17/2016 10:41 AM, Yakir Yang wrote: > Sean, > > Thanks a lot for your good fixes. I have reviewed most of them, and > all looks good to me. > > But I got a question for merging things. My PSR patch set still under > reviewing, haven't been picked up Mark or other maintainers. Feel a > little bit embarrassed, how could we handle this situation ? > > - Yakir > > On 08/17/2016 09:11 AM, Sean Paul wrote: >> This is a follow-on set to Yakir's original PSR set here: >> https://lkml.org/lkml/2016/7/24/34 >> and applies to the for-next branch at: >> https://cgit.freedesktop.org/~seanpaul/dogwood Oops, sorry for missing this comment, do you mean my PSR patch already have been site on your tree :-D - Yakir >> >> There are a few issues with the code that needed to be >> shored up. >> (1) The use of mutexes instead of spinlocks caused issues calling the >> psr functions from vblank_enable/disable. >> (2) The proliferation of workers due to (1) >> (3) A bunch of races due to (2) >> (4) vblank is not enabled unless an event is requested, this breaks >> a lot of things, but most noticeable was cursor. >> >> Changes in v2: >> - Rebased on https://cgit.freedesktop.org/~seanpaul/dogwood >> instead of random on-list patches (some of which had drifted) >> - Added the "small fixes" patch to catch some nits >> >> >> Sean Paul (6): >>drm/rockchip: Convert psr_list_mutex to spinlock and use it >>drm/rockchip: Don't use a delayed worker for psr state changes >>drm/rockchip: Use a spinlock to protect psr state >>drm/rockchip: A couple small fixes to psr >>drm/rockchip: Improve analogix-dp psr handling >>drm/rockchip: Enable vblank without event >> >> drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 19 -- >> drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- >> drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 2 +- >> drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 90 >> - >> drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 15 +++-- >> 5 files changed, 69 insertions(+), 59 deletions(-) >> >
[PATCH v2 0/6] drm/rockchip: Some patches to update the PSR series
Sean, On 08/17/2016 10:45 AM, Sean Paul wrote: > > On Aug 16, 2016 7:41 PM, "Yakir Yang" <mailto:ykk at rock-chips.com>> wrote: > > > > Sean, > > > > Thanks a lot for your good fixes. I have reviewed most of them, and > all looks good to me. > > > > But I got a question for merging things. My PSR patch set still > under reviewing, haven't been picked up Mark or other maintainers. > > I've picked them up in my tree. I'll send a pull request to Dave once > all of the dependencies have been reviewed (marked NEEDS REVIEW). > Got it, thanks. - Yakir > Sean > > > Feel a little bit embarrassed, how could we handle this situation ? > > > > - Yakir > > > > > > On 08/17/2016 09:11 AM, Sean Paul wrote: > >> > >> This is a follow-on set to Yakir's original PSR set here: > >> https://lkml.org/lkml/2016/7/24/34 > >> and applies to the for-next branch at: > >> https://cgit.freedesktop.org/~seanpaul/dogwood > <https://cgit.freedesktop.org/%7Eseanpaul/dogwood> > >> > >> There are a few issues with the code that needed to be > >> shored up. > >> (1) The use of mutexes instead of spinlocks caused issues calling the > >> psr functions from vblank_enable/disable. > >> (2) The proliferation of workers due to (1) > >> (3) A bunch of races due to (2) > >> (4) vblank is not enabled unless an event is requested, this breaks > >> a lot of things, but most noticeable was cursor. > >> > >> Changes in v2: > >> - Rebased on https://cgit.freedesktop.org/~seanpaul/dogwood > <https://cgit.freedesktop.org/%7Eseanpaul/dogwood> > >> instead of random on-list patches (some of which had drifted) > >> - Added the "small fixes" patch to catch some nits > >> > >> > >> Sean Paul (6): > >>drm/rockchip: Convert psr_list_mutex to spinlock and use it > >>drm/rockchip: Don't use a delayed worker for psr state changes > >>drm/rockchip: Use a spinlock to protect psr state > >>drm/rockchip: A couple small fixes to psr > >>drm/rockchip: Improve analogix-dp psr handling > >>drm/rockchip: Enable vblank without event > >> > >> drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 19 -- > >> drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- > >> drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 2 +- > >> drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 90 > - > >> drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 15 +++-- > >> 5 files changed, 69 insertions(+), 59 deletions(-) > >> > > > > > -- next part -- An HTML attachment was scrubbed... URL: <https://lists.freedesktop.org/archives/dri-devel/attachments/20160817/6767c7a5/attachment.html>
[PATCH v2 6/6] drm/rockchip: Enable vblank without event
Sean, On 08/17/2016 09:11 AM, Sean Paul wrote: > vblank should be enabled regardless of whether an event > is expected back. This is especially important for a cursor > plane. Yep, I also found that sometimes vblank haven't been enabled when I move the mouse lightly, that would cause eDP panel wound't exit from PSR active state, and then nothing would be updated on panel. After apply this patch, things work rightly now, thanks for fixing. Reviewed-by: Yakir Yang Tested-by: Yakir Yang > Signed-off-by: Sean Paul > --- > > Changes in v2: > - Rebased on > https://cgit.freedesktop.org/~seanpaul/dogwood/log/?h=for-next > > drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 15 ++- > 1 file changed, 10 insertions(+), 5 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > index d1e0e06..1787084 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > @@ -112,6 +112,7 @@ struct vop { > struct device *dev; > struct drm_device *drm_dev; > bool is_enabled; > + bool vblank_active; > > /* mutex vsync_ work */ > struct mutex vsync_mutex; > @@ -1107,10 +1108,11 @@ static void vop_crtc_atomic_begin(struct drm_crtc > *crtc, > struct vop *vop = to_vop(crtc); > > spin_lock_irq(&crtc->dev->event_lock); > - if (crtc->state->event) { > - WARN_ON(drm_crtc_vblank_get(crtc) != 0); > - WARN_ON(vop->event); > + vop->vblank_active = true; > + WARN_ON(drm_crtc_vblank_get(crtc) != 0); > + WARN_ON(vop->event); > > + if (crtc->state->event) { > vop->event = crtc->state->event; > crtc->state->event = NULL; > } > @@ -1197,12 +1199,14 @@ static void vop_handle_vblank(struct vop *vop) > > spin_lock_irqsave(&drm->event_lock, flags); > if (vop->event) { > - > drm_crtc_send_vblank_event(crtc, vop->event); > - drm_crtc_vblank_put(crtc); > vop->event = NULL; > > } > + if (vop->vblank_active) { > + vop->vblank_active = false; > + drm_crtc_vblank_put(crtc); > + } > spin_unlock_irqrestore(&drm->event_lock, flags); > > if (!completion_done(&vop->wait_update_complete)) > @@ -1472,6 +1476,7 @@ static int vop_initial(struct vop *vop) > clk_disable(vop->aclk); > > vop->is_enabled = false; > + vop->vblank_active = false; > > return 0; >
[PATCH v5 3/4] drm/bridge: analogix_dp: add the PSR function support
Hello Archit, On 08/17/2016 01:41 PM, Archit Taneja wrote: > Hi, > > On 07/24/2016 12:27 PM, Yakir Yang wrote: >> The full name of PSR is Panel Self Refresh, panel device could refresh >> itself with the hardware framebuffer in panel, this would make lots of >> sense to save the power consumption. >> >> This patch have exported two symbols for platform driver to implement >> the PSR function in hardware side: >> - analogix_dp_active_psr() >> - analogix_dp_inactive_psr() > > Could this in any way mess things up if the dev_type is EXYNOS_DP? > Nop, I have enabled the panel PSR function by default (if driver detect panel support PSR), but this would active the PSR (cause eDP controller haven't send the right SDP header), which means panel would stay in normal refresh mode on Exynos platform. I also have tested that case on RK3399 platform. Enable the panel PSR, but never call the analogix_dp_active_psr() symbols, and them I found panel still refresh normally. Only when platform driver call the analogix_dp_active_psr()/analogix_dp_inactive_psr() symbols in vblank time, make the controller to send the active SDP header, then panel could enter into PSR mode. > Otherwise, > > Reviewed-by: Archit Taneja Thanks for your reviewed. - Yakir > >> >> Signed-off-by: Yakir Yang >> Reviewed-by: Sean Paul >> --- >> Changes in v5: >> - Add reviewed flag from Sean. >> >> Changes in v4.1: >> - Take use of existing edp_psr_vsc struct to swap HBx and DBx >> setting. (Sean) >> - Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc(). >> - Add comment about PBx magic numbers. (Sean) >> >> Changes in v4: >> - Downgrade the PSR version print message to debug level. (Sean) >> - Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). >> (Sean) >> - Delete the unused read dpcd operations in >> analogix_dp_enable_sink_psr(). (Sean) >> - Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. >> (Sean). >> - Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean) >> - Rename "active/inactive" to "enable/disable". (Sean, Dominik) >> - Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc(). >> >> Changes in v3: >> - split analogix_dp_enable_psr(), make it more clearly >> analogix_dp_detect_sink_psr() >> analogix_dp_enable_sink_psr() >> - remove some nosie register setting comments >> >> Changes in v2: >> - introduce in v2, splite the common Analogix DP changes out >> >> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 >> ++ >> drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 ++ >> drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 51 ++ >> drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 34 + >> include/drm/bridge/analogix_dp.h | 3 + >> 5 files changed, 174 insertions(+) >> >> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> index 32715da..381b25e 100644 >> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> @@ -97,6 +97,83 @@ static int analogix_dp_detect_hpd(struct >> analogix_dp_device *dp) >> return 0; >> } >> >> +int analogix_dp_enable_psr(struct device *dev) >> +{ >> +struct analogix_dp_device *dp = dev_get_drvdata(dev); >> +struct edp_vsc_psr psr_vsc; >> + >> +if (!dp->psr_support) >> +return -EINVAL; >> + >> +/* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ >> +memset(&psr_vsc, 0, sizeof(psr_vsc)); >> +psr_vsc.sdp_header.HB0 = 0; >> +psr_vsc.sdp_header.HB1 = 0x7; >> +psr_vsc.sdp_header.HB2 = 0x2; >> +psr_vsc.sdp_header.HB3 = 0x8; >> + >> +psr_vsc.DB0 = 0; >> +psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | >> EDP_VSC_PSR_CRC_VALUES_VALID; >> + >> +analogix_dp_send_psr_spd(dp, &psr_vsc); >> +return 0; >> +} >> +EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); >> + >> +int analogix_dp_disable_psr(struct device *dev) >> +{ >> +struct analogix_dp_device *dp = dev_get_drvdata(dev); >> +struct edp_vsc_psr psr_vsc; >> + >> +if (!dp->psr_support) >> +return -EINVAL; >> + >> +/* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ >> +memset(&psr_vsc, 0, sizeof(psr_vsc)); >> +
[PATCH v2] drm/rockchip: Don't continue trying to enable crtc on failure
Sean, On 08/16/2016 07:12 AM, Sean Paul wrote: > If vop_enable fails, don't continue on, it causes system hangs. > > Signed-off-by: Sean Paul Also meet this problem on my Rk3399 Kevin board. VOP just failed to get the pm_runtime at resume time, but ï½ï½ï½ï½er still just continue without anything enable rightly, oops, and then system crashed :( So this patch looks good to me, and also fix my problem, thanks: ï¼²ï½ viewed-by: Yakir Yang Tested-by: Yakir Yang Thanks, - Yakir > --- > > This patch uses the new DRM_DEV_ERROR logging, so it should be applied on > top of "[PATCH 2/2] drm/rockchip: Use DRM_DEV_ERROR in vop". > > Changes in v2: > - Escalate dev_err to WARN_ON for clk_enable failures (Daniel Vetter) > > Sean > > > drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 31 > - > 1 file changed, 17 insertions(+), 14 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > index ec8ad00..a176d03 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > @@ -428,7 +428,7 @@ static void vop_dsp_hold_valid_irq_disable(struct vop > *vop) > spin_unlock_irqrestore(&vop->irq_lock, flags); > } > > -static void vop_enable(struct drm_crtc *crtc) > +static int vop_enable(struct drm_crtc *crtc) > { > struct vop *vop = to_vop(crtc); > int ret; > @@ -436,26 +436,20 @@ static void vop_enable(struct drm_crtc *crtc) > ret = pm_runtime_get_sync(vop->dev); > if (ret < 0) { > dev_err(vop->dev, "failed to get pm runtime: %d\n", ret); > - return; > + goto err_put_pm_runtime; > } > > ret = clk_enable(vop->hclk); > - if (ret < 0) { > - dev_err(vop->dev, "failed to enable hclk - %d\n", ret); > - return; > - } > + if (WARN_ON(ret < 0)) > + goto err_put_pm_runtime; > > ret = clk_enable(vop->dclk); > - if (ret < 0) { > - dev_err(vop->dev, "failed to enable dclk - %d\n", ret); > + if (WARN_ON(ret < 0)) > goto err_disable_hclk; > - } > > ret = clk_enable(vop->aclk); > - if (ret < 0) { > - dev_err(vop->dev, "failed to enable aclk - %d\n", ret); > + if (WARN_ON(ret < 0)) > goto err_disable_dclk; > - } > > /* >* Slave iommu shares power, irq and clock with vop. It was associated > @@ -485,7 +479,7 @@ static void vop_enable(struct drm_crtc *crtc) > > drm_crtc_vblank_on(crtc); > > - return; > + return 0; > > err_disable_aclk: > clk_disable(vop->aclk); > @@ -493,6 +487,9 @@ err_disable_dclk: > clk_disable(vop->dclk); > err_disable_hclk: > clk_disable(vop->hclk); > +err_put_pm_runtime: > + pm_runtime_put_sync(vop->dev); > + return ret; > } > > static void vop_crtc_disable(struct drm_crtc *crtc) > @@ -912,10 +909,16 @@ static void vop_crtc_enable(struct drm_crtc *crtc) > u16 vact_st = adjusted_mode->vtotal - adjusted_mode->vsync_start; > u16 vact_end = vact_st + vdisplay; > uint32_t val; > + int ret; > > WARN_ON(vop->event); > > - vop_enable(crtc); > + ret = vop_enable(crtc); > + if (ret) { > + DRM_DEV_ERROR(vop->dev, "Failed to enable vop (%d)\n", ret); > + return; > + } > + > /* >* If dclk rate is zero, mean that scanout is stop, >* we don't need wait any more.
[RFC PATCH v1 0/2]
The full name of PSR is Panel Self Refresh, panel device could refresh itself with the hardware framebuffer in panel, this would make a lots of sense to save the power consumption. For example, when desktop haven't change the context for a long time, then we could refresh the data to the hardware framebuffer of panel, and then let panel enter into PSR mode. After that system could poweroff the LCDC controller and eDP controller, just let panel refresh the screen by itself. It's hard to decide when panel should enter into PSR or exit from PSR, in this time I chose to let the drm_vblank enable/disable event driver the PSR. This thread is based on Mark's RK3399 VOP thread[0] and my RK3399 eDP thread[1]. [0]: https://patchwork.kernel.org/patch/8886041/ [1]: https://patchwork.kernel.org/patch/9132713/ - Yakir Thanks, Yakir Yang (2): drm/rockchip: add a notify event about vblank enable/disable drm/rockchip: analogix: add eDP PSR function drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 69 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 + drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 54 +++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 28 ++ drivers/gpu/drm/rockchip/Makefile | 2 +- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c| 65 + drivers/gpu/drm/rockchip/rockchip_drm_notify.c | 105 + drivers/gpu/drm/rockchip/rockchip_drm_notify.h | 33 +++ drivers/gpu/drm/rockchip/rockchip_drm_vop.c| 96 +++ drivers/gpu/drm/rockchip/rockchip_drm_vop.h| 3 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c| 2 + include/drm/bridge/analogix_dp.h | 3 + 12 files changed, 464 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_notify.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_notify.h -- 1.9.1
[RFC PATCH v1 1/2] drm/rockchip: add a notify event about vblank enable/disable
EDP PSR function is interesting in vblank enable or disable event, so it would be great introduce a way to notify encoder about this event. Signed-off-by: Yakir Yang --- drivers/gpu/drm/rockchip/Makefile | 2 +- drivers/gpu/drm/rockchip/rockchip_drm_notify.c | 66 ++ drivers/gpu/drm/rockchip/rockchip_drm_notify.h | 29 +++ drivers/gpu/drm/rockchip/rockchip_drm_vop.c| 5 ++ 4 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_notify.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_notify.h diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 05d0713..49fee8c 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -3,7 +3,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ - rockchip_drm_gem.o rockchip_drm_vop.o + rockchip_drm_gem.o rockchip_drm_vop.o rockchip_drm_notify.o rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_notify.c b/drivers/gpu/drm/rockchip/rockchip_drm_notify.c new file mode 100644 index 000..84111d9 --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_drm_notify.c @@ -0,0 +1,66 @@ +#include "rockchip_drm_notify.h" + +static RAW_NOTIFIER_HEAD(vblank_chain); +static DEFINE_MUTEX(vblank_lock); + +/** + * rockchip_drm_vblank_enable - Send Vblank enable event. Will only enable send + * Vblank if there are 1 or fewer notifiers. + */ +void rockchip_drm_vblank_enable(void) +{ + mutex_lock(&vblank_lock); + raw_notifier_call_chain(&vblank_chain, VBLANK_ENABLE, NULL); + mutex_unlock(&vblank_lock); +} +EXPORT_SYMBOL_GPL(rockchip_drm_vblank_enable); + +/** + * rockchip_drm_vblank_disable - Send VBlank disable event. + */ +void rockchip_drm_vblank_disable(void) +{ + mutex_lock(&vblank_lock); + raw_notifier_call_chain(&vblank_chain, VBLANK_DISABLE, NULL); + mutex_unlock(&vblank_lock); +} +EXPORT_SYMBOL_GPL(rockchip_drm_vblank_disable); + +/** + * rockchip_drm_vblank_register_notifier - Add notifier to Vblank notifiers. + * + * Enable notifiers are called when we enable/disable vblank. This can be done + * through rockchip_drm_vblank_enable/disable or when there is more than one + * sync notifier. Must call rockchip_drm_vblank_lock before calling this. + * @nb The notifier to add + */ +int rockchip_drm_vblank_register_notifier(struct notifier_block *nb) +{ + int ret = 0; + + if (!nb) + return -EINVAL; + + ret = raw_notifier_chain_register(&vblank_chain, nb); + return ret; +} +EXPORT_SYMBOL_GPL(rockchip_drm_vblank_register_notifier); + +/** + * rockchip_drm_vblank_unregister_notifier - Remove notifier from Vblank + * notifiers. + * + * Must call rockchip_drm_vblank_lock before calling this. + * @nb The notifier to remove. + */ +int rockchip_drm_vblank_unregister_notifier(struct notifier_block *nb) +{ + int ret = 0; + + if (!nb) + return -EINVAL; + + ret = raw_notifier_chain_unregister(&vblank_chain, nb); + return ret; +} +EXPORT_SYMBOL_GPL(rockchip_drm_vblank_unregister_notifier); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_notify.h b/drivers/gpu/drm/rockchip/rockchip_drm_notify.h new file mode 100644 index 000..2f28afa --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_drm_notify.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2014 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __ROCKCHIP_DRM_NOTIFY_H +#define __ROCKCHIP_DRM_NOTIFY_H + +#include + +enum vblank_enable_op { + VBLANK_ENABLE = 0, + VBLANK_DISABLE, +}; + +void rockchip_drm_vblank_enable(void); +void rockchip_drm_vblank_disable(void); +int rockchip_drm_vblank_register_notifier(struct notifier_block *nb); +int rockchip_drm_vblank_unregister_notifier(struct notifier_block *nb); + +#endif /* __ROCKCHIP_DRM_NOTIFY_H */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 257501f..fb6ce4b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -35,6 +35,7 @@ #include "rockchip_drm_gem.h" #include "rockchip_drm_fb.h" #include "rockchip_drm_vop.h" +#include &q
[RFC PATCH v1 2/2] drm/rockchip: analogix: add eDP PSR function
The full name of PSR is Panel Self Refresh, panel device could refresh itself with the hardware framebuffer in panel, this would make a lots of sense to save the power consumption. For example, when desktop haven't change the context for a long time, then we could refresh the data to the hardware framebuffer of panel, and then let panel enter into PSR mode. After that system could poweroff the LCDC controller and eDP controller, just let panel refresh the screen by itself. Signed-off-by: Yakir Yang --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 69 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 54 + drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 28 +++ drivers/gpu/drm/rockchip/analogix_dp-rockchip.c| 65 drivers/gpu/drm/rockchip/rockchip_drm_notify.c | 39 ++ drivers/gpu/drm/rockchip/rockchip_drm_notify.h | 4 + drivers/gpu/drm/rockchip/rockchip_drm_vop.c| 91 ++ drivers/gpu/drm/rockchip/rockchip_drm_vop.h| 3 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c| 2 + include/drm/bridge/analogix_dp.h | 3 + 11 files changed, 363 insertions(+) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 5af9ce4..a66ccb6 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -39,6 +39,72 @@ struct bridge_init { struct device_node *node; }; +int analogix_dp_actice_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + + if (!dp->psr_support) + return -EINVAL; + + analogix_dp_send_vsc(dp, EDP_VSC_PSR_STATE_ACTIVE | +EDP_VSC_PSR_CRC_VALUES_VALID); + + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_actice_psr); + +int analogix_dp_inactice_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + + if (!dp->psr_support) + return -EINVAL; + + analogix_dp_send_vsc(dp, 0); + + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_inactice_psr); + +int analogix_dp_enable_psr(struct analogix_dp_device *dp) +{ + unsigned char psr_version, psr_caps; + unsigned char psr_en; + + /* disable psr function */ + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_en); + psr_en &= ~DP_PSR_ENABLE; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* check panel psr version */ + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, &psr_version); + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_CAPS, &psr_caps); + dev_info(dp->dev, "Panel PSR version : %x.%x\n", psr_version, psr_caps); + + if (!(psr_version & DP_PSR_IS_SUPPORTED)) + return -1; + + /* Main-Link transmitter remains active during PSR active states */ + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_en); + psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* enable PSR function */ + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_en); + psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE | +DP_PSR_CRC_VERIFICATION; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* read sink psr state */ + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_en); + dev_info(dp->dev, "DP_PSR_EN_CFG: %x\n", psr_en); + + analogix_dp_enable_psr_crc(dp); + dp->psr_support = true; + + return 0; +} + static void analogix_dp_init_dp(struct analogix_dp_device *dp) { analogix_dp_reset(dp); @@ -921,6 +987,9 @@ static void analogix_dp_commit(struct analogix_dp_device *dp) /* Enable video */ analogix_dp_start_video(dp); + + /* Enable PSR support */ + analogix_dp_enable_psr(dp); } int analogix_dp_get_modes(struct drm_connector *connector) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index b456380..948e59a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -178,6 +178,8 @@ struct analogix_dp_device { boolforce_hpd; unsigned char edid[EDID_BLOCK_LENGTH * 2]; + boolpsr_support; + struct analogix_dp_plat_data *plat_data; }; @@ -278,4 +280,7 @@ int analogix_dp_is_video_stream_on(struct analogix_dp_device *dp); void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); v
[PATCH] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR
Sean, Thanks for your comments. On 09/07/2016 03:51 AM, Sean Paul wrote: > On Fri, Aug 26, 2016 at 6:19 AM, Yakir Yang wrote: >> Make sure the request PSR state could effect in analogix_dp_send_psr_spd() >> function, or printing the error Sink PSR state if we failed to effect >> the request PSR setting. >> >> Signed-off-by: Yakir Yang >> --- >> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 ++--- >> drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 ++-- >> drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 26 >> -- >> 3 files changed, 28 insertions(+), 8 deletions(-) >> >> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> index efac8ab..5a37de8 100644 >> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> @@ -115,8 +115,7 @@ int analogix_dp_enable_psr(struct device *dev) >> psr_vsc.DB0 = 0; >> psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | >> EDP_VSC_PSR_CRC_VALUES_VALID; >> >> - analogix_dp_send_psr_spd(dp, &psr_vsc); >> - return 0; >> + return analogix_dp_send_psr_spd(dp, &psr_vsc); >> } >> EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); >> >> @@ -138,8 +137,7 @@ int analogix_dp_disable_psr(struct device *dev) >> psr_vsc.DB0 = 0; >> psr_vsc.DB1 = 0; >> >> - analogix_dp_send_psr_spd(dp, &psr_vsc); >> - return 0; >> + return analogix_dp_send_psr_spd(dp, &psr_vsc); >> } >> EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); >> >> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h >> b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h >> index 473b980..f617a9d 100644 >> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h >> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h >> @@ -283,7 +283,7 @@ void analogix_dp_config_video_slave_mode(struct >> analogix_dp_device *dp); >> void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); >> void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); >> void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); >> -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, >> - struct edp_vsc_psr *vsc); >> +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, >> +struct edp_vsc_psr *vsc); >> >> #endif /* _ANALOGIX_DP_CORE_H */ >> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c >> b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c >> index 52c1b6b..505e9d8 100644 >> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c >> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c >> @@ -1328,9 +1328,11 @@ void analogix_dp_enable_psr_crc(struct >> analogix_dp_device *dp) >> writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); >> } >> >> -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, >> - struct edp_vsc_psr *vsc) >> +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, >> +struct edp_vsc_psr *vsc) >> { >> + unsigned long timeout; >> + unsigned char sink; > u8 Done >> unsigned int val; >> >> /* don't send info frame */ >> @@ -1372,4 +1374,24 @@ void analogix_dp_send_psr_spd(struct >> analogix_dp_device *dp, >> val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); >> val |= IF_EN; >> writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); >> + >> + timeout = jiffies + msecs_to_jiffies(100); > Pull 100 out into a #define Done >> + while (1) { >> + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_STATUS, &sink); > You should be checking return value here. Done >> + >> + if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB) >> + break; >> + >> + if (!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE) >> + break; >> + >> + if (time_after(jiffies, timeout)) { >> + dev_warn(dp->dev, "Failed to effect PSR: %x", sink); >> + return -EBUSY; > -ETIMEDOUT is more appropriate Done >> + } >> + >> + usleep_range(1000, 1500); >&
[PATCH v2 1/2] drm/bridge: analogix_dp: Remove duplicated code v2
From: Tomeu Vizoso Remove code for reading the EDID and DPCD fields and use the helpers instead. Besides the obvious code reduction, other helpers are being added to the core that could be used in this driver and will be good to be able to use them instead of duplicating them. Signed-off-by: Tomeu Vizoso Cc: Javier Martinez Canillas Cc: Mika Kahola Cc: Yakir Yang Cc: Daniel Vetter Reviewed-by: Sean Paul Reviewed-by: Yakir Yang Tested-by: Javier Martinez Canillas Tested-by: Sean Paul --- Changes in v2: - A bunch of good fixes from Sean and Yakir - Moved the transfer function to analogix_dp_reg.c - Removed reference to the EDID from the dp struct - Rebase on Sean's next tree git://people.freedesktop.org/~seanpaul/dogwood drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 263 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 41 +- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 451 ++--- 3 files changed, 204 insertions(+), 551 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index efac8ab..5fe3982 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -31,6 +31,7 @@ #include #include "analogix_dp_core.h" +#include "analogix_dp_reg.h" #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) @@ -174,150 +175,21 @@ static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) analogix_dp_enable_psr_crc(dp); } -static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) -{ - int i; - unsigned char sum = 0; - - for (i = 0; i < EDID_BLOCK_LENGTH; i++) - sum = sum + edid_data[i]; - - return sum; -} - -static int analogix_dp_read_edid(struct analogix_dp_device *dp) -{ - unsigned char *edid = dp->edid; - unsigned int extend_block = 0; - unsigned char sum; - unsigned char test_vector; - int retval; - - /* -* EDID device address is 0x50. -* However, if necessary, you must have set upper address -* into E-EDID in I2C device, 0x30. -*/ - - /* Read Extension Flag, Number of 128-byte EDID extension blocks */ - retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, - EDID_EXTENSION_FLAG, - &extend_block); - if (retval) - return retval; - - if (extend_block > 0) { - dev_dbg(dp->dev, "EDID data includes a single extension!\n"); - - /* Read EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, - &edid[EDID_HEADER_PATTERN]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum(edid); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - /* Read additional EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_BLOCK_LENGTH, - EDID_BLOCK_LENGTH, - &edid[EDID_BLOCK_LENGTH]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, - &test_vector); - if (test_vector & DP_TEST_LINK_EDID_READ) { - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_EDID_CHECKSUM, - edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_RESPONSE, - DP_TEST_EDID_CHECKSUM_WRITE); - } - } else { - dev_info(dp->dev, "EDID data does not include any extensions.\n"); - - /* Read EDID data *
[PATCH v2 2/2] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR
Make sure the request PSR state could effect in analogix_dp_send_psr_spd() function, or printing the error Sink PSR state if we failed to effect the request PSR setting. Signed-off-by: Yakir Yang --- Changes in v2: - A bunch of good fixes from Sean drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 ++-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 25 -- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 5fe3982..c0ce16a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; - analogix_dp_send_psr_spd(dp, &psr_vsc); - return 0; + return analogix_dp_send_psr_spd(dp, &psr_vsc); } EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); @@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = 0; - analogix_dp_send_psr_spd(dp, &psr_vsc); - return 0; + return analogix_dp_send_psr_spd(dp, &psr_vsc); } EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index a15f076..6c07a50 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -247,8 +247,8 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc); +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc); ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, struct drm_dp_aux_msg *msg); #endif /* _ANALOGIX_DP_CORE_H */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index a4d17b8..09d703b 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp) writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); } -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc) +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc) { + unsigned long timeout; unsigned int val; + u8 sink; /* don't send info frame */ val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); @@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); val |= IF_EN; writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + + timeout = jiffies + msecs_to_jiffies(DP_TIMEOUT_LOOP_COUNT); + while (time_before(jiffies, timeout)) { + val = drm_dp_dpcd_readb(&dp->aux, DP_PSR_STATUS, &sink); + if (val != 1) { + dev_err(dp->dev, "PSR_STATUS read failed ret=%d", val); + return val; + } + + if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB || + !vsc->DB1 && sink == DP_PSR_SINK_INACTIVE) + break; + + usleep_range(1000, 1500); + } + + dev_warn(dp->dev, "Failed to effect PSR: %x", sink); + + return -ETIMEDOUT; } ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, -- 1.9.1
[PATCH v2 2/2] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR
On 09/08/2016 10:12 PM, Sean Paul wrote: > On Wed, Sep 7, 2016 at 11:48 PM, Yakir Yang wrote: >> Make sure the request PSR state could effect in analogix_dp_send_psr_spd() >> function, or printing the error Sink PSR state if we failed to effect >> the request PSR setting. >> > > Let's change to: > > Make sure the request PSR state takes effect in analogix_dp_send_psr_spd() > function, or print the sink PSR error state if we failed to apply the > requested PSR > setting. Done, >> Signed-off-by: Yakir Yang >> --- >> Changes in v2: >> - A bunch of good fixes from Sean >> >> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 ++ >> drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 ++-- >> drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 25 >> -- >> 3 files changed, 27 insertions(+), 8 deletions(-) >> >> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> index 5fe3982..c0ce16a 100644 >> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> @@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev) >> psr_vsc.DB0 = 0; >> psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | >> EDP_VSC_PSR_CRC_VALUES_VALID; >> >> - analogix_dp_send_psr_spd(dp, &psr_vsc); >> - return 0; >> + return analogix_dp_send_psr_spd(dp, &psr_vsc); >> } >> EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); >> >> @@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev) >> psr_vsc.DB0 = 0; >> psr_vsc.DB1 = 0; >> >> - analogix_dp_send_psr_spd(dp, &psr_vsc); >> - return 0; >> + return analogix_dp_send_psr_spd(dp, &psr_vsc); >> } >> EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); >> >> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h >> b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h >> index a15f076..6c07a50 100644 >> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h >> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h >> @@ -247,8 +247,8 @@ void analogix_dp_config_video_slave_mode(struct >> analogix_dp_device *dp); >> void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); >> void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); >> void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); >> -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, >> - struct edp_vsc_psr *vsc); >> +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, >> +struct edp_vsc_psr *vsc); >> ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, >> struct drm_dp_aux_msg *msg); >> #endif /* _ANALOGIX_DP_CORE_H */ >> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c >> b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c >> index a4d17b8..09d703b 100644 >> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c >> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c >> @@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct >> analogix_dp_device *dp) >> writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); >> } >> >> -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, >> - struct edp_vsc_psr *vsc) >> +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, >> +struct edp_vsc_psr *vsc) >> { >> + unsigned long timeout; >> unsigned int val; >> + u8 sink; >> >> /* don't send info frame */ >> val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); >> @@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct >> analogix_dp_device *dp, >> val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); >> val |= IF_EN; >> writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); >> + >> + timeout = jiffies + msecs_to_jiffies(DP_TIMEOUT_LOOP_COUNT); > Mismatched units here. DP_TIMEOUT_LOOP_COUNT is defined as number of > retries, whereas you're using it as number of ms. Fortunately, the > retry number is so high that this works out :) > > In a separate patch preceding this one, can you change > DP_TIMEOUT_LOOP_COUNT to DP_TIMEOUT_LOOP_MS and alter the other > timeout loops to
[PATCH v3 2/3] drm/bridge: analogix_dp: use jiffies to simulate timeout loop
Signed-off-by: Yakir Yang --- Changes in v3: - Suggested by Sean Changes in v2: None drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 3 ++- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 18 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index a15f076..d564e90 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -16,10 +16,11 @@ #include #include -#define DP_TIMEOUT_LOOP_COUNT 100 #define MAX_CR_LOOP 5 #define MAX_EQ_LOOP 5 +#define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1) + /* DP_MAX_LANE_COUNT */ #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index a4d17b8..15a4cf0 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -335,7 +335,7 @@ void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp, void analogix_dp_init_analog_func(struct analogix_dp_device *dp) { u32 reg; - int timeout_loop = 0; + unsigned long timeout; analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); @@ -350,9 +350,9 @@ void analogix_dp_init_analog_func(struct analogix_dp_device *dp) if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { analogix_dp_set_pll_power_down(dp, 0); + timeout = jiffies + DP_TIMEOUT_LOOP_MS; while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { - timeout_loop++; - if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { + if (time_after(jiffies, timeout)) { dev_err(dp->dev, "failed to get pll lock status\n"); return; } @@ -501,7 +501,7 @@ int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp) { int reg; int retval = 0; - int timeout_loop = 0; + unsigned long timeout; /* Enable AUX CH operation */ reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); @@ -509,10 +509,10 @@ int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp) writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); /* Is AUX CH command reply received? */ + timeout = jiffies + DP_TIMEOUT_LOOP_MS; reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); while (!(reg & RPLY_RECEIV)) { - timeout_loop++; - if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { + if (time_after(jiffies, timeout)) { dev_err(dp->dev, "AUX CH command reply failed!\n"); return -ETIMEDOUT; } @@ -1055,7 +1055,7 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, { u32 reg; u8 *buffer = msg->buffer; - int timeout_loop = 0; + unsigned long timeout; unsigned int i; int num_transferred = 0; @@ -1123,10 +1123,10 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, /* Is AUX CH command reply received? */ /* TODO: Wait for an interrupt instead of looping? */ + timeout = jiffies + DP_TIMEOUT_LOOP_MS; reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); while (!(reg & RPLY_RECEIV)) { - timeout_loop++; - if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { + if (time_after(jiffies, timeout)) { dev_err(dp->dev, "AUX CH command reply failed!\n"); return -ETIMEDOUT; } -- 1.9.1
[PATCH v3 3/3] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR
Make sure the request PSR state takes effect in analogix_dp_send_psr_spd() function, or print the sink PSR error state if we failed to apply the requested PSR setting. Signed-off-by: Yakir Yang --- Changes in v3: - Update commit message - Add DP_TIMEOUT_PSR_LOOP_MS marcos - Correct the return values of analogix_dp_send_psr_spd() Changes in v2: - A bunch of good fixes from Sean drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 +++-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 25 -- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 5fe3982..c0ce16a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; - analogix_dp_send_psr_spd(dp, &psr_vsc); - return 0; + return analogix_dp_send_psr_spd(dp, &psr_vsc); } EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); @@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = 0; - analogix_dp_send_psr_spd(dp, &psr_vsc); - return 0; + return analogix_dp_send_psr_spd(dp, &psr_vsc); } EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index d564e90..a27f1e3 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -20,6 +20,7 @@ #define MAX_EQ_LOOP 5 #define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1) +#define DP_TIMEOUT_PSR_LOOP_MS msecs_to_jiffies(300) /* DP_MAX_LANE_COUNT */ #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) @@ -248,8 +249,8 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc); +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc); ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, struct drm_dp_aux_msg *msg); #endif /* _ANALOGIX_DP_CORE_H */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index 15a4cf0..7fd4ed0 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp) writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); } -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc) +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc) { + unsigned long timeout; unsigned int val; + u8 sink; /* don't send info frame */ val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); @@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); val |= IF_EN; writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + + timeout = jiffies + DP_TIMEOUT_PSR_LOOP_MS; + while (time_before(jiffies, timeout)) { + val = drm_dp_dpcd_readb(&dp->aux, DP_PSR_STATUS, &sink); + if (val != 1) { + dev_err(dp->dev, "PSR_STATUS read failed ret=%d", val); + return -EBUSY; + } + + if ((vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB) || + (!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE)) + return 0; + + usleep_range(1000, 1500); + } + + dev_warn(dp->dev, "Failed to apply PSR, sink state was [%x]", sink); + + return -ETIMEDOUT; } ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, -- 1.9.1
[PATCH v3 2/3] drm/bridge: analogix_dp: use jiffies to simulate timeout loop
Hi Sean, On 09/12/2016 09:51 PM, Sean Paul wrote: > On Fri, Sep 9, 2016 at 5:44 AM, Yakir Yang wrote: >> Signed-off-by: Yakir Yang >> --- >> Changes in v3: >> - Suggested by Sean >> >> Changes in v2: None >> >> drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 3 ++- >> drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 18 +- >> 2 files changed, 11 insertions(+), 10 deletions(-) >> >> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h >> b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h >> index a15f076..d564e90 100644 >> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h >> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h >> @@ -16,10 +16,11 @@ >> #include >> #include >> >> -#define DP_TIMEOUT_LOOP_COUNT 100 >> #define MAX_CR_LOOP 5 >> #define MAX_EQ_LOOP 5 >> >> +#define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1) > The name suggests the units here are ms, but you're storing jiffies. > Do the msecs_to_jiffies conversion down below. I suddenly realized that 'analogix_dp_core.c' also used the 'DP_TIMEOUT_LOOP_COUNT' macros, and 'analogix_dp_core.c' have four kinds of timeout, - DP_TIMEOUT_LOOP_COUNT * 1us - DP_TIMEOUT_LOOP_COUNT * 10us - DP_TIMEOUT_LOOP_COUNT * 100us - DP_TIMEOUT_LOOP_COUNT * 1000us I may guess it's not necessary to replace the 'DP_TIMEOUT_LOOP_COUNT' now :-) - Yakir > >> + >> /* DP_MAX_LANE_COUNT */ >> #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) >> #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) >> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c >> b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c >> index a4d17b8..15a4cf0 100644 >> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c >> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c >> @@ -335,7 +335,7 @@ void analogix_dp_set_analog_power_down(struct >> analogix_dp_device *dp, >> void analogix_dp_init_analog_func(struct analogix_dp_device *dp) >> { >> u32 reg; >> - int timeout_loop = 0; >> + unsigned long timeout; >> >> analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); >> >> @@ -350,9 +350,9 @@ void analogix_dp_init_analog_func(struct >> analogix_dp_device *dp) >> if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { >> analogix_dp_set_pll_power_down(dp, 0); >> >> + timeout = jiffies + DP_TIMEOUT_LOOP_MS; > timeout = jiffies + msecs_to_jiffies(DP_TIMEOUT_LOOP_MS); > >> while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) >> { >> - timeout_loop++; >> - if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { >> + if (time_after(jiffies, timeout)) { >> dev_err(dp->dev, "failed to get pll lock >> status\n"); >> return; >> } >> @@ -501,7 +501,7 @@ int analogix_dp_start_aux_transaction(struct >> analogix_dp_device *dp) >> { >> int reg; >> int retval = 0; >> - int timeout_loop = 0; >> + unsigned long timeout; >> >> /* Enable AUX CH operation */ >> reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); >> @@ -509,10 +509,10 @@ int analogix_dp_start_aux_transaction(struct >> analogix_dp_device *dp) >> writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); >> >> /* Is AUX CH command reply received? */ >> + timeout = jiffies + DP_TIMEOUT_LOOP_MS; >> reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); >> while (!(reg & RPLY_RECEIV)) { >> - timeout_loop++; >> - if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { >> + if (time_after(jiffies, timeout)) { >> dev_err(dp->dev, "AUX CH command reply failed!\n"); >> return -ETIMEDOUT; >> } >> @@ -1055,7 +1055,7 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device >> *dp, >> { >> u32 reg; >> u8 *buffer = msg->buffer; >> - int timeout_loop = 0; >> + unsigned long timeout; >> unsigned int i; >> int num_transferred = 0; >> >> @@ -1123,10 +1123,10 @@ ssize_t analogix_dp_transfer(struct >> analogix_dp_device *dp, >> >> /* Is AUX CH command reply received? */ >> /* TODO: Wait for an interrupt instead of looping? */ >> + timeout = jiffies + DP_TIMEOUT_LOOP_MS; >> reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); >> while (!(reg & RPLY_RECEIV)) { >> - timeout_loop++; >> - if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { >> + if (time_after(jiffies, timeout)) { >> dev_err(dp->dev, "AUX CH command reply failed!\n"); >> return -ETIMEDOUT; >> } >> -- >> 1.9.1 >> >> > >
[PATCH v3 3/3] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR
Hi Sean, On 09/12/2016 09:52 PM, Sean Paul wrote: > On Fri, Sep 9, 2016 at 5:45 AM, Yakir Yang wrote: >> Make sure the request PSR state takes effect in analogix_dp_send_psr_spd() >> function, or print the sink PSR error state if we failed to apply the >> requested PSR setting. >> >> Signed-off-by: Yakir Yang >> --- >> Changes in v3: >> - Update commit message >> - Add DP_TIMEOUT_PSR_LOOP_MS marcos >> - Correct the return values of analogix_dp_send_psr_spd() >> >> Changes in v2: >> - A bunch of good fixes from Sean >> >> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 ++ >> drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 +++-- >> drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 25 >> -- >> 3 files changed, 28 insertions(+), 8 deletions(-) >> >> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> index 5fe3982..c0ce16a 100644 >> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> @@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev) >> psr_vsc.DB0 = 0; >> psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | >> EDP_VSC_PSR_CRC_VALUES_VALID; >> >> - analogix_dp_send_psr_spd(dp, &psr_vsc); >> - return 0; >> + return analogix_dp_send_psr_spd(dp, &psr_vsc); >> } >> EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); >> >> @@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev) >> psr_vsc.DB0 = 0; >> psr_vsc.DB1 = 0; >> >> - analogix_dp_send_psr_spd(dp, &psr_vsc); >> - return 0; >> + return analogix_dp_send_psr_spd(dp, &psr_vsc); >> } >> EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); >> >> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h >> b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h >> index d564e90..a27f1e3 100644 >> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h >> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h >> @@ -20,6 +20,7 @@ >> #define MAX_EQ_LOOP 5 >> >> #define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1) >> +#define DP_TIMEOUT_PSR_LOOP_MS msecs_to_jiffies(300) > Same comment here re: units. > > 300ms seems like a really long time. Why does it take this long? This magic number '300ms' just come from my test, I haven't found the description in eDP 1.4a Spec about what exact time should Sink take to entry PSR. - Yakir > Sean > > >> /* DP_MAX_LANE_COUNT */ >> #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) >> @@ -248,8 +249,8 @@ void analogix_dp_config_video_slave_mode(struct >> analogix_dp_device *dp); >> void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); >> void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); >> void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); >> -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, >> - struct edp_vsc_psr *vsc); >> +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, >> +struct edp_vsc_psr *vsc); >> ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, >> struct drm_dp_aux_msg *msg); >> #endif /* _ANALOGIX_DP_CORE_H */ >> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c >> b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c >> index 15a4cf0..7fd4ed0 100644 >> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c >> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c >> @@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct >> analogix_dp_device *dp) >> writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); >> } >> >> -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, >> - struct edp_vsc_psr *vsc) >> +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, >> +struct edp_vsc_psr *vsc) >> { >> + unsigned long timeout; >> unsigned int val; >> + u8 sink; >> >> /* don't send info frame */ >> val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); >> @@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct >> analogix_dp_device *dp, >>
[PATCH 1/4] drm/panel: simple: Add support for LG LP097QX1-SPA1 2048x1536 panel
The LG LP097QX1-SPA1 is an 9.7", 2048x1536 (QXGA) TFT-LCD panel connected using eDP interfaces. Signed-off-by: Yakir Yang --- drivers/gpu/drm/panel/panel-simple.c | 25 + 1 file changed, 25 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 3a7bdf1..41020e1 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1040,6 +1040,28 @@ static const struct panel_desc lg_lp120up1 = { }, }; +static const struct drm_display_mode lg_lp097qx1_spa1_mode = { + .clock = 205210, + .hdisplay = 2048, + .hsync_start = 2048 + 150, + .hsync_end = 2048 + 150 + 5, + .htotal = 2048 + 150 + 5 + 5, + .vdisplay = 1536, + .vsync_start = 1536 + 3, + .vsync_end = 1536 + 3 + 1, + .vtotal = 1536 + 3 + 1 + 9, + .vrefresh = 60, +}; + +static const struct panel_desc lg_lp097qx1_spa1 = { + .modes = &lg_lp097qx1_spa1_mode, + .num_modes = 1, + .size = { + .width = 2048, + .height = 1536, + }, +}; + static const struct drm_display_mode lg_lp129qe_mode = { .clock = 285250, .hdisplay = 2560, @@ -1460,6 +1482,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "lg,lp120up1", .data = &lg_lp120up1, }, { + .compatible = "lg,lp097qx1-spa1", + .data = &lg_lp097qx1_spa1, + }, { .compatible = "lg,lp129qe", .data = &lg_lp129qe, }, { -- 1.9.1
[PATCH 2/4] dt-bindings: add LG LP097QX1-SPA1 panle binding
The LG LP097QX1-SPA1 is an 9.7", 2048x1536 (QXGA) TFT-LCD panel connected using eDP interfaces. Signed-off-by: Yakir Yang --- .../devicetree/bindings/display/panel/lg,lp097qx1-spa1.txt | 7 +++ 1 file changed, 7 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/lg,lp097qx1-spa1.txt diff --git a/Documentation/devicetree/bindings/display/panel/lg,lp097qx1-spa1.txt b/Documentation/devicetree/bindings/display/panel/lg,lp097qx1-spa1.txt new file mode 100644 index 000..4214151 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/lg,lp097qx1-spa1.txt @@ -0,0 +1,7 @@ +LG 9.7" (2048x1536 pixels) TFT LCD panel + +Required properties: +- compatible: should be "lg,lp097qx1-spa1" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. -- 1.9.1
[PATCH 3/4] drm/panel: simple: Add support for Samsung LSN122DL01-C01 2560x1600 panel
The Samsung LSN122DL01-C01 is an 12.2" 2560x1600 (WQXGA) TFT-LCD panel connected using eDP interfaces. Signed-off-by: Yakir Yang --- drivers/gpu/drm/panel/panel-simple.c | 25 + 1 file changed, 25 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 41020e1..067a5c4 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1246,6 +1246,28 @@ static const struct panel_desc qd43003c0_40 = { .bus_format = MEDIA_BUS_FMT_RGB888_1X24, }; +static const struct drm_display_mode samsung_lsn122dl01_c01_mode = { + .clock = 271560, + .hdisplay = 2560, + .hsync_start = 2560 + 48, + .hsync_end = 2560 + 48 + 32, + .htotal = 2560 + 48 + 32 + 80, + .vdisplay = 1600, + .vsync_start = 1600 + 2, + .vsync_end = 1600 + 2 + 5, + .vtotal = 1600 + 2 + 5 + 57, + .vrefresh = 60, +}; + +static const struct panel_desc samsung_lsn122dl01_c01 = { + .modes = &samsung_lsn122dl01_c01_mode, + .num_modes = 1, + .size = { + .width = 2560, + .height = 1600, + }, +}; + static const struct drm_display_mode samsung_ltn101nt05_mode = { .clock = 54030, .hdisplay = 1024, @@ -1506,6 +1528,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "qiaodian,qd43003c0-40", .data = &qd43003c0_40, }, { + .compatible = "samsung,lsn122dl01-c01", + .data = &samsung_lsn122dl01_c01, + }, { .compatible = "samsung,ltn101nt05", .data = &samsung_ltn101nt05, }, { -- 1.9.1
[PATCH 4/4] dt-bindings: add Samsung LSN122DL01-C01 panel binding
The Samsung LSN122DL01-C01 is an 12.2" 2560x1600 (WQXGA) TFT-LCD panel connected using eDP interfaces. Signed-off-by: Yakir Yang --- .../devicetree/bindings/display/panel/samsung,lsn122dl01-c01.txt | 7 +++ 1 file changed, 7 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/samsung,lsn122dl01-c01.txt diff --git a/Documentation/devicetree/bindings/display/panel/samsung,lsn122dl01-c01.txt b/Documentation/devicetree/bindings/display/panel/samsung,lsn122dl01-c01.txt new file mode 100644 index 000..dba298b --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/samsung,lsn122dl01-c01.txt @@ -0,0 +1,7 @@ +Samsung 12.2" (2560x1600 pixels) TFT LCD panel + +Required properties: +- compatible: should be "samsung,lsn122dl01-c01" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. -- 1.9.1
[PATCH v2 0/10] Add RK3399 eDP support and fix some bugs to analogix_dp driver.
Hi all, This series have been posted about one month, still no comments, help here :( RK3399 and RK3288 shared the same eDP IP controller, only some light difference with VOP configure and GRF configure. Also same misc fix to analogix_dp driver: - Hotplug invalid which report by Dan Carpenter - Make panel detect to an optional action - correct the register bit define error in ANALOGIX_DP_PLL_REG_1 Changes in v2: - new patch in v2 - rebase with drm-next, fix some conflicts - new patch in v2 Yakir Yang (10): drm/bridge: analogix_dp: rename RK3288_DP to ROCKCHIP_DP drm/rockchip: analogix_dp: split the lcdc select setting into device data drm/bridge: analogix_dp: correct the register bit define error in ANALOGIX_DP_PLL_REG_1 drm/bridge: analogix_dp: some rockchip chips need to flip REF_CLK bit setting drm/rockchip: analogix_dp: add rk3399 eDP support drm/rockchip: analogix_dp: make panel detect to an optional action drm/bridge: analogix_dp: introduce connector mode_valid callback to plat driver drm/rockchip: analogix_dp: correct the connector display color format and bpc drm/rockchip: analogix_dp: update the comments about why need to hardcode VOP output mode drm/bridge: analogix_dp: fix no drm hpd event when panel plug in .../bindings/display/bridge/analogix_dp.txt| 1 + .../display/rockchip/analogix_dp-rockchip.txt | 2 +- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 19 ++- drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 8 +- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 12 +- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 5 +- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c| 157 ++--- include/drm/bridge/analogix_dp.h | 10 ++ 8 files changed, 152 insertions(+), 62 deletions(-) -- 1.9.1
[PATCH v2 01/10] drm/bridge: analogix_dp: rename RK3288_DP to ROCKCHIP_DP
Rename RK3288_DP marcos to ROCKCHIP_DP, prepare to add eDP support for more Rockchip chips. Signed-off-by: Yakir Yang --- Changes in v2: None drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 ++-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 6 +++--- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c| 2 +- include/drm/bridge/analogix_dp.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 7699597..4a1b3b8 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1207,9 +1207,9 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp) struct video_info *video_info = &dp->video_info; switch (dp->plat_data->dev_type) { - case RK3288_DP: + case ROCKCHIP_DP: /* -* Like Rk3288 DisplayPort TRM indicate that "Main link +* Like Rockchip DisplayPort TRM indicate that "Main link * containing 4 physical lanes of 2.7/1.62 Gbps/lane". */ video_info->max_link_rate = 0x0A; diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index 49205ef..931a76c 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -74,7 +74,7 @@ void analogix_dp_init_analog_param(struct analogix_dp_device *dp) reg = SEL_24M | TX_DVDD_BIT_1_0625V; writel(reg, dp->reg_base + ANALOGIX_DP_ANALOG_CTL_2); - if (dp->plat_data && (dp->plat_data->dev_type == RK3288_DP)) { + if (dp->plat_data && (dp->plat_data->dev_type == ROCKCHIP_DP)) { writel(REF_CLK_24M, dp->reg_base + ANALOGIX_DP_PLL_REG_1); writel(0x95, dp->reg_base + ANALOGIX_DP_PLL_REG_2); writel(0x40, dp->reg_base + ANALOGIX_DP_PLL_REG_3); @@ -244,7 +244,7 @@ void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp, u32 reg; u32 phy_pd_addr = ANALOGIX_DP_PHY_PD; - if (dp->plat_data && (dp->plat_data->dev_type == RK3288_DP)) + if (dp->plat_data && (dp->plat_data->dev_type == ROCKCHIP_DP)) phy_pd_addr = ANALOGIX_DP_PD; switch (block) { @@ -448,7 +448,7 @@ void analogix_dp_init_aux(struct analogix_dp_device *dp) analogix_dp_reset_aux(dp); /* Disable AUX transaction H/W retry */ - if (dp->plat_data && (dp->plat_data->dev_type == RK3288_DP)) + if (dp->plat_data && (dp->plat_data->dev_type == ROCKCHIP_DP)) reg = AUX_BIT_PERIOD_EXPECTED_DELAY(0) | AUX_HW_RETRY_COUNT_SEL(3) | AUX_HW_RETRY_INTERVAL_600_MICROSECONDS; diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 7f6a55c..2bc8a7e 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -270,7 +270,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, dp->plat_data.encoder = &dp->encoder; - dp->plat_data.dev_type = RK3288_DP; + dp->plat_data.dev_type = ROCKCHIP_DP; dp->plat_data.power_on = rockchip_dp_poweron; dp->plat_data.power_off = rockchip_dp_powerdown; diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h index 25afb31..9e5d013 100644 --- a/include/drm/bridge/analogix_dp.h +++ b/include/drm/bridge/analogix_dp.h @@ -15,7 +15,7 @@ enum analogix_dp_devtype { EXYNOS_DP, - RK3288_DP, + ROCKCHIP_DP, }; struct analogix_dp_plat_data { -- 1.9.1
[PATCH v2 02/10] drm/rockchip: analogix_dp: split the lcdc select setting into device data
eDP controller need to declare which vop provide the video source, and it's defined in GRF registers. But different chips have different GRF register address, so we need to create a device data to declare the GRF messages for each chips. Signed-off-by: Yakir Yang --- Changes in v2: None drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 35 ++--- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 2bc8a7e..260c43f 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -35,11 +36,12 @@ #define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm) -/* dp grf register offset */ -#define GRF_SOC_CON60x025c -#define GRF_EDP_LCD_SEL_MASKBIT(5) -#define GRF_EDP_SEL_VOP_LIT BIT(5) -#define GRF_EDP_SEL_VOP_BIG 0 +struct rockchip_dp_chip_data { + u32 lcdsel_grf_reg; + u32 lcdsel_big; + u32 lcdsel_lit; + u32 lcdsel_mask; +}; struct rockchip_dp_device { struct drm_device*drm_dev; @@ -51,6 +53,8 @@ struct rockchip_dp_device { struct regmap*grf; struct reset_control *rst; + const struct rockchip_dp_chip_data *data; + struct analogix_dp_plat_data plat_data; }; @@ -119,13 +123,13 @@ static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder) return; if (ret) - val = GRF_EDP_SEL_VOP_LIT | (GRF_EDP_LCD_SEL_MASK << 16); + val = dp->data->lcdsel_lit | dp->data->lcdsel_mask; else - val = GRF_EDP_SEL_VOP_BIG | (GRF_EDP_LCD_SEL_MASK << 16); + val = dp->data->lcdsel_big | dp->data->lcdsel_mask; dev_dbg(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG"); - ret = regmap_write(dp->grf, GRF_SOC_CON6, val); + ret = regmap_write(dp->grf, dp->data->lcdsel_grf_reg, val); if (ret != 0) { dev_err(dp->dev, "Could not write to GRF: %d\n", ret); return; @@ -246,6 +250,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, void *data) { struct rockchip_dp_device *dp = dev_get_drvdata(dev); + const struct rockchip_dp_chip_data *dp_data; struct drm_device *drm_dev = data; int ret; @@ -256,10 +261,15 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, */ dev_set_drvdata(dev, NULL); + dp_data = of_device_get_match_data(dev); + if (!dp_data) + return -ENODEV; + ret = rockchip_dp_init(dp); if (ret < 0) return ret; + dp->data = dp_data; dp->drm_dev = drm_dev; ret = rockchip_dp_drm_create_encoder(dp); @@ -365,8 +375,15 @@ static const struct dev_pm_ops rockchip_dp_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(rockchip_dp_suspend, rockchip_dp_resume) }; +static const struct rockchip_dp_chip_data rk3288_dp = { + .lcdsel_grf_reg = 0x025c, + .lcdsel_big = 0, + .lcdsel_lit = BIT(5), + .lcdsel_mask = BIT(21), +}; + static const struct of_device_id rockchip_dp_dt_ids[] = { - {.compatible = "rockchip,rk3288-dp",}, + {.compatible = "rockchip,rk3288-dp", .data = &rk3288_dp }, {} }; MODULE_DEVICE_TABLE(of, rockchip_dp_dt_ids); -- 1.9.1
[PATCH v2 03/10] drm/bridge: analogix_dp: correct the register bit define error in ANALOGIX_DP_PLL_REG_1
There're an register define error in ANALOGIX_DP_PLL_REG_1 which introduced by commit bcec20fd5ad6 ("drm: bridge: analogix/dp: add some rk3288 special registers setting"). The PHY PLL input clock source is selected by ANALOGIX_DP_PLL_REG_1 BIT 0, not BIT 1. Signed-off-by: Yakir Yang --- Changes in v2: None drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h index 337912b..88d56ad 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h @@ -163,8 +163,8 @@ #define HSYNC_POLARITY_CFG (0x1 << 0) /* ANALOGIX_DP_PLL_REG_1 */ -#define REF_CLK_24M(0x1 << 1) -#define REF_CLK_27M(0x0 << 1) +#define REF_CLK_24M(0x1 << 0) +#define REF_CLK_27M(0x0 << 0) /* ANALOGIX_DP_LANE_MAP */ #define LANE3_MAP_LOGIC_LANE_0 (0x0 << 6) -- 1.9.1
[PATCH v2 04/10] drm/bridge: analogix_dp: some rockchip chips need to flip REF_CLK bit setting
As vendor document indicate, when REF_CLK bit set 0, then DP phy's REF_CLK should switch to 24M source clock. But due to IC PHY layout mistaken, some chips need to flip this bit(like RK3288), and unfortunately they didn't indicate in the DP version register. That's why we have to make this little hack. Signed-off-by: Yakir Yang --- Changes in v2: - new patch in v2 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 6 +- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 1 + drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 3 +++ include/drm/bridge/analogix_dp.h | 5 + 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index 931a76c..31366bf 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -75,7 +75,11 @@ void analogix_dp_init_analog_param(struct analogix_dp_device *dp) writel(reg, dp->reg_base + ANALOGIX_DP_ANALOG_CTL_2); if (dp->plat_data && (dp->plat_data->dev_type == ROCKCHIP_DP)) { - writel(REF_CLK_24M, dp->reg_base + ANALOGIX_DP_PLL_REG_1); + reg = REF_CLK_24M; + if (dp->plat_data->subdev_type == RK3288_DP) + reg = ~reg & REF_CLK_MASK; + + writel(reg, dp->reg_base + ANALOGIX_DP_PLL_REG_1); writel(0x95, dp->reg_base + ANALOGIX_DP_PLL_REG_2); writel(0x40, dp->reg_base + ANALOGIX_DP_PLL_REG_3); writel(0x58, dp->reg_base + ANALOGIX_DP_PLL_REG_4); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h index 88d56ad..cdcc6c5 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h @@ -165,6 +165,7 @@ /* ANALOGIX_DP_PLL_REG_1 */ #define REF_CLK_24M(0x1 << 0) #define REF_CLK_27M(0x0 << 0) +#define REF_CLK_MASK (0x1 << 0) /* ANALOGIX_DP_LANE_MAP */ #define LANE3_MAP_LOGIC_LANE_0 (0x0 << 6) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 260c43f..29c4105 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -41,6 +41,7 @@ struct rockchip_dp_chip_data { u32 lcdsel_big; u32 lcdsel_lit; u32 lcdsel_mask; + u32 chip_type; }; struct rockchip_dp_device { @@ -281,6 +282,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, dp->plat_data.encoder = &dp->encoder; dp->plat_data.dev_type = ROCKCHIP_DP; + dp->plat_data.subdev_type = dp_data->chip_type; dp->plat_data.power_on = rockchip_dp_poweron; dp->plat_data.power_off = rockchip_dp_powerdown; @@ -380,6 +382,7 @@ static const struct rockchip_dp_chip_data rk3288_dp = { .lcdsel_big = 0, .lcdsel_lit = BIT(5), .lcdsel_mask = BIT(21), + .chip_type = RK3288_DP, }; static const struct of_device_id rockchip_dp_dt_ids[] = { diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h index 9e5d013..06c0250 100644 --- a/include/drm/bridge/analogix_dp.h +++ b/include/drm/bridge/analogix_dp.h @@ -18,8 +18,13 @@ enum analogix_dp_devtype { ROCKCHIP_DP, }; +enum analogix_dp_sub_devtype { + RK3288_DP, +}; + struct analogix_dp_plat_data { enum analogix_dp_devtype dev_type; + enum analogix_dp_sub_devtype subdev_type; struct drm_panel *panel; struct drm_encoder *encoder; struct drm_connector *connector; -- 1.9.1
[PATCH v2 05/10] drm/rockchip: analogix_dp: add rk3399 eDP support
RK3399 and RK3288 shared the same eDP IP controller, only some light difference with VOP configure and GRF configure. Signed-off-by: Yakir Yang --- Changes in v2: - rebase with drm-next, fix some conflicts .../bindings/display/bridge/analogix_dp.txt| 1 + .../display/rockchip/analogix_dp-rockchip.txt | 2 +- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c| 34 -- include/drm/bridge/analogix_dp.h | 1 + 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt index 4f2ba8c..4a0f4f7 100644 --- a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt +++ b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt @@ -5,6 +5,7 @@ Required properties for dp-controller: platform specific such as: * "samsung,exynos5-dp" * "rockchip,rk3288-dp" +* "rockchip,rk3399-edp" -reg: physical base address of the controller and length of memory mapped region. diff --git a/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt index e832ff9..5ae55ca 100644 --- a/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt @@ -2,7 +2,7 @@ Rockchip RK3288 specific extensions to the Analogix Display Port Required properties: -- compatible: "rockchip,rk3288-edp"; +- compatible: "rockchip,rk3288-edp" or "rockchip,rk3399-edp"; - reg: physical base address of the controller and length diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 29c4105..d684c97 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -149,6 +149,8 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, { struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + s->output_type = DRM_MODE_CONNECTOR_eDP; + /* * FIXME(Yakir): driver should configure the CRTC output video * mode with the display information which indicated the monitor @@ -162,8 +164,27 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, * But if I configure CTRC to RGBaaa, and eDP driver still keep * RGB666 input video mode, then screen would works prefect. */ - s->output_mode = ROCKCHIP_OUT_MODE_; - s->output_type = DRM_MODE_CONNECTOR_eDP; + + ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder); + if (ret < 0) + return; + + switch (dp->data->chip_type) { + case RK3399_EDP: + /* +* For RK3399, VOP Lit must code the out mode to RGB888, +* VOP Big must code the out mode to RGB10. +*/ + if (ret) + s->output_mode = ROCKCHIP_OUT_MODE_P888; + else + s->output_mode = ROCKCHIP_OUT_MODE_; + break; + + default: + s->output_mode = ROCKCHIP_OUT_MODE_; + break; + } return 0; } @@ -377,6 +398,14 @@ static const struct dev_pm_ops rockchip_dp_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(rockchip_dp_suspend, rockchip_dp_resume) }; +static const struct rockchip_dp_chip_data rk3399_edp = { + .lcdsel_grf_reg = 0x6250, + .lcdsel_big = 0, + .lcdsel_lit = BIT(5), + .lcdsel_mask = BIT(21), + .chip_type = RK3399_EDP, +}; + static const struct rockchip_dp_chip_data rk3288_dp = { .lcdsel_grf_reg = 0x025c, .lcdsel_big = 0, @@ -387,6 +416,7 @@ static const struct rockchip_dp_chip_data rk3288_dp = { static const struct of_device_id rockchip_dp_dt_ids[] = { {.compatible = "rockchip,rk3288-dp", .data = &rk3288_dp }, + {.compatible = "rockchip,rk3399-edp", .data = &rk3399_edp }, {} }; MODULE_DEVICE_TABLE(of, rockchip_dp_dt_ids); diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h index 06c0250..82b8135 100644 --- a/include/drm/bridge/analogix_dp.h +++ b/include/drm/bridge/analogix_dp.h @@ -20,6 +20,7 @@ enum analogix_dp_devtype { enum analogix_dp_sub_devtype { RK3288_DP, + RK3399_EDP, }; struct analogix_dp_plat_data { -- 1.9.1
[PATCH v2 06/10] drm/rockchip: analogix_dp: make panel detect to an optional action
Some boards don't need to declare a panel device node, like the display interface is DP monitors, so it's necessary to make the panel detect to an optional action. Signed-off-by: Yakir Yang --- Changes in v2: None drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 48 - 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index d684c97..f29ca3d 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -325,38 +325,34 @@ static int rockchip_dp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *panel_node, *port, *endpoint; + struct drm_panel *panel = NULL; struct rockchip_dp_device *dp; - struct drm_panel *panel; port = of_graph_get_port_by_id(dev->of_node, 1); - if (!port) { - dev_err(dev, "can't find output port\n"); - return -EINVAL; - } - - endpoint = of_get_child_by_name(port, "endpoint"); - of_node_put(port); - if (!endpoint) { - dev_err(dev, "no output endpoint found\n"); - return -EINVAL; - } - - panel_node = of_graph_get_remote_port_parent(endpoint); - of_node_put(endpoint); - if (!panel_node) { - dev_err(dev, "no output node found\n"); - return -EINVAL; - } - - panel = of_drm_find_panel(panel_node); - if (!panel) { - DRM_ERROR("failed to find panel\n"); + if (port) { + endpoint = of_get_child_by_name(port, "endpoint"); + of_node_put(port); + if (!endpoint) { + dev_err(dev, "no output endpoint found\n"); + return -EINVAL; + } + + panel_node = of_graph_get_remote_port_parent(endpoint); + of_node_put(endpoint); + if (!panel_node) { + dev_err(dev, "no output node found\n"); + return -EINVAL; + } + + panel = of_drm_find_panel(panel_node); + if (!panel) { + DRM_ERROR("failed to find panel\n"); + of_node_put(panel_node); + return -EPROBE_DEFER; + } of_node_put(panel_node); - return -EPROBE_DEFER; } - of_node_put(panel_node); - dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); if (!dp) return -ENOMEM; -- 1.9.1
[PATCH v2 07/10] drm/bridge: analogix_dp: introduce connector mode_valid callback to plat driver
It's helpful to expand the mode_valid callback to platform driver, so they could valid the display mode or information. Signed-off-by: Yakir Yang --- Changes in v2: None drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 15 +++ include/drm/bridge/analogix_dp.h | 4 2 files changed, 19 insertions(+) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 4a1b3b8..5af9ce4 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -943,6 +943,20 @@ int analogix_dp_get_modes(struct drm_connector *connector) return num_modes; } +static enum drm_mode_status +analogix_dp_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct analogix_dp_device *dp = to_dp(connector); + enum drm_mode_status status = MODE_OK; + + if (dp->plat_data->mode_valid) + status = dp->plat_data->mode_valid(dp->plat_data, connector, + mode); + + return status; +} + static struct drm_encoder * analogix_dp_best_encoder(struct drm_connector *connector) { @@ -954,6 +968,7 @@ analogix_dp_best_encoder(struct drm_connector *connector) static const struct drm_connector_helper_funcs analogix_dp_connector_helper_funcs = { .get_modes = analogix_dp_get_modes, .best_encoder = analogix_dp_best_encoder, + .mode_valid = analogix_dp_mode_valid, }; enum drm_connector_status diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h index 82b8135..9ef89de 100644 --- a/include/drm/bridge/analogix_dp.h +++ b/include/drm/bridge/analogix_dp.h @@ -35,6 +35,10 @@ struct analogix_dp_plat_data { int (*attach)(struct analogix_dp_plat_data *, struct drm_bridge *, struct drm_connector *); int (*get_modes)(struct analogix_dp_plat_data *); + + enum drm_mode_status (*mode_valid)(struct analogix_dp_plat_data *, + struct drm_connector *, + struct drm_display_mode *); }; int analogix_dp_resume(struct device *dev); -- 1.9.1
[PATCH v2 08/10] drm/rockchip: analogix_dp: correct the connector display color format and bpc
Rockchip VOP couldn't output YUV video format for eDP controller, so when driver detect connector support YUV video format, we need to hack it down to RGB888. Signed-off-by: Yakir Yang --- Changes in v2: None drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 19 +++ 1 file changed, 19 insertions(+) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index f29ca3d..910cceb 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -97,6 +97,24 @@ static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data) return 0; } +static enum drm_mode_status +rockchip_dp_mode_valid(struct analogix_dp_plat_data *plat_data, + struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct drm_display_info *di = &connector->display_info; + + if (di->color_formats & DRM_COLOR_FORMAT_YCRCB444 || + di->color_formats & DRM_COLOR_FORMAT_YCRCB422) { + di->color_formats &= ~(DRM_COLOR_FORMAT_YCRCB422 | + DRM_COLOR_FORMAT_YCRCB444); + di->color_formats |= DRM_COLOR_FORMAT_RGB444; + di->bpc = 8; + } + + return MODE_OK; +} + static bool rockchip_dp_drm_encoder_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, @@ -306,6 +324,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, dp->plat_data.subdev_type = dp_data->chip_type; dp->plat_data.power_on = rockchip_dp_poweron; dp->plat_data.power_off = rockchip_dp_powerdown; + dp->plat_data.mode_valid = rockchip_dp_mode_valid; return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data); } -- 1.9.1
[PATCH v2 09/10] drm/rockchip: analogix_dp: update the comments about why need to hardcode VOP output mode
The hardware IC designed that VOP must output the RGB10 video format to eDP contoller, and if eDP panel only support RGB8, then eDP contoller should cut down the video data, not via VOP contoller, that's why we need to hardcode the VOP output mode to RGA10 here. Signed-off-by: Yakir Yang --- Changes in v2: - new patch in v2 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 16 +--- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 910cceb..4b64964 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -170,17 +170,11 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, s->output_type = DRM_MODE_CONNECTOR_eDP; /* -* FIXME(Yakir): driver should configure the CRTC output video -* mode with the display information which indicated the monitor -* support colorimetry. -* -* But don't know why the CRTC driver seems could only output the -* RGBaaa rightly. For example, if connect the "innolux,n116bge" -* eDP screen, EDID would indicated that screen only accepted the -* 6bpc mode. But if I configure CRTC to RGB666 output, then eDP -* screen would show a blue picture (RGB888 show a green picture). -* But if I configure CTRC to RGBaaa, and eDP driver still keep -* RGB666 input video mode, then screen would works prefect. +* The hardware IC designed that VOP must output the RGB10 video +* format to eDP contoller, and if eDP panel only support RGB8, +* then eDP contoller should cut down the video data, not via VOP +* contoller, that's why we need to hardcode the VOP output mode +* to RGA10 here. */ ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder); -- 1.9.1
[PATCH v2 10/10] drm/bridge: analogix_dp: fix no drm hpd event when panel plug in
The enum value of DP_IRQ_TYPE_HP_CABLE_IN is zero, but driver only send drm hp event when the irq_type and the enum value is true. if (irq_type & DP_IRQ_TYPE_HP_CABLE_IN || ...) drm_helper_hpd_irq_event(dp->drm_dev); So there would no drm hpd event when cable plug in, to fix that just need to assign all hotplug enum with no-zero values. Reported-by: Dan Carpenter Signed-off-by: Yakir Yang --- Changes in v2: None drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index f09275d..b456380 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -127,10 +127,10 @@ enum analog_power_block { }; enum dp_irq_type { - DP_IRQ_TYPE_HP_CABLE_IN, - DP_IRQ_TYPE_HP_CABLE_OUT, - DP_IRQ_TYPE_HP_CHANGE, - DP_IRQ_TYPE_UNKNOWN, + DP_IRQ_TYPE_HP_CABLE_IN = BIT(0), + DP_IRQ_TYPE_HP_CABLE_OUT = BIT(1), + DP_IRQ_TYPE_HP_CHANGE= BIT(2), + DP_IRQ_TYPE_UNKNOWN = BIT(3), }; struct video_info { -- 1.9.1
[PATCH v2 05/10] drm/rockchip: analogix_dp: add rk3399 eDP support
RK3399 and RK3288 shared the same eDP IP controller, only some light difference with VOP configure and GRF configure. Signed-off-by: Yakir Yang --- Changes in v2: - rebase with drm-next, fix some conflicts .../bindings/display/bridge/analogix_dp.txt| 1 + .../display/rockchip/analogix_dp-rockchip.txt | 2 +- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c| 36 -- include/drm/bridge/analogix_dp.h | 1 + 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt index 4f2ba8c..4a0f4f7 100644 --- a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt +++ b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt @@ -5,6 +5,7 @@ Required properties for dp-controller: platform specific such as: * "samsung,exynos5-dp" * "rockchip,rk3288-dp" +* "rockchip,rk3399-edp" -reg: physical base address of the controller and length of memory mapped region. diff --git a/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt index e832ff9..5ae55ca 100644 --- a/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt @@ -2,7 +2,7 @@ Rockchip RK3288 specific extensions to the Analogix Display Port Required properties: -- compatible: "rockchip,rk3288-edp"; +- compatible: "rockchip,rk3288-edp" or "rockchip,rk3399-edp"; - reg: physical base address of the controller and length diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 29c4105..d5d4e04 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -148,6 +148,10 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, struct drm_connector_state *conn_state) { struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + struct rockchip_dp_device *dp = to_dp(encoder); + int ret; + + s->output_type = DRM_MODE_CONNECTOR_eDP; /* * FIXME(Yakir): driver should configure the CRTC output video @@ -162,8 +166,27 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, * But if I configure CTRC to RGBaaa, and eDP driver still keep * RGB666 input video mode, then screen would works prefect. */ - s->output_mode = ROCKCHIP_OUT_MODE_; - s->output_type = DRM_MODE_CONNECTOR_eDP; + + ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder); + if (ret < 0) + return; + + switch (dp->data->chip_type) { + case RK3399_EDP: + /* +* For RK3399, VOP Lit must code the out mode to RGB888, +* VOP Big must code the out mode to RGB10. +*/ + if (ret) + s->output_mode = ROCKCHIP_OUT_MODE_P888; + else + s->output_mode = ROCKCHIP_OUT_MODE_; + break; + + default: + s->output_mode = ROCKCHIP_OUT_MODE_; + break; + } return 0; } @@ -377,6 +400,14 @@ static const struct dev_pm_ops rockchip_dp_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(rockchip_dp_suspend, rockchip_dp_resume) }; +static const struct rockchip_dp_chip_data rk3399_edp = { + .lcdsel_grf_reg = 0x6250, + .lcdsel_big = 0, + .lcdsel_lit = BIT(5), + .lcdsel_mask = BIT(21), + .chip_type = RK3399_EDP, +}; + static const struct rockchip_dp_chip_data rk3288_dp = { .lcdsel_grf_reg = 0x025c, .lcdsel_big = 0, @@ -387,6 +418,7 @@ static const struct rockchip_dp_chip_data rk3288_dp = { static const struct of_device_id rockchip_dp_dt_ids[] = { {.compatible = "rockchip,rk3288-dp", .data = &rk3288_dp }, + {.compatible = "rockchip,rk3399-edp", .data = &rk3399_edp }, {} }; MODULE_DEVICE_TABLE(of, rockchip_dp_dt_ids); diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h index 06c0250..82b8135 100644 --- a/include/drm/bridge/analogix_dp.h +++ b/include/drm/bridge/analogix_dp.h @@ -20,6 +20,7 @@ enum analogix_dp_devtype { enum analogix_dp_sub_devtype { RK3288_DP, + RK3399_EDP, }; struct analogix_dp_plat_data { -- 1.9.1
[PATCH v2 05/10] drm/rockchip: analogix_dp: add rk3399 eDP support
On 05/25/2016 02:23 AM, Heiko Stuebner wrote: > Am Dienstag, 24. Mai 2016, 11:12:20 schrieb Doug Anderson: >> Hi, >> >> On Tue, May 24, 2016 at 3:17 AM, Heiko Stuebner wrote: --- a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt +++ b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt @@ -5,6 +5,7 @@ Required properties for dp-controller: platform specific such as: * "samsung,exynos5-dp" * "rockchip,rk3288-dp" + * "rockchip,rk3399-edp" >>> the cleanlines-freak in my likes to know if there is a difference >>> between >>> the rk3399 being called -edp here and -dp on the rk3288 :-) >>> >>> [...] >> If I was a guessing man (which I'm not, but if I was), I'd guess that >> this is because on rk3288 there was only one DP port and it was an EDP >> port. ...but since there was only one people just referred to it as >> the "DP" port and that was codified in the bindings. On rk3399 there >> are two ports: one EDP and one DP. All of a sudden we need to >> differentiate. >> >> Any better suggestions for how to deal with that? > nope - everything as it should be in that regard then - the rk3288-dp is > permanent now anyway. > > But it looks like I'm sort of blind blind and only now have seen the > separate DP controller chapter in the TRM (probably because I somehow didn't > expect a second controller). RK3399 eDP controller have cut off the DP-Audio function and DP-HDCP function, so it can't be treated as DP interfaces any more, that's why I call it "eDP". > >
[PATCH v2 05/10] drm/rockchip: analogix_dp: add rk3399 eDP support
On 05/24/2016 06:17 PM, Heiko Stuebner wrote: > Am Dienstag, 24. Mai 2016, 14:57:23 schrieb Yakir Yang: > [] >> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c >> b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 29c4105..d5d4e04 >> 100644 >> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c >> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c >> @@ -148,6 +148,10 @@ rockchip_dp_drm_encoder_atomic_check(struct >> drm_encoder *encoder, struct drm_connector_state *conn_state) >> { >> struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); >> +struct rockchip_dp_device *dp = to_dp(encoder); >> +int ret; >> + >> +s->output_type = DRM_MODE_CONNECTOR_eDP; >> >> /* >> * FIXME(Yakir): driver should configure the CRTC output video >> @@ -162,8 +166,27 @@ rockchip_dp_drm_encoder_atomic_check(struct >> drm_encoder *encoder, * But if I configure CTRC to RGBaaa, and eDP driver >> still keep * RGB666 input video mode, then screen would works prefect. >> */ >> -s->output_mode = ROCKCHIP_OUT_MODE_; >> -s->output_type = DRM_MODE_CONNECTOR_eDP; >> + >> +ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder); >> +if (ret < 0) >> + return; > this needs a value returned (probably ret), otherwise you create a > warning: âreturnâ with no value, in function returning non-void Done, Thanks, - Yakir > > drm_of_encoder_active_endpoint_id also always returns -EINVAL on rk3288- > veyron-jerry because encoder->crtc is unset in > drm_of_encoder_active_endpoint and that breaks display output right now. > > Looking through drm code it seems only two functions would set encoder->crtc > - drm_atomic_helper_update_legacy_modeset_state > - drm_crtc_helper_set_config > > drm_crtc_helper_set_config callback got dropped in the atomic-conversion and > the other sounds to be somewhat in the legacy area. > > After that drm-internals get a bit confusing. > > > Heiko > > >
[PATCH v2 0/10] Add RK3399 eDP support and fix some bugs to analogix_dp driver.
Hi Javier, On 05/24/2016 01:01 PM, Yakir Yang wrote: > Hi all, > > This series have been posted about one month, still no comments, help here :( This series works rightly on Rockchip platform, and most of them haven't touch the common analogix_dp driver (except for the hotplug fixed). So i guess Exynos platform should also happy with this changes. But not sure about that. So, is it possible that you could help to check this on Exynos Chromebook, if so i would be very grateful about that. Thanks, - Yakir > > RK3399 and RK3288 shared the same eDP IP controller, only some light > difference with VOP configure and GRF configure. > > Also same misc fix to analogix_dp driver: > - Hotplug invalid which report by Dan Carpenter > - Make panel detect to an optional action > - correct the register bit define error in ANALOGIX_DP_PLL_REG_1 > > > Changes in v2: > - new patch in v2 > - rebase with drm-next, fix some conflicts > - new patch in v2 > > Yakir Yang (10): >drm/bridge: analogix_dp: rename RK3288_DP to ROCKCHIP_DP >drm/rockchip: analogix_dp: split the lcdc select setting into device > data >drm/bridge: analogix_dp: correct the register bit define error in > ANALOGIX_DP_PLL_REG_1 >drm/bridge: analogix_dp: some rockchip chips need to flip REF_CLK bit > setting >drm/rockchip: analogix_dp: add rk3399 eDP support >drm/rockchip: analogix_dp: make panel detect to an optional action >drm/bridge: analogix_dp: introduce connector mode_valid callback to > plat driver >drm/rockchip: analogix_dp: correct the connector display color format > and bpc >drm/rockchip: analogix_dp: update the comments about why need to > hardcode VOP output mode >drm/bridge: analogix_dp: fix no drm hpd event when panel plug in > > .../bindings/display/bridge/analogix_dp.txt| 1 + > .../display/rockchip/analogix_dp-rockchip.txt | 2 +- > drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 19 ++- > drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 8 +- > drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 12 +- > drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 5 +- > drivers/gpu/drm/rockchip/analogix_dp-rockchip.c| 157 > ++--- > include/drm/bridge/analogix_dp.h | 10 ++ > 8 files changed, 152 insertions(+), 62 deletions(-) >
[PATCH v2 0/10] Add RK3399 eDP support and fix some bugs to analogix_dp driver.
Hi Javier, On 05/26/2016 08:48 PM, Javier Martinez Canillas wrote: > Hello Yakir, > > On 05/26/2016 05:34 AM, Yakir Yang wrote: >> Hi Javier, >> >> On 05/24/2016 01:01 PM, Yakir Yang wrote: >>> Hi all, >>> >>> This series have been posted about one month, still no comments, help here >>> :( >> This series works rightly on Rockchip platform, and most of them haven't >> touch the >> common analogix_dp driver (except for the hotplug fixed). So i guess Exynos >> platform >> should also happy with this changes. >> >> But not sure about that. So, is it possible that you could help to check >> this on Exynos >> Chromebook, if so i would be very grateful about that. >> > Of course, I' ll test. Could you please provide me a branch that I can > pull directly to avoid cherry-picking all the patches from the list? > Ah, thanks a lot, I do have a tree https://github.com/yakir-Yang/linux/tree/fromlist/3399-edp - Yakir >> Thanks, >> - Yakir > Best regards,
[PATCH v8 0/2] Add Rockchip Inno-HDMI driver
Hi Mark, Thanks for your apply ;) - Yakir On 02/18/2016 02:12 PM, Mark yao wrote: > On 2016å¹´01æ29æ¥ 14:42, Yakir Yang wrote: >> Here are a brief introduction to Innosilicon HDMI IP: >>- Support HDMI 1.4a, HDCP 1.2 and DVI 1.0 standard compliant >> transmitter >>- Support HDMI1.4 a/b 3D function defined in HDMI 1.4 a/b spec >>- Digital video interface supports a pixel size of 24, 30, 36, >> 48bits color depth in RGB >>- S/PDIF output supports PCM, Dolby Digital, DTS digital audio >> transmission >> (32-192kHz Fs) using IEC60958 and IEC 61937 >>- The EDID and CEC function are also supported by Innosilicon HDMI >> Transmitter Controlle >> >> Changes in v8: >> - Don't check whether encoder output format is RGB colorspace, cause >> driver >>default configure the output colorspace to RGB. (ZhengYang) >> - Correct the check condition in inno_hdmi_config_video_csc() >> (ZhengYang) >> - if (data->enc_out_format == data->enc_out_format) { >> + if (data->enc_in_format == data->enc_out_format) { >> >> Changes in v7: >> - Correct the module licnese statement (Paul) >> - MODULE_LICENSE("GPL"); >> + MODULE_LICENSE("GPLv2"); >> - Start indentation with tabs and fix the misspell in Kconfig (Paul) >> - Carry the lost device-binding document (Heiko) >> >> Changes in v6: >> - Rebase the Makefile/Kconfig files which add by Chris's >> rockchip-mipi driver (Caeser) >> >> Changes in v5: >> - Use hdmi_infoframe helper functions to packed the infoframe (Russell) >> - Remove the unused double wait_for_completion_timeout for ddc >> transfer (Russell) >> - Remove the unused local variable in "inno_hdmi_i2c_write()" >> function (Russell) >> >> Changes in v4: >> - Modify the commit title "drm/rockchip: hdmi: ..." (Mark) >> - Correct the "DKMS" to "DPMS" (Mark) >> - Fix over 80 characters problems (Mark) >> - Remove encoder .prepare/.commit helper functions, and move the vop >> mode >> configure function into encoder .enable helper functions. (Mark) >> >> Changes in v3: >> - Use encoder enable/disable function, and remove the encoder DPMS >> function >> - Keep HDMI PLL power on in standby mode >> >> Changes in v2: >> - Using DRM atomic helper functions for connector init (Mark) >> - Remove "hdmi->connector.encoder = encoder;" (Mark) >> - Add the Acked-by tags from Rob >> - Correct the misspell "rk3036-dw-hdmi" (Heiko) >> >> Yakir Yang (2): >>drm/rockchip: hdmi: add Innosilicon HDMI support >>dt-bindings: add document for Innosilicon HDMI on Rockchip platform >> >> .../display/rockchip/inno_hdmi-rockchip.txt| 50 ++ >> drivers/gpu/drm/rockchip/Kconfig | 8 + >> drivers/gpu/drm/rockchip/Makefile | 1 + >> drivers/gpu/drm/rockchip/inno_hdmi.c | 939 >> + >> drivers/gpu/drm/rockchip/inno_hdmi.h | 362 >> 5 files changed, 1360 insertions(+) >> create mode 100644 >> Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt >> create mode 100644 drivers/gpu/drm/rockchip/inno_hdmi.c >> create mode 100644 drivers/gpu/drm/rockchip/inno_hdmi.h >> > > Applied to my branch :-) . > > Thanks. >
[patch] drm/rockchip: inno_hdmi: fix an error code
Dan, On 02/26/2016 05:30 AM, Dan Carpenter wrote: > We were accidentally returning PTR_ERR(NULL) which means success when we > wanted to return a negative error code. > > Fixes: 412d4ae6b7a5 ('drm/rockchip: hdmi: add Innosilicon HDMI support') > Signed-off-by: Dan Carpenter Reviewed-by: Yakir Yang Thanks, - Yakir > diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c > b/drivers/gpu/drm/rockchip/inno_hdmi.c > index 10d62ff..f252441 100644 > --- a/drivers/gpu/drm/rockchip/inno_hdmi.c > +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c > @@ -855,8 +855,9 @@ static int inno_hdmi_bind(struct device *dev, struct > device *master, > > hdmi->ddc = inno_hdmi_i2c_adapter(hdmi); > if (IS_ERR(hdmi->ddc)) { > + ret = PTR_ERR(hdmi->ddc); > hdmi->ddc = NULL; > - return PTR_ERR(hdmi->ddc); > + return ret; > } > > /* > > >
[RFC PATCH v1 0/2] Add RK3229 vop support
Add RK3229 vop support Yakir Yang (2): drm/rockchip: vop: add rk3229 vop support dt-bindings: add document for rk3229-vop .../bindings/display/rockchip/rockchip-vop.txt | 1 + drivers/gpu/drm/rockchip/rockchip_drm_vop.c| 7 +- drivers/gpu/drm/rockchip/rockchip_drm_vop.h| 2 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c| 120 + drivers/gpu/drm/rockchip/rockchip_vop_reg.h| 90 5 files changed, 218 insertions(+), 2 deletions(-) -- 1.9.1
[RFC PATCH v1 1/2] drm/rockchip: vop: add rk3229 vop support
RK3228 registers layout is simalar to RK3288 layout, only the interruput registers is different to RK3288. RK3228 support two overlay plane and one hwc plane, max output resolution is 4K. it support IOMMU, and its IOMMU same as rk3288's. Signed-off-by: Yakir Yang --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 7 +- drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 120 drivers/gpu/drm/rockchip/rockchip_vop_reg.h | 90 + 4 files changed, 217 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index d83bf87..3c83097 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -63,9 +63,12 @@ #define VOP_INTR_SET_TYPE(vop, name, type, v) \ do { \ int i, reg = 0; \ - for (i = 0; i < vop->data->intr->nintrs; i++) { \ - if (vop->data->intr->intrs[i] & type) \ + const struct vop_intr *intr = vop->data->intr; \ + for (i = 0; i < intr->nintrs; i++) { \ + if (intr->intrs[i] & type) { \ reg |= (v) << i; \ + reg |= intr->write_mask ? (1 << (i + 16)) : 0; \ + } \ } \ VOP_INTR_SET(vop, name, reg); \ } while (0) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 071ff0b..1e839e8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -60,6 +60,7 @@ struct vop_ctrl { }; struct vop_intr { + bool write_mask; const int *intrs; uint32_t nintrs; struct vop_reg enable; @@ -136,6 +137,7 @@ struct vop_data { }; /* interrupt define */ +#define DUMMY_INTR (0 << 0) #define DSP_HOLD_VALID_INTR(1 << 0) #define FS_INTR(1 << 1) #define LINE_FLAG_INTR (1 << 2) diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 3166b46..bbcd128 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -174,6 +174,7 @@ static const int rk3288_vop_intrs[] = { }; static const struct vop_intr rk3288_vop_intr = { + .write_mask = false, .intrs = rk3288_vop_intrs, .nintrs = ARRAY_SIZE(rk3288_vop_intrs), .status = VOP_REG(RK3288_INTR_CTRL0, 0xf, 0), @@ -190,6 +191,122 @@ static const struct vop_data rk3288_vop = { .win_size = ARRAY_SIZE(rk3288_vop_win_data), }; +static const struct vop_scl_extension rk3229_win_full_scl_ext = { + .cbcr_vsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 31), + .cbcr_vsu_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 30), + .cbcr_hsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 28), + .cbcr_ver_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 26), + .cbcr_hor_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 24), + .yrgb_vsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 23), + .yrgb_vsu_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 22), + .yrgb_hsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 20), + .yrgb_ver_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 18), + .yrgb_hor_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 16), + .line_load_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 15), + .cbcr_axi_gather_num = VOP_REG(RK3229_WIN0_CTRL1, 0x7, 12), + .yrgb_axi_gather_num = VOP_REG(RK3229_WIN0_CTRL1, 0xf, 8), + .vsd_cbcr_gt2 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 7), + .vsd_cbcr_gt4 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 6), + .vsd_yrgb_gt2 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 5), + .vsd_yrgb_gt4 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 4), + .bic_coe_sel = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 2), + .cbcr_axi_gather_en = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 1), + .yrgb_axi_gather_en = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 0), + .lb_mode = VOP_REG(RK3229_WIN0_CTRL0, 0x7, 5), +}; + +static const struct vop_scl_regs rk3229_win_full_scl = { + .ext = &rk3229_win_full_scl_ext, + .scale_yrgb_x = VOP_REG(RK3229_WIN0_SCL_FACTOR_YRGB, 0x, 0x0), + .scale_yrgb_y = VOP_REG(RK3229_WIN0_SCL_FACTOR_YRGB, 0x, 16), + .scale_cbcr_x = VOP_REG(RK3229_WIN0_SCL_FACTOR_CBR, 0x, 0x0), + .scale_cbcr_y = VOP_REG(RK3229_WIN0_SCL_FACTOR_CBR, 0x, 16), +}; + +static const struct vop_win_phy rk3229_win01_data = { + .scl = &rk3229_win_full_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .enable = VOP_REG(RK3229_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3229_WIN0_CTRL0, 0x7, 1), +
[RFC PATCH v1 2/2] dt-bindings: add document for rk3229-vop
Signed-off-by: Yakir Yang --- Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt index 5489b59..75ebc20 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt @@ -7,6 +7,7 @@ buffer to an external LCD interface. Required properties: - compatible: value should be one of the following "rockchip,rk3288-vop"; + "rockchip,rk3229-vop"; "rockchip,rk3036-vop"; - interrupts: should contain a list of all VOP IP block interrupts in the -- 1.9.1
[RFC PATCH v1 1/2] drm/rockchip: vop: add rk3229 vop support
RK3229 registers layout is simalar to RK3288 layout, only the interruput registers is different to RK3288. RK3229 support two overlay plane and one hwc plane, max output resolution is 4K. it support IOMMU, and its IOMMU same as rk3288's. Signed-off-by: Yakir Yang --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 7 +- drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 120 drivers/gpu/drm/rockchip/rockchip_vop_reg.h | 90 + 4 files changed, 217 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index d83bf87..3c83097 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -63,9 +63,12 @@ #define VOP_INTR_SET_TYPE(vop, name, type, v) \ do { \ int i, reg = 0; \ - for (i = 0; i < vop->data->intr->nintrs; i++) { \ - if (vop->data->intr->intrs[i] & type) \ + const struct vop_intr *intr = vop->data->intr; \ + for (i = 0; i < intr->nintrs; i++) { \ + if (intr->intrs[i] & type) { \ reg |= (v) << i; \ + reg |= intr->write_mask ? (1 << (i + 16)) : 0; \ + } \ } \ VOP_INTR_SET(vop, name, reg); \ } while (0) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 071ff0b..1e839e8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -60,6 +60,7 @@ struct vop_ctrl { }; struct vop_intr { + bool write_mask; const int *intrs; uint32_t nintrs; struct vop_reg enable; @@ -136,6 +137,7 @@ struct vop_data { }; /* interrupt define */ +#define DUMMY_INTR (0 << 0) #define DSP_HOLD_VALID_INTR(1 << 0) #define FS_INTR(1 << 1) #define LINE_FLAG_INTR (1 << 2) diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 3166b46..bbcd128 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -174,6 +174,7 @@ static const int rk3288_vop_intrs[] = { }; static const struct vop_intr rk3288_vop_intr = { + .write_mask = false, .intrs = rk3288_vop_intrs, .nintrs = ARRAY_SIZE(rk3288_vop_intrs), .status = VOP_REG(RK3288_INTR_CTRL0, 0xf, 0), @@ -190,6 +191,122 @@ static const struct vop_data rk3288_vop = { .win_size = ARRAY_SIZE(rk3288_vop_win_data), }; +static const struct vop_scl_extension rk3229_win_full_scl_ext = { + .cbcr_vsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 31), + .cbcr_vsu_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 30), + .cbcr_hsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 28), + .cbcr_ver_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 26), + .cbcr_hor_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 24), + .yrgb_vsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 23), + .yrgb_vsu_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 22), + .yrgb_hsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 20), + .yrgb_ver_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 18), + .yrgb_hor_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 16), + .line_load_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 15), + .cbcr_axi_gather_num = VOP_REG(RK3229_WIN0_CTRL1, 0x7, 12), + .yrgb_axi_gather_num = VOP_REG(RK3229_WIN0_CTRL1, 0xf, 8), + .vsd_cbcr_gt2 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 7), + .vsd_cbcr_gt4 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 6), + .vsd_yrgb_gt2 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 5), + .vsd_yrgb_gt4 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 4), + .bic_coe_sel = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 2), + .cbcr_axi_gather_en = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 1), + .yrgb_axi_gather_en = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 0), + .lb_mode = VOP_REG(RK3229_WIN0_CTRL0, 0x7, 5), +}; + +static const struct vop_scl_regs rk3229_win_full_scl = { + .ext = &rk3229_win_full_scl_ext, + .scale_yrgb_x = VOP_REG(RK3229_WIN0_SCL_FACTOR_YRGB, 0x, 0x0), + .scale_yrgb_y = VOP_REG(RK3229_WIN0_SCL_FACTOR_YRGB, 0x, 16), + .scale_cbcr_x = VOP_REG(RK3229_WIN0_SCL_FACTOR_CBR, 0x, 0x0), + .scale_cbcr_y = VOP_REG(RK3229_WIN0_SCL_FACTOR_CBR, 0x, 16), +}; + +static const struct vop_win_phy rk3229_win01_data = { + .scl = &rk3229_win_full_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .enable = VOP_REG(RK3229_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3229_WIN0_CTRL0, 0x7, 1), +
[RFC PATCH v1 1/2] drm/rockchip: vop: add rk3229 vop support
Sorry, there shouldn't have the "3228" prefix, %s/3228/3229 I have send the new patch out, please ignore this one. Thanks, - Yakir On 01/04/2016 07:50 PM, Yakir Yang wrote: > RK3228 registers layout is simalar to RK3288 layout, only the > interruput registers is different to RK3288. > > RK3228 support two overlay plane and one hwc plane, max output > resolution is 4K. it support IOMMU, and its IOMMU same as rk3288's. > > Signed-off-by: Yakir Yang > --- > drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 7 +- > drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 + > drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 120 > > drivers/gpu/drm/rockchip/rockchip_vop_reg.h | 90 + > 4 files changed, 217 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > index d83bf87..3c83097 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > @@ -63,9 +63,12 @@ > #define VOP_INTR_SET_TYPE(vop, name, type, v) \ > do { \ > int i, reg = 0; \ > - for (i = 0; i < vop->data->intr->nintrs; i++) { \ > - if (vop->data->intr->intrs[i] & type) \ > + const struct vop_intr *intr = vop->data->intr; \ > + for (i = 0; i < intr->nintrs; i++) { \ > + if (intr->intrs[i] & type) { \ > reg |= (v) << i; \ > + reg |= intr->write_mask ? (1 << (i + 16)) : 0; \ > + } \ > } \ > VOP_INTR_SET(vop, name, reg); \ > } while (0) > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h > b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h > index 071ff0b..1e839e8 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h > @@ -60,6 +60,7 @@ struct vop_ctrl { > }; > > struct vop_intr { > + bool write_mask; > const int *intrs; > uint32_t nintrs; > struct vop_reg enable; > @@ -136,6 +137,7 @@ struct vop_data { > }; > > /* interrupt define */ > +#define DUMMY_INTR (0 << 0) > #define DSP_HOLD_VALID_INTR (1 << 0) > #define FS_INTR (1 << 1) > #define LINE_FLAG_INTR (1 << 2) > diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c > b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c > index 3166b46..bbcd128 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c > +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c > @@ -174,6 +174,7 @@ static const int rk3288_vop_intrs[] = { > }; > > static const struct vop_intr rk3288_vop_intr = { > + .write_mask = false, > .intrs = rk3288_vop_intrs, > .nintrs = ARRAY_SIZE(rk3288_vop_intrs), > .status = VOP_REG(RK3288_INTR_CTRL0, 0xf, 0), > @@ -190,6 +191,122 @@ static const struct vop_data rk3288_vop = { > .win_size = ARRAY_SIZE(rk3288_vop_win_data), > }; > > +static const struct vop_scl_extension rk3229_win_full_scl_ext = { > + .cbcr_vsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 31), > + .cbcr_vsu_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 30), > + .cbcr_hsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 28), > + .cbcr_ver_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 26), > + .cbcr_hor_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 24), > + .yrgb_vsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 23), > + .yrgb_vsu_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 22), > + .yrgb_hsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 20), > + .yrgb_ver_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 18), > + .yrgb_hor_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 16), > + .line_load_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 15), > + .cbcr_axi_gather_num = VOP_REG(RK3229_WIN0_CTRL1, 0x7, 12), > + .yrgb_axi_gather_num = VOP_REG(RK3229_WIN0_CTRL1, 0xf, 8), > + .vsd_cbcr_gt2 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 7), > + .vsd_cbcr_gt4 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 6), > + .vsd_yrgb_gt2 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 5), > + .vsd_yrgb_gt4 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 4), > + .bic_coe_sel = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 2), > + .cbcr_axi_gather_en = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 1), > + .yrgb_axi_gather_en = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 0), > + .lb_mode = VOP_REG(RK3229_WIN0_CTRL0, 0x7, 5), > +}; > + > +static const struct vop_scl_regs rk3229_win_full_scl = { > + .ext = &
[RFC PATCH v1 2/2] dt-bindings: add document for rk3229-vop
Thanks, Rob - Yakir On 01/04/2016 10:11 PM, Rob Herring wrote: > On Mon, Jan 04, 2016 at 07:50:30PM +0800, Yakir Yang wrote: >> Signed-off-by: Yakir Yang >> --- >> Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt | 1 + >> 1 file changed, 1 insertion(+) > Acked-by: Rob Herring > > >
[RFC PATCH v1 1/2] drm/rockchip: vop: add rk3229 vop support
Hi Heiko, On 01/04/2016 08:23 PM, Heiko Stuebner wrote: > Hi Yakir, > > Am Montag, 4. Januar 2016, 19:53:58 schrieb Yakir Yang: >> RK3229 registers layout is simalar to RK3288 layout, only the >> interruput registers is different to RK3288. >> >> RK3229 support two overlay plane and one hwc plane, max output >> resolution is 4K. it support IOMMU, and its IOMMU same as rk3288's. >> >> Signed-off-by: Yakir Yang >> --- >> drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 7 +- >> drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 + >> drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 120 >> drivers/gpu/drm/rockchip/rockchip_vop_reg.h >> | 90 + 4 files changed, 217 insertions(+), 2 >> deletions(-) >> >> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c >> b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index d83bf87..3c83097 >> 100644 >> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c >> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c >> @@ -63,9 +63,12 @@ >> #define VOP_INTR_SET_TYPE(vop, name, type, v) \ >> do { \ >> int i, reg = 0; \ >> -for (i = 0; i < vop->data->intr->nintrs; i++) { \ >> -if (vop->data->intr->intrs[i] & type) \ >> +const struct vop_intr *intr = vop->data->intr; \ >> +for (i = 0; i < intr->nintrs; i++) { \ >> +if (intr->intrs[i] & type) { \ >> reg |= (v) << i; \ >> +reg |= intr->write_mask ? (1 << (i + 16)) : 0; \ >> +} \ >> } \ >> VOP_INTR_SET(vop, name, reg); \ >> } while (0) > I do believe this part, as well as setting the default .write_mask = false > for the existing parts should get its own patch + a bit more explanation > on what this does and why it's needed. > > 8< > drm/rockchip: Add support for interrupt registers using write-masks > > Some new display-controllers are need to set write-masks to enable writes > to interrupt registers. Allow this to be set on a per-vop basis. > 8< > > or something like that, and then patches 2+3 being the rk3229 support + > binding. Great, will send the new version out. > >> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h >> b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 071ff0b..1e839e8 >> 100644 >> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h >> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h >> @@ -60,6 +60,7 @@ struct vop_ctrl { >> }; >> >> struct vop_intr { >> +bool write_mask; >> const int *intrs; >> uint32_t nintrs; >> struct vop_reg enable; >> @@ -136,6 +137,7 @@ struct vop_data { >> }; >> >> /* interrupt define */ >> +#define DUMMY_INTR (0 << 0) >> #define DSP_HOLD_VALID_INTR(1 << 0) >> #define FS_INTR(1 << 1) >> #define LINE_FLAG_INTR (1 << 2) >> diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c >> b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 3166b46..bbcd128 >> 100644 >> --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c >> +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c >> @@ -174,6 +174,7 @@ static const int rk3288_vop_intrs[] = { >> }; >> >> static const struct vop_intr rk3288_vop_intr = { >> +.write_mask = false, >> .intrs = rk3288_vop_intrs, >> .nintrs = ARRAY_SIZE(rk3288_vop_intrs), >> .status = VOP_REG(RK3288_INTR_CTRL0, 0xf, 0), >> @@ -190,6 +191,122 @@ static const struct vop_data rk3288_vop = { >> .win_size = ARRAY_SIZE(rk3288_vop_win_data), >> }; >> >> +static const struct vop_scl_extension rk3229_win_full_scl_ext = { >> +.cbcr_vsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 31), >> +.cbcr_vsu_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 30), >> +.cbcr_hsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 28), >> +.cbcr_ver_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 26), >> +.cbcr_hor_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 24), >> +.yrgb_vsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 23), >> +.yrgb_vsu_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 22), >> +.yrgb_hsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 20), >> +.yrgb_ver_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 18), >> +.yrgb_hor_scl_mode = VOP_REG(R
[PATCH v2 0/3] Add RK3229 vop support
Based on Mark Yao's drm-next branch [https://github.com/markyzq/kernel-drm-rockchip/tree/drm-rockchip-next-2015-12-28] Changes in v2: - Add this patch in v2 (Heiko) - Separate the write-mask changes out, and remove the DUMMY_INTR marcos (Heiko) - acked by Rob Yakir Yang (3): drm/rockchip: vop: Add support for interrupt registers using write-masks drm/rockchip: vop: add rk3229 vop support dt-bindings: add document for rk3229-vop .../bindings/display/rockchip/rockchip-vop.txt | 1 + drivers/gpu/drm/rockchip/rockchip_drm_vop.c| 7 +- drivers/gpu/drm/rockchip/rockchip_drm_vop.h| 1 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c| 112 + drivers/gpu/drm/rockchip/rockchip_vop_reg.h| 90 + 5 files changed, 209 insertions(+), 2 deletions(-) -- 1.9.1
[PATCH v2 1/3] drm/rockchip: vop: Add support for interrupt registers using write-masks
Some new display-controllers are need to set write-masks to enable writes to interrupt registers. Allow this to be set on a per-vop basis. Signed-off-by: Yakir Yang --- Changes in v2: - Add this patch in v2 (Heiko) drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 7 +-- drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 1 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index d83bf87..3c83097 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -63,9 +63,12 @@ #define VOP_INTR_SET_TYPE(vop, name, type, v) \ do { \ int i, reg = 0; \ - for (i = 0; i < vop->data->intr->nintrs; i++) { \ - if (vop->data->intr->intrs[i] & type) \ + const struct vop_intr *intr = vop->data->intr; \ + for (i = 0; i < intr->nintrs; i++) { \ + if (intr->intrs[i] & type) { \ reg |= (v) << i; \ + reg |= intr->write_mask ? (1 << (i + 16)) : 0; \ + } \ } \ VOP_INTR_SET(vop, name, reg); \ } while (0) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 071ff0b..f1bb84d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -60,6 +60,7 @@ struct vop_ctrl { }; struct vop_intr { + bool write_mask; const int *intrs; uint32_t nintrs; struct vop_reg enable; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 3166b46..7fbaf76 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -174,6 +174,7 @@ static const int rk3288_vop_intrs[] = { }; static const struct vop_intr rk3288_vop_intr = { + .write_mask = false, .intrs = rk3288_vop_intrs, .nintrs = ARRAY_SIZE(rk3288_vop_intrs), .status = VOP_REG(RK3288_INTR_CTRL0, 0xf, 0), @@ -240,6 +241,7 @@ static const int rk3036_vop_intrs[] = { }; static const struct vop_intr rk3036_intr = { + .write_mask = false, .intrs = rk3036_vop_intrs, .nintrs = ARRAY_SIZE(rk3036_vop_intrs), .status = VOP_REG(RK3036_INT_STATUS, 0xf, 0), -- 1.9.1
[PATCH v2 2/3] drm/rockchip: vop: add rk3229 vop support
RK3229 registers layout is simalar to RK3288 layout, only the interruput registers is different to RK3288. RK3229 support two overlay plane and one hwc plane, max output resolution is 4K. it support IOMMU, and its IOMMU same as rk3288's. Signed-off-by: Yakir Yang --- Changes in v2: - Separate the write-mask changes out, and remove the DUMMY_INTR marcos (Heiko) drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 110 drivers/gpu/drm/rockchip/rockchip_vop_reg.h | 90 +++ 2 files changed, 200 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 7fbaf76..f1358f9 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -191,6 +191,114 @@ static const struct vop_data rk3288_vop = { .win_size = ARRAY_SIZE(rk3288_vop_win_data), }; +static const struct vop_scl_extension rk3229_win_full_scl_ext = { + .cbcr_vsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 31), + .cbcr_vsu_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 30), + .cbcr_hsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 28), + .cbcr_ver_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 26), + .cbcr_hor_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 24), + .yrgb_vsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 23), + .yrgb_vsu_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 22), + .yrgb_hsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 20), + .yrgb_ver_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 18), + .yrgb_hor_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 16), + .line_load_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 15), + .cbcr_axi_gather_num = VOP_REG(RK3229_WIN0_CTRL1, 0x7, 12), + .yrgb_axi_gather_num = VOP_REG(RK3229_WIN0_CTRL1, 0xf, 8), + .vsd_cbcr_gt2 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 7), + .vsd_cbcr_gt4 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 6), + .vsd_yrgb_gt2 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 5), + .vsd_yrgb_gt4 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 4), + .bic_coe_sel = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 2), + .cbcr_axi_gather_en = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 1), + .yrgb_axi_gather_en = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 0), + .lb_mode = VOP_REG(RK3229_WIN0_CTRL0, 0x7, 5), +}; + +static const struct vop_scl_regs rk3229_win_full_scl = { + .ext = &rk3229_win_full_scl_ext, + .scale_yrgb_x = VOP_REG(RK3229_WIN0_SCL_FACTOR_YRGB, 0x, 0x0), + .scale_yrgb_y = VOP_REG(RK3229_WIN0_SCL_FACTOR_YRGB, 0x, 16), + .scale_cbcr_x = VOP_REG(RK3229_WIN0_SCL_FACTOR_CBR, 0x, 0x0), + .scale_cbcr_y = VOP_REG(RK3229_WIN0_SCL_FACTOR_CBR, 0x, 16), +}; + +static const struct vop_win_phy rk3229_win01_data = { + .scl = &rk3229_win_full_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .enable = VOP_REG(RK3229_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3229_WIN0_CTRL0, 0x7, 1), + .rb_swap = VOP_REG(RK3229_WIN0_CTRL0, 0x1, 12), + .act_info = VOP_REG(RK3229_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3229_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3229_WIN0_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3229_WIN0_YRGB_MST, 0x, 0), + .uv_mst = VOP_REG(RK3229_WIN0_CBR_MST, 0x, 0), + .yrgb_vir = VOP_REG(RK3229_WIN0_VIR, 0x3fff, 0), + .uv_vir = VOP_REG(RK3229_WIN0_VIR, 0x3fff, 16), + .src_alpha_ctl = VOP_REG(RK3229_WIN0_SRC_ALPHA_CTRL, 0xff, 0), + .dst_alpha_ctl = VOP_REG(RK3229_WIN0_DST_ALPHA_CTRL, 0xff, 0), +}; + +static const struct vop_win_data rk3229_vop_win_data[] = { + { .base = 0x00, .phy = &rk3229_win01_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x40, .phy = &rk3229_win01_data, + .type = DRM_PLANE_TYPE_CURSOR }, +}; + +static const struct vop_ctrl rk3229_ctrl_data = { + .cfg_done = VOP_REG(RK3229_REG_CFG_DONE, 0x1, 0), + .standby = VOP_REG(RK3229_SYS_CTRL, 0x1, 22), + .gate_en = VOP_REG(RK3229_SYS_CTRL, 0x1, 23), + .mmu_en = VOP_REG(RK3229_SYS_CTRL, 0x1, 20), + .rgb_en = VOP_REG(RK3229_SYS_CTRL, 0x1, 12), + .hdmi_en = VOP_REG(RK3229_SYS_CTRL, 0x1, 13), + .edp_en = VOP_REG(RK3229_SYS_CTRL, 0x1, 14), + .mipi_en = VOP_REG(RK3229_SYS_CTRL, 0x1, 15), + .data_blank = VOP_REG(RK3229_DSP_CTRL0, 0x1, 19), + .out_mode = VOP_REG(RK3229_DSP_CTRL0, 0xf, 0), + .pin_pol = VOP_REG(RK3229_DSP_CTRL1, 0xf, 20), + .dither_up = VOP_REG(RK3229_DSP_CTRL1, 0x1, 6), + .htotal_pw = VOP_REG(RK3229_DSP_HTOTAL_HS_END, 0x1fff1fff, 0), + .hact_st_end = VOP_REG(RK3229_DSP_HACT_ST_END, 0x1fff1fff, 0), + .vtotal_pw = VOP_REG(RK3229_DSP_VTOTAL_VS_END, 0x1fff1fff, 0), + .vact_st_end = VOP_REG(RK3229_DSP_VACT_ST_END, 0x1fff1fff, 0), + .hpost_st_end = VOP_REG(RK3229_POST_DSP_HACT_INFO, 0x1fff1fff, 0), + .v
[PATCH v2 3/3] dt-bindings: add document for rk3229-vop
Signed-off-by: Yakir Yang Acked-by: Rob Herring --- Changes in v2: - acked by Rob Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt index 5489b59..75ebc20 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt @@ -7,6 +7,7 @@ buffer to an external LCD interface. Required properties: - compatible: value should be one of the following "rockchip,rk3288-vop"; + "rockchip,rk3229-vop"; "rockchip,rk3036-vop"; - interrupts: should contain a list of all VOP IP block interrupts in the -- 1.9.1
[PATCH v2 3/3] dt-bindings: add document for rk3229-vop
On 01/06/2016 12:06 AM, Rob Herring wrote: > On Mon, Jan 4, 2016 at 10:00 PM, Yakir Yang wrote: >> Signed-off-by: Yakir Yang >> Acked-by: Rob Herring >> --- >> Changes in v2: >> - acked by Rob > It doesn't hurt, but there is no point to send a new version just to > add acks. The maintainer should add any for the current version. If > you do send a new version with changes, then it is your responsibility > to add acks. Maintainers are not going to look at older versions. Got it :) - Yakir > Rob > > >
[PATCH v2 2/3] drm/rockchip: vop: add rk3229 vop support
Hi Mark, On 01/06/2016 08:56 AM, Mark yao wrote: > On 2016å¹´01æ05æ¥ 11:58, Yakir Yang wrote: >> RK3229 registers layout is simalar to RK3288 layout, only the >> interruput registers is different to RK3288. >> >> RK3229 support two overlay plane and one hwc plane, max output >> resolution is 4K. it support IOMMU, and its IOMMU same as rk3288's. >> >> Signed-off-by: Yakir Yang >> --- >> Changes in v2: >> - Separate the write-mask changes out, and remove the DUMMY_INTR >> marcos (Heiko) >> >> drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 110 >> >> drivers/gpu/drm/rockchip/rockchip_vop_reg.h | 90 >> +++ >> 2 files changed, 200 insertions(+) >> >> diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c >> b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c >> index 7fbaf76..f1358f9 100644 >> --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c >> +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c >> @@ -191,6 +191,114 @@ static const struct vop_data rk3288_vop = { >> .win_size = ARRAY_SIZE(rk3288_vop_win_data), >> }; >> +static const struct vop_scl_extension rk3229_win_full_scl_ext = { >> +.cbcr_vsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 31), >> +.cbcr_vsu_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 30), >> +.cbcr_hsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 28), >> +.cbcr_ver_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 26), >> +.cbcr_hor_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 24), >> +.yrgb_vsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 23), >> +.yrgb_vsu_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 22), >> +.yrgb_hsd_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 20), >> +.yrgb_ver_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 18), >> +.yrgb_hor_scl_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 16), >> +.line_load_mode = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 15), >> +.cbcr_axi_gather_num = VOP_REG(RK3229_WIN0_CTRL1, 0x7, 12), >> +.yrgb_axi_gather_num = VOP_REG(RK3229_WIN0_CTRL1, 0xf, 8), >> +.vsd_cbcr_gt2 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 7), >> +.vsd_cbcr_gt4 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 6), >> +.vsd_yrgb_gt2 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 5), >> +.vsd_yrgb_gt4 = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 4), >> +.bic_coe_sel = VOP_REG(RK3229_WIN0_CTRL1, 0x3, 2), >> +.cbcr_axi_gather_en = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 1), >> +.yrgb_axi_gather_en = VOP_REG(RK3229_WIN0_CTRL1, 0x1, 0), >> +.lb_mode = VOP_REG(RK3229_WIN0_CTRL0, 0x7, 5), >> +}; >> + >> +static const struct vop_scl_regs rk3229_win_full_scl = { >> +.ext = &rk3229_win_full_scl_ext, >> +.scale_yrgb_x = VOP_REG(RK3229_WIN0_SCL_FACTOR_YRGB, 0x, 0x0), >> +.scale_yrgb_y = VOP_REG(RK3229_WIN0_SCL_FACTOR_YRGB, 0x, 16), >> +.scale_cbcr_x = VOP_REG(RK3229_WIN0_SCL_FACTOR_CBR, 0x, 0x0), >> +.scale_cbcr_y = VOP_REG(RK3229_WIN0_SCL_FACTOR_CBR, 0x, 16), >> +}; >> + >> +static const struct vop_win_phy rk3229_win01_data = { >> +.scl = &rk3229_win_full_scl, >> +.data_formats = formats_win_full, >> +.nformats = ARRAY_SIZE(formats_win_full), >> +.enable = VOP_REG(RK3229_WIN0_CTRL0, 0x1, 0), >> +.format = VOP_REG(RK3229_WIN0_CTRL0, 0x7, 1), >> +.rb_swap = VOP_REG(RK3229_WIN0_CTRL0, 0x1, 12), >> +.act_info = VOP_REG(RK3229_WIN0_ACT_INFO, 0x1fff1fff, 0), >> +.dsp_info = VOP_REG(RK3229_WIN0_DSP_INFO, 0x0fff0fff, 0), >> +.dsp_st = VOP_REG(RK3229_WIN0_DSP_ST, 0x1fff1fff, 0), >> +.yrgb_mst = VOP_REG(RK3229_WIN0_YRGB_MST, 0x, 0), >> +.uv_mst = VOP_REG(RK3229_WIN0_CBR_MST, 0x, 0), >> +.yrgb_vir = VOP_REG(RK3229_WIN0_VIR, 0x3fff, 0), >> +.uv_vir = VOP_REG(RK3229_WIN0_VIR, 0x3fff, 16), >> +.src_alpha_ctl = VOP_REG(RK3229_WIN0_SRC_ALPHA_CTRL, 0xff, 0), >> +.dst_alpha_ctl = VOP_REG(RK3229_WIN0_DST_ALPHA_CTRL, 0xff, 0), >> +}; >> + >> +static const struct vop_win_data rk3229_vop_win_data[] = { >> +{ .base = 0x00, .phy = &rk3229_win01_data, >> + .type = DRM_PLANE_TYPE_PRIMARY }, >> +{ .base = 0x40, .phy = &rk3229_win01_data, >> + .type = DRM_PLANE_TYPE_CURSOR }, >> +}; >> + >> +static const struct vop_ctrl rk3229_ctrl_data = { >> +.cfg_done = VOP_REG(RK3229_REG_CFG_DONE, 0x1, 0), >> +.standby = VOP_REG(RK3229_SYS_CTRL, 0x1, 22), >> +.gate_en = VOP_REG(RK3229_SYS_CTRL, 0x1, 23), >> +.mmu_en = VOP_REG(RK3229_SYS_CTRL, 0x1, 20), >> +.rgb_en = VOP_REG(RK3229_SYS_CTRL, 0x1, 12
[RFC PATCH v1 0/2] Add RK3229 HDMI support
RK3229 have integrated an DesignedWare HDMI controller and an INNO HDMI phy, so we can still reuse the dw-hdmi driver for RK3229 HDMI controller, but we need to create an separate driver for RK3229 HDMI PHY. Yakir Yang (2): drm: rockchip: hdmi: add RK3229 HDMI support dt-bindings: add document for rk3229-hdmi .../bindings/display/rockchip/dw_hdmi-rockchip.txt | 4 +- drivers/gpu/drm/bridge/dw-hdmi.c | 33 +- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c| 380 +++-- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.h| 137 include/drm/bridge/dw_hdmi.h | 5 +- 5 files changed, 519 insertions(+), 40 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.h -- 2.1.2
[RFC PATCH v1 1/2] drm: rockchip: hdmi: add RK3229 HDMI support
RK3229 integrate an DesignedWare HDMI2.0 controller and an INNO HDMI2.0 phy, the max output resolution is 4K. Signed-off-by: Yakir Yang --- drivers/gpu/drm/bridge/dw-hdmi.c| 33 ++- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 380 +--- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.h | 137 ++ include/drm/bridge/dw_hdmi.h| 5 +- 4 files changed, 516 insertions(+), 39 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.h diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 6fbec99..60b1dcf 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -735,10 +735,12 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, { unsigned res_idx; u8 val, msec; + int ret; const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg; const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr; const struct dw_hdmi_phy_config *phy_config = pdata->phy_config; + int mpixelclock = hdmi->hdmi_data.video_mode.mpixelclock; if (prep) return -EINVAL; @@ -758,27 +760,38 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, return -EINVAL; } + if (hdmi->plat_data->extphy_config) { + /* gen2 tx power off */ + dw_hdmi_phy_gen2_txpwron(hdmi, 0); + dw_hdmi_phy_gen2_pddq(hdmi, 1); + + ret = hdmi->plat_data->extphy_config(hdmi->plat_data, res_idx, +mpixelclock); + /* gen2 tx power on */ + dw_hdmi_phy_gen2_txpwron(hdmi, 1); + dw_hdmi_phy_gen2_pddq(hdmi, 0); + + return ret; + } + /* PLL/MPLL Cfg - always match on final entry */ for (; mpll_config->mpixelclock != ~0UL; mpll_config++) - if (hdmi->hdmi_data.video_mode.mpixelclock <= - mpll_config->mpixelclock) + if (mpixelclock <= mpll_config->mpixelclock) break; for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++) - if (hdmi->hdmi_data.video_mode.mpixelclock <= - curr_ctrl->mpixelclock) + if (mpixelclock <= curr_ctrl->mpixelclock) break; for (; phy_config->mpixelclock != ~0UL; phy_config++) - if (hdmi->hdmi_data.video_mode.mpixelclock <= - phy_config->mpixelclock) + if (mpixelclock <= phy_config->mpixelclock) break; if (mpll_config->mpixelclock == ~0UL || curr_ctrl->mpixelclock == ~0UL || phy_config->mpixelclock == ~0UL) { dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n", - hdmi->hdmi_data.video_mode.mpixelclock); + mpixelclock); return -EINVAL; } @@ -1476,14 +1489,16 @@ dw_hdmi_connector_mode_valid(struct drm_connector *connector, { struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, connector); + struct dw_hdmi_plat_data *plat_data = hdmi->plat_data; enum drm_mode_status mode_status = MODE_OK; /* We don't support double-clocked modes */ if (mode->flags & DRM_MODE_FLAG_DBLCLK) return MODE_BAD; - if (hdmi->plat_data->mode_valid) - mode_status = hdmi->plat_data->mode_valid(connector, mode); + if (plat_data->mode_valid) + mode_status = plat_data->mode_valid(plat_data, mode); + return mode_status; } diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index c65ce8c..424d548 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -7,6 +7,7 @@ * (at your option) any later version. */ +#include #include #include #include @@ -21,18 +22,135 @@ #include "rockchip_drm_drv.h" #include "rockchip_drm_vop.h" -#define GRF_SOC_CON60x025c -#define HDMI_SEL_VOP_LIT(1 << 4) +#include "dw_hdmi-rockchip.h" struct rockchip_hdmi { struct device *dev; struct regmap *regmap; struct drm_encoder encoder; + struct dw_hdmi_plat_data plat_data; + + void __iomem *extphy_regbase; + struct clk *extphy_pclk; }; #define to_rockchip_hdmi(x)container_of(x, struct rockchip_hdmi, x) -static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { +static const s
[RFC PATCH v1 2/2] dt-bindings: add document for rk3229-hdmi
Signed-off-by: Yakir Yang --- .../devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt index 668091f..1cdc627 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt @@ -2,7 +2,7 @@ Rockchip specific extensions to the Synopsys Designware HDMI Required properties: -- compatible: "rockchip,rk3288-dw-hdmi"; +- compatible: "rockchip,rk3288-dw-hdmi", "rockchip,rk3229-dw-hdmi"; - reg: Physical base address and length of the controller's registers. - clocks: phandle to hdmi iahb and isfr clocks. - clock-names: should be "iahb" "isfr" @@ -15,8 +15,10 @@ Required properties: rk3288 platform Optional properties +- reg: Physical base address and length of the external HDMI PHY's registers. - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing - clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec" + phandle to the external HDMI PHY clock, name should be "extphy" Example: hdmi: hdmi at ff98 { -- 2.1.2
[RFC PATCH v1 1/2] drm: rockchip: hdmi: add RK3229 HDMI support
Thanks for "Kbuild test robot" reminding, I forget to update "mode_valid" function define in imx-hdmi side, would send new version out, -- >> drivers/gpu/drm/imx/dw_hdmi-imx.c:181:2: warning: initialization from >> incompatible pointer type .mode_valid = imx6q_hdmi_mode_valid, ^ drivers/gpu/drm/imx/dw_hdmi-imx.c:181:2: warning: (near initialization for 'imx6q_hdmi_drv_data.mode_valid') drivers/gpu/drm/imx/dw_hdmi-imx.c:189:2: warning: initialization from incompatible pointer type .mode_valid = imx6dl_hdmi_mode_valid, ^ drivers/gpu/drm/imx/dw_hdmi-imx.c:189:2: warning: (near initialization for 'imx6dl_hdmi_drv_data.mode_valid') Sorry, - Yakir On 01/07/2016 12:37 PM, Yakir Yang wrote: > RK3229 integrate an DesignedWare HDMI2.0 controller and an INNO HDMI2.0 phy, > the max output resolution is 4K. > > Signed-off-by: Yakir Yang > --- > drivers/gpu/drm/bridge/dw-hdmi.c| 33 ++- > drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 380 > +--- > drivers/gpu/drm/rockchip/dw_hdmi-rockchip.h | 137 ++ > include/drm/bridge/dw_hdmi.h| 5 +- > 4 files changed, 516 insertions(+), 39 deletions(-) > create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.h > > diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c > b/drivers/gpu/drm/bridge/dw-hdmi.c > index 6fbec99..60b1dcf 100644 > --- a/drivers/gpu/drm/bridge/dw-hdmi.c > +++ b/drivers/gpu/drm/bridge/dw-hdmi.c > @@ -735,10 +735,12 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, > unsigned char prep, > { > unsigned res_idx; > u8 val, msec; > + int ret; > const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; > const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg; > const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr; > const struct dw_hdmi_phy_config *phy_config = pdata->phy_config; > + int mpixelclock = hdmi->hdmi_data.video_mode.mpixelclock; > > if (prep) > return -EINVAL; > @@ -758,27 +760,38 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, > unsigned char prep, > return -EINVAL; > } > > + if (hdmi->plat_data->extphy_config) { > + /* gen2 tx power off */ > + dw_hdmi_phy_gen2_txpwron(hdmi, 0); > + dw_hdmi_phy_gen2_pddq(hdmi, 1); > + > + ret = hdmi->plat_data->extphy_config(hdmi->plat_data, res_idx, > + mpixelclock); > + /* gen2 tx power on */ > + dw_hdmi_phy_gen2_txpwron(hdmi, 1); > + dw_hdmi_phy_gen2_pddq(hdmi, 0); > + > + return ret; > + } > + > /* PLL/MPLL Cfg - always match on final entry */ > for (; mpll_config->mpixelclock != ~0UL; mpll_config++) > - if (hdmi->hdmi_data.video_mode.mpixelclock <= > - mpll_config->mpixelclock) > + if (mpixelclock <= mpll_config->mpixelclock) > break; > > for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++) > - if (hdmi->hdmi_data.video_mode.mpixelclock <= > - curr_ctrl->mpixelclock) > + if (mpixelclock <= curr_ctrl->mpixelclock) > break; > > for (; phy_config->mpixelclock != ~0UL; phy_config++) > - if (hdmi->hdmi_data.video_mode.mpixelclock <= > - phy_config->mpixelclock) > + if (mpixelclock <= phy_config->mpixelclock) > break; > > if (mpll_config->mpixelclock == ~0UL || > curr_ctrl->mpixelclock == ~0UL || > phy_config->mpixelclock == ~0UL) { > dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n", > - hdmi->hdmi_data.video_mode.mpixelclock); > + mpixelclock); > return -EINVAL; > } > > @@ -1476,14 +1489,16 @@ dw_hdmi_connector_mode_valid(struct drm_connector > *connector, > { > struct dw_hdmi *hdmi = container_of(connector, > struct dw_hdmi, connector); > + struct dw_hdmi_plat_data *plat_data = hdmi->plat_data; > enum drm_mode_status mode_status = MODE_OK; > > /* We don't support double-clocked modes */ > if (mode->flags & DRM_MODE_FLAG_DBLCLK) > return MODE_BAD; > > - if (hdmi->plat_data->mode_valid) > - mode_status = hdmi->plat_data->mode_valid(co
[RFC PATCH v2 0/4] Add RK3229 HDMI support
RK3229 have integrated an DesignedWare HDMI controller and an INNO HDMI phy, so we can still reuse the dw-hdmi driver for RK3229 HDMI controller, but we need to create an separate driver for RK3229 HDMI PHY. This series is based on Mark Yao's drm-next branch [https://github.com/markyzq/kernel-drm-rockchip/tree/drm-rockchip-next-2015-12-28] After picking my "Add RK3229 vop support" series, HDMI monitor could light up normally on RK3229 SDK board. Changes in v2: - Split some dw-hdmi driver changes into separate patches [01/04] & [02/04] Yakir Yang (4): drm: dw-hdmi: make it easy to recovery the platform data for platform driver drm: dw-hdmi: passing the "plat_data" when calling platform mode_valid drm: rockchip: hdmi: add RK3229 HDMI support dt-bindings: add document for rk3229-hdmi .../bindings/display/rockchip/dw_hdmi-rockchip.txt | 4 +- drivers/gpu/drm/bridge/dw-hdmi.c | 32 +- drivers/gpu/drm/imx/dw_hdmi-imx.c | 17 +- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c| 376 +++-- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.h| 137 include/drm/bridge/dw_hdmi.h | 5 +- 6 files changed, 529 insertions(+), 42 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.h -- 2.1.2
[RFC PATCH v2 1/4] drm: dw-hdmi: make it easy to recovery the platform data for platform driver
Signed-off-by: Yakir Yang --- Changes in v2: None drivers/gpu/drm/imx/dw_hdmi-imx.c | 7 --- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 7 --- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index 063825f..0968610 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c @@ -26,6 +26,7 @@ struct imx_hdmi { struct device *dev; struct drm_encoder encoder; struct regmap *regmap; + struct dw_hdmi_plat_data plat_data; }; static const struct dw_hdmi_mpll_config imx_mpll_cfg[] = { @@ -204,7 +205,6 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); - const struct dw_hdmi_plat_data *plat_data; const struct of_device_id *match; struct drm_device *drm = data; struct drm_encoder *encoder; @@ -221,7 +221,7 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master, return -ENOMEM; match = of_match_node(dw_hdmi_imx_dt_ids, pdev->dev.of_node); - plat_data = match->data; + hdmi->plat_data = *(const struct dw_hdmi_plat_data *)match->data; hdmi->dev = &pdev->dev; encoder = &hdmi->encoder; @@ -253,7 +253,8 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master, drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL); - return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data); + return dw_hdmi_bind(dev, master, data, encoder, iores, irq, + &hdmi->plat_data); } static void dw_hdmi_imx_unbind(struct device *dev, struct device *master, diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index c65ce8c..d5816b3 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -28,6 +28,7 @@ struct rockchip_hdmi { struct device *dev; struct regmap *regmap; struct drm_encoder encoder; + struct dw_hdmi_plat_data plat_data; }; #define to_rockchip_hdmi(x)container_of(x, struct rockchip_hdmi, x) @@ -242,7 +243,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); - const struct dw_hdmi_plat_data *plat_data; const struct of_device_id *match; struct drm_device *drm = data; struct drm_encoder *encoder; @@ -259,7 +259,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, return -ENOMEM; match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node); - plat_data = match->data; + hdmi->plat_data = *(const struct dw_hdmi_plat_data *)match->data; hdmi->dev = &pdev->dev; encoder = &hdmi->encoder; @@ -293,7 +293,8 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL); - return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data); + return dw_hdmi_bind(dev, master, data, encoder, iores, irq, + &hdmi->plat_data); } static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master, -- 2.1.2
[RFC PATCH v2 2/4] drm: dw-hdmi: passing the "plat_data" when calling platform mode_valid
Make it easy for platform driver could recovery the private data that would help to valid the display mode. Signed-off-by: Yakir Yang --- Changes in v2: None drivers/gpu/drm/bridge/dw-hdmi.c| 5 +++-- drivers/gpu/drm/imx/dw_hdmi-imx.c | 10 ++ drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 +- include/drm/bridge/dw_hdmi.h| 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 6fbec99..5ad72ec 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -1476,14 +1476,15 @@ dw_hdmi_connector_mode_valid(struct drm_connector *connector, { struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, connector); + const struct dw_hdmi_plat_data *plat_data = hdmi->plat_data; enum drm_mode_status mode_status = MODE_OK; /* We don't support double-clocked modes */ if (mode->flags & DRM_MODE_FLAG_DBLCLK) return MODE_BAD; - if (hdmi->plat_data->mode_valid) - mode_status = hdmi->plat_data->mode_valid(connector, mode); + if (plat_data->mode_valid) + mode_status = plat_data->mode_valid(plat_data, mode); return mode_status; } diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index 0968610..8b0a7da 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c @@ -150,8 +150,9 @@ static const struct drm_encoder_funcs dw_hdmi_imx_encoder_funcs = { .destroy = drm_encoder_cleanup, }; -static enum drm_mode_status imx6q_hdmi_mode_valid(struct drm_connector *con, - struct drm_display_mode *mode) +static enum drm_mode_status +imx6q_hdmi_mode_valid(const struct dw_hdmi_plat_data *plat_data, + struct drm_display_mode *mode) { if (mode->clock < 13500) return MODE_CLOCK_LOW; @@ -162,8 +163,9 @@ static enum drm_mode_status imx6q_hdmi_mode_valid(struct drm_connector *con, return MODE_OK; } -static enum drm_mode_status imx6dl_hdmi_mode_valid(struct drm_connector *con, - struct drm_display_mode *mode) +static enum drm_mode_status +imx6dl_hdmi_mode_valid(const struct dw_hdmi_plat_data *plat_data, + struct drm_display_mode *mode) { if (mode->clock < 13500) return MODE_CLOCK_LOW; diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index d5816b3..8164823 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -156,7 +156,7 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) } static enum drm_mode_status -dw_hdmi_rockchip_mode_valid(struct drm_connector *connector, +dw_hdmi_rockchip_mode_valid(const struct dw_hdmi_plat_data *plat_data, struct drm_display_mode *mode) { const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg; diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index bae79f3..f8dec64 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -52,7 +52,7 @@ struct dw_hdmi_plat_data { const struct dw_hdmi_mpll_config *mpll_cfg; const struct dw_hdmi_curr_ctrl *cur_ctr; const struct dw_hdmi_phy_config *phy_config; - enum drm_mode_status (*mode_valid)(struct drm_connector *connector, + enum drm_mode_status (*mode_valid)(const struct dw_hdmi_plat_data *pd, struct drm_display_mode *mode); }; -- 2.1.2
[RFC PATCH v2 3/4] drm: rockchip: hdmi: add RK3229 HDMI support
RK3229 integrate an DesignedWare HDMI2.0 controller and an INNO HDMI2.0 phy, the max output resolution is 4K. Signed-off-by: Yakir Yang --- Changes in v2: - Split some dw-hdmi driver changes into separate patches [01/04] & [02/04] drivers/gpu/drm/bridge/dw-hdmi.c| 27 +- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 367 ++-- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.h | 137 +++ include/drm/bridge/dw_hdmi.h| 3 + 4 files changed, 507 insertions(+), 27 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.h diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 5ad72ec..5e03d83 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -735,10 +735,12 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, { unsigned res_idx; u8 val, msec; + int ret; const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg; const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr; const struct dw_hdmi_phy_config *phy_config = pdata->phy_config; + int mpixelclock = hdmi->hdmi_data.video_mode.mpixelclock; if (prep) return -EINVAL; @@ -758,27 +760,38 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, return -EINVAL; } + if (hdmi->plat_data->extphy_config) { + /* gen2 tx power off */ + dw_hdmi_phy_gen2_txpwron(hdmi, 0); + dw_hdmi_phy_gen2_pddq(hdmi, 1); + + ret = hdmi->plat_data->extphy_config(hdmi->plat_data, res_idx, +mpixelclock); + /* gen2 tx power on */ + dw_hdmi_phy_gen2_txpwron(hdmi, 1); + dw_hdmi_phy_gen2_pddq(hdmi, 0); + + return ret; + } + /* PLL/MPLL Cfg - always match on final entry */ for (; mpll_config->mpixelclock != ~0UL; mpll_config++) - if (hdmi->hdmi_data.video_mode.mpixelclock <= - mpll_config->mpixelclock) + if (mpixelclock <= mpll_config->mpixelclock) break; for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++) - if (hdmi->hdmi_data.video_mode.mpixelclock <= - curr_ctrl->mpixelclock) + if (mpixelclock <= curr_ctrl->mpixelclock) break; for (; phy_config->mpixelclock != ~0UL; phy_config++) - if (hdmi->hdmi_data.video_mode.mpixelclock <= - phy_config->mpixelclock) + if (mpixelclock <= phy_config->mpixelclock) break; if (mpll_config->mpixelclock == ~0UL || curr_ctrl->mpixelclock == ~0UL || phy_config->mpixelclock == ~0UL) { dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n", - hdmi->hdmi_data.video_mode.mpixelclock); + mpixelclock); return -EINVAL; } diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 8164823..24fffaa 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -7,6 +7,7 @@ * (at your option) any later version. */ +#include #include #include #include @@ -21,18 +22,134 @@ #include "rockchip_drm_drv.h" #include "rockchip_drm_vop.h" -#define GRF_SOC_CON60x025c -#define HDMI_SEL_VOP_LIT(1 << 4) +#include "dw_hdmi-rockchip.h" struct rockchip_hdmi { struct device *dev; struct regmap *regmap; struct drm_encoder encoder; struct dw_hdmi_plat_data plat_data; + + void __iomem *extphy_regbase; + struct clk *extphy_pclk; }; #define to_rockchip_hdmi(x)container_of(x, struct rockchip_hdmi, x) +static const struct extphy_config_tab rockchip_extphy_cfg[] = { + { .mpixelclock = 16500, + .pre_emphasis = 0, .slopeboost = 0, .clk_level = 4, + .data0_level = 4, 4, 4, + }, + + { .mpixelclock = 22500, + .pre_emphasis = 0, .slopeboost = 0, .clk_level = 6, + .data0_level = 6, 6, 6, + }, + + { .mpixelclock = 34000, + .pre_emphasis = 1, .slopeboost = 0, .clk_level = 6, + .data0_level = 10, 10, 10, + }, + + { .mpixelclock = 59400, + .pre_emphasis = 1, .slopeboost = 0, .clk_level = 7, + .data0_level = 10, 10, 10, + }, + + { .mpixelclock = ~0UL}, +}; + +static const struct extphy_pll_config_tab rockchip_extphy_pll_cfg[] = { + { +
[RFC PATCH v2 4/4] dt-bindings: add document for rk3229-hdmi
Signed-off-by: Yakir Yang --- Changes in v2: None .../devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt index 668091f..1cdc627 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt @@ -2,7 +2,7 @@ Rockchip specific extensions to the Synopsys Designware HDMI Required properties: -- compatible: "rockchip,rk3288-dw-hdmi"; +- compatible: "rockchip,rk3288-dw-hdmi", "rockchip,rk3229-dw-hdmi"; - reg: Physical base address and length of the controller's registers. - clocks: phandle to hdmi iahb and isfr clocks. - clock-names: should be "iahb" "isfr" @@ -15,8 +15,10 @@ Required properties: rk3288 platform Optional properties +- reg: Physical base address and length of the external HDMI PHY's registers. - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing - clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec" + phandle to the external HDMI PHY clock, name should be "extphy" Example: hdmi: hdmi at ff98 { -- 2.1.2
[PATCH v2 0/2] Introduce Innosilicon HDMI driver on Rockchip platforms
Here are a brief introduction to Innosilicon HDMI IP: - Support HDMI 1.4a, HDCP 1.2 and DVI 1.0 standard compliant transmitter - Support HDMI1.4 a/b 3D function defined in HDMI 1.4 a/b spec - Digital video interface supports a pixel size of 24, 30, 36, 48bits color depth in RGB - S/PDIF output supports PCM, Dolby Digital, DTS digital audio transmission (32-192kHz Fs) using IEC60958 and IEC 61937 - The EDID and CEC function are also supported by Innosilicon HDMI Transmitter Controlle Changes in v2: - Using DRM atomic helper functions for connector init (Mark) - Remove "hdmi->connector.encoder = encoder;" (Mark) - Correct the misspell "rk3036-dw-hdmi" (Heiko) Yakir Yang (2): drm: rockchip/hdmi: add Innosilicon HDMI support dt-bindings: add document for Innosilicon HDMI on Rockchip platform .../display/rockchip/inno_hdmi-rockchip.txt| 50 + drivers/gpu/drm/rockchip/Kconfig |8 + drivers/gpu/drm/rockchip/Makefile |1 + drivers/gpu/drm/rockchip/inno_hdmi.c | 1010 drivers/gpu/drm/rockchip/inno_hdmi.h | 364 +++ 5 files changed, 1433 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt create mode 100644 drivers/gpu/drm/rockchip/inno_hdmi.c create mode 100644 drivers/gpu/drm/rockchip/inno_hdmi.h -- 2.1.2
[PATCH v2 1/2] drm: rockchip/hdmi: add Innosilicon HDMI support
The Innosilicon HDMI is a low power HDMI 1.4 transmitter IP, and it have been integrated on some rockchip CPUs (like RK3036, RK312x). Signed-off-by: Yakir Yang --- Changes in v2: - Using DRM atomic helper functions for connector init (Mark) - Remove "hdmi->connector.encoder = encoder;" (Mark) drivers/gpu/drm/rockchip/Kconfig |8 + drivers/gpu/drm/rockchip/Makefile|1 + drivers/gpu/drm/rockchip/inno_hdmi.c | 1010 ++ drivers/gpu/drm/rockchip/inno_hdmi.h | 364 4 files changed, 1383 insertions(+) create mode 100644 drivers/gpu/drm/rockchip/inno_hdmi.c create mode 100644 drivers/gpu/drm/rockchip/inno_hdmi.h diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 35215f6..a5014e0 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -25,3 +25,11 @@ config ROCKCHIP_DW_HDMI for the Synopsys DesignWare HDMI driver. If you want to enable HDMI on RK3288 based SoC, you should selet this option. + +config ROCKCHIP_INNO_HDMI + tristate "Rockchip specific extensions for Innosilicon HDMI" +depends on DRM_ROCKCHIP +help + This selects support for Rockchip SoC specific extensions + for the Innosilicon HDMI driver. If you want to enable + HDMI on RK3036 based SoC, you should selet this option. diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index a9d380f..da2bf76 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -6,6 +6,7 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o rockchip_drm_fbdev.o \ rockchip_drm_gem.o obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o +obj-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o rockchip_drm_vop.o \ rockchip_vop_reg.o diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c new file mode 100644 index 000..9327617 --- /dev/null +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -0,0 +1,1010 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + *Zheng Yang + *Yakir Yang + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "rockchip_drm_drv.h" +#include "rockchip_drm_vop.h" + +#include "inno_hdmi.h" + +#define to_inno_hdmi(x)container_of(x, struct inno_hdmi, x) + +struct hdmi_data_info { + int vic; + bool sink_is_hdmi; + bool sink_has_audio; + unsigned int enc_in_format; + unsigned int enc_out_format; + unsigned int colorimetry; +}; + +struct inno_hdmi_i2c { + struct i2c_adapter adap; + + u8 ddc_addr; + u8 segment_addr; + + struct mutex lock; + struct completion cmp; +}; + +struct inno_hdmi { + struct device *dev; + struct drm_device *drm_dev; + + int irq; + struct clk *pclk; + void __iomem *regs; + + struct drm_connectorconnector; + struct drm_encoder encoder; + + struct inno_hdmi_i2c *i2c; + struct i2c_adapter *ddc; + + int dpms_mode; + unsigned int tmds_rate; + + struct hdmi_data_info hdmi_data; + struct drm_display_mode previous_mode; +}; + +enum { + CSC_ITU601_16_235_TO_RGB_0_255_8BIT, + CSC_ITU601_0_255_TO_RGB_0_255_8BIT, + CSC_ITU709_16_235_TO_RGB_0_255_8BIT, + CSC_RGB_0_255_TO_ITU601_16_235_8BIT, + CSC_RGB_0_255_TO_ITU709_16_235_8BIT, + CSC_RGB_0_255_TO_RGB_16_235_8BIT, +}; + +static const char coeff_csc[][24] = { + /* +* YUV2RGB:601 SD mode(Y[16:235], UV[16:240], RGB[0:255]): +* R = 1.164*Y + 1.596*V - 204 +* G = 1.164*Y - 0.391*U - 0.813*V + 154 +* B = 1.164*Y + 2.018*U - 258 +*/ + { + 0x04, 0xa7, 0x00, 0x00, 0x06, 0x62, 0x02, 0xcc, + 0x04, 0xa7, 0x11, 0x90, 0x13, 0x40, 0x00, 0x9a, + 0x04, 0xa7, 0x08, 0x12, 0x00, 0x00, 0x03, 0x02 + }, + /* +* YUV2RGB:601 SD mode(YUV[0:255],RGB[0:255]): +* R = Y + 1.402*V - 248 +* G = Y - 0.344*U - 0.714*V + 135 +* B = Y + 1.772*U - 227 +*/ + { + 0x04, 0x00, 0x00, 0x00, 0x05, 0x9b, 0x02, 0xf8, +
[PATCH v2 2/2] dt-bindings: add document for Innosilicon HDMI on Rockchip platform
Signed-off-by: Yakir Yang Acked-by: Rob Herring --- Changes in v2: - Correct the misspell "rk3036-dw-hdmi" (Heiko) .../display/rockchip/inno_hdmi-rockchip.txt| 50 ++ 1 file changed, 50 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt diff --git a/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt new file mode 100644 index 000..8096a29 --- /dev/null +++ b/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt @@ -0,0 +1,50 @@ +Rockchip specific extensions to the Innosilicon HDMI + + +Required properties: +- compatible: + "rockchip,rk3036-inno-hdmi"; +- reg: + Physical base address and length of the controller's registers. +- clocks, clock-names: + Phandle to hdmi controller clock, name should be "pclk" +- interrupts: + HDMI interrupt number +- ports: + Contain one port node with endpoint definitions as defined in + Documentation/devicetree/bindings/graph.txt. +- pinctrl-0, pinctrl-name: + Switch the iomux of HPD/CEC pins to HDMI function. + +Example: +hdmi: hdmi at 20034000 { + compatible = "rockchip,rk3036-inno-hdmi"; + reg = <0x20034000 0x4000>; + interrupts = ; + clocks = <&cru PCLK_HDMI>; + clock-names = "pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_ctl>; + status = "disabled"; + + hdmi_in: port { + #address-cells = <1>; + #size-cells = <0>; + hdmi_in_lcdc: endpoint at 0 { + reg = <0>; + remote-endpoint = <&lcdc_out_hdmi>; + }; + }; +}; + +&pinctrl { + hdmi { + hdmi_ctl: hdmi-ctl { + rockchip,pins = <1 8 RK_FUNC_1 &pcfg_pull_none>, + <1 9 RK_FUNC_1 &pcfg_pull_none>, + <1 10 RK_FUNC_1 &pcfg_pull_none>, + <1 11 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + +}; -- 2.1.2
[RFC PATCH v2 3/4] drm: rockchip: hdmi: add RK3229 HDMI support
Hi Philipp, Thanks for your fast respond :) On 01/07/2016 06:04 PM, Philipp Zabel wrote: > Am Donnerstag, den 07.01.2016, 17:02 +0800 schrieb Yakir Yang: >> RK3229 integrate an DesignedWare HDMI2.0 controller and an INNO HDMI2.0 phy, >> the max output resolution is 4K. >> >> Signed-off-by: Yakir Yang > It sounds like the INNO HDMI2.0 phy is not necessarily specific to > RK3229 but might also appear in other SoCs? If so, I think this should > be implemented in a separate phy driver and be used by dw_hdmi-rockchip. Do you mean I should create a new phy driver that place in "driver/phy" directly ? I have think about this idea, and it would make things much clean. But INNO PHY driver need the target pixel clock in drm_display_mode, I didn't find a good way to pass this variable to separate phy driver. Do you have some idea ? Thanks, - Yakir > regards > Philipp > >> --- >> Changes in v2: >> - Split some dw-hdmi driver changes into separate patches [01/04] & [02/04] >> >> drivers/gpu/drm/bridge/dw-hdmi.c| 27 +- >> drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 367 >> ++-- >> drivers/gpu/drm/rockchip/dw_hdmi-rockchip.h | 137 +++ >> include/drm/bridge/dw_hdmi.h| 3 + >> 4 files changed, 507 insertions(+), 27 deletions(-) >> create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.h >> >> diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c >> b/drivers/gpu/drm/bridge/dw-hdmi.c >> index 5ad72ec..5e03d83 100644 >> --- a/drivers/gpu/drm/bridge/dw-hdmi.c >> +++ b/drivers/gpu/drm/bridge/dw-hdmi.c >> @@ -735,10 +735,12 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, >> unsigned char prep, >> { >> unsigned res_idx; >> u8 val, msec; >> +int ret; >> const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; >> const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg; >> const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr; >> const struct dw_hdmi_phy_config *phy_config = pdata->phy_config; >> +int mpixelclock = hdmi->hdmi_data.video_mode.mpixelclock; >> >> if (prep) >> return -EINVAL; >> @@ -758,27 +760,38 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, >> unsigned char prep, >> return -EINVAL; >> } >> >> +if (hdmi->plat_data->extphy_config) { >> +/* gen2 tx power off */ >> +dw_hdmi_phy_gen2_txpwron(hdmi, 0); >> +dw_hdmi_phy_gen2_pddq(hdmi, 1); >> + >> +ret = hdmi->plat_data->extphy_config(hdmi->plat_data, res_idx, >> + mpixelclock); >> +/* gen2 tx power on */ >> +dw_hdmi_phy_gen2_txpwron(hdmi, 1); >> +dw_hdmi_phy_gen2_pddq(hdmi, 0); >> + >> +return ret; >> +} >> + >> /* PLL/MPLL Cfg - always match on final entry */ >> for (; mpll_config->mpixelclock != ~0UL; mpll_config++) >> -if (hdmi->hdmi_data.video_mode.mpixelclock <= >> -mpll_config->mpixelclock) >> +if (mpixelclock <= mpll_config->mpixelclock) >> break; >> >> for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++) >> -if (hdmi->hdmi_data.video_mode.mpixelclock <= >> -curr_ctrl->mpixelclock) >> +if (mpixelclock <= curr_ctrl->mpixelclock) >> break; >> >> for (; phy_config->mpixelclock != ~0UL; phy_config++) >> -if (hdmi->hdmi_data.video_mode.mpixelclock <= >> -phy_config->mpixelclock) >> +if (mpixelclock <= phy_config->mpixelclock) >> break; >> >> if (mpll_config->mpixelclock == ~0UL || >> curr_ctrl->mpixelclock == ~0UL || >> phy_config->mpixelclock == ~0UL) { >> dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n", >> -hdmi->hdmi_data.video_mode.mpixelclock); >> +mpixelclock); >> return -EINVAL; >> } >> >> diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c >> b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c >> index 8164823..24fffaa 100644 >> --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c >> +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.
[RFC PATCH v2 3/4] drm: rockchip: hdmi: add RK3229 HDMI support
Hi Philipp, On 01/08/2016 12:50 AM, Philipp Zabel wrote: > Hi Yakir, > > Am Donnerstag, den 07.01.2016, 18:15 +0800 schrieb Yakir Yang: >> Hi Philipp, >> >> Thanks for your fast respond :) >> >> On 01/07/2016 06:04 PM, Philipp Zabel wrote: >>> Am Donnerstag, den 07.01.2016, 17:02 +0800 schrieb Yakir Yang: >>>> RK3229 integrate an DesignedWare HDMI2.0 controller and an INNO HDMI2.0 >>>> phy, >>>> the max output resolution is 4K. >>>> >>>> Signed-off-by: Yakir Yang >>> It sounds like the INNO HDMI2.0 phy is not necessarily specific to >>> RK3229 but might also appear in other SoCs? If so, I think this should >>> be implemented in a separate phy driver and be used by dw_hdmi-rockchip. >> Do you mean I should create a new phy driver that place in "driver/phy" >> directly ? > Possibly, yes. The exynos video phys are already there. I have kept the > mediatek dsi/hdmi phys together with the DRM driver, but I suppose I > could move them there, too. > >> I have think about this idea, and it would make things much clean. But >> INNO PHY >> driver need the target pixel clock in drm_display_mode, I didn't find a >> good way >> to pass this variable to separate phy driver. Do you have some idea ? > We'd need to extend the PHY API for this. For the mediatek phys we have > side-stepped the issue by wiring up the PLL output to the common clock > framework. Wow, I have look at your "drm/mediatek: Add HDMI support" patch, it's great to registers a common clock framework. > I expect besides the pixel clock frequency, it might also be necessary > to inform the PHY about cycles per pixel for deep color modes. INNO PHY didn't need the color depth directly, driver could get the input pixel clock rate, and then hdmi core driver could set TMDS rate though common clock framework. Anyway it's great material, I would update the new version out. Thanks a lot - Yakir > regards > Philipp > > > >