Re: [PATCH 5/6] fbdev: sh-mobile: HDMI support for SH-Mobile SoCs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Jun 30, 2010 at 6:55 PM, Guennadi Liakhovetski
<g.liakhovetski@xxxxxx> wrote:
> Some SH-Mobile SoCs have an HDMI controller and a PHY, attached to one of their
> LCDC interfaces. This patch adds a preliminary static support for such
> controllers, this means, that only the 720p mode is handled ATM. Support for
> more modes and a dynamic switching between them will be added by a follow up
> patch.
>
> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@xxxxxx>
> ---
>  arch/arm/mach-shmobile/clock-sh7372.c |    2 +-
>  drivers/video/Kconfig                 |    8 +
>  drivers/video/Makefile                |    1 +
>  drivers/video/sh_mobile_hdmi.c        | 1070 +++++++++++++++++++++++++++++++++
>  drivers/video/sh_mobile_lcdcfb.c      |  190 +++++--
>  include/video/sh_mobile_hdmi.h        |   22 +
>  include/video/sh_mobile_lcdc.h        |    1 +
>  7 files changed, 1243 insertions(+), 51 deletions(-)
>  create mode 100644 drivers/video/sh_mobile_hdmi.c
>  create mode 100644 include/video/sh_mobile_hdmi.h
>
> diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c
> index 21cb629..506a8c5 100644
> --- a/arch/arm/mach-shmobile/clock-sh7372.c
> +++ b/arch/arm/mach-shmobile/clock-sh7372.c
> @@ -484,7 +484,7 @@ static struct clk_lookup lookups[] = {
>        CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]),
>        CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]),
>        CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]),
> -       CLKDEV_CON_ID("hdmi_clk", &div6_reparent_clks[DIV6_HDMI]),
> +       CLKDEV_DEV_ID("sh-mobile-hdmi", &div6_reparent_clks[DIV6_HDMI]),
>        CLKDEV_CON_ID("dsit_clk", &div6_clks[DIV6_DSIT]),
>        CLKDEV_CON_ID("dsi0p_clk", &div6_clks[DIV6_DSI0P]),
>        CLKDEV_CON_ID("dsi1p_clk", &div6_clks[DIV6_DSI1P]),

No. =)

You're changing the name of the clock specified in the data sheet. The
clock name comes from the data sheet. It's not supposed to be tied in
the the device name on this level.

The MSTP bit should be a CLKDEV_DEV_ID().

> +static int __init sh_hdmi_probe(struct platform_device *pdev)
> +{
> +       struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data;
> +       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       int irq = platform_get_irq(pdev, 0), ret;
> +       struct sh_hdmi *hdmi;
> +       struct clk *pllc2, *dv_clki_div2;
> +       long rate, prate;
> +
> +       if (!res || !pdata || irq < 0)
> +               return -ENODEV;
> +
> +       hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
> +       if (!hdmi) {
> +               dev_err(&pdev->dev, "Cannot allocate device data\n");
> +               return -ENOMEM;
> +       }
> +
> +       hdmi->pdata = pdata;
> +
> +       hdmi->hdmi_clk = clk_get(&pdev->dev, "sh-mobile-hdmi");
> +       if (IS_ERR(hdmi->hdmi_clk)) {
> +               ret = PTR_ERR(hdmi->hdmi_clk);
> +               dev_err(&pdev->dev, "Unable to get clock: %d\n", ret);
> +               goto egetclk;
> +       }
>

So clkdev already should figure out that "sh-mobile-hdmi" is needed by
the device name. The string should be used to specify interface clock
or function clock. For most drivers you do not need to pass any
string. Make sure your platform device id is setup correctly so the
platform device name matches properly with your clkdev table.

> +       dv_clki_div2 = clk_get(NULL, "dv_clki_div2_clk");
> +       if (IS_ERR(dv_clki_div2)) {
> +               ret = PTR_ERR(dv_clki_div2);
> +               dev_err(&pdev->dev, "Unable to get clock: %d\n", ret);
> +               goto egetdvclki;
> +       }
> +
> +       pllc2 = clk_get(NULL, "pllc2_clk");
> +       if (IS_ERR(pllc2)) {
> +               ret = PTR_ERR(pllc2);
> +               dev_err(&pdev->dev, "Unable to get clock: %d\n", ret);
> +               goto egetpllc2;
> +       }
> +
> +       clk_disable(pllc2);

You do realize that "pllc2" is shared between a bunch of different
clocks? You most likely do not want to disable it here. Would you like
to disable all other drivers that use this clock? =)

