* Re: [PATCH 19/20] OMAPDSS: DSI: fix DSI channel source initialization
From: Tomi Valkeinen @ 2013-03-11 7:02 UTC (permalink / raw)
To: Archit Taneja; +Cc: linux-omap, linux-fbdev
In-Reply-To: <513D754A.4000607@ti.com>
[-- Attachment #1: Type: text/plain, Size: 1502 bytes --]
On 2013-03-11 08:10, Archit Taneja wrote:
> Hi,
>
> On Friday 08 March 2013 05:21 PM, Tomi Valkeinen wrote:
>> During the initialization of the DSI protocol registers, we always set
>> the sources of all DSI channels to L4. However, we don't update the
>> value in the dsi_data, so we may end up with a different value in the
>> register and in the dsi_data, leading to DSI problems.
>>
>> This patch fixes the issue by initializing also the channel source in
>> the dsi_data.
>
> We set in omap_dsihw_probe:
>
> static int __init omap_dsihw_probe(struct platform_device *dsidev)
> {
> ...
> ...
> /* DSI VCs initialization */
> for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
> dsi->vc[i].source = DSI_VC_SOURCE_L4;
> dsi->vc[i].dssdev = NULL;
> dsi->vc[i].vc_id = 0;
> }
> ...
> ...
> }
Hmm... I did have a bug related to this when prototyping CDF. Ah.
Consider this:
Panel powers up and uses DSI normally. A DSI VC is set to video mode.
Then the panel power down. Then it powers up again, and enables DSI. At
this time, dsi_vc_initial_config() is called again, setting the source
in the registers to L4. But the source in dsi_data is still VP.
So perhaps the whole piece of code from omap_dsihw_probe should be moved
to somewhere else (dsi_vc_initial_config() sounds like a good place), so
that they are initialized each time the registers are initialized.
Tomi
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 899 bytes --]
^ permalink raw reply
* Re: [PATCH 20/20] OMAPDSS: Taal: remove rotate & mirror support
From: Tomi Valkeinen @ 2013-03-11 6:51 UTC (permalink / raw)
To: Archit Taneja; +Cc: linux-omap, linux-fbdev
In-Reply-To: <513D7807.2010509@ti.com>
[-- Attachment #1: Type: text/plain, Size: 1341 bytes --]
On 2013-03-11 08:21, Archit Taneja wrote:
> Hi,
>
> On Friday 08 March 2013 05:21 PM, Tomi Valkeinen wrote:
>> Taal panel driver has support to set rotation and mirroring. However,
>> these features cannot be used without causing tearing, and are never
>> used. The code is just extra bloat, so let's remove it.
>>
>> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
>
> <snip>
>> static ssize_t taal_num_errors_show(struct device *dev,
>> @@ -1025,10 +973,6 @@ static int taal_power_on(struct omap_dss_device
>> *dssdev)
>> if (r)
>> goto err;
>>
>> - r = taal_set_addr_mode(td, td->rotate, td->mirror);
>> - if (r)
>> - goto err;
>> -
>
> I'm curious if we need to set the address mode(to the default value) at
> least once. It may not be a requirement for Taal, but if that's the
> case, why did we have a set_addr_mode() call in taal_power_on() in the
> first place? Is it because we can prepare rotation and mirroring before
> we enable the panel?
The panel resets its registers at HW reset, so in case we have changed
the rotation or mirroring, we need to set the addr more at power_on to
keep the user's rotation and mirroring after resuming from blanking. But
now that the rotation or mirroring is never changed, the default value
is always fine.
Tomi
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 899 bytes --]
^ permalink raw reply
* Re: [PATCH 14/20] OMAPDSS: remove dssdev->channel assignments
From: Archit Taneja @ 2013-03-11 6:36 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: linux-omap, linux-fbdev
In-Reply-To: <1362743515-10152-15-git-send-email-tomi.valkeinen@ti.com>
On Friday 08 March 2013 05:21 PM, Tomi Valkeinen wrote:
> Now that the driver uses ooutput->recommended_channel, we can remove the
Typo above for 'output'. We could discard this patch if we don't add
dssdev->channel assignments in patch # 10.
Archit
^ permalink raw reply
* Re: [PATCH 20/20] OMAPDSS: Taal: remove rotate & mirror support
From: Archit Taneja @ 2013-03-11 6:33 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: linux-omap, linux-fbdev
In-Reply-To: <1362743515-10152-21-git-send-email-tomi.valkeinen@ti.com>
Hi,
On Friday 08 March 2013 05:21 PM, Tomi Valkeinen wrote:
> Taal panel driver has support to set rotation and mirroring. However,
> these features cannot be used without causing tearing, and are never
> used. The code is just extra bloat, so let's remove it.
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
<snip>
> static ssize_t taal_num_errors_show(struct device *dev,
> @@ -1025,10 +973,6 @@ static int taal_power_on(struct omap_dss_device *dssdev)
> if (r)
> goto err;
>
> - r = taal_set_addr_mode(td, td->rotate, td->mirror);
> - if (r)
> - goto err;
> -
I'm curious if we need to set the address mode(to the default value) at
least once. It may not be a requirement for Taal, but if that's the
case, why did we have a set_addr_mode() call in taal_power_on() in the
first place? Is it because we can prepare rotation and mirroring before
we enable the panel?
Archit
^ permalink raw reply
* Re: [PATCH 19/20] OMAPDSS: DSI: fix DSI channel source initialization
From: Archit Taneja @ 2013-03-11 6:22 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: linux-omap, linux-fbdev
In-Reply-To: <1362743515-10152-20-git-send-email-tomi.valkeinen@ti.com>
Hi,
On Friday 08 March 2013 05:21 PM, Tomi Valkeinen wrote:
> During the initialization of the DSI protocol registers, we always set
> the sources of all DSI channels to L4. However, we don't update the
> value in the dsi_data, so we may end up with a different value in the
> register and in the dsi_data, leading to DSI problems.
>
> This patch fixes the issue by initializing also the channel source in
> the dsi_data.
We set in omap_dsihw_probe:
static int __init omap_dsihw_probe(struct platform_device *dsidev)
{
...
...
/* DSI VCs initialization */
for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
dsi->vc[i].source = DSI_VC_SOURCE_L4;
dsi->vc[i].dssdev = NULL;
dsi->vc[i].vc_id = 0;
}
...
...
}
<snip>
Archit
^ permalink raw reply
* Re: [PATCH 1/3] video: backlight: adp5520: fix compiler warning in adp5520_show
From: devendra.aaru @ 2013-03-11 6:18 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1362771069-16345-1-git-send-email-devendra.aaru@gmail.com>
On Sun, Mar 10, 2013 at 8:56 PM, Jingoo Han <jg1.han@samsung.com> wrote:
> On Saturday, March 09, 2013 4:31 AM, Devendra Naga wrote:
>>
>> while compiling with make W=1 (gcc gcc (GCC) 4.7.2 20121109 (Red Hat 4.7.2-8))
>>
>> found the following warning
>>
>> drivers/video/backlight/adp5520_bl.c: In function ‘adp5520_show’:
>> drivers/video/backlight/adp5520_bl.c:146:6: warning: variable ‘error’ set but not used [-Wunused-but-
>> set-variable]
>>
>> fixed by removing the variable
>>
>> Cc: Jingoo Han <jg1.han@samsung.com>
>> Cc: Michael Hennerich <michael.hennerich@analog.com>
>> Cc: Richard Purdie <rpurdie@rpsys.net>
>>
>> Signed-off-by: Devendra Naga <devendra.aaru@gmail.com>
>> ---
>> drivers/video/backlight/adp5520_bl.c | 3 +--
>> 1 file changed, 1 insertion(+), 2 deletions(-)
>>
>> diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c
>> index a1e41d4..9f8b20b 100644
>> --- a/drivers/video/backlight/adp5520_bl.c
>> +++ b/drivers/video/backlight/adp5520_bl.c
>> @@ -143,11 +143,10 @@ static int adp5520_bl_setup(struct backlight_device *bl)
>> static ssize_t adp5520_show(struct device *dev, char *buf, int reg)
>> {
>> struct adp5520_bl *data = dev_get_drvdata(dev);
>> - int error;
>> uint8_t reg_val;
>>
>> mutex_lock(&data->lock);
>> - error = adp5520_read(data->master, reg, ®_val);
>> + adp5520_read(data->master, reg, ®_val);
>> mutex_unlock(&data->lock);
>
> Hi Devendra Naga,
>
> I also agree with Andrew Morton's opinion.
> It would be better to check return value from I2C read/write functions.
>
thanks, i will do and send a patch sooner or Andrew can merge his
patch with my Acked By.
> Best regards,
> Jingoo Han
>
>>
>> return sprintf(buf, "%u\n", reg_val);
>> --
>> 1.8.1.2
>
^ permalink raw reply
* Re: [PATCH 18/20] OMAPDSS: DSI: delay dispc initialization
From: Archit Taneja @ 2013-03-11 6:17 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: linux-omap, linux-fbdev
In-Reply-To: <1362743515-10152-19-git-send-email-tomi.valkeinen@ti.com>
On Friday 08 March 2013 05:21 PM, Tomi Valkeinen wrote:
> We currently setup both DSI and DISPC related things when the DSI bus is
> enabled. There's no need for DISPC related thing at that point, though,
> but only later when the video output is enabled.
>
> To make it possible to use the DSI bus before DISPC overlay manager is
> selected, this patch moves DSI's DISPC initialization to
> dsi_enable_video_output(), from omapdss_dsi_display_enable(). We also
> move the selection of DISPC's LCD clock to dsi_enable_video_output.
>
> This way there are no DISPC dependencies until the video output is
> enabled.
This is a good patch. I hope CDF also makes sure the Display controller
and DSI bus are made more independent in this manner.
One thing which we should eventually add is to ensure that
omap_dsi_update() for command mode panels is called only after
dsi_enable_video_output() is called. I think we manage this in our panel
driver, but maybe some sort of check could help there.
<snip>
Archit
^ permalink raw reply
* Re: [PATCH 1/3] video: backlight: adp5520: fix compiler warning in adp5520_show
From: devendra.aaru @ 2013-03-11 6:16 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1362771069-16345-1-git-send-email-devendra.aaru@gmail.com>
On Fri, Mar 8, 2013 at 4:01 PM, Andrew Morton <akpm@linux-foundation.org> wrote:
> On Fri, 8 Mar 2013 14:31:07 -0500 Devendra Naga <devendra.aaru@gmail.com> wrote:
>
>> while compiling with make W=1 (gcc gcc (GCC) 4.7.2 20121109 (Red Hat 4.7.2-8))
>>
>> found the following warning
>>
>> drivers/video/backlight/adp5520_bl.c: In function ___adp5520_show___:
>> drivers/video/backlight/adp5520_bl.c:146:6: warning: variable ___error___ set but not used [-Wunused-but-set-variable]
>>
>> fixed by removing the variable
>>
>> ...
>>
>> --- a/drivers/video/backlight/adp5520_bl.c
>> +++ b/drivers/video/backlight/adp5520_bl.c
>> @@ -143,11 +143,10 @@ static int adp5520_bl_setup(struct backlight_device *bl)
>> static ssize_t adp5520_show(struct device *dev, char *buf, int reg)
>> {
>> struct adp5520_bl *data = dev_get_drvdata(dev);
>> - int error;
>> uint8_t reg_val;
>>
>> mutex_lock(&data->lock);
>> - error = adp5520_read(data->master, reg, ®_val);
>> + adp5520_read(data->master, reg, ®_val);
>> mutex_unlock(&data->lock);
>>
>> return sprintf(buf, "%u\n", reg_val);
>
> We shouldn't just ignore the error; with the code as it stands, a
> adp5520_read() failure will result in the kernel displaying
> uninitialised garbage.
>
> So it would be better to propagate the adp5520_read() return value back
> to the caller if it's negative.
>
>
> (This assumes that the i2c layer returns a sane return value - if it
> does, that would make i2c pretty unique :( We could get paranoid and
> return a hard-wired -EIO, but it would be bad of us to overwrite things
> like -ENOMEM).
>
> So I'd suggest this:
>
> --- a/drivers/video/backlight/adp5520_bl.c~video-backlight-adp5520-fix-compiler-warning-in-adp5520_show
> +++ a/drivers/video/backlight/adp5520_bl.c
> @@ -143,13 +143,15 @@ static int adp5520_bl_setup(struct backl
> static ssize_t adp5520_show(struct device *dev, char *buf, int reg)
> {
> struct adp5520_bl *data = dev_get_drvdata(dev);
> - int error;
> + int ret;
> uint8_t reg_val;
>
> mutex_lock(&data->lock);
> - error = adp5520_read(data->master, reg, ®_val);
> + ret = adp5520_read(data->master, reg, ®_val);
> mutex_unlock(&data->lock);
>
> + if (ret < 0)
> + return ret;
> return sprintf(buf, "%u\n", reg_val);
> }
>
Thanks for the suggestion, i will do the same and i will send you a
patch sooner.
or you can merge your change with my Acked By too :).
> _
>
^ permalink raw reply
* Re: [PATCH 10/20] OMAPDSS: Resolve channels for outputs
From: Archit Taneja @ 2013-03-11 5:54 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: linux-omap, linux-fbdev
In-Reply-To: <1362743515-10152-11-git-send-email-tomi.valkeinen@ti.com>
On Friday 08 March 2013 05:21 PM, Tomi Valkeinen wrote:
> The DISPC channel used for each output is currently passed in panel
> platform data from the board files.
>
> To simplify this, and to make the panel drivers less dependent on OMAP,
> this patch changes omapdss to resolve the channel independently. The
> channel is resolved based on the OMAP version and, in case of DSI, the
> DSI module id.
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
> ---
> drivers/video/omap2/dss/dpi.c | 37 ++++++++++++++++++++++++++-----
> drivers/video/omap2/dss/dsi.c | 48 ++++++++++++++++++++++++++++++++++++++++
> drivers/video/omap2/dss/rfbi.c | 2 ++
> drivers/video/omap2/dss/sdi.c | 2 ++
> 4 files changed, 84 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
> index e282456..3261644 100644
> --- a/drivers/video/omap2/dss/dpi.c
> +++ b/drivers/video/omap2/dss/dpi.c
> @@ -396,12 +396,44 @@ static int __init dpi_verify_dsi_pll(struct platform_device *dsidev)
> return 0;
> }
>
> +/*
> + * Return a hardcoded channel for the DPI output. This should work for
> + * current use cases, but this can be later expanded to either resolve
> + * the channel in some more dynamic manner, or get the channel as a user
> + * parameter.
> + */
> +static enum omap_channel dpi_get_channel(void)
> +{
> + switch (omapdss_get_version()) {
> + case OMAPDSS_VER_OMAP24xx:
> + case OMAPDSS_VER_OMAP34xx_ES1:
> + case OMAPDSS_VER_OMAP34xx_ES3:
> + case OMAPDSS_VER_OMAP3630:
> + case OMAPDSS_VER_AM35xx:
> + return OMAP_DSS_CHANNEL_LCD;
> +
> + case OMAPDSS_VER_OMAP4430_ES1:
> + case OMAPDSS_VER_OMAP4430_ES2:
> + case OMAPDSS_VER_OMAP4:
> + return OMAP_DSS_CHANNEL_LCD2;
> +
> + case OMAPDSS_VER_OMAP5:
> + return OMAP_DSS_CHANNEL_LCD2;
> +
> + default:
> + DSSWARN("unsupported DSS version\n");
> + return OMAP_DSS_CHANNEL_LCD;
> + }
> +}
I had another comment for this patch. On OMAP5, it makes sense for us to
not use LCD2 as the recommended channel. LCD2_CLK's only source is
DSS_CLK from PRCM. So it's not a very flexible channel to use. We could
use LCD3 (at the cost of not using DSI2).
We also need to fix dpi_get_dsidev() for OMAP5. Currently, it assumes
that LCD2_CLK can be sourced from DSI2 PLL, we need to ensure DPI has a
dsidev only if it's LCD1 or LCD3.
Archit
> +
> static int __init dpi_init_display(struct omap_dss_device *dssdev)
> {
> struct platform_device *dsidev;
>
> DSSDBG("init_display\n");
>
> + dssdev->channel = dpi_get_channel();
> +
> if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) &&
> dpi.vdds_dsi_reg = NULL) {
> struct regulator *vdds_dsi;
> @@ -416,11 +448,6 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev)
> dpi.vdds_dsi_reg = vdds_dsi;
> }
>
> - /*
> - * XXX We shouldn't need dssdev->channel for this. The dsi pll clock
> - * source for DPI is SoC integration detail, not something that should
> - * be configured in the dssdev
> - */
> dsidev = dpi_get_dsidev(dssdev->channel);
>
> if (dsidev && dpi_verify_dsi_pll(dsidev)) {
> diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
> index 1a6ad6f..c39ca86 100644
> --- a/drivers/video/omap2/dss/dsi.c
> +++ b/drivers/video/omap2/dss/dsi.c
> @@ -4946,6 +4946,52 @@ void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev,
> }
> EXPORT_SYMBOL(omapdss_dsi_set_videomode_timings);
>
> +/*
> + * Return a hardcoded channel for the DSI output. This should work for
> + * current use cases, but this can be later expanded to either resolve
> + * the channel in some more dynamic manner, or get the channel as a user
> + * parameter.
> + */
> +static enum omap_channel dsi_get_channel(int module_id)
> +{
> + switch (omapdss_get_version()) {
> + case OMAPDSS_VER_OMAP24xx:
> + case OMAPDSS_VER_OMAP34xx_ES1:
> + case OMAPDSS_VER_OMAP34xx_ES3:
> + case OMAPDSS_VER_OMAP3630:
> + case OMAPDSS_VER_AM35xx:
> + return OMAP_DSS_CHANNEL_LCD;
> +
> + case OMAPDSS_VER_OMAP4430_ES1:
> + case OMAPDSS_VER_OMAP4430_ES2:
> + case OMAPDSS_VER_OMAP4:
> + switch (module_id) {
> + case 0:
> + return OMAP_DSS_CHANNEL_LCD;
> + case 1:
> + return OMAP_DSS_CHANNEL_LCD2;
> + default:
> + DSSWARN("unsupported module id\n");
> + return OMAP_DSS_CHANNEL_LCD;
> + }
> +
> + case OMAPDSS_VER_OMAP5:
> + switch (module_id) {
> + case 0:
> + return OMAP_DSS_CHANNEL_LCD;
> + case 1:
> + return OMAP_DSS_CHANNEL_LCD3;
> + default:
> + DSSWARN("unsupported module id\n");
> + return OMAP_DSS_CHANNEL_LCD;
> + }
> +
> + default:
> + DSSWARN("unsupported DSS version\n");
> + return OMAP_DSS_CHANNEL_LCD;
> + }
> +}
> +
> static int __init dsi_init_display(struct omap_dss_device *dssdev)
> {
> struct platform_device *dsidev > @@ -4954,6 +5000,8 @@ static int __init dsi_init_display(struct omap_dss_device *dssdev)
>
> DSSDBG("DSI init\n");
>
> + dssdev->channel = dsi_get_channel(dsi->module_id);
> +
> if (dsi->vdds_dsi_reg = NULL) {
> struct regulator *vdds_dsi;
>
> diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
> index a47a9e5..04c4ab6 100644
> --- a/drivers/video/omap2/dss/rfbi.c
> +++ b/drivers/video/omap2/dss/rfbi.c
> @@ -945,6 +945,8 @@ EXPORT_SYMBOL(omapdss_rfbi_display_disable);
>
> static int __init rfbi_init_display(struct omap_dss_device *dssdev)
> {
> + dssdev->channel = OMAP_DSS_CHANNEL_LCD;
> +
> rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
> return 0;
> }
> diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
> index 0802927..d24e971 100644
> --- a/drivers/video/omap2/dss/sdi.c
> +++ b/drivers/video/omap2/dss/sdi.c
> @@ -186,6 +186,8 @@ static int __init sdi_init_display(struct omap_dss_device *dssdev)
> {
> DSSDBG("SDI init\n");
>
> + dssdev->channel = OMAP_DSS_CHANNEL_LCD;
> +
> if (sdi.vdds_sdi_reg = NULL) {
> struct regulator *vdds_sdi;
>
>
^ permalink raw reply
* Re: [PATCH 10/20] OMAPDSS: Resolve channels for outputs
From: Archit Taneja @ 2013-03-11 5:47 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: linux-omap, linux-fbdev
In-Reply-To: <1362743515-10152-11-git-send-email-tomi.valkeinen@ti.com>
Hi,
On Friday 08 March 2013 05:21 PM, Tomi Valkeinen wrote:
> The DISPC channel used for each output is currently passed in panel
> platform data from the board files.
>
> To simplify this, and to make the panel drivers less dependent on OMAP,
> this patch changes omapdss to resolve the channel independently. The
> channel is resolved based on the OMAP version and, in case of DSI, the
> DSI module id.
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
> ---
> drivers/video/omap2/dss/dpi.c | 37 ++++++++++++++++++++++++++-----
> drivers/video/omap2/dss/dsi.c | 48 ++++++++++++++++++++++++++++++++++++++++
> drivers/video/omap2/dss/rfbi.c | 2 ++
> drivers/video/omap2/dss/sdi.c | 2 ++
> 4 files changed, 84 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
> index e282456..3261644 100644
> --- a/drivers/video/omap2/dss/dpi.c
> +++ b/drivers/video/omap2/dss/dpi.c
> @@ -396,12 +396,44 @@ static int __init dpi_verify_dsi_pll(struct platform_device *dsidev)
> return 0;
> }
>
> +/*
> + * Return a hardcoded channel for the DPI output. This should work for
> + * current use cases, but this can be later expanded to either resolve
> + * the channel in some more dynamic manner, or get the channel as a user
> + * parameter.
> + */
> +static enum omap_channel dpi_get_channel(void)
> +{
> + switch (omapdss_get_version()) {
> + case OMAPDSS_VER_OMAP24xx:
> + case OMAPDSS_VER_OMAP34xx_ES1:
> + case OMAPDSS_VER_OMAP34xx_ES3:
> + case OMAPDSS_VER_OMAP3630:
> + case OMAPDSS_VER_AM35xx:
> + return OMAP_DSS_CHANNEL_LCD;
> +
> + case OMAPDSS_VER_OMAP4430_ES1:
> + case OMAPDSS_VER_OMAP4430_ES2:
> + case OMAPDSS_VER_OMAP4:
> + return OMAP_DSS_CHANNEL_LCD2;
> +
> + case OMAPDSS_VER_OMAP5:
> + return OMAP_DSS_CHANNEL_LCD2;
> +
> + default:
> + DSSWARN("unsupported DSS version\n");
> + return OMAP_DSS_CHANNEL_LCD;
> + }
> +}
> +
> static int __init dpi_init_display(struct omap_dss_device *dssdev)
> {
> struct platform_device *dsidev;
>
> DSSDBG("init_display\n");
>
> + dssdev->channel = dpi_get_channel();
In patch 14 of the series, we remove these dssdev->channel assignments.
I don't see the point of adding them in this patch in the first place.
The dssdev->channel assignments will not be modified in this series, so
we don't need to worry about a kernel crash or something after this patch.
I feel this patch should only add the dpi_get_channel and
dsi_get_channel funcs.
> +
> if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) &&
> dpi.vdds_dsi_reg = NULL) {
> struct regulator *vdds_dsi;
> @@ -416,11 +448,6 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev)
> dpi.vdds_dsi_reg = vdds_dsi;
> }
>
> - /*
> - * XXX We shouldn't need dssdev->channel for this. The dsi pll clock
> - * source for DPI is SoC integration detail, not something that should
> - * be configured in the dssdev
> - */
> dsidev = dpi_get_dsidev(dssdev->channel);
>
> if (dsidev && dpi_verify_dsi_pll(dsidev)) {
> diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
> index 1a6ad6f..c39ca86 100644
> --- a/drivers/video/omap2/dss/dsi.c
> +++ b/drivers/video/omap2/dss/dsi.c
> @@ -4946,6 +4946,52 @@ void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev,
> }
> EXPORT_SYMBOL(omapdss_dsi_set_videomode_timings);
>
> +/*
> + * Return a hardcoded channel for the DSI output. This should work for
> + * current use cases, but this can be later expanded to either resolve
> + * the channel in some more dynamic manner, or get the channel as a user
> + * parameter.
> + */
> +static enum omap_channel dsi_get_channel(int module_id)
> +{
> + switch (omapdss_get_version()) {
> + case OMAPDSS_VER_OMAP24xx:
We should remove the above case so that we hit the default case and get
a warning about omap2 not having DSI.
> + case OMAPDSS_VER_OMAP34xx_ES1:
> + case OMAPDSS_VER_OMAP34xx_ES3:
> + case OMAPDSS_VER_OMAP3630:
> + case OMAPDSS_VER_AM35xx:
<snip>
Archit
^ permalink raw reply
* Re: [PATCH 1/3] video: backlight: adp5520: fix compiler warning in adp5520_show
From: Jingoo Han @ 2013-03-11 0:56 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1362771069-16345-1-git-send-email-devendra.aaru@gmail.com>
On Saturday, March 09, 2013 4:31 AM, Devendra Naga wrote:
>
> while compiling with make W=1 (gcc gcc (GCC) 4.7.2 20121109 (Red Hat 4.7.2-8))
>
> found the following warning
>
> drivers/video/backlight/adp5520_bl.c: In function ‘adp5520_show’:
> drivers/video/backlight/adp5520_bl.c:146:6: warning: variable ‘error’ set but not used [-Wunused-but-
> set-variable]
>
> fixed by removing the variable
>
> Cc: Jingoo Han <jg1.han@samsung.com>
> Cc: Michael Hennerich <michael.hennerich@analog.com>
> Cc: Richard Purdie <rpurdie@rpsys.net>
>
> Signed-off-by: Devendra Naga <devendra.aaru@gmail.com>
> ---
> drivers/video/backlight/adp5520_bl.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c
> index a1e41d4..9f8b20b 100644
> --- a/drivers/video/backlight/adp5520_bl.c
> +++ b/drivers/video/backlight/adp5520_bl.c
> @@ -143,11 +143,10 @@ static int adp5520_bl_setup(struct backlight_device *bl)
> static ssize_t adp5520_show(struct device *dev, char *buf, int reg)
> {
> struct adp5520_bl *data = dev_get_drvdata(dev);
> - int error;
> uint8_t reg_val;
>
> mutex_lock(&data->lock);
> - error = adp5520_read(data->master, reg, ®_val);
> + adp5520_read(data->master, reg, ®_val);
> mutex_unlock(&data->lock);
Hi Devendra Naga,
I also agree with Andrew Morton's opinion.
It would be better to check return value from I2C read/write functions.
Best regards,
Jingoo Han
>
> return sprintf(buf, "%u\n", reg_val);
> --
> 1.8.1.2
^ permalink raw reply
* RE: [PATCH 2/3] video: backlight: lp855x_bl: fix compiler warning in lp855x_probe
From: Kim, Milo @ 2013-03-10 23:04 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1362771069-16345-2-git-send-email-devendra.aaru@gmail.com>
PiB3aGlsZSBkb2luZyB3aXRoIG1ha2UgVz0xIGdjYyAoZ2NjIChHQ0MpIDQuNy4yIDIwMTIxMTA5
IChSZWQgSGF0IDQuNy4yLQ0KPiA4KSkNCj4gDQo+IGZvdW5kDQo+IA0KPiBkcml2ZXJzL3ZpZGVv
L2JhY2tsaWdodC9scDg1NXhfYmwuYzogSW4gZnVuY3Rpb24g4oCYbHA4NTV4X3Byb2Jl4oCZOg0K
PiBkcml2ZXJzL3ZpZGVvL2JhY2tsaWdodC9scDg1NXhfYmwuYzozNDI6MzU6IHdhcm5pbmc6IHZh
cmlhYmxlIOKAmG1vZGXigJkNCj4gc2V0IGJ1dCBub3QgdXNlZCBbLVd1bnVzZWQtYnV0LXNldC12
YXJpYWJsZV0NCj4gDQo+IGZpeGVkIGJ5IHJlbW92aW5nIGl0IGFzIHNpbmNlIGl0cyBub3QgdXNl
ZCBhbnl3aGVyZQ0KDQpBY2tlZC1ieTogTWlsbyBLaW0gPG1pbG8ua2ltQHRpLmNvbT4NCg0K
^ permalink raw reply
* [PATCH linux-next] mfd: max8925: max8925_backlight_probe: Silence 'statement with no effect' warning
From: Tim Gardner @ 2013-03-10 18:12 UTC (permalink / raw)
To: linux-kernel
Cc: Tim Gardner, Richard Purdie, Florian Tobias Schandinat,
linux-fbdev
Commit 47ec340cb8e232671e7c4a4689ff32c3bdf329da 'mfd: max8925: Support dt for backlight'
caused a gcc warning if CONFIG_OF is not defined:
drivers/video/backlight/max8925_bl.c: In function 'max8925_backlight_probe':
drivers/video/backlight/max8925_bl.c:177:3: warning: statement with no effect [-Wunused-value]
gcc version 4.6.3
Convert max8925_backlight_dt_init() to an 'inline void' since it is only
called from one place where the return code is ignored. Protect the
guts of the function with '#ifdef CONFIG_OF'.
Cc: Richard Purdie <rpurdie@rpsys.net>
Cc: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Cc: linux-fbdev@vger.kernel.org
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
---
drivers/video/backlight/max8925_bl.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c
index 5ca11b0..199f887 100644
--- a/drivers/video/backlight/max8925_bl.c
+++ b/drivers/video/backlight/max8925_bl.c
@@ -101,10 +101,10 @@ static const struct backlight_ops max8925_backlight_ops = {
.get_brightness = max8925_backlight_get_brightness,
};
-#ifdef CONFIG_OF
-static int max8925_backlight_dt_init(struct platform_device *pdev,
+static inline void max8925_backlight_dt_init(struct platform_device *pdev,
struct max8925_backlight_pdata *pdata)
{
+#ifdef CONFIG_OF
struct device_node *nproot = pdev->dev.parent->of_node, *np;
int dual_string;
@@ -118,11 +118,8 @@ static int max8925_backlight_dt_init(struct platform_device *pdev,
of_property_read_u32(np, "maxim,max8925-dual-string", &dual_string);
pdata->dual_string = dual_string;
- return 0;
-}
-#else
-#define max8925_backlight_dt_init(x, y) (-1)
#endif
+}
static int max8925_backlight_probe(struct platform_device *pdev)
{
--
1.7.9.5
^ permalink raw reply related
* [PATCH linux-next] intelfb: intelfbhw_mode_to_hw: Silence m1/m2 'may be used uninitialized' warnings
From: Tim Gardner @ 2013-03-10 17:53 UTC (permalink / raw)
To: linux-kernel
Cc: Tim Gardner, Maik Broemme, Florian Tobias Schandinat, linux-fbdev
drivers/video/intelfb/intelfbhw.c: In function 'intelfbhw_mode_to_hw':
drivers/video/intelfb/intelfbhw.c:1144:35: warning: 'm2' may be used uninitialized in this function [-Wuninitialized]
drivers/video/intelfb/intelfbhw.c:1145:13: warning: 'm1' may be used uninitialized in this function [-Wuninitialized]
gcc version 4.6.3
Cc: Maik Broemme <mbroemme@plusserver.de>
Cc: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Cc: linux-fbdev@vger.kernel.org
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
---
drivers/video/intelfb/intelfbhw.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index fbad61d..cb05307 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -935,7 +935,7 @@ static int splitp(int index, unsigned int p, unsigned int *retp1,
static int calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2,
u32 *retn, u32 *retp1, u32 *retp2, u32 *retclock)
{
- u32 m1, m2, n, p1, p2, n1, testm;
+ u32 m1 = 0, m2 = 0, n, p1, p2, n1, testm;
u32 f_vco, p, p_best = 0, m, f_out = 0;
u32 err_max, err_target, err_best = 10000000;
u32 n_best = 0, m_best = 0, f_best, f_err;
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3] video: Add Hyper-V Synthetic Video Frame Buffer Driver
From: Haiyang Zhang @ 2013-03-08 21:45 UTC (permalink / raw)
To: FlorianSchandinat, linux-fbdev
Cc: haiyangz, kys, olaf, jasowang, linux-kernel, devel
This is the driver for the Hyper-V Synthetic Video, which supports screen
resolution up to Full HD 1920x1080 on Windows Server 2012 host, and 1600x1200
on Windows Server 2008 R2 or earlier.
It also solves the double mouse cursor issue of the emulated video mode.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: K. Y. Srinivasan <kys@microsoft.com>
---
v3:
According to the comment from Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
moved pci ids back to the hyperv_fb.c, because it is the only driver using
them.
v2:
Made changes based on reviews from Olaf Hering <olaf@aepfle.de>, Geert
Uytterhoeven <geert@linux-m68k.org>.
Renamed the Kconfig string to FB_HYPERV. And, use KBUILD_MODNAME in two
additional places to keep consistency in naming.
Switched fb from system RAM to PCI mmio space, so the workaround for large
memory allocation is not necessary. The fb ops and screen refresh mechanism is
updated accordingly.
Added aperture setting so that VESA fb can be disabled automatically without
code change on the vesafb.c.
---
drivers/video/Kconfig | 9 +
drivers/video/Makefile | 1 +
drivers/video/hyperv_fb.c | 829 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/hyperv.h | 11 +
4 files changed, 850 insertions(+), 0 deletions(-)
create mode 100644 drivers/video/hyperv_fb.c
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 4c1546f..5d1a35e 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2451,6 +2451,15 @@ config FB_PUV3_UNIGFX
Choose this option if you want to use the Unigfx device as a
framebuffer device. Without the support of PCI & AGP.
+config FB_HYPERV
+ tristate "Microsoft Hyper-V Synthetic Video support"
+ depends on FB && HYPERV
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
+
source "drivers/video/omap/Kconfig"
source "drivers/video/omap2/Kconfig"
source "drivers/video/exynos/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 9df3873..97f7b6d 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -149,6 +149,7 @@ obj-$(CONFIG_FB_MSM) += msm/
obj-$(CONFIG_FB_NUC900) += nuc900fb.o
obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o
obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o
+obj-$(CONFIG_FB_HYPERV) += hyperv_fb.o
# Platform or fallback drivers go here
obj-$(CONFIG_FB_UVESA) += uvesafb.o
diff --git a/drivers/video/hyperv_fb.c b/drivers/video/hyperv_fb.c
new file mode 100644
index 0000000..ceb33b0
--- /dev/null
+++ b/drivers/video/hyperv_fb.c
@@ -0,0 +1,829 @@
+/*
+ * Copyright (c) 2012, Microsoft Corporation.
+ *
+ * Author:
+ * Haiyang Zhang <haiyangz@microsoft.com>
+ *
+ * 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 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/*
+ * Hyper-V Synthetic Video Frame Buffer Driver
+ *
+ * This is the driver for the Hyper-V Synthetic Video, which supports
+ * screen resolution up to Full HD 1920x1080 with 32 bit color on Windows
+ * Server 2012, and 1600x1200 with 16 bit color on Windows Server 2008 R2
+ * or earlier.
+ *
+ * It also solves the double mouse cursor issue of the emulated video mode.
+ *
+ * The default screen resolution is 1152x864, which may be changed by a
+ * kernel parameter:
+ * video=hyperv_fb:<width>x<height>
+ * For example: video=hyperv_fb:1280x1024
+ *
+ * Portrait orientation is also supported:
+ * For example: video=hyperv_fb:864x1152
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+
+#include <linux/hyperv.h>
+
+
+/* Hyper-V Synthetic Video Protocol definitions and structures */
+#define MAX_VMBUS_PKT_SIZE 0x4000
+
+#define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
+#define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)
+#define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2)
+
+#define SYNTHVID_DEPTH_WIN7 16
+#define SYNTHVID_DEPTH_WIN8 32
+
+#define SYNTHVID_FB_SIZE_WIN7 (4 * 1024 * 1024)
+#define SYNTHVID_WIDTH_MAX_WIN7 1600
+#define SYNTHVID_HEIGHT_MAX_WIN7 1200
+
+#define SYNTHVID_FB_SIZE_WIN8 (8 * 1024 * 1024)
+
+#define PCI_VENDOR_ID_MICROSOFT 0x1414
+#define PCI_DEVICE_ID_HYPERV_VIDEO 0x5353
+
+
+enum pipe_msg_type {
+ PIPE_MSG_INVALID,
+ PIPE_MSG_DATA,
+ PIPE_MSG_MAX
+};
+
+struct pipe_msg_hdr {
+ u32 type;
+ u32 size; /* size of message after this field */
+} __packed;
+
+
+enum synthvid_msg_type {
+ SYNTHVID_ERROR = 0,
+ SYNTHVID_VERSION_REQUEST = 1,
+ SYNTHVID_VERSION_RESPONSE = 2,
+ SYNTHVID_VRAM_LOCATION = 3,
+ SYNTHVID_VRAM_LOCATION_ACK = 4,
+ SYNTHVID_SITUATION_UPDATE = 5,
+ SYNTHVID_SITUATION_UPDATE_ACK = 6,
+ SYNTHVID_POINTER_POSITION = 7,
+ SYNTHVID_POINTER_SHAPE = 8,
+ SYNTHVID_FEATURE_CHANGE = 9,
+ SYNTHVID_DIRT = 10,
+
+ SYNTHVID_MAX = 11
+};
+
+struct synthvid_msg_hdr {
+ u32 type;
+ u32 size; /* size of this header + payload after this field*/
+} __packed;
+
+
+struct synthvid_version_req {
+ u32 version;
+} __packed;
+
+struct synthvid_version_resp {
+ u32 version;
+ u8 is_accepted;
+ u8 max_video_outputs;
+} __packed;
+
+struct synthvid_vram_location {
+ u64 user_ctx;
+ u8 is_vram_gpa_specified;
+ u64 vram_gpa;
+} __packed;
+
+struct synthvid_vram_location_ack {
+ u64 user_ctx;
+} __packed;
+
+struct video_output_situation {
+ u8 active;
+ u32 vram_offset;
+ u8 depth_bits;
+ u32 width_pixels;
+ u32 height_pixels;
+ u32 pitch_bytes;
+} __packed;
+
+struct synthvid_situation_update {
+ u64 user_ctx;
+ u8 video_output_count;
+ struct video_output_situation video_output[1];
+} __packed;
+
+struct synthvid_situation_update_ack {
+ u64 user_ctx;
+} __packed;
+
+struct synthvid_pointer_position {
+ u8 is_visible;
+ u8 video_output;
+ s32 image_x;
+ s32 image_y;
+} __packed;
+
+
+#define CURSOR_MAX_X 96
+#define CURSOR_MAX_Y 96
+#define CURSOR_ARGB_PIXEL_SIZE 4
+#define CURSOR_MAX_SIZE (CURSOR_MAX_X * CURSOR_MAX_Y * CURSOR_ARGB_PIXEL_SIZE)
+#define CURSOR_COMPLETE (-1)
+
+struct synthvid_pointer_shape {
+ u8 part_idx;
+ u8 is_argb;
+ u32 width; /* CURSOR_MAX_X at most */
+ u32 height; /* CURSOR_MAX_Y at most */
+ u32 hot_x; /* hotspot relative to upper-left of pointer image */
+ u32 hot_y;
+ u8 data[4];
+} __packed;
+
+struct synthvid_feature_change {
+ u8 is_dirt_needed;
+ u8 is_ptr_pos_needed;
+ u8 is_ptr_shape_needed;
+ u8 is_situ_needed;
+} __packed;
+
+struct rect {
+ s32 x1, y1; /* top left corner */
+ s32 x2, y2; /* bottom right corner, exclusive */
+} __packed;
+
+struct synthvid_dirt {
+ u8 video_output;
+ u8 dirt_count;
+ struct rect rect[1];
+} __packed;
+
+struct synthvid_msg {
+ struct pipe_msg_hdr pipe_hdr;
+ struct synthvid_msg_hdr vid_hdr;
+ union {
+ struct synthvid_version_req ver_req;
+ struct synthvid_version_resp ver_resp;
+ struct synthvid_vram_location vram;
+ struct synthvid_vram_location_ack vram_ack;
+ struct synthvid_situation_update situ;
+ struct synthvid_situation_update_ack situ_ack;
+ struct synthvid_pointer_position ptr_pos;
+ struct synthvid_pointer_shape ptr_shape;
+ struct synthvid_feature_change feature_chg;
+ struct synthvid_dirt dirt;
+ };
+} __packed;
+
+
+
+/* FB driver definitions and structures */
+#define HVFB_WIDTH 1152 /* default screen width */
+#define HVFB_HEIGHT 864 /* default screen height */
+#define HVFB_WIDTH_MIN 640
+#define HVFB_HEIGHT_MIN 480
+
+#define RING_BUFSIZE (256 * 1024)
+#define VSP_TIMEOUT (10 * HZ)
+#define HVFB_UPDATE_DELAY (HZ / 20)
+
+struct hvfb_par {
+ struct fb_info *info;
+ bool fb_ready; /* fb device is ready */
+ struct completion wait;
+ u32 synthvid_version;
+
+ struct delayed_work dwork;
+ bool update;
+
+ u32 pseudo_palette[16];
+ u8 init_buf[MAX_VMBUS_PKT_SIZE];
+ u8 recv_buf[MAX_VMBUS_PKT_SIZE];
+};
+
+static uint screen_width = HVFB_WIDTH;
+static uint screen_height = HVFB_HEIGHT;
+static uint screen_depth;
+static uint screen_fb_size;
+
+/* Send message to Hyper-V host */
+static inline int synthvid_send(struct hv_device *hdev,
+ struct synthvid_msg *msg)
+{
+ static atomic64_t request_id = ATOMIC64_INIT(0);
+ int ret;
+
+ msg->pipe_hdr.type = PIPE_MSG_DATA;
+ msg->pipe_hdr.size = msg->vid_hdr.size;
+
+ ret = vmbus_sendpacket(hdev->channel, msg,
+ msg->vid_hdr.size + sizeof(struct pipe_msg_hdr),
+ atomic64_inc_return(&request_id),
+ VM_PKT_DATA_INBAND, 0);
+
+ if (ret)
+ pr_err("Unable to send packet via vmbus\n");
+
+ return ret;
+}
+
+
+/* Send screen resolution info to host */
+static int synthvid_send_situ(struct hv_device *hdev)
+{
+ struct fb_info *info = hv_get_drvdata(hdev);
+ struct synthvid_msg msg;
+
+ if (!info)
+ return -ENODEV;
+
+ memset(&msg, 0, sizeof(struct synthvid_msg));
+
+ msg.vid_hdr.type = SYNTHVID_SITUATION_UPDATE;
+ msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+ sizeof(struct synthvid_situation_update);
+ msg.situ.user_ctx = 0;
+ msg.situ.video_output_count = 1;
+ msg.situ.video_output[0].active = 1;
+ msg.situ.video_output[0].vram_offset = 0;
+ msg.situ.video_output[0].depth_bits = info->var.bits_per_pixel;
+ msg.situ.video_output[0].width_pixels = info->var.xres;
+ msg.situ.video_output[0].height_pixels = info->var.yres;
+ msg.situ.video_output[0].pitch_bytes = info->fix.line_length;
+
+ synthvid_send(hdev, &msg);
+
+ return 0;
+}
+
+/* Send mouse pointer info to host */
+static int synthvid_send_ptr(struct hv_device *hdev)
+{
+ struct synthvid_msg msg;
+
+ memset(&msg, 0, sizeof(struct synthvid_msg));
+ msg.vid_hdr.type = SYNTHVID_POINTER_POSITION;
+ msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+ sizeof(struct synthvid_pointer_position);
+ msg.ptr_pos.is_visible = 1;
+ msg.ptr_pos.video_output = 0;
+ msg.ptr_pos.image_x = 0;
+ msg.ptr_pos.image_y = 0;
+ synthvid_send(hdev, &msg);
+
+ memset(&msg, 0, sizeof(struct synthvid_msg));
+ msg.vid_hdr.type = SYNTHVID_POINTER_SHAPE;
+ msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+ sizeof(struct synthvid_pointer_shape);
+ msg.ptr_shape.part_idx = CURSOR_COMPLETE;
+ msg.ptr_shape.is_argb = 1;
+ msg.ptr_shape.width = 1;
+ msg.ptr_shape.height = 1;
+ msg.ptr_shape.hot_x = 0;
+ msg.ptr_shape.hot_y = 0;
+ msg.ptr_shape.data[0] = 0;
+ msg.ptr_shape.data[1] = 1;
+ msg.ptr_shape.data[2] = 1;
+ msg.ptr_shape.data[3] = 1;
+ synthvid_send(hdev, &msg);
+
+ return 0;
+}
+
+/* Send updated screen area (dirty rectangle) location to host */
+static int synthvid_update(struct fb_info *info)
+{
+ struct hv_device *hdev = device_to_hv_device(info->device);
+ struct synthvid_msg msg;
+
+ memset(&msg, 0, sizeof(struct synthvid_msg));
+
+ msg.vid_hdr.type = SYNTHVID_DIRT;
+ msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+ sizeof(struct synthvid_dirt);
+ msg.dirt.video_output = 0;
+ msg.dirt.dirt_count = 1;
+ msg.dirt.rect[0].x1 = 0;
+ msg.dirt.rect[0].y1 = 0;
+ msg.dirt.rect[0].x2 = info->var.xres;
+ msg.dirt.rect[0].y2 = info->var.yres;
+
+ synthvid_send(hdev, &msg);
+
+ return 0;
+}
+
+
+/*
+ * Actions on received messages from host:
+ * Complete the wait event.
+ * Or, reply with screen and cursor info.
+ */
+static void synthvid_recv_sub(struct hv_device *hdev)
+{
+ struct fb_info *info = hv_get_drvdata(hdev);
+ struct hvfb_par *par;
+ struct synthvid_msg *msg;
+
+ if (!info)
+ return;
+
+ par = info->par;
+ msg = (struct synthvid_msg *)par->recv_buf;
+
+ /* Complete the wait event */
+ if (msg->vid_hdr.type = SYNTHVID_VERSION_RESPONSE ||
+ msg->vid_hdr.type = SYNTHVID_VRAM_LOCATION_ACK) {
+ memcpy(par->init_buf, msg, MAX_VMBUS_PKT_SIZE);
+ complete(&par->wait);
+ return;
+ }
+
+ /* Reply with screen and cursor info */
+ if (msg->vid_hdr.type = SYNTHVID_FEATURE_CHANGE) {
+ if (par->fb_ready) {
+ synthvid_send_ptr(hdev);
+ synthvid_send_situ(hdev);
+ }
+
+ par->update = msg->feature_chg.is_dirt_needed;
+ if (par->update)
+ schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
+ }
+}
+
+/* Receive callback for messages from the host */
+static void synthvid_receive(void *ctx)
+{
+ struct hv_device *hdev = ctx;
+ struct fb_info *info = hv_get_drvdata(hdev);
+ struct hvfb_par *par;
+ struct synthvid_msg *recv_buf;
+ u32 bytes_recvd;
+ u64 req_id;
+ int ret;
+
+ if (!info)
+ return;
+
+ par = info->par;
+ recv_buf = (struct synthvid_msg *)par->recv_buf;
+
+ do {
+ ret = vmbus_recvpacket(hdev->channel, recv_buf,
+ MAX_VMBUS_PKT_SIZE,
+ &bytes_recvd, &req_id);
+ if (bytes_recvd > 0 &&
+ recv_buf->pipe_hdr.type = PIPE_MSG_DATA)
+ synthvid_recv_sub(hdev);
+ } while (bytes_recvd > 0 && ret = 0);
+}
+
+/* Check synthetic video protocol version with the host */
+static int synthvid_negotiate_ver(struct hv_device *hdev, u32 ver)
+{
+ struct fb_info *info = hv_get_drvdata(hdev);
+ struct hvfb_par *par = info->par;
+ struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
+ int t, ret = 0;
+
+ memset(msg, 0, sizeof(struct synthvid_msg));
+ msg->vid_hdr.type = SYNTHVID_VERSION_REQUEST;
+ msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+ sizeof(struct synthvid_version_req);
+ msg->ver_req.version = ver;
+ synthvid_send(hdev, msg);
+
+ t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT);
+ if (!t) {
+ pr_err("Time out on waiting version response\n");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+ if (!msg->ver_resp.is_accepted) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ par->synthvid_version = ver;
+
+out:
+ return ret;
+}
+
+/* Connect to VSP (Virtual Service Provider) on host */
+static int synthvid_connect_vsp(struct hv_device *hdev)
+{
+ struct fb_info *info = hv_get_drvdata(hdev);
+ struct hvfb_par *par = info->par;
+ int ret;
+
+ ret = vmbus_open(hdev->channel, RING_BUFSIZE, RING_BUFSIZE,
+ NULL, 0, synthvid_receive, hdev);
+ if (ret) {
+ pr_err("Unable to open vmbus channel\n");
+ return ret;
+ }
+
+ /* Negotiate the protocol version with host */
+ if (vmbus_proto_version = VERSION_WS2008 ||
+ vmbus_proto_version = VERSION_WIN7)
+ ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN7);
+ else
+ ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN8);
+
+ if (ret) {
+ pr_err("Synthetic video device version not accepted\n");
+ goto error;
+ }
+
+ if (par->synthvid_version = SYNTHVID_VERSION_WIN7) {
+ screen_depth = SYNTHVID_DEPTH_WIN7;
+ screen_fb_size = SYNTHVID_FB_SIZE_WIN7;
+ } else {
+ screen_depth = SYNTHVID_DEPTH_WIN8;
+ screen_fb_size = SYNTHVID_FB_SIZE_WIN8;
+ }
+
+ return 0;
+
+error:
+ vmbus_close(hdev->channel);
+ return ret;
+}
+
+/* Send VRAM and Situation messages to the host */
+static int synthvid_send_config(struct hv_device *hdev)
+{
+ struct fb_info *info = hv_get_drvdata(hdev);
+ struct hvfb_par *par = info->par;
+ struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
+ int t, ret = 0;
+
+ /* Send VRAM location */
+ memset(msg, 0, sizeof(struct synthvid_msg));
+ msg->vid_hdr.type = SYNTHVID_VRAM_LOCATION;
+ msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+ sizeof(struct synthvid_vram_location);
+ msg->vram.user_ctx = msg->vram.vram_gpa = info->fix.smem_start;
+ msg->vram.is_vram_gpa_specified = 1;
+ synthvid_send(hdev, msg);
+
+ t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT);
+ if (!t) {
+ pr_err("Time out on waiting vram location ack\n");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+ if (msg->vram_ack.user_ctx != info->fix.smem_start) {
+ pr_err("Unable to set VRAM location\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* Send pointer and situation update */
+ synthvid_send_ptr(hdev);
+ synthvid_send_situ(hdev);
+
+out:
+ return ret;
+}
+
+
+/*
+ * Delayed work callback:
+ * It is called at HVFB_UPDATE_DELAY or longer time interval to process
+ * screen updates. It is re-scheduled if further update is necessary.
+ */
+static void hvfb_update_work(struct work_struct *w)
+{
+ struct hvfb_par *par = container_of(w, struct hvfb_par, dwork.work);
+ struct fb_info *info = par->info;
+
+ if (par->fb_ready)
+ synthvid_update(info);
+
+ if (par->update)
+ schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
+}
+
+
+/* Framebuffer operation handlers */
+
+static int hvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ if (var->xres < HVFB_WIDTH_MIN || var->yres < HVFB_HEIGHT_MIN ||
+ var->xres > screen_width || var->yres > screen_height ||
+ var->bits_per_pixel != screen_depth)
+ return -EINVAL;
+
+ var->xres_virtual = var->xres;
+ var->yres_virtual = var->yres;
+
+ return 0;
+}
+
+static int hvfb_set_par(struct fb_info *info)
+{
+ struct hv_device *hdev = device_to_hv_device(info->device);
+
+ return synthvid_send_situ(hdev);
+}
+
+
+static inline u32 chan_to_field(u32 chan, struct fb_bitfield *bf)
+{
+ return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
+}
+
+static int hvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp, struct fb_info *info)
+{
+ u32 *pal = info->pseudo_palette;
+
+ if (regno > 15)
+ return -EINVAL;
+
+ pal[regno] = chan_to_field(red, &info->var.red)
+ | chan_to_field(green, &info->var.green)
+ | chan_to_field(blue, &info->var.blue)
+ | chan_to_field(transp, &info->var.transp);
+
+ return 0;
+}
+
+
+static struct fb_ops hvfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = hvfb_check_var,
+ .fb_set_par = hvfb_set_par,
+ .fb_setcolreg = hvfb_setcolreg,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+
+/* Get options from kernel paramenter "video=" */
+static void hvfb_get_option(struct fb_info *info)
+{
+ struct hvfb_par *par = info->par;
+ char *opt = NULL, *p;
+ uint x = 0, y = 0;
+
+ if (fb_get_options(KBUILD_MODNAME, &opt) || !opt || !*opt)
+ return;
+
+ p = strsep(&opt, "x");
+ if (!*p || kstrtouint(p, 0, &x) ||
+ !opt || !*opt || kstrtouint(opt, 0, &y)) {
+ pr_err("Screen option is invalid: skipped\n");
+ return;
+ }
+
+ if (x < HVFB_WIDTH_MIN || y < HVFB_HEIGHT_MIN ||
+ (par->synthvid_version = SYNTHVID_VERSION_WIN8 &&
+ x * y * screen_depth / 8 > SYNTHVID_FB_SIZE_WIN8) ||
+ (par->synthvid_version = SYNTHVID_VERSION_WIN7 &&
+ (x > SYNTHVID_WIDTH_MAX_WIN7 || y > SYNTHVID_HEIGHT_MAX_WIN7))) {
+ pr_err("Screen resolution option is out of range: skipped\n");
+ return;
+ }
+
+ screen_width = x;
+ screen_height = y;
+ return;
+}
+
+
+/* Get framebuffer memory from Hyper-V video pci space */
+static int hvfb_getmem(struct fb_info *info)
+{
+ struct pci_dev *pdev;
+ ulong fb_phys;
+ void *fb_virt;
+
+ pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT,
+ PCI_DEVICE_ID_HYPERV_VIDEO, NULL);
+ if (!pdev) {
+ pr_err("Unable to find PCI Hyper-V video\n");
+ return -ENODEV;
+ }
+
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
+ pci_resource_len(pdev, 0) < screen_fb_size)
+ goto err1;
+
+ fb_phys = pci_resource_end(pdev, 0) - screen_fb_size + 1;
+ if (!request_mem_region(fb_phys, screen_fb_size, KBUILD_MODNAME))
+ goto err1;
+
+ fb_virt = ioremap(fb_phys, screen_fb_size);
+ if (!fb_virt)
+ goto err2;
+
+ info->apertures = alloc_apertures(1);
+ if (!info->apertures)
+ goto err3;
+
+ info->apertures->ranges[0].base = pci_resource_start(pdev, 0);
+ info->apertures->ranges[0].size = pci_resource_len(pdev, 0);
+ info->fix.smem_start = fb_phys;
+ info->fix.smem_len = screen_fb_size;
+ info->screen_base = fb_virt;
+ info->screen_size = screen_fb_size;
+
+ pci_dev_put(pdev);
+ return 0;
+
+err3:
+ iounmap(fb_virt);
+err2:
+ release_mem_region(fb_phys, screen_fb_size);
+err1:
+ pci_dev_put(pdev);
+ return -ENOMEM;
+}
+
+/* Release the framebuffer */
+static void hvfb_putmem(struct fb_info *info)
+{
+ iounmap(info->screen_base);
+ release_mem_region(info->fix.smem_start, screen_fb_size);
+}
+
+
+static int hvfb_probe(struct hv_device *hdev,
+ const struct hv_vmbus_device_id *dev_id)
+{
+ struct fb_info *info;
+ struct hvfb_par *par;
+ int ret;
+
+ info = framebuffer_alloc(sizeof(struct hvfb_par), &hdev->device);
+ if (!info) {
+ pr_err("No memory for framebuffer info\n");
+ return -ENOMEM;
+ }
+
+ par = info->par;
+ par->info = info;
+ par->fb_ready = false;
+ init_completion(&par->wait);
+ INIT_DELAYED_WORK(&par->dwork, hvfb_update_work);
+
+ /* Connect to VSP */
+ hv_set_drvdata(hdev, info);
+ ret = synthvid_connect_vsp(hdev);
+ if (ret) {
+ pr_err("Unable to connect to VSP\n");
+ goto error1;
+ }
+
+ ret = hvfb_getmem(info);
+ if (ret) {
+ pr_err("No memory for framebuffer\n");
+ goto error2;
+ }
+
+ hvfb_get_option(info);
+ pr_info("Screen resolution: %dx%d, Color depth: %d\n",
+ screen_width, screen_height, screen_depth);
+
+
+ /* Set up fb_info */
+ info->flags = FBINFO_DEFAULT;
+
+ info->var.xres_virtual = info->var.xres = screen_width;
+ info->var.yres_virtual = info->var.yres = screen_height;
+ info->var.bits_per_pixel = screen_depth;
+
+ if (info->var.bits_per_pixel = 16) {
+ info->var.red = (struct fb_bitfield){11, 5, 0};
+ info->var.green = (struct fb_bitfield){5, 6, 0};
+ info->var.blue = (struct fb_bitfield){0, 5, 0};
+ info->var.transp = (struct fb_bitfield){0, 0, 0};
+ } else {
+ info->var.red = (struct fb_bitfield){16, 8, 0};
+ info->var.green = (struct fb_bitfield){8, 8, 0};
+ info->var.blue = (struct fb_bitfield){0, 8, 0};
+ info->var.transp = (struct fb_bitfield){24, 8, 0};
+ }
+
+ info->var.activate = FB_ACTIVATE_NOW;
+ info->var.height = -1;
+ info->var.width = -1;
+ info->var.vmode = FB_VMODE_NONINTERLACED;
+
+ strcpy(info->fix.id, KBUILD_MODNAME);
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ info->fix.line_length = screen_width * screen_depth / 8;
+ info->fix.accel = FB_ACCEL_NONE;
+
+ info->fbops = &hvfb_ops;
+ info->pseudo_palette = par->pseudo_palette;
+
+ /* Send config to host */
+ ret = synthvid_send_config(hdev);
+ if (ret)
+ goto error;
+
+ ret = register_framebuffer(info);
+ if (ret) {
+ pr_err("Unable to register framebuffer\n");
+ goto error;
+ }
+
+ par->fb_ready = true;
+
+ return 0;
+
+error:
+ hvfb_putmem(info);
+error2:
+ vmbus_close(hdev->channel);
+error1:
+ cancel_delayed_work_sync(&par->dwork);
+ hv_set_drvdata(hdev, NULL);
+ framebuffer_release(info);
+ return ret;
+}
+
+
+static int hvfb_remove(struct hv_device *hdev)
+{
+ struct fb_info *info = hv_get_drvdata(hdev);
+ struct hvfb_par *par = info->par;
+
+ par->update = false;
+ par->fb_ready = false;
+
+ unregister_framebuffer(info);
+ cancel_delayed_work_sync(&par->dwork);
+
+ vmbus_close(hdev->channel);
+ hv_set_drvdata(hdev, NULL);
+
+ hvfb_putmem(info);
+ framebuffer_release(info);
+
+ return 0;
+}
+
+
+static const struct hv_vmbus_device_id id_table[] = {
+ /* Synthetic Video Device GUID */
+ {HV_SYNTHVID_GUID},
+ {}
+};
+
+MODULE_DEVICE_TABLE(vmbus, id_table);
+
+static struct hv_driver hvfb_drv = {
+ .name = KBUILD_MODNAME,
+ .id_table = id_table,
+ .probe = hvfb_probe,
+ .remove = hvfb_remove,
+};
+
+
+static int __init hvfb_drv_init(void)
+{
+ return vmbus_driver_register(&hvfb_drv);
+}
+
+static void __exit hvfb_drv_exit(void)
+{
+ vmbus_driver_unregister(&hvfb_drv);
+}
+
+module_init(hvfb_drv_init);
+module_exit(hvfb_drv_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION(HV_DRV_VERSION);
+MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic Video Frame Buffer Driver");
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index df77ba9..a460ee4 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -1253,6 +1253,17 @@ void vmbus_driver_unregister(struct hv_driver *hv_driver);
}
/*
+ * Synthetic Video GUID
+ * {DA0A7802-E377-4aac-8E77-0558EB1073F8}
+ */
+#define HV_SYNTHVID_GUID \
+ .guid = { \
+ 0x02, 0x78, 0x0a, 0xda, 0x77, 0xe3, 0xac, 0x4a, \
+ 0x8e, 0x77, 0x05, 0x58, 0xeb, 0x10, 0x73, 0xf8 \
+ }
+
+
+/*
* Common header for Hyper-V ICs
*/
--
1.7.4.1
^ permalink raw reply related
* Re: [PATCH 1/3] video: backlight: adp5520: fix compiler warning in adp5520_show
From: Andrew Morton @ 2013-03-08 21:01 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1362771069-16345-1-git-send-email-devendra.aaru@gmail.com>
On Fri, 8 Mar 2013 14:31:07 -0500 Devendra Naga <devendra.aaru@gmail.com> wrote:
> while compiling with make W=1 (gcc gcc (GCC) 4.7.2 20121109 (Red Hat 4.7.2-8))
>
> found the following warning
>
> drivers/video/backlight/adp5520_bl.c: In function ___adp5520_show___:
> drivers/video/backlight/adp5520_bl.c:146:6: warning: variable ___error___ set but not used [-Wunused-but-set-variable]
>
> fixed by removing the variable
>
> ...
>
> --- a/drivers/video/backlight/adp5520_bl.c
> +++ b/drivers/video/backlight/adp5520_bl.c
> @@ -143,11 +143,10 @@ static int adp5520_bl_setup(struct backlight_device *bl)
> static ssize_t adp5520_show(struct device *dev, char *buf, int reg)
> {
> struct adp5520_bl *data = dev_get_drvdata(dev);
> - int error;
> uint8_t reg_val;
>
> mutex_lock(&data->lock);
> - error = adp5520_read(data->master, reg, ®_val);
> + adp5520_read(data->master, reg, ®_val);
> mutex_unlock(&data->lock);
>
> return sprintf(buf, "%u\n", reg_val);
We shouldn't just ignore the error; with the code as it stands, a
adp5520_read() failure will result in the kernel displaying
uninitialised garbage.
So it would be better to propagate the adp5520_read() return value back
to the caller if it's negative.
(This assumes that the i2c layer returns a sane return value - if it
does, that would make i2c pretty unique :( We could get paranoid and
return a hard-wired -EIO, but it would be bad of us to overwrite things
like -ENOMEM).
So I'd suggest this:
--- a/drivers/video/backlight/adp5520_bl.c~video-backlight-adp5520-fix-compiler-warning-in-adp5520_show
+++ a/drivers/video/backlight/adp5520_bl.c
@@ -143,13 +143,15 @@ static int adp5520_bl_setup(struct backl
static ssize_t adp5520_show(struct device *dev, char *buf, int reg)
{
struct adp5520_bl *data = dev_get_drvdata(dev);
- int error;
+ int ret;
uint8_t reg_val;
mutex_lock(&data->lock);
- error = adp5520_read(data->master, reg, ®_val);
+ ret = adp5520_read(data->master, reg, ®_val);
mutex_unlock(&data->lock);
+ if (ret < 0)
+ return ret;
return sprintf(buf, "%u\n", reg_val);
}
_
^ permalink raw reply
* [PATCH 3/3] drivers: video: console: fbcon_cw: fix compiler warning in cw_update_attr
From: Devendra Naga @ 2013-03-08 19:31 UTC (permalink / raw)
To: linux-fbdev
with make W=1
saw
drivers/video/console/fbcon_cw.c: In function ‘cw_update_attr’:
drivers/video/console/fbcon_cw.c:30:8: warning: variable ‘t’ set but not used [-Wunused-but-set-variable]
fixed by removing as since its used nowhere
Cc: Antonino A. Daplas <adaplas@gmail.com>
Signed-off-by: Devendra Naga <devendra.aaru@gmail.com>
---
drivers/video/console/fbcon_cw.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c
index 6a73782..a93670e 100644
--- a/drivers/video/console/fbcon_cw.c
+++ b/drivers/video/console/fbcon_cw.c
@@ -27,7 +27,7 @@ static void cw_update_attr(u8 *dst, u8 *src, int attribute,
{
int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;
int width = (vc->vc_font.height + 7) >> 3;
- u8 c, t = 0, msk = ~(0xff >> offset);
+ u8 c, msk = ~(0xff >> offset);
for (i = 0; i < vc->vc_font.width; i++) {
for (j = 0; j < width; j++) {
@@ -40,7 +40,6 @@ static void cw_update_attr(u8 *dst, u8 *src, int attribute,
c = ~c;
src++;
*dst++ = c;
- t = c;
}
}
}
--
1.8.1.2
^ permalink raw reply related
* [PATCH 2/3] video: backlight: lp855x_bl: fix compiler warning in lp855x_probe
From: Devendra Naga @ 2013-03-08 19:31 UTC (permalink / raw)
To: linux-fbdev
while doing with make W=1 gcc (gcc (GCC) 4.7.2 20121109 (Red Hat 4.7.2-8))
found
drivers/video/backlight/lp855x_bl.c: In function ‘lp855x_probe’:
drivers/video/backlight/lp855x_bl.c:342:35: warning: variable ‘mode’ set but not used [-Wunused-but-set-variable]
fixed by removing it as since its not used anywhere
Cc: Milo(Woogyom) Kim <milo.kim@ti.com>
Cc: Jingoo Han <jg1.han@samsung.com>
Signed-off-by: Devendra Naga <devendra.aaru@gmail.com>
---
drivers/video/backlight/lp855x_bl.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c
index 7ae9ae6..20111ef 100644
--- a/drivers/video/backlight/lp855x_bl.c
+++ b/drivers/video/backlight/lp855x_bl.c
@@ -339,7 +339,6 @@ static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
{
struct lp855x *lp;
struct lp855x_platform_data *pdata = cl->dev.platform_data;
- enum lp855x_brightness_ctrl_mode mode;
int ret;
if (!pdata) {
@@ -354,7 +353,6 @@ static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
if (!lp)
return -ENOMEM;
- mode = pdata->mode;
lp->client = cl;
lp->dev = &cl->dev;
lp->pdata = pdata;
--
1.8.1.2
^ permalink raw reply related
* [PATCH 1/3] video: backlight: adp5520: fix compiler warning in adp5520_show
From: Devendra Naga @ 2013-03-08 19:31 UTC (permalink / raw)
To: linux-fbdev
while compiling with make W=1 (gcc gcc (GCC) 4.7.2 20121109 (Red Hat 4.7.2-8))
found the following warning
drivers/video/backlight/adp5520_bl.c: In function ‘adp5520_show’:
drivers/video/backlight/adp5520_bl.c:146:6: warning: variable ‘error’ set but not used [-Wunused-but-set-variable]
fixed by removing the variable
Cc: Jingoo Han <jg1.han@samsung.com>
Cc: Michael Hennerich <michael.hennerich@analog.com>
Cc: Richard Purdie <rpurdie@rpsys.net>
Signed-off-by: Devendra Naga <devendra.aaru@gmail.com>
---
drivers/video/backlight/adp5520_bl.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c
index a1e41d4..9f8b20b 100644
--- a/drivers/video/backlight/adp5520_bl.c
+++ b/drivers/video/backlight/adp5520_bl.c
@@ -143,11 +143,10 @@ static int adp5520_bl_setup(struct backlight_device *bl)
static ssize_t adp5520_show(struct device *dev, char *buf, int reg)
{
struct adp5520_bl *data = dev_get_drvdata(dev);
- int error;
uint8_t reg_val;
mutex_lock(&data->lock);
- error = adp5520_read(data->master, reg, ®_val);
+ adp5520_read(data->master, reg, ®_val);
mutex_unlock(&data->lock);
return sprintf(buf, "%u\n", reg_val);
--
1.8.1.2
^ permalink raw reply related
* [PATCH 14/14] OMAPDSS: remove dsi videomode from dssdev
From: Tomi Valkeinen @ 2013-03-08 11:52 UTC (permalink / raw)
To: Archit Taneja, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1362743569-10289-1-git-send-email-tomi.valkeinen@ti.com>
DSI videomode is no longer needed in the omap_dss_device, so remove it.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
include/video/omapdss.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index cbaf60f..8979086 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -631,7 +631,6 @@ struct omap_dss_device {
enum omap_dss_dsi_pixel_format dsi_pix_fmt;
enum omap_dss_dsi_mode dsi_mode;
- struct omap_dss_dsi_videomode_timings dsi_vm_timings;
} panel;
struct {
--
1.7.10.4
^ permalink raw reply related
* [PATCH 13/14] OMAPDSS: remove unused old clock calculation code
From: Tomi Valkeinen @ 2013-03-08 11:52 UTC (permalink / raw)
To: Archit Taneja, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1362743569-10289-1-git-send-email-tomi.valkeinen@ti.com>
Now that the old clock calculation code is no longer used, we can remove
it from the driver.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dispc.c | 48 ------
drivers/video/omap2/dss/dsi.c | 317 ---------------------------------------
drivers/video/omap2/dss/dss.c | 115 --------------
drivers/video/omap2/dss/dss.h | 15 --
4 files changed, 495 deletions(-)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index cd54e8f..8cfa27b 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -3311,54 +3311,6 @@ static void dispc_dump_regs(struct seq_file *s)
#undef DUMPREG
}
-/* with fck as input clock rate, find dispc dividers that produce req_pck */
-void dispc_find_clk_divs(unsigned long req_pck, unsigned long fck,
- struct dispc_clock_info *cinfo)
-{
- u16 pcd_min, pcd_max;
- unsigned long best_pck;
- u16 best_ld, cur_ld;
- u16 best_pd, cur_pd;
-
- pcd_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD);
- pcd_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD);
-
- best_pck = 0;
- best_ld = 0;
- best_pd = 0;
-
- for (cur_ld = 1; cur_ld <= 255; ++cur_ld) {
- unsigned long lck = fck / cur_ld;
-
- for (cur_pd = pcd_min; cur_pd <= pcd_max; ++cur_pd) {
- unsigned long pck = lck / cur_pd;
- long old_delta = abs(best_pck - req_pck);
- long new_delta = abs(pck - req_pck);
-
- if (best_pck = 0 || new_delta < old_delta) {
- best_pck = pck;
- best_ld = cur_ld;
- best_pd = cur_pd;
-
- if (pck = req_pck)
- goto found;
- }
-
- if (pck < req_pck)
- break;
- }
-
- if (lck / pcd_min < req_pck)
- break;
- }
-
-found:
- cinfo->lck_div = best_ld;
- cinfo->pck_div = best_pd;
- cinfo->lck = fck / cinfo->lck_div;
- cinfo->pck = cinfo->lck / cinfo->pck_div;
-}
-
/* calculate clock rates using dividers in cinfo */
int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
struct dispc_clock_info *cinfo)
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 593022b..46e3d47 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -1430,190 +1430,6 @@ static int dsi_calc_clock_rates(struct platform_device *dsidev,
return 0;
}
-int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev,
- unsigned long req_pck, struct dsi_clock_info *dsi_cinfo,
- struct dispc_clock_info *dispc_cinfo)
-{
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct dsi_clock_info cur, best;
- struct dispc_clock_info best_dispc;
- int min_fck_per_pck;
- int match = 0;
- unsigned long dss_sys_clk, max_dss_fck;
-
- dss_sys_clk = clk_get_rate(dsi->sys_clk);
-
- max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
-
- if (req_pck = dsi->cache_req_pck &&
- dsi->cache_cinfo.clkin = dss_sys_clk) {
- DSSDBG("DSI clock info found from cache\n");
- *dsi_cinfo = dsi->cache_cinfo;
- dispc_find_clk_divs(req_pck, dsi_cinfo->dsi_pll_hsdiv_dispc_clk,
- dispc_cinfo);
- return 0;
- }
-
- min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
-
- if (min_fck_per_pck &&
- req_pck * min_fck_per_pck > max_dss_fck) {
- DSSERR("Requested pixel clock not possible with the current "
- "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
- "the constraint off.\n");
- min_fck_per_pck = 0;
- }
-
- DSSDBG("dsi_pll_calc\n");
-
-retry:
- memset(&best, 0, sizeof(best));
- memset(&best_dispc, 0, sizeof(best_dispc));
-
- memset(&cur, 0, sizeof(cur));
- cur.clkin = dss_sys_clk;
-
- /* 0.75MHz < Fint = clkin / regn < 2.1MHz */
- /* To reduce PLL lock time, keep Fint high (around 2 MHz) */
- for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) {
- cur.fint = cur.clkin / cur.regn;
-
- if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min)
- continue;
-
- /* DSIPHY(MHz) = (2 * regm / regn) * clkin */
- for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) {
- unsigned long a, b;
-
- a = 2 * cur.regm * (cur.clkin/1000);
- b = cur.regn;
- cur.clkin4ddr = a / b * 1000;
-
- if (cur.clkin4ddr > 1800 * 1000 * 1000)
- break;
-
- /* dsi_pll_hsdiv_dispc_clk(MHz) - * DSIPHY(MHz) / regm_dispc < 173MHz/186Mhz */
- for (cur.regm_dispc = 1; cur.regm_dispc <
- dsi->regm_dispc_max; ++cur.regm_dispc) {
- struct dispc_clock_info cur_dispc;
- cur.dsi_pll_hsdiv_dispc_clk - cur.clkin4ddr / cur.regm_dispc;
-
- if (cur.regm_dispc > 1 &&
- cur.regm_dispc % 2 != 0 &&
- req_pck >= 1000000)
- continue;
-
- /* this will narrow down the search a bit,
- * but still give pixclocks below what was
- * requested */
- if (cur.dsi_pll_hsdiv_dispc_clk < req_pck)
- break;
-
- if (cur.dsi_pll_hsdiv_dispc_clk > max_dss_fck)
- continue;
-
- if (min_fck_per_pck &&
- cur.dsi_pll_hsdiv_dispc_clk <
- req_pck * min_fck_per_pck)
- continue;
-
- match = 1;
-
- dispc_find_clk_divs(req_pck,
- cur.dsi_pll_hsdiv_dispc_clk,
- &cur_dispc);
-
- if (abs(cur_dispc.pck - req_pck) <
- abs(best_dispc.pck - req_pck)) {
- best = cur;
- best_dispc = cur_dispc;
-
- if (cur_dispc.pck = req_pck)
- goto found;
- }
- }
- }
- }
-found:
- if (!match) {
- if (min_fck_per_pck) {
- DSSERR("Could not find suitable clock settings.\n"
- "Turning FCK/PCK constraint off and"
- "trying again.\n");
- min_fck_per_pck = 0;
- goto retry;
- }
-
- DSSERR("Could not find suitable clock settings.\n");
-
- return -EINVAL;
- }
-
- /* dsi_pll_hsdiv_dsi_clk (regm_dsi) is not used */
- best.regm_dsi = 0;
- best.dsi_pll_hsdiv_dsi_clk = 0;
-
- if (dsi_cinfo)
- *dsi_cinfo = best;
- if (dispc_cinfo)
- *dispc_cinfo = best_dispc;
-
- dsi->cache_req_pck = req_pck;
- dsi->cache_clk_freq = 0;
- dsi->cache_cinfo = best;
-
- return 0;
-}
-
-static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev,
- unsigned long req_clkin4ddr, struct dsi_clock_info *cinfo)
-{
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct dsi_clock_info cur, best;
-
- DSSDBG("dsi_pll_calc_ddrfreq\n");
-
- memset(&best, 0, sizeof(best));
- memset(&cur, 0, sizeof(cur));
-
- cur.clkin = clk_get_rate(dsi->sys_clk);
-
- for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) {
- cur.fint = cur.clkin / cur.regn;
-
- if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min)
- continue;
-
- /* DSIPHY(MHz) = (2 * regm / regn) * clkin */
- for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) {
- unsigned long a, b;
-
- a = 2 * cur.regm * (cur.clkin/1000);
- b = cur.regn;
- cur.clkin4ddr = a / b * 1000;
-
- if (cur.clkin4ddr > 1800 * 1000 * 1000)
- break;
-
- if (abs(cur.clkin4ddr - req_clkin4ddr) <
- abs(best.clkin4ddr - req_clkin4ddr)) {
- best = cur;
- DSSDBG("best %ld\n", best.clkin4ddr);
- }
-
- if (cur.clkin4ddr = req_clkin4ddr)
- goto found;
- }
- }
-found:
- if (cinfo)
- *cinfo = best;
-
- return 0;
-}
-
static void dsi_pll_calc_dsi_fck(struct dsi_clock_info *cinfo)
{
unsigned long max_dsi_fck;
@@ -1624,90 +1440,6 @@ static void dsi_pll_calc_dsi_fck(struct dsi_clock_info *cinfo)
cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi;
}
-static int dsi_pll_calc_dispc_fck(struct platform_device *dsidev,
- unsigned long req_pck, struct dsi_clock_info *cinfo,
- struct dispc_clock_info *dispc_cinfo)
-{
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- unsigned regm_dispc, best_regm_dispc;
- unsigned long dispc_clk, best_dispc_clk;
- int min_fck_per_pck;
- unsigned long max_dss_fck;
- struct dispc_clock_info best_dispc;
- bool match;
-
- max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
-
- min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
-
- if (min_fck_per_pck &&
- req_pck * min_fck_per_pck > max_dss_fck) {
- DSSERR("Requested pixel clock not possible with the current "
- "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
- "the constraint off.\n");
- min_fck_per_pck = 0;
- }
-
-retry:
- best_regm_dispc = 0;
- best_dispc_clk = 0;
- memset(&best_dispc, 0, sizeof(best_dispc));
- match = false;
-
- for (regm_dispc = 1; regm_dispc < dsi->regm_dispc_max; ++regm_dispc) {
- struct dispc_clock_info cur_dispc;
-
- dispc_clk = cinfo->clkin4ddr / regm_dispc;
-
- /* this will narrow down the search a bit,
- * but still give pixclocks below what was
- * requested */
- if (dispc_clk < req_pck)
- break;
-
- if (dispc_clk > max_dss_fck)
- continue;
-
- if (min_fck_per_pck && dispc_clk < req_pck * min_fck_per_pck)
- continue;
-
- match = true;
-
- dispc_find_clk_divs(req_pck, dispc_clk, &cur_dispc);
-
- if (abs(cur_dispc.pck - req_pck) <
- abs(best_dispc.pck - req_pck)) {
- best_regm_dispc = regm_dispc;
- best_dispc_clk = dispc_clk;
- best_dispc = cur_dispc;
-
- if (cur_dispc.pck = req_pck)
- goto found;
- }
- }
-
- if (!match) {
- if (min_fck_per_pck) {
- DSSERR("Could not find suitable clock settings.\n"
- "Turning FCK/PCK constraint off and"
- "trying again.\n");
- min_fck_per_pck = 0;
- goto retry;
- }
-
- DSSERR("Could not find suitable clock settings.\n");
-
- return -EINVAL;
- }
-found:
- cinfo->regm_dispc = best_regm_dispc;
- cinfo->dsi_pll_hsdiv_dispc_clk = best_dispc_clk;
-
- *dispc_cinfo = best_dispc;
-
- return 0;
-}
-
int dsi_pll_set_clock_div(struct platform_device *dsidev,
struct dsi_clock_info *cinfo)
{
@@ -4384,55 +4116,6 @@ int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
}
EXPORT_SYMBOL(omapdss_dsi_configure_pins);
-static int dsi_set_clocks(struct omap_dss_device *dssdev,
- unsigned long ddr_clk, unsigned long lp_clk)
-{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct dsi_clock_info cinfo;
- struct dispc_clock_info dispc_cinfo;
- unsigned lp_clk_div;
- unsigned long dsi_fclk;
- int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
- unsigned long pck;
- int r;
-
- DSSDBG("Setting DSI clocks: ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk);
-
- /* Calculate PLL output clock */
- r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk * 4, &cinfo);
- if (r)
- goto err;
-
- /* Calculate PLL's DSI clock */
- dsi_pll_calc_dsi_fck(&cinfo);
-
- /* Calculate PLL's DISPC clock and pck & lck divs */
- pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp;
- DSSDBG("finding dispc dividers for pck %lu\n", pck);
- r = dsi_pll_calc_dispc_fck(dsidev, pck, &cinfo, &dispc_cinfo);
- if (r)
- goto err;
-
- /* Calculate LP clock */
- dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk;
- lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2);
-
- dsi->user_dsi_cinfo.regn = cinfo.regn;
- dsi->user_dsi_cinfo.regm = cinfo.regm;
- dsi->user_dsi_cinfo.regm_dispc = cinfo.regm_dispc;
- dsi->user_dsi_cinfo.regm_dsi = cinfo.regm_dsi;
-
- dsi->user_dsi_cinfo.lp_clk_div = lp_clk_div;
-
- dsi->user_dispc_cinfo.lck_div = dispc_cinfo.lck_div;
- dsi->user_dispc_cinfo.pck_div = dispc_cinfo.pck_div;
-
- return 0;
-err:
- return r;
-}
-
int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 21a3dc8..ee288f0 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -578,121 +578,6 @@ static int dss_setup_default_clock(void)
return 0;
}
-int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
- struct dispc_clock_info *dispc_cinfo)
-{
- unsigned long prate;
- struct dss_clock_info best_dss;
- struct dispc_clock_info best_dispc;
-
- unsigned long fck, max_dss_fck;
-
- u16 fck_div;
-
- int match = 0;
- int min_fck_per_pck;
-
- prate = dss_get_dpll4_rate();
-
- max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
-
- fck = clk_get_rate(dss.dss_clk);
- if (req_pck = dss.cache_req_pck && prate = dss.cache_prate &&
- dss.cache_dss_cinfo.fck = fck) {
- DSSDBG("dispc clock info found from cache.\n");
- *dss_cinfo = dss.cache_dss_cinfo;
- *dispc_cinfo = dss.cache_dispc_cinfo;
- return 0;
- }
-
- min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
-
- if (min_fck_per_pck &&
- req_pck * min_fck_per_pck > max_dss_fck) {
- DSSERR("Requested pixel clock not possible with the current "
- "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
- "the constraint off.\n");
- min_fck_per_pck = 0;
- }
-
-retry:
- memset(&best_dss, 0, sizeof(best_dss));
- memset(&best_dispc, 0, sizeof(best_dispc));
-
- if (dss.dpll4_m4_ck = NULL) {
- struct dispc_clock_info cur_dispc;
- /* XXX can we change the clock on omap2? */
- fck = clk_get_rate(dss.dss_clk);
- fck_div = 1;
-
- dispc_find_clk_divs(req_pck, fck, &cur_dispc);
- match = 1;
-
- best_dss.fck = fck;
- best_dss.fck_div = fck_div;
-
- best_dispc = cur_dispc;
-
- goto found;
- } else {
- for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) {
- struct dispc_clock_info cur_dispc;
-
- fck = prate / fck_div * dss.feat->dss_fck_multiplier;
-
- if (fck > max_dss_fck)
- continue;
-
- if (min_fck_per_pck &&
- fck < req_pck * min_fck_per_pck)
- continue;
-
- match = 1;
-
- dispc_find_clk_divs(req_pck, fck, &cur_dispc);
-
- if (abs(cur_dispc.pck - req_pck) <
- abs(best_dispc.pck - req_pck)) {
-
- best_dss.fck = fck;
- best_dss.fck_div = fck_div;
-
- best_dispc = cur_dispc;
-
- if (cur_dispc.pck = req_pck)
- goto found;
- }
- }
- }
-
-found:
- if (!match) {
- if (min_fck_per_pck) {
- DSSERR("Could not find suitable clock settings.\n"
- "Turning FCK/PCK constraint off and"
- "trying again.\n");
- min_fck_per_pck = 0;
- goto retry;
- }
-
- DSSERR("Could not find suitable clock settings.\n");
-
- return -EINVAL;
- }
-
- if (dss_cinfo)
- *dss_cinfo = best_dss;
- if (dispc_cinfo)
- *dispc_cinfo = best_dispc;
-
- dss.cache_req_pck = req_pck;
- dss.cache_prate = prate;
- dss.cache_dss_cinfo = best_dss;
- dss.cache_dispc_cinfo = best_dispc;
-
- return 0;
-}
-
void dss_set_venc_output(enum omap_dss_venc_type type)
{
int l = 0;
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index dde6cc1..faaf358 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -268,8 +268,6 @@ void dss_set_dac_pwrdn_bgz(bool enable);
unsigned long dss_get_dpll4_rate(void);
int dss_calc_clock_rates(struct dss_clock_info *cinfo);
int dss_set_clock_div(struct dss_clock_info *cinfo);
-int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
- struct dispc_clock_info *dispc_cinfo);
typedef bool (*dss_div_calc_func)(int fckd, unsigned long fck, void *data);
bool dss_div_calc(unsigned long fck_min, dss_div_calc_func func, void *data);
@@ -310,9 +308,6 @@ bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
int dsi_pll_set_clock_div(struct platform_device *dsidev,
struct dsi_clock_info *cinfo);
-int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev,
- unsigned long req_pck, struct dsi_clock_info *cinfo,
- struct dispc_clock_info *dispc_cinfo);
int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
bool enable_hsdiv);
void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
@@ -343,14 +338,6 @@ static inline int dsi_pll_set_clock_div(struct platform_device *dsidev,
WARN("%s: DSI not compiled in\n", __func__);
return -ENODEV;
}
-static inline int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev,
- unsigned long req_pck,
- struct dsi_clock_info *dsi_cinfo,
- struct dispc_clock_info *dispc_cinfo)
-{
- WARN("%s: DSI not compiled in\n", __func__);
- return -ENODEV;
-}
static inline int dsi_pll_init(struct platform_device *dsidev,
bool enable_hsclk, bool enable_hsdiv)
{
@@ -400,8 +387,6 @@ bool dispc_div_calc(unsigned long dispc,
bool dispc_mgr_timings_ok(enum omap_channel channel,
const struct omap_video_timings *timings);
unsigned long dispc_fclk_rate(void);
-void dispc_find_clk_divs(unsigned long req_pck, unsigned long fck,
- struct dispc_clock_info *cinfo);
int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
struct dispc_clock_info *cinfo);
--
1.7.10.4
^ permalink raw reply related
* [PATCH 12/14] OMAPDSS: DSI: use new clock calculation code
From: Tomi Valkeinen @ 2013-03-08 11:52 UTC (permalink / raw)
To: Archit Taneja, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1362743569-10289-1-git-send-email-tomi.valkeinen@ti.com>
Use the new clock calculation code in the DSI driver.
The new code does not need DSI video mode parameters from the panel
driver, like the old code does. Instead the new code is given the normal
video timings, and a few DSI parameters, which are used to create DSI
video timings.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/displays/panel-taal.c | 7 +-
drivers/video/omap2/dss/dsi.c | 504 ++++++++++++++++++++++++++++-
include/video/omapdss.h | 20 +-
3 files changed, 513 insertions(+), 18 deletions(-)
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index eb86cba..2fc923d 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -787,6 +787,7 @@ static int taal_probe(struct omap_dss_device *dssdev)
dssdev->panel.timings.x_res = 864;
dssdev->panel.timings.y_res = 480;
+ dssdev->panel.timings.pixel_clock = DIV_ROUND_UP(864 * 480 * 60, 1000);
dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888;
dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
@@ -923,8 +924,10 @@ static int taal_power_on(struct omap_dss_device *dssdev)
.mode = OMAP_DSS_DSI_CMD_MODE,
.pixel_format = OMAP_DSS_DSI_FMT_RGB888,
.timings = &dssdev->panel.timings,
- .hs_clk = 216000000,
- .lp_clk = 10000000,
+ .hs_clk_min = 150000000,
+ .hs_clk_max = 300000000,
+ .lp_clk_min = 7000000,
+ .lp_clk_max = 10000000,
};
r = omapdss_dsi_configure_pins(dssdev, &td->pin_config);
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index c8d5574..593022b 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -255,6 +255,24 @@ struct dsi_isr_tables {
struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS];
};
+struct dsi_clk_calc_ctx {
+ struct platform_device *dsidev;
+
+ /* inputs */
+
+ const struct omap_dss_dsi_config *config;
+
+ unsigned long req_pck_min, req_pck_nom, req_pck_max;
+
+ /* outputs */
+
+ struct dsi_clock_info dsi_cinfo;
+ struct dispc_clock_info dispc_cinfo;
+
+ struct omap_video_timings dispc_vm;
+ struct omap_dss_dsi_videomode_timings dsi_vm;
+};
+
struct dsi_data {
struct platform_device *pdev;
void __iomem *base;
@@ -1201,6 +1219,25 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
return r;
}
+static int dsi_lp_clock_calc(struct dsi_clock_info *cinfo,
+ unsigned long lp_clk_min, unsigned long lp_clk_max)
+{
+ unsigned long dsi_fclk = cinfo->dsi_pll_hsdiv_dsi_clk;
+ unsigned lp_clk_div;
+ unsigned long lp_clk;
+
+ lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk_max * 2);
+ lp_clk = dsi_fclk / 2 / lp_clk_div;
+
+ if (lp_clk < lp_clk_min || lp_clk > lp_clk_max)
+ return -EINVAL;
+
+ cinfo->lp_clk_div = lp_clk_div;
+ cinfo->lp_clk = lp_clk;
+
+ return 0;
+}
+
static int dsi_set_lp_clk_divisor(struct platform_device *dsidev)
{
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
@@ -1577,8 +1614,7 @@ found:
return 0;
}
-static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev,
- struct dsi_clock_info *cinfo)
+static void dsi_pll_calc_dsi_fck(struct dsi_clock_info *cinfo)
{
unsigned long max_dsi_fck;
@@ -4369,7 +4405,7 @@ static int dsi_set_clocks(struct omap_dss_device *dssdev,
goto err;
/* Calculate PLL's DSI clock */
- dsi_pll_calc_dsi_fck(dsidev, &cinfo);
+ dsi_pll_calc_dsi_fck(&cinfo);
/* Calculate PLL's DISPC clock and pck & lck divs */
pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp;
@@ -4693,13 +4729,6 @@ static int dsi_display_init_dispc(struct platform_device *dsidev,
OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC);
if (dsi->mode = OMAP_DSS_DSI_CMD_MODE) {
- dsi->timings.hsw = 1;
- dsi->timings.hfp = 1;
- dsi->timings.hbp = 1;
- dsi->timings.vsw = 1;
- dsi->timings.vfp = 0;
- dsi->timings.vbp = 0;
-
r = dss_mgr_register_framedone_handler(mgr,
dsi_framedone_irq_callback, dsidev);
if (r) {
@@ -4941,24 +4970,473 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
}
EXPORT_SYMBOL(omapdss_dsi_enable_te);
+#ifdef PRINT_VERBOSE_VM_TIMINGS
+static void print_dsi_vm(const char *str,
+ const struct omap_dss_dsi_videomode_timings *t)
+{
+ unsigned long byteclk = t->hsclk / 4;
+ int bl, wc, pps, tot;
+
+ wc = DIV_ROUND_UP(t->hact * t->bitspp, 8);
+ pps = DIV_ROUND_UP(wc + 6, t->ndl); /* pixel packet size */
+ bl = t->hss + t->hsa + t->hse + t->hbp + t->hfp;
+ tot = bl + pps;
+
+#define TO_DSI_T(x) ((u32)div64_u64((u64)x * 1000000000llu, byteclk))
+
+ pr_debug("%s bck %lu, %u/%u/%u/%u/%u/%u = %u+%u = %u, "
+ "%u/%u/%u/%u/%u/%u = %u + %u = %u\n",
+ str,
+ byteclk,
+ t->hss, t->hsa, t->hse, t->hbp, pps, t->hfp,
+ bl, pps, tot,
+ TO_DSI_T(t->hss),
+ TO_DSI_T(t->hsa),
+ TO_DSI_T(t->hse),
+ TO_DSI_T(t->hbp),
+ TO_DSI_T(pps),
+ TO_DSI_T(t->hfp),
+
+ TO_DSI_T(bl),
+ TO_DSI_T(pps),
+
+ TO_DSI_T(tot));
+#undef TO_DSI_T
+}
+
+static void print_dispc_vm(const char *str, const struct omap_video_timings *t)
+{
+ unsigned long pck = t->pixel_clock * 1000;
+ int hact, bl, tot;
+
+ hact = t->x_res;
+ bl = t->hsw + t->hbp + t->hfp;
+ tot = hact + bl;
+
+#define TO_DISPC_T(x) ((u32)div64_u64((u64)x * 1000000000llu, pck))
+
+ pr_debug("%s pck %lu, %u/%u/%u/%u = %u+%u = %u, "
+ "%u/%u/%u/%u = %u + %u = %u\n",
+ str,
+ pck,
+ t->hsw, t->hbp, hact, t->hfp,
+ bl, hact, tot,
+ TO_DISPC_T(t->hsw),
+ TO_DISPC_T(t->hbp),
+ TO_DISPC_T(hact),
+ TO_DISPC_T(t->hfp),
+ TO_DISPC_T(bl),
+ TO_DISPC_T(hact),
+ TO_DISPC_T(tot));
+#undef TO_DISPC_T
+}
+
+/* note: this is not quite accurate */
+static void print_dsi_dispc_vm(const char *str,
+ const struct omap_dss_dsi_videomode_timings *t)
+{
+ struct omap_video_timings vm = { 0 };
+ unsigned long byteclk = t->hsclk / 4;
+ unsigned long pck;
+ u64 dsi_tput;
+ int dsi_hact, dsi_htot;
+
+ dsi_tput = (u64)byteclk * t->ndl * 8;
+ pck = (u32)div64_u64(dsi_tput, t->bitspp);
+ dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(t->hact * t->bitspp, 8) + 6, t->ndl);
+ dsi_htot = t->hss + t->hsa + t->hse + t->hbp + dsi_hact + t->hfp;
+
+ vm.pixel_clock = pck / 1000;
+ vm.hsw = div64_u64((u64)(t->hsa + t->hse) * pck, byteclk);
+ vm.hbp = div64_u64((u64)t->hbp * pck, byteclk);
+ vm.hfp = div64_u64((u64)t->hfp * pck, byteclk);
+ vm.x_res = t->hact;
+
+ print_dispc_vm(str, &vm);
+}
+#endif /* PRINT_VERBOSE_VM_TIMINGS */
+
+static bool dsi_cm_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
+ unsigned long pck, void *data)
+{
+ struct dsi_clk_calc_ctx *ctx = data;
+ struct omap_video_timings *t = &ctx->dispc_vm;
+
+ ctx->dispc_cinfo.lck_div = lckd;
+ ctx->dispc_cinfo.pck_div = pckd;
+ ctx->dispc_cinfo.lck = lck;
+ ctx->dispc_cinfo.pck = pck;
+
+ *t = *ctx->config->timings;
+ t->pixel_clock = pck / 1000;
+ t->x_res = ctx->config->timings->x_res;
+ t->y_res = ctx->config->timings->y_res;
+ t->hsw = t->hfp = t->hbp = t->vsw = 1;
+ t->vfp = t->vbp = 0;
+
+ return true;
+}
+
+static bool dsi_cm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
+ void *data)
+{
+ struct dsi_clk_calc_ctx *ctx = data;
+
+ ctx->dsi_cinfo.regm_dispc = regm_dispc;
+ ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
+
+ return dispc_div_calc(dispc, ctx->req_pck_min, ctx->req_pck_max,
+ dsi_cm_calc_dispc_cb, ctx);
+}
+
+static bool dsi_cm_calc_pll_cb(int regn, int regm, unsigned long fint,
+ unsigned long pll, void *data)
+{
+ struct dsi_clk_calc_ctx *ctx = data;
+
+ ctx->dsi_cinfo.regn = regn;
+ ctx->dsi_cinfo.regm = regm;
+ ctx->dsi_cinfo.fint = fint;
+ ctx->dsi_cinfo.clkin4ddr = pll;
+
+ return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min,
+ dsi_cm_calc_hsdiv_cb, ctx);
+}
+
+static bool dsi_cm_calc(struct dsi_data *dsi,
+ const struct omap_dss_dsi_config *cfg,
+ struct dsi_clk_calc_ctx *ctx)
+{
+ unsigned long clkin;
+ int bitspp, ndl;
+ unsigned long pll_min, pll_max;
+ unsigned long pck, txbyteclk;
+
+ clkin = clk_get_rate(dsi->sys_clk);
+ bitspp = dsi_get_pixel_size(cfg->pixel_format);
+ ndl = dsi->num_lanes_used - 1;
+
+ /*
+ * Here we should calculate minimum txbyteclk to be able to send the
+ * frame in time, and also to handle TE. That's not very simple, though,
+ * especially as we go to LP between each pixel packet due to HW
+ * "feature". So let's just estimate very roughly and multiply by 1.5.
+ */
+ pck = cfg->timings->pixel_clock * 1000;
+ pck = pck * 3 / 2;
+ txbyteclk = pck * bitspp / 8 / ndl;
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->dsidev = dsi->pdev;
+ ctx->config = cfg;
+ ctx->req_pck_min = pck;
+ ctx->req_pck_nom = pck;
+ ctx->req_pck_max = pck * 3 / 2;
+ ctx->dsi_cinfo.clkin = clkin;
+
+ pll_min = max(cfg->hs_clk_min * 4, txbyteclk * 4 * 4);
+ pll_max = cfg->hs_clk_max * 4;
+
+ return dsi_pll_calc(dsi->pdev, clkin,
+ pll_min, pll_max,
+ dsi_cm_calc_pll_cb, ctx);
+}
+
+static bool dsi_vm_calc_blanking(struct dsi_clk_calc_ctx *ctx)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(ctx->dsidev);
+ const struct omap_dss_dsi_config *cfg = ctx->config;
+ int bitspp = dsi_get_pixel_size(cfg->pixel_format);
+ int ndl = dsi->num_lanes_used - 1;
+ unsigned long hsclk = ctx->dsi_cinfo.clkin4ddr / 4;
+ unsigned long byteclk = hsclk / 4;
+
+ unsigned long dispc_pck, req_pck_min, req_pck_nom, req_pck_max;
+ int xres;
+ int panel_htot, panel_hbl; /* pixels */
+ int dispc_htot, dispc_hbl; /* pixels */
+ int dsi_htot, dsi_hact, dsi_hbl, hss, hse; /* byteclks */
+ const struct omap_video_timings *req_vm;
+ struct omap_video_timings *dispc_vm;
+ struct omap_dss_dsi_videomode_timings *dsi_vm;
+ u64 dsi_tput, dispc_tput;
+
+ dsi_tput = (u64)byteclk * ndl * 8;
+
+ req_vm = cfg->timings;
+ req_pck_min = ctx->req_pck_min;
+ req_pck_max = ctx->req_pck_max;
+ req_pck_nom = ctx->req_pck_nom;
+
+ dispc_pck = ctx->dispc_cinfo.pck;
+ dispc_tput = (u64)dispc_pck * bitspp;
+
+ xres = req_vm->x_res;
+
+ panel_hbl = req_vm->hfp + req_vm->hbp + req_vm->hsw;
+ panel_htot = xres + panel_hbl;
+
+ dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(xres * bitspp, 8) + 6, ndl);
+
+ /*
+ * When there are no line buffers, DISPC and DSI must have the
+ * same tput. Otherwise DISPC tput needs to be higher than DSI's.
+ */
+ if (dsi->line_buffer_size < xres * bitspp / 8) {
+ if (dispc_tput != dsi_tput)
+ return false;
+ } else {
+ if (dispc_tput < dsi_tput)
+ return false;
+ }
+
+ /* DSI tput must be over the min requirement */
+ if (dsi_tput < (u64)bitspp * req_pck_min)
+ return false;
+
+ /* When non-burst mode, DSI tput must be below max requirement. */
+ if (cfg->trans_mode != OMAP_DSS_DSI_BURST_MODE) {
+ if (dsi_tput > (u64)bitspp * req_pck_max)
+ return false;
+ }
+
+ hss = DIV_ROUND_UP(4, ndl);
+
+ if (cfg->trans_mode = OMAP_DSS_DSI_PULSE_MODE) {
+ if (ndl = 3 && req_vm->hsw = 0)
+ hse = 1;
+ else
+ hse = DIV_ROUND_UP(4, ndl);
+ } else {
+ hse = 0;
+ }
+
+ /* DSI htot to match the panel's nominal pck */
+ dsi_htot = div64_u64((u64)panel_htot * byteclk, req_pck_nom);
+
+ /* fail if there would be no time for blanking */
+ if (dsi_htot < hss + hse + dsi_hact)
+ return false;
+
+ /* total DSI blanking needed to achieve panel's TL */
+ dsi_hbl = dsi_htot - dsi_hact;
+
+ /* DISPC htot to match the DSI TL */
+ dispc_htot = div64_u64((u64)dsi_htot * dispc_pck, byteclk);
+
+ /* verify that the DSI and DISPC TLs are the same */
+ if ((u64)dsi_htot * dispc_pck != (u64)dispc_htot * byteclk)
+ return false;
+
+ dispc_hbl = dispc_htot - xres;
+
+ /* setup DSI videomode */
+
+ dsi_vm = &ctx->dsi_vm;
+ memset(dsi_vm, 0, sizeof(*dsi_vm));
+
+ dsi_vm->hsclk = hsclk;
+
+ dsi_vm->ndl = ndl;
+ dsi_vm->bitspp = bitspp;
+ dsi_vm->hact = xres;
+ dsi_vm->vact = req_vm->y_res;
+
+ dsi_vm->hss = hss;
+ if (cfg->trans_mode != OMAP_DSS_DSI_PULSE_MODE)
+ dsi_vm->hsa = 0;
+ else if (ndl = 3 && req_vm->hsw = 0)
+ dsi_vm->hsa = 0;
+ else
+ dsi_vm->hsa = div64_u64((u64)req_vm->hsw * byteclk, req_pck_nom)
+ - hse;
+
+ dsi_vm->hse = hse;
+ dsi_vm->hbp = div64_u64((u64)req_vm->hbp * byteclk, req_pck_nom);
+ dsi_vm->hfp = dsi_hbl - (hss + dsi_vm->hsa + hse + dsi_vm->hbp);
+
+ dsi_vm->vsa = req_vm->vsw;
+ dsi_vm->vbp = req_vm->vbp;
+ dsi_vm->vfp = req_vm->vfp;
+
+ dsi_vm->trans_mode = cfg->trans_mode;
+
+ dsi_vm->blanking_mode = 0;
+ dsi_vm->hsa_blanking_mode = 1;
+ dsi_vm->hfp_blanking_mode = 1;
+ dsi_vm->hbp_blanking_mode = 1;
+
+ dsi_vm->ddr_clk_always_on = cfg->ddr_clk_always_on;
+ dsi_vm->window_sync = 4;
+
+ /* setup DISPC videomode */
+
+ dispc_vm = &ctx->dispc_vm;
+ *dispc_vm = *req_vm;
+ dispc_vm->pixel_clock = dispc_pck / 1000;
+
+ if (cfg->trans_mode = OMAP_DSS_DSI_PULSE_MODE)
+ dispc_vm->hsw = div64_u64((u64)req_vm->hsw * dispc_pck,
+ req_pck_nom);
+ else
+ dispc_vm->hsw = 1;
+ dispc_vm->hbp = div64_u64((u64)req_vm->hbp * dispc_pck, req_pck_nom);
+ dispc_vm->hfp = dispc_hbl - dispc_vm->hsw - dispc_vm->hbp;
+
+ return true;
+}
+
+
+static bool dsi_vm_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
+ unsigned long pck, void *data)
+{
+ struct dsi_clk_calc_ctx *ctx = data;
+
+ ctx->dispc_cinfo.lck_div = lckd;
+ ctx->dispc_cinfo.pck_div = pckd;
+ ctx->dispc_cinfo.lck = lck;
+ ctx->dispc_cinfo.pck = pck;
+
+ if (dsi_vm_calc_blanking(ctx) = false)
+ return false;
+
+#ifdef PRINT_VERBOSE_VM_TIMINGS
+ print_dispc_vm("dispc", &ctx->dispc_vm);
+ print_dsi_vm("dsi ", &ctx->dsi_vm);
+ print_dispc_vm("req ", ctx->config->timings);
+ print_dsi_dispc_vm("act ", &ctx->dsi_vm);
+#endif
+
+ return true;
+}
+
+static bool dsi_vm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
+ void *data)
+{
+ struct dsi_clk_calc_ctx *ctx = data;
+ unsigned long pck_max;
+
+ ctx->dsi_cinfo.regm_dispc = regm_dispc;
+ ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
+
+ /*
+ * In burst mode we can let the dispc pck be arbitrarily high, but it
+ * limits our scaling abilities. So for now, don't aim too high.
+ */
+
+ if (ctx->config->trans_mode = OMAP_DSS_DSI_BURST_MODE)
+ pck_max = ctx->req_pck_max + 10000000;
+ else
+ pck_max = ctx->req_pck_max;
+
+ return dispc_div_calc(dispc, ctx->req_pck_min, pck_max,
+ dsi_vm_calc_dispc_cb, ctx);
+}
+
+static bool dsi_vm_calc_pll_cb(int regn, int regm, unsigned long fint,
+ unsigned long pll, void *data)
+{
+ struct dsi_clk_calc_ctx *ctx = data;
+
+ ctx->dsi_cinfo.regn = regn;
+ ctx->dsi_cinfo.regm = regm;
+ ctx->dsi_cinfo.fint = fint;
+ ctx->dsi_cinfo.clkin4ddr = pll;
+
+ return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min,
+ dsi_vm_calc_hsdiv_cb, ctx);
+}
+
+static bool dsi_vm_calc(struct dsi_data *dsi,
+ const struct omap_dss_dsi_config *cfg,
+ struct dsi_clk_calc_ctx *ctx)
+{
+ const struct omap_video_timings *t = cfg->timings;
+ unsigned long clkin;
+ unsigned long pll_min;
+ unsigned long pll_max;
+ int ndl = dsi->num_lanes_used - 1;
+ int bitspp = dsi_get_pixel_size(cfg->pixel_format);
+ unsigned long byteclk_min;
+
+ clkin = clk_get_rate(dsi->sys_clk);
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->dsidev = dsi->pdev;
+ ctx->config = cfg;
+
+ ctx->dsi_cinfo.clkin = clkin;
+
+ /* these limits should come from the panel driver */
+ ctx->req_pck_min = t->pixel_clock * 1000 - 1000;
+ ctx->req_pck_nom = t->pixel_clock * 1000;
+ ctx->req_pck_max = t->pixel_clock * 1000 + 1000;
+
+ byteclk_min = div64_u64((u64)ctx->req_pck_min * bitspp, ndl * 8);
+ pll_min = max(cfg->hs_clk_min * 4, byteclk_min * 4 * 4);
+
+ if (cfg->trans_mode = OMAP_DSS_DSI_BURST_MODE) {
+ pll_max = cfg->hs_clk_max * 4;
+ } else {
+ unsigned long byteclk_max;
+ byteclk_max = div64_u64((u64)ctx->req_pck_max * bitspp,
+ ndl * 8);
+
+ pll_max = byteclk_max * 4 * 4;
+ }
+
+ return dsi_pll_calc(dsi->pdev, clkin,
+ pll_min, pll_max,
+ dsi_vm_calc_pll_cb, ctx);
+}
+
int omapdss_dsi_set_config(struct omap_dss_device *dssdev,
const struct omap_dss_dsi_config *config)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct dsi_clk_calc_ctx ctx;
+ bool ok;
+ int r;
mutex_lock(&dsi->lock);
- dsi->timings = *config->timings;
- dsi->vm_timings = *config->vm_timings;
dsi->pix_fmt = config->pixel_format;
dsi->mode = config->mode;
- dsi_set_clocks(dssdev, config->hs_clk, config->lp_clk);
+ if (config->mode = OMAP_DSS_DSI_VIDEO_MODE)
+ ok = dsi_vm_calc(dsi, config, &ctx);
+ else
+ ok = dsi_cm_calc(dsi, config, &ctx);
+
+ if (!ok) {
+ DSSERR("failed to find suitable DSI clock settings\n");
+ r = -EINVAL;
+ goto err;
+ }
+
+ dsi_pll_calc_dsi_fck(&ctx.dsi_cinfo);
+
+ r = dsi_lp_clock_calc(&ctx.dsi_cinfo, config->lp_clk_min,
+ config->lp_clk_max);
+ if (r) {
+ DSSERR("failed to find suitable DSI LP clock settings\n");
+ goto err;
+ }
+
+ dsi->user_dsi_cinfo = ctx.dsi_cinfo;
+ dsi->user_dispc_cinfo = ctx.dispc_cinfo;
+
+ dsi->timings = ctx.dispc_vm;
+ dsi->vm_timings = ctx.dsi_vm;
mutex_unlock(&dsi->lock);
return 0;
+err:
+ mutex_unlock(&dsi->lock);
+
+ return r;
}
EXPORT_SYMBOL(omapdss_dsi_set_config);
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index 161011e..cbaf60f 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -267,9 +267,21 @@ enum omap_dss_dsi_trans_mode {
};
struct omap_dss_dsi_videomode_timings {
+ unsigned long hsclk;
+
+ unsigned ndl;
+ unsigned bitspp;
+
+ /* pixels */
+ u16 hact;
+ /* lines */
+ u16 vact;
+
/* DSI video mode blanking data */
/* Unit: byte clock cycles */
+ u16 hss;
u16 hsa;
+ u16 hse;
u16 hfp;
u16 hbp;
/* Unit: line clocks */
@@ -293,10 +305,12 @@ struct omap_dss_dsi_config {
enum omap_dss_dsi_mode mode;
enum omap_dss_dsi_pixel_format pixel_format;
const struct omap_video_timings *timings;
- const struct omap_dss_dsi_videomode_timings *vm_timings;
- unsigned long hs_clk;
- unsigned long lp_clk;
+ unsigned long hs_clk_min, hs_clk_max;
+ unsigned long lp_clk_min, lp_clk_max;
+
+ bool ddr_clk_always_on;
+ enum omap_dss_dsi_trans_mode trans_mode;
};
void dsi_bus_lock(struct omap_dss_device *dssdev);
--
1.7.10.4
^ permalink raw reply related
* [PATCH 11/14] OMAPDSS: DPI: use new clock calculation code
From: Tomi Valkeinen @ 2013-03-08 11:52 UTC (permalink / raw)
To: Archit Taneja, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1362743569-10289-1-git-send-email-tomi.valkeinen@ti.com>
Use the new clock calculation code in the DPI driver.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dpi.c | 212 +++++++++++++++++++++++++++++++++--------
1 file changed, 172 insertions(+), 40 deletions(-)
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 775214c..c7363b1 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -91,31 +91,170 @@ static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
}
}
+struct dpi_clk_calc_ctx {
+ struct platform_device *dsidev;
+
+ /* inputs */
+
+ unsigned long pck_min, pck_max;
+
+ /* outputs */
+
+ struct dsi_clock_info dsi_cinfo;
+ struct dss_clock_info dss_cinfo;
+ struct dispc_clock_info dispc_cinfo;
+};
+
+static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
+ unsigned long pck, void *data)
+{
+ struct dpi_clk_calc_ctx *ctx = data;
+
+ /*
+ * Odd dividers give us uneven duty cycle, causing problem when level
+ * shifted. So skip all odd dividers when the pixel clock is on the
+ * higher side.
+ */
+ if (ctx->pck_min >= 1000000) {
+ if (lckd > 1 && lckd % 2 != 0)
+ return false;
+
+ if (pckd > 1 && pckd % 2 != 0)
+ return false;
+ }
+
+ ctx->dispc_cinfo.lck_div = lckd;
+ ctx->dispc_cinfo.pck_div = pckd;
+ ctx->dispc_cinfo.lck = lck;
+ ctx->dispc_cinfo.pck = pck;
+
+ return true;
+}
+
+
+static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
+ void *data)
+{
+ struct dpi_clk_calc_ctx *ctx = data;
+
+ /*
+ * Odd dividers give us uneven duty cycle, causing problem when level
+ * shifted. So skip all odd dividers when the pixel clock is on the
+ * higher side.
+ */
+ if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 1000000)
+ return false;
+
+ ctx->dsi_cinfo.regm_dispc = regm_dispc;
+ ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
+
+ return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
+ dpi_calc_dispc_cb, ctx);
+}
+
+
+static bool dpi_calc_pll_cb(int regn, int regm, unsigned long fint,
+ unsigned long pll,
+ void *data)
+{
+ struct dpi_clk_calc_ctx *ctx = data;
+
+ ctx->dsi_cinfo.regn = regn;
+ ctx->dsi_cinfo.regm = regm;
+ ctx->dsi_cinfo.fint = fint;
+ ctx->dsi_cinfo.clkin4ddr = pll;
+
+ return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->pck_min,
+ dpi_calc_hsdiv_cb, ctx);
+}
+
+static bool dpi_calc_dss_cb(int fckd, unsigned long fck, void *data)
+{
+ struct dpi_clk_calc_ctx *ctx = data;
+
+ ctx->dss_cinfo.fck = fck;
+ ctx->dss_cinfo.fck_div = fckd;
+
+ return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
+ dpi_calc_dispc_cb, ctx);
+}
+
+static bool dpi_dsi_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
+{
+ unsigned long clkin;
+ unsigned long pll_min, pll_max;
+
+ clkin = dsi_get_pll_clkin(dpi.dsidev);
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->dsidev = dpi.dsidev;
+ ctx->pck_min = pck - 1000;
+ ctx->pck_max = pck + 1000;
+ ctx->dsi_cinfo.clkin = clkin;
+
+ pll_min = 0;
+ pll_max = 0;
+
+ return dsi_pll_calc(dpi.dsidev, clkin,
+ pll_min, pll_max,
+ dpi_calc_pll_cb, ctx);
+}
+
+static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
+{
+ int i;
+
+ /*
+ * DSS fck gives us very few possibilities, so finding a good pixel
+ * clock may not be possible. We try multiple times to find the clock,
+ * each time widening the pixel clock range we look for, up to
+ * +/- 1MHz.
+ */
+
+ for (i = 0; i < 10; ++i) {
+ bool ok;
+
+ memset(ctx, 0, sizeof(*ctx));
+ if (pck > 1000 * i * i * i)
+ ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);
+ else
+ ctx->pck_min = 0;
+ ctx->pck_max = pck + 1000 * i * i * i;
+
+ ok = dss_div_calc(ctx->pck_min, dpi_calc_dss_cb, ctx);
+ if (ok)
+ return ok;
+ }
+
+ return false;
+}
+
+
+
static int dpi_set_dsi_clk(enum omap_channel channel,
unsigned long pck_req, unsigned long *fck, int *lck_div,
int *pck_div)
{
- struct dsi_clock_info dsi_cinfo;
- struct dispc_clock_info dispc_cinfo;
+ struct dpi_clk_calc_ctx ctx;
int r;
+ bool ok;
- r = dsi_pll_calc_clock_div_pck(dpi.dsidev, pck_req, &dsi_cinfo,
- &dispc_cinfo);
- if (r)
- return r;
+ ok = dpi_dsi_clk_calc(pck_req, &ctx);
+ if (!ok)
+ return -EINVAL;
- r = dsi_pll_set_clock_div(dpi.dsidev, &dsi_cinfo);
+ r = dsi_pll_set_clock_div(dpi.dsidev, &ctx.dsi_cinfo);
if (r)
return r;
dss_select_lcd_clk_source(channel,
dpi_get_alt_clk_src(channel));
- dpi.mgr_config.clock_info = dispc_cinfo;
+ dpi.mgr_config.clock_info = ctx.dispc_cinfo;
- *fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
- *lck_div = dispc_cinfo.lck_div;
- *pck_div = dispc_cinfo.pck_div;
+ *fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
+ *lck_div = ctx.dispc_cinfo.lck_div;
+ *pck_div = ctx.dispc_cinfo.pck_div;
return 0;
}
@@ -123,23 +262,23 @@ static int dpi_set_dsi_clk(enum omap_channel channel,
static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
int *lck_div, int *pck_div)
{
- struct dss_clock_info dss_cinfo;
- struct dispc_clock_info dispc_cinfo;
+ struct dpi_clk_calc_ctx ctx;
int r;
+ bool ok;
- r = dss_calc_clock_div(pck_req, &dss_cinfo, &dispc_cinfo);
- if (r)
- return r;
+ ok = dpi_dss_clk_calc(pck_req, &ctx);
+ if (!ok)
+ return -EINVAL;
- r = dss_set_clock_div(&dss_cinfo);
+ r = dss_set_clock_div(&ctx.dss_cinfo);
if (r)
return r;
- dpi.mgr_config.clock_info = dispc_cinfo;
+ dpi.mgr_config.clock_info = ctx.dispc_cinfo;
- *fck = dss_cinfo.fck;
- *lck_div = dispc_cinfo.lck_div;
- *pck_div = dispc_cinfo.pck_div;
+ *fck = ctx.dss_cinfo.fck;
+ *lck_div = ctx.dispc_cinfo.lck_div;
+ *pck_div = ctx.dispc_cinfo.pck_div;
return 0;
}
@@ -319,12 +458,12 @@ EXPORT_SYMBOL(omapdss_dpi_set_timings);
int dpi_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
- int r;
struct omap_overlay_manager *mgr = dpi.output.manager;
int lck_div, pck_div;
unsigned long fck;
unsigned long pck;
- struct dispc_clock_info dispc_cinfo;
+ struct dpi_clk_calc_ctx ctx;
+ bool ok;
if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
return -EINVAL;
@@ -333,28 +472,21 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
return -EINVAL;
if (dpi.dsidev) {
- struct dsi_clock_info dsi_cinfo;
- r = dsi_pll_calc_clock_div_pck(dpi.dsidev,
- timings->pixel_clock * 1000,
- &dsi_cinfo, &dispc_cinfo);
+ ok = dpi_dsi_clk_calc(timings->pixel_clock * 1000, &ctx);
+ if (!ok)
+ return -EINVAL;
- if (r)
- return r;
-
- fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
+ fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
} else {
- struct dss_clock_info dss_cinfo;
- r = dss_calc_clock_div(timings->pixel_clock * 1000,
- &dss_cinfo, &dispc_cinfo);
-
- if (r)
- return r;
+ ok = dpi_dss_clk_calc(timings->pixel_clock * 1000, &ctx);
+ if (!ok)
+ return -EINVAL;
- fck = dss_cinfo.fck;
+ fck = ctx.dss_cinfo.fck;
}
- lck_div = dispc_cinfo.lck_div;
- pck_div = dispc_cinfo.pck_div;
+ lck_div = ctx.dispc_cinfo.lck_div;
+ pck_div = ctx.dispc_cinfo.pck_div;
pck = fck / lck_div / pck_div / 1000;
--
1.7.10.4
^ permalink raw reply related
* [PATCH 10/14] OMAPDSS: SDI: use new clock calculation code
From: Tomi Valkeinen @ 2013-03-08 11:52 UTC (permalink / raw)
To: Archit Taneja, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1362743569-10289-1-git-send-email-tomi.valkeinen@ti.com>
Use the new clock calculation code in the SDI driver.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/sdi.c | 68 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 67 insertions(+), 1 deletion(-)
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index eb4ee17..5754245 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -41,6 +41,72 @@ static struct {
struct omap_dss_output output;
} sdi;
+struct sdi_clk_calc_ctx {
+ unsigned long pck_min, pck_max;
+
+ struct dss_clock_info dss_cinfo;
+ struct dispc_clock_info dispc_cinfo;
+};
+
+static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
+ unsigned long pck, void *data)
+{
+ struct sdi_clk_calc_ctx *ctx = data;
+
+ ctx->dispc_cinfo.lck_div = lckd;
+ ctx->dispc_cinfo.pck_div = pckd;
+ ctx->dispc_cinfo.lck = lck;
+ ctx->dispc_cinfo.pck = pck;
+
+ return true;
+}
+
+static bool dpi_calc_dss_cb(int fckd, unsigned long fck, void *data)
+{
+ struct sdi_clk_calc_ctx *ctx = data;
+
+ ctx->dss_cinfo.fck = fck;
+ ctx->dss_cinfo.fck_div = fckd;
+
+ return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
+ dpi_calc_dispc_cb, ctx);
+}
+
+static int sdi_calc_clock_div(unsigned long pclk,
+ struct dss_clock_info *dss_cinfo,
+ struct dispc_clock_info *dispc_cinfo)
+{
+ int i;
+ struct sdi_clk_calc_ctx ctx;
+
+ /*
+ * DSS fclk gives us very few possibilities, so finding a good pixel
+ * clock may not be possible. We try multiple times to find the clock,
+ * each time widening the pixel clock range we look for, up to
+ * +/- 1MHz.
+ */
+
+ for (i = 0; i < 10; ++i) {
+ bool ok;
+
+ memset(&ctx, 0, sizeof(ctx));
+ if (pclk > 1000 * i * i * i)
+ ctx.pck_min = max(pclk - 1000 * i * i * i, 0lu);
+ else
+ ctx.pck_min = 0;
+ ctx.pck_max = pclk + 1000 * i * i * i;
+
+ ok = dss_div_calc(ctx.pck_min, dpi_calc_dss_cb, &ctx);
+ if (ok) {
+ *dss_cinfo = ctx.dss_cinfo;
+ *dispc_cinfo = ctx.dispc_cinfo;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
{
struct omap_overlay_manager *mgr = dssdev->output->manager;
@@ -88,7 +154,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
- r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo);
+ r = sdi_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo);
if (r)
goto err_calc_clock_div;
--
1.7.10.4
^ permalink raw reply related
* [PATCH 09/14] OMAPDSS: DSI: add new clock calculation code
From: Tomi Valkeinen @ 2013-03-08 11:52 UTC (permalink / raw)
To: Archit Taneja, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1362743569-10289-1-git-send-email-tomi.valkeinen@ti.com>
Add new way to iterate over DSI PLL and HSDIV clock divisors.
dsi_pll_calc() and dss_hsdiv_calc() provide a generic way to go over
all the divisors, within given clock range. The functions will call a
callback function for each divider set, making the function reusable for
all use cases.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dsi.c | 69 +++++++++++++++++++++++++++++++++++++++++
drivers/video/omap2/dss/dss.h | 12 +++++++
2 files changed, 81 insertions(+)
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index aabe472..c8d5574 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -1280,6 +1280,75 @@ static int dsi_pll_power(struct platform_device *dsidev,
return 0;
}
+unsigned long dsi_get_pll_clkin(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ return clk_get_rate(dsi->sys_clk);
+}
+
+bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll,
+ unsigned long out_min, dsi_hsdiv_calc_func func, void *data)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int regm, regm_start, regm_stop;
+ unsigned long out_max;
+ unsigned long out;
+
+ out_min = out_min ? out_min : 1;
+ out_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
+
+ regm_start = max(DIV_ROUND_UP(pll, out_max), 1ul);
+ regm_stop = min(pll / out_min, dsi->regm_dispc_max);
+
+ for (regm = regm_start; regm <= regm_stop; ++regm) {
+ out = pll / regm;
+
+ if (func(regm, out, data))
+ return true;
+ }
+
+ return false;
+}
+
+bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
+ unsigned long pll_min, unsigned long pll_max,
+ dsi_pll_calc_func func, void *data)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int regn, regn_start, regn_stop;
+ int regm, regm_start, regm_stop;
+ unsigned long fint, pll;
+ const unsigned long pll_hw_max = 1800000000;
+ unsigned long fint_hw_min, fint_hw_max;
+
+ fint_hw_min = dsi->fint_min;
+ fint_hw_max = dsi->fint_max;
+
+ regn_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul);
+ regn_stop = min(clkin / fint_hw_min, dsi->regn_max);
+
+ pll_max = pll_max ? pll_max : ULONG_MAX;
+
+ for (regn = regn_start; regn <= regn_stop; ++regn) {
+ fint = clkin / regn;
+
+ regm_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2),
+ 1ul);
+ regm_stop = min3(pll_max / fint / 2,
+ pll_hw_max / fint / 2,
+ dsi->regm_max);
+
+ for (regm = regm_start; regm <= regm_stop; ++regm) {
+ pll = 2 * regm * fint;
+
+ if (func(regn, regm, fint, pll, data))
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* calculate clock rates using dividers in cinfo */
static int dsi_calc_clock_rates(struct platform_device *dsidev,
struct dsi_clock_info *cinfo)
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 4180302..dde6cc1 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -295,6 +295,18 @@ void dsi_dump_clocks(struct seq_file *s);
void dsi_irq_handler(void);
u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt);
+unsigned long dsi_get_pll_clkin(struct platform_device *dsidev);
+
+typedef bool (*dsi_pll_calc_func)(int regn, int regm, unsigned long fint,
+ unsigned long pll, void *data);
+typedef bool (*dsi_hsdiv_calc_func)(int regm_dispc, unsigned long dispc,
+ void *data);
+bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll,
+ unsigned long out_min, dsi_hsdiv_calc_func func, void *data);
+bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
+ unsigned long pll_min, unsigned long pll_max,
+ dsi_pll_calc_func func, void *data);
+
unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
int dsi_pll_set_clock_div(struct platform_device *dsidev,
struct dsi_clock_info *cinfo);
--
1.7.10.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox