diff options
-rw-r--r-- | Documentation/devicetree/bindings/powerpc/fsl/diu.txt | 16 | ||||
-rw-r--r-- | drivers/video/fsl-diu-fb.c | 63 |
2 files changed, 76 insertions, 3 deletions
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/diu.txt b/Documentation/devicetree/bindings/powerpc/fsl/diu.txt index b66cb6d..fa902c8 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/diu.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/diu.txt @@ -6,7 +6,11 @@ drive DVI monitors. Required properties: - compatible : should be "fsl,diu" or "fsl,mpc5121-diu". - reg : should contain at least address and length of the DIU register - set. + set. The address and length for pixel clock register is optional, it's + not needed for the platforms with the pixel clock setting function, such + as P1022, MPC8610, MPC5121; for the platform without clock setting function, + the pixel clock register and settings in 'pixclk' node work together to + provide the pixel clock setting in the diu driver. - interrupts : one DIU interrupt should be described here. - interrupt-parent : the phandle for the interrupt controller that services interrupts for this device. @@ -15,6 +19,8 @@ Optional properties: - edid : verbatim EDID data block describing attached display. Data from the detailed timing descriptor will be used to program the display controller. +- pixclk : the pixel clock register setting, includeing PXCKDLYDIR, PXCK + and PXCKDLY. Example (MPC8610HPCD): display@2c000 { @@ -32,3 +38,11 @@ Example for MPC5121: interrupt-parent = <&ipic>; edid = [edid-data]; }; + +Example for T1040: + display:display@180000 { + compatible = "fsl,t1040-diu", "fsl,diu"; + reg = <0x180000 1000 0xfc028 4>; + pixclk = <0 255 0>; + interrupts = <74 2 0 0>; + }; diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index 4bc4730..47b97e5 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -50,6 +50,7 @@ #define INT_PARERR 0x08 /* Display parameters error interrupt */ #define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */ +#define PIXCLKCR_PXCKEN 0x80000000 /* * List of supported video modes * @@ -372,6 +373,8 @@ struct fsl_diu_data { unsigned int irq; enum fsl_diu_monitor_port monitor_port; struct diu __iomem *diu_reg; + void __iomem *pixelclk_reg; + u32 pixclkcr[3]; spinlock_t reg_lock; u8 dummy_aoi[4 * 4 * 4]; struct diu_ad dummy_ad __aligned(8); @@ -479,7 +482,10 @@ static enum fsl_diu_monitor_port fsl_diu_name_to_port(const char *s) port = FSL_DIU_PORT_DLVDS; } - return diu_ops.valid_monitor_port(port); + if (diu_ops.valid_monitor_port) + return diu_ops.valid_monitor_port(port); + + return port; } /* @@ -798,6 +804,35 @@ static void set_fix(struct fb_info *info) fix->ypanstep = 1; } +static void set_pixel_clock(struct fsl_diu_data *data, unsigned int pixclock) +{ + unsigned long freq; + u64 temp; + u32 pxclk; + u32 pxclkdl_dir, pxckmax, pxclk_delay; + + /* Convert pixclock from a wavelength to a frequency */ + temp = 1000000000000ULL; + do_div(temp, pixclock); + freq = temp; + + pxclkdl_dir = data->pixclkcr[0] << 30; + pxckmax = data->pixclkcr[1]; + pxclk_delay = data->pixclkcr[2] << 8; + + /* + * 'pxclk' is the ratio of the platform clock to the pixel clock. + * This number is programmed into the PIXCLKCR register, and the valid + * range of values is 2- pxckmax. + */ + pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq); + pxclk = clamp_t(u32, pxclk, 2, pxckmax); + + out_be32(data->pixelclk_reg, 0); + out_be32(data->pixelclk_reg, PIXCLKCR_PXCKEN + | pxclkdl_dir | (pxclk << 16) | pxclk_delay); +} + static void update_lcdc(struct fb_info *info) { struct fb_var_screeninfo *var = &info->var; @@ -846,7 +881,13 @@ static void update_lcdc(struct fb_info *info) out_be32(&hw->vsyn_para, temp); - diu_ops.set_pixel_clock(var->pixclock); + /* If the pixel clock setting function can not be used on the platform, + * then use the platform one. + */ + if (diu_ops.set_pixel_clock) + diu_ops.set_pixel_clock(var->pixclock); + else + set_pixel_clock(data, var->pixclock); #ifndef CONFIG_PPC_MPC512x /* @@ -1752,6 +1793,24 @@ static int fsl_diu_probe(struct platform_device *pdev) goto error; } + if (!diu_ops.set_pixel_clock) { + data->pixelclk_reg = of_iomap(np, 1); + if (!data->pixelclk_reg) { + dev_err(&pdev->dev, + "Cannot map pixelclk register.\n"); + ret = -EFAULT; + goto error; + } + /*Get the pixclkcr settings: PXCKDLYDIR; MAXPXCK, PXCKDLY*/ + ret = of_property_read_u32_array(np, "pixclk", + data->pixclkcr, 3); + if (ret) { + dev_err(&pdev->dev, + "Cannot get pixelclk register information.\n"); + goto error; + } + } + /* Get the IRQ of the DIU */ data->irq = irq_of_parse_and_map(np, 0); |