Also, that "pllc2" may be a good fit for HDMI is really a cpu-specific
property, and this driver is for the HDMI block that will be present
on multiple processors. So we really don't want any cpu-specific bits
in here.

Remember to pass the device to clk_get(). No need to pass NULL here.

> +       ret = clk_set_parent(pllc2, dv_clki_div2);
> +       if (ret < 0) {
> +               dev_err(&pdev->dev, "Cannot set parent: %d\n", ret);
> +               goto esetdvclki;
> +       }
> +
> +       pr_debug("PLLC2 initial frequency %lu\n", clk_get_rate(pllc2));
> +
> +       prate = clk_round_rate(pllc2, 594000000);
> +       if (prate < 0) {
> +               dev_err(&pdev->dev, "Cannot get suitable rate: %ld\n", prate);
> +               ret = prate;
> +               goto eprate;
> +       }
> +
> +       ret = clk_set_rate(pllc2, prate);
> +       if (ret < 0) {
> +               dev_err(&pdev->dev, "Cannot set rate %ld: %d\n", prate, ret);
> +               goto eprate;
> +       }
> +
> +       pr_debug("PLLC2 set frequency %lu\n", prate);

So you're setting the pllc2 rate here...

> +       ret = clk_enable(pllc2);
> +       if (ret < 0) {
> +               dev_err(&pdev->dev, "Cannot enable clock: %d\n", ret);
> +               goto epclkenable;
> +       }
> +
> +       ret = clk_set_parent(hdmi->hdmi_clk, pllc2);
> +       if (ret < 0) {
> +               dev_err(&pdev->dev, "Cannot set parent: %d\n", ret);
> +               goto esetpllc2;
> +       }
> +
> +       rate = PICOS2KHZ(pdata->lcd_chan->lcd_cfg.pixclock) * 1000;
> +
> +       rate = clk_round_rate(hdmi->hdmi_clk, rate);
> +       if (rate < 0) {
> +               ret = rate;
> +               dev_err(&pdev->dev, "Cannot get suitable rate: %ld\n", rate);
> +               goto erate;
> +       }
> +
> +       clk_enable(hdmi->hdmi_clk);
> +       clk_disable(hdmi->hdmi_clk);

(This is far from pretty)

> +       ret = clk_set_rate(hdmi->hdmi_clk, rate);
> +       if (ret < 0) {
> +               dev_err(&pdev->dev, "Cannot set rate %ld: %d\n", rate, ret);
> +               goto erate;
> +       }

... and then you set the rate of the "hdmi_clk" here...

> +       pr_debug("HDMI set frequency %lu\n", rate);
> +
> +       ret = clk_enable(hdmi->hdmi_clk);
> +       if (ret < 0) {
> +               dev_err(&pdev->dev, "Cannot enable clock: %d\n", ret);
> +               goto eclkenable;
> +       }
> +
> +       dev_info(&pdev->dev, "Enabled HDMI clock at %luHz\n", rate);

Isn't "pllc2_clk" the parent of "hdmi_clk"? Most of this needs to be
dealt with from the processor or board specific code IMO.

Perhaps this is a pretty clear case when we should use function clocks
and interface clocks?

Paul [CC:ed] may have different ideas about this but below is how I
think it should be mapped out:

The function clock should be managed by Runtime PM and MSTP. After
thinking a bit about it I believe that the correct parent of the MSTP
bit should be "hp_clk" (see "Clock Assignment to Modules" table in the
data sheet).

The interface clock should be "hdmi_clk", and the parent of this clock
should be setup by the processor specific code. It should not be part
of the HDMI driver.

I think the mapping between the driver and the clock should be handled
by the clkdev tables. So this HDMI driver should not ask for any
"hdmi_clk".

We need to work a bit more on this part I think. =)

Cheers,

/ magnus
--
To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Video for Linux]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Tourism]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux