* Re: [PATCH] video: exynos_dp: increase AUX channel voltage level
From: Florian Tobias Schandinat @ 2012-09-23 19:50 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <003e01cd90bb$8332a1b0$8997e510$%han@samsung.com>
On 09/12/2012 07:52 AM, Jingoo Han wrote:
> The value of AUX channel differential amplitude current is changed
> from 8 mA to 16 mA, in order to increase AUX channel voltage level.
> In this case, AUX channel voltage level can be changed from 400 mV
> to 800 mV, when resistance between AUX TX and RX is 100 ohm.
>
> According to DP spec, although the normative voltage level is 390 mV,
> the informative voltage level is 430 mV. So, 800 mV can be helpful
> to improve voltage margin of AUX channel.
>
> Signed-off-by: Jingoo Han <jg1.han@samsung.com>
Applied. But it might be a good idea to keep the old definition in the
header file for documentation purposes.
Thanks,
Florian Tobias Schandinat
> ---
> drivers/video/exynos/exynos_dp_reg.c | 2 +-
> drivers/video/exynos/exynos_dp_reg.h | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/video/exynos/exynos_dp_reg.c b/drivers/video/exynos/exynos_dp_reg.c
> index 20e441f..5fd1214 100644
> --- a/drivers/video/exynos/exynos_dp_reg.c
> +++ b/drivers/video/exynos/exynos_dp_reg.c
> @@ -77,7 +77,7 @@ void exynos_dp_init_analog_param(struct exynos_dp_device *dp)
> writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_3);
>
> reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM |
> - TX_CUR1_2X | TX_CUR_8_MA;
> + TX_CUR1_2X | TX_CUR_16_MA;
> writel(reg, dp->reg_base + EXYNOS_DP_PLL_FILTER_CTL_1);
>
> reg = CH3_AMP_400_MV | CH2_AMP_400_MV |
> diff --git a/drivers/video/exynos/exynos_dp_reg.h b/drivers/video/exynos/exynos_dp_reg.h
> index 125b27c..0e79031 100644
> --- a/drivers/video/exynos/exynos_dp_reg.h
> +++ b/drivers/video/exynos/exynos_dp_reg.h
> @@ -187,7 +187,7 @@
> #define PD_RING_OSC (0x1 << 6)
> #define AUX_TERMINAL_CTRL_50_OHM (0x2 << 4)
> #define TX_CUR1_2X (0x1 << 2)
> -#define TX_CUR_8_MA (0x2 << 0)
> +#define TX_CUR_16_MA (0x3 << 0)
>
> /* EXYNOS_DP_TX_AMP_TUNING_CTL */
> #define CH3_AMP_400_MV (0x0 << 24)
^ permalink raw reply
* Re: [PATCH 01/10] drivers/video/mb862xx/mb862xxfbdrv.c: fix error return code
From: Florian Tobias Schandinat @ 2012-09-23 19:52 UTC (permalink / raw)
To: Peter Senna Tschudin
Cc: paul.gortmaker, hsweeten, agust, davidb, linux-fbdev,
linux-kernel, kernel-janitors
In-Reply-To: <1347970080-25175-1-git-send-email-peter.senna@gmail.com>
Applied all 10 patches of this series.
Thanks,
Florian Tobias Schandinat
On 09/18/2012 12:07 PM, Peter Senna Tschudin wrote:
> From: Peter Senna Tschudin <peter.senna@gmail.com>
>
> Convert a nonnegative error return code to a negative one, as returned
> elsewhere in the function.
>
> A simplified version of the semantic match that finds this problem is as
> follows: (http://coccinelle.lip6.fr/)
>
> // <smpl>
> (
> if@p1 (\(ret < 0\|ret != 0\))
> { ... return ret; }
> |
> ret@p1 = 0
> )
> ... when != ret = e1
> when != &ret
> *if(...)
> {
> ... when != ret = e2
> when forall
> return ret;
> }
> // </smpl>
>
> Signed-off-by: Peter Senna Tschudin <peter.senna@gmail.com>
> ---
> drivers/video/mb862xx/mb862xxfbdrv.c | 10 +++++++---
> 1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/video/mb862xx/mb862xxfbdrv.c b/drivers/video/mb862xx/mb862xxfbdrv.c
> index 57d940b..d68e332 100644
> --- a/drivers/video/mb862xx/mb862xxfbdrv.c
> +++ b/drivers/video/mb862xx/mb862xxfbdrv.c
> @@ -1052,12 +1052,14 @@ static int __devinit mb862xx_pci_probe(struct pci_dev *pdev,
> break;
> default:
> /* should never occur */
> + ret = -EIO;
> goto rel_reg;
> }
>
> par->fb_base = ioremap(par->fb_base_phys, par->mapped_vram);
> if (par->fb_base = NULL) {
> dev_err(dev, "Cannot map framebuffer\n");
> + ret = -EIO;
> goto rel_reg;
> }
>
> @@ -1073,11 +1075,13 @@ static int __devinit mb862xx_pci_probe(struct pci_dev *pdev,
> dev_dbg(dev, "mmio phys 0x%llx 0x%lx\n",
> (unsigned long long)par->mmio_base_phys, (ulong)par->mmio_len);
>
> - if (mb862xx_pci_gdc_init(par))
> + ret = mb862xx_pci_gdc_init(par);
> + if (ret)
> goto io_unmap;
>
> - if (request_irq(par->irq, mb862xx_intr, IRQF_SHARED,
> - DRV_NAME, (void *)par)) {
> + ret = request_irq(par->irq, mb862xx_intr, IRQF_SHARED,
> + DRV_NAME, (void *)par);
> + if (ret) {
> dev_err(dev, "Cannot request irq\n");
> goto io_unmap;
> }
^ permalink raw reply
* Re: [PATCH v2 1/2] video: exynos_mipi_dsi: Remove unused code
From: Florian Tobias Schandinat @ 2012-09-23 19:54 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1348204007-1347-1-git-send-email-sachin.kamat@linaro.org>
Applied both patches of this series.
Thanks,
Florian Tobias Schandinat
On 09/21/2012 05:06 AM, Sachin Kamat wrote:
> This code is never executed and hence removed.
>
> Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
> Acked-by: Inki Dae <inki.dae@samsung.com>
>
> ---
> drivers/video/exynos/exynos_mipi_dsi_common.c | 3 ---
> 1 files changed, 0 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.c b/drivers/video/exynos/exynos_mipi_dsi_common.c
> index 47b533a..7cc4113 100644
> --- a/drivers/video/exynos/exynos_mipi_dsi_common.c
> +++ b/drivers/video/exynos/exynos_mipi_dsi_common.c
> @@ -288,9 +288,6 @@ int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
> mutex_unlock(&dsim->lock);
> return -EINVAL;
> }
> -
> - mutex_unlock(&dsim->lock);
> - return 0;
> }
>
> static unsigned int exynos_mipi_dsi_long_data_rd(struct mipi_dsim_device *dsim,
^ permalink raw reply
* [PATCH] OMAPDSS: DISPC: Add predecimation limit for TILER based rotations
From: Chandrabhanu Mahapatra @ 2012-09-24 6:50 UTC (permalink / raw)
To: tomi.valkeinen; +Cc: linux-omap, linux-fbdev, Chandrabhanu Mahapatra
In OMAP4 and OMAP5 when TILER 2D burst mode is used, a maximum of one line can
be skipped as per the respective TRMs. The MBlockStride OCP signal, which is
sum of ROWINC and image width in memory, is only 17 bits wide. In 2D mode TILER
supports 8192, 16384, 32768 and 65536 values of MBlockStride. In case when 2 or
more lines are skipped the ROWINC value exceeds 65536 resulting in OCP errors.
So, maximum vertical predecimation achievable is 2.
Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
---
drivers/video/omap2/dss/dispc.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index d512c38..61f8369 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -2195,7 +2195,8 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
const struct omap_video_timings *mgr_timings,
u16 width, u16 height, u16 out_width, u16 out_height,
enum omap_color_mode color_mode, bool *five_taps,
- int *x_predecim, int *y_predecim, u16 pos_x)
+ int *x_predecim, int *y_predecim, u16 pos_x,
+ enum omap_dss_rotation_type rotation_type)
{
struct omap_overlay *ovl = omap_dss_get_overlay(plane);
const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
@@ -2210,7 +2211,8 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
return -EINVAL;
*x_predecim = max_decim_limit;
- *y_predecim = max_decim_limit;
+ *y_predecim = (rotation_type = OMAP_DSS_ROT_TILER &&
+ dss_has_feature(FEAT_BURST_2D)) ? 2 : max_decim_limit;
if (color_mode = OMAP_DSS_COLOR_CLUT1 ||
color_mode = OMAP_DSS_COLOR_CLUT2 ||
@@ -2306,7 +2308,8 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
r = dispc_ovl_calc_scaling(plane, channel, mgr_timings, in_width,
in_height, out_width, out_height, oi->color_mode,
- &five_taps, &x_predecim, &y_predecim, oi->pos_x);
+ &five_taps, &x_predecim, &y_predecim, oi->pos_x,
+ oi->rotation_type);
if (r)
return r;
--
1.7.10
^ permalink raw reply related
* Re: [RFC PATCH 1/3] amba-clcd: Add Device Tree support to amba-clcd driver
From: Ryan Harkin @ 2012-09-24 7:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20120921121903.GE15609@n2100.arm.linux.org.uk>
Thanks for all the comments.
Pawel, good point about the framebuffer. Fixing this will also
address one of Russell's concerns. I don't know how to use a phandle,
so I have some reading to do.
Russell, all good points and exactly the type of feedback I needed.
I'll re-work your suggestions into my code and re-post a V2 of the
patches.
Sascha, I see your point. I'll work on the feedback above first
before getting to looking at how to handle the thread you linked to.
Thanks all,
Regards,
Ryan.
^ permalink raw reply
* linux-next: manual merge of the arm-soc tree with the fbdev tree
From: Stephen Rothwell @ 2012-09-24 9:15 UTC (permalink / raw)
To: linux-arm-kernel
[-- Attachment #1: Type: text/plain, Size: 1105 bytes --]
Hi all,
Today's linux-next merge of the arm-soc tree got a conflict in arch/arm/mach-s3c64xx/mach-mini6410.c between commit 5a213a55c6d3 ("include/video: move fimd register headers from platform to include/video") from the fbdev tree and commit 436d42c61c3e ("ARM: samsung: move platform_data definitions") from the arm-soc tree.
I fixed it up (see below) and can carry the fix as necessary (no action
is required).
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
diff --cc arch/arm/mach-s3c64xx/mach-mini6410.c
index 96ebcc5,09311cc..0000000
--- a/arch/arm/mach-s3c64xx/mach-mini6410.c
+++ b/arch/arm/mach-s3c64xx/mach-mini6410.c
@@@ -38,12 -38,12 +38,12 @@@
#include <plat/cpu.h>
#include <plat/devs.h>
#include <plat/fb.h>
- #include <plat/nand.h>
+ #include <linux/platform_data/mtd-nand-s3c2410.h>
#include <plat/regs-serial.h>
- #include <plat/ts.h>
+ #include <linux/platform_data/touchscreen-s3c2410.h>
-#include <plat/regs-fb-v4.h>
#include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
#include "common.h"
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* linux-next: manual merge of the arm-soc tree with the fbdev tree
From: Stephen Rothwell @ 2012-09-24 9:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20120924191508.6100b0603d2642c1e7a36679@canb.auug.org.au>
[-- Attachment #1: Type: text/plain, Size: 1109 bytes --]
Hi all,
Today's linux-next merge of the arm-soc tree got a conflict in
arch/arm/mach-s3c64xx/mach-real6410.c between commit 5a213a55c6d3
("include/video: move fimd register headers from platform to
include/video") from the fbdev tree and commit 436d42c61c3e ("ARM:
samsung: move platform_data definitions") from the arm-soc tree.
I fixed it up (see below) and can carry the fix as necessary (no action
is required).
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
diff --cc arch/arm/mach-s3c64xx/mach-real6410.c
index 76d3ffb,6daca20..0000000
--- a/arch/arm/mach-s3c64xx/mach-real6410.c
+++ b/arch/arm/mach-s3c64xx/mach-real6410.c
@@@ -39,12 -39,12 +39,12 @@@
#include <plat/cpu.h>
#include <plat/devs.h>
#include <plat/fb.h>
- #include <plat/nand.h>
+ #include <linux/platform_data/mtd-nand-s3c2410.h>
#include <plat/regs-serial.h>
- #include <plat/ts.h>
+ #include <linux/platform_data/touchscreen-s3c2410.h>
-#include <plat/regs-fb-v4.h>
#include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
#include "common.h"
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* linux-next: manual merge of the arm-soc tree with the fbdev tree
From: Stephen Rothwell @ 2012-09-24 9:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20120924191508.6100b0603d2642c1e7a36679@canb.auug.org.au>
[-- Attachment #1: Type: text/plain, Size: 1755 bytes --]
Hi all,
Today's linux-next merge of the arm-soc tree got conflicts in
drivers/video/msm/mddi.c, drivers/video/msm/mdp.c and
drivers/video/msm/mdp_hw.h between commit 8abf0b31e161 ("video: msm:
Remove useless mach/* includes") from the fbdev tree and commit
1ef21f6343ff ("ARM: msm: move platform_data definitions") from the
arm-soc tree.
I fixed it up (see below) and can carry the fix as necessary (no action
is required).
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
diff --cc drivers/video/msm/mddi.c
index d43e178,bf73f04..0000000
--- a/drivers/video/msm/mddi.c
+++ b/drivers/video/msm/mddi.c
@@@ -26,7 -26,10 +26,7 @@@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/sched.h>
- #include <mach/msm_fb.h>
-#include <mach/msm_iomap.h>
-#include <mach/irqs.h>
-#include <mach/board.h>
+ #include <linux/platform_data/video-msm_fb.h>
#include "mddi_hw.h"
#define FLAG_DISABLE_HIBERNATION 0x0001
diff --cc drivers/video/msm/mdp.c
index 7570908,d1f881e..0000000
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@@ -25,7 -25,8 +25,7 @@@
#include <linux/major.h>
#include <linux/slab.h>
- #include <mach/msm_fb.h>
-#include <mach/msm_iomap.h>
+ #include <linux/platform_data/video-msm_fb.h>
#include <linux/platform_device.h>
#include <linux/export.h>
diff --cc drivers/video/msm/mdp_hw.h
index 2a84137,a0bacf5..0000000
--- a/drivers/video/msm/mdp_hw.h
+++ b/drivers/video/msm/mdp_hw.h
@@@ -15,7 -15,8 +15,7 @@@
#ifndef _MDP_HW_H_
#define _MDP_HW_H_
- #include <mach/msm_fb.h>
-#include <mach/msm_iomap.h>
+ #include <linux/platform_data/video-msm_fb.h>
struct mdp_info {
struct mdp_device mdp_dev;
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* [PATCH V3] video: exynos_dp: Add device tree support to DP driver
From: Ajay Kumar @ 2012-09-24 12:45 UTC (permalink / raw)
To: linux-samsung-soc, linux-fbdev, jg1.han; +Cc: FlorianSchandinat, thomas.ab
This patch enables device tree based discovery support for DP driver.
The driver is modified to handle platform data in both the cases:
with DT and non-DT.
Documentation is also added for the DT bindings.
DP-PHY should be regarded as a seperate device node while
being passed from device tree list, and device node for
DP should contain DP-PHY as child node with property name "dp-phy"
associated with it.
Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
---
.../devicetree/bindings/video/exynos_dp.txt | 83 ++++++++++
drivers/video/exynos/exynos_dp_core.c | 168 ++++++++++++++++++--
drivers/video/exynos/exynos_dp_core.h | 2 +
3 files changed, 239 insertions(+), 14 deletions(-)
create mode 100644 Documentation/devicetree/bindings/video/exynos_dp.txt
diff --git a/Documentation/devicetree/bindings/video/exynos_dp.txt b/Documentation/devicetree/bindings/video/exynos_dp.txt
new file mode 100644
index 0000000..c27f892
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/exynos_dp.txt
@@ -0,0 +1,83 @@
+Exynos Displayport driver should configure the displayport interface
+based on the type of panel connected to it.
+
+We use two nodes:
+ -dptx_phy node
+ -display-port-controller node
+
+For the dp-phy initialization, we use a dptx_phy node.
+Required properties for dptx_phy:
+ -compatible:
+ Should be "samsung,dp-phy".
+ -samsung,dptx_phy_reg:
+ Base address of DP PHY register.
+ -samsung,enable_bit:
+ The bit used to enable/disable DP PHY.
+
+For the Panel initialization, we read data from display-port-controller node.
+Required properties for display-port-controller:
+ -compatible:
+ Should be "samsung,exynos5-dp".
+ -reg:
+ physical base address of the controller and length
+ of memory mapped region.
+ -interrupts:
+ Internet combiner values.
+ -interrupt-parent:
+ Address of Interrupt combiner node.
+ -dp_phy:
+ Address of dptx_phy node.
+ -samsung,color_space:
+ input video data format.
+ COLOR_RGB = 0, COLOR_YCBCR422 = 1, COLOR_YCBCR444 = 2
+ -samsung,dynamic_range:
+ dynamic range for input video data.
+ VESA = 0, CEA = 1
+ -samsung,ycbcr_coeff:
+ YCbCr co-efficients for input video.
+ COLOR_YCBCR601 = 0, COLOR_YCBCR709 = 1
+ -samsung,color_depth:
+ Bit per color component.
+ COLOR_6 = 0, COLOR_8 = 1, COLOR_10 = 2, COLOR_12 = 3
+ -samsung,link_rate:
+ link rates supportd by the panel.
+ LINK_RATE_1_62GBPS = 0x6, LINK_RATE_2_70GBPS = 0x0A
+ -samsung,lane_count:
+ number of lanes supported by the panel.
+ LANE_COUNT1 = 1, LANE_COUNT2 = 2, LANE_COUNT4 = 4
+ -samsung,interlaced:
+ Interlace scan mode.
+ Progressive if defined, Interlaced if not defined
+ -samsung,v_sync_polarity:
+ VSYNC polarity configuration.
+ High if defined, Low if not defined
+ -samsung,h_sync_polarity:
+ HSYNC polarity configuration.
+ High if defined, Low if not defined
+
+Example:
+
+SOC specific portion:
+ dptx_phy: dptx_phy@0x10040720 {
+ compatible = "samsung,dp-phy";
+ samsung,dptx_phy_reg = <0x10040720>;
+ samsung,enable_bit = <1>;
+ };
+
+ display-port-controller {
+ compatible = "samsung,exynos5-dp";
+ reg = <0x145B0000 0x10000>;
+ interrupts = <10 3>;
+ interrupt-parent = <&combiner>;
+ dp_phy = <&dptx_phy>;
+ };
+
+Board Specific portion:
+ display-port-controller {
+ samsung,color_space = <0>;
+ samsung,dynamic_range = <0>;
+ samsung,ycbcr_coeff = <0>;
+ samsung,color_depth = <1>;
+ samsung,link_rate = <0x0a>;
+ samsung,lane_count = <2>;
+ };
diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
index cdc1398..bb0f10c 100644
--- a/drivers/video/exynos/exynos_dp_core.c
+++ b/drivers/video/exynos/exynos_dp_core.c
@@ -18,6 +18,7 @@
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <linux/of.h>
#include <video/exynos_dp.h>
@@ -856,6 +857,106 @@ static irqreturn_t exynos_dp_irq_handler(int irq, void *arg)
return IRQ_HANDLED;
}
+#ifdef CONFIG_OF
+struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
+{
+ struct device_node *dp_node = dev->of_node;
+ struct exynos_dp_platdata *pd;
+ struct video_info *dp_video_config;
+
+ pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+ if (!pd) {
+ dev_err(dev, "memory allocation for pdata failed\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ dp_video_config = devm_kzalloc(dev,
+ sizeof(*dp_video_config), GFP_KERNEL);
+
+ if (!dp_video_config) {
+ dev_err(dev, "memory allocation for video config failed\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ pd->video_info = dp_video_config;
+
+ if (of_get_property(dp_node, "samsung,h-sync-polarity", NULL))
+ dp_video_config->h_sync_polarity = 1;
+
+ if (of_get_property(dp_node, "samsung,v-sync-polarity", NULL))
+ dp_video_config->v_sync_polarity = 1;
+
+ if (of_get_property(dp_node, "samsung,interlaced", NULL))
+ dp_video_config->interlaced = 1;
+
+ of_property_read_u32(dp_node, "samsung,color_space",
+ &dp_video_config->color_space);
+
+ of_property_read_u32(dp_node, "samsung,dynamic_range",
+ &dp_video_config->dynamic_range);
+
+ of_property_read_u32(dp_node, "samsung,ycbcr_coeff",
+ &dp_video_config->ycbcr_coeff);
+
+ of_property_read_u32(dp_node, "samsung,color_depth",
+ &dp_video_config->color_depth);
+
+ of_property_read_u32(dp_node, "samsung,link_rate",
+ &dp_video_config->link_rate);
+
+ of_property_read_u32(dp_node, "samsung,lane_count",
+ &dp_video_config->lane_count);
+ return pd;
+}
+
+void exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
+{
+ struct device_node *dp_phy_node;
+ const __be32 *parp;
+ u32 phy_base;
+ void *virt_phy_base;
+
+ parp = of_get_property(dp->dev->of_node, "dp_phy", NULL);
+ if (!parp) {
+ dp->dp_phy_addr = NULL;
+ return;
+ }
+
+ dp_phy_node = of_find_node_by_phandle(be32_to_cpup(parp));
+ if (!dp_phy_node) {
+ dp->dp_phy_addr = NULL;
+ return;
+ }
+
+ of_property_read_u32(dp_phy_node, "samsung,dptx_phy_reg", &phy_base);
+ of_property_read_u32(dp_phy_node, "samsung,enable_bit",
+ &dp->enable_bit);
+ virt_phy_base = ioremap(phy_base, SZ_4);
+ if (!virt_phy_base) {
+ dev_err(dp->dev, "failed to ioremap dp-phy\n");
+ dp->dp_phy_addr = NULL;
+ return;
+ }
+ dp->dp_phy_addr = virt_phy_base;
+}
+
+void exynos_dp_phy_init(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = __raw_readl(dp->dp_phy_addr);
+ reg |= dp->enable_bit;
+ __raw_writel(reg, dp->dp_phy_addr);
+}
+
+void exynos_dp_phy_exit(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = __raw_readl(dp->dp_phy_addr);
+ reg &= ~(dp->enable_bit);
+ __raw_writel(reg, dp->dp_phy_addr);
+}
+#endif /* CONFIG_OF */
+
static int __devinit exynos_dp_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -864,12 +965,6 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
int ret = 0;
- pdata = pdev->dev.platform_data;
- if (!pdata) {
- dev_err(&pdev->dev, "no platform data\n");
- return -EINVAL;
- }
-
dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
GFP_KERNEL);
if (!dp) {
@@ -879,6 +974,21 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
dp->dev = &pdev->dev;
+ if (pdev->dev.of_node) {
+ pdata = exynos_dp_dt_parse_pdata(&pdev->dev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+
+ exynos_dp_dt_parse_phydata(dp);
+ } else {
+ pdata = pdev->dev.platform_data;
+ }
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -EINVAL;
+ }
+
dp->clock = devm_clk_get(&pdev->dev, "dp");
if (IS_ERR(dp->clock)) {
dev_err(&pdev->dev, "failed to get clock\n");
@@ -909,8 +1019,14 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
}
dp->video_info = pdata->video_info;
- if (pdata->phy_init)
- pdata->phy_init();
+
+ if (pdev->dev.of_node) {
+ if (dp->dp_phy_addr)
+ exynos_dp_phy_init(dp);
+ } else {
+ if (pdata->phy_init)
+ pdata->phy_init();
+ }
exynos_dp_init_dp(dp);
@@ -953,8 +1069,13 @@ static int __devexit exynos_dp_remove(struct platform_device *pdev)
struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
struct exynos_dp_device *dp = platform_get_drvdata(pdev);
- if (pdata && pdata->phy_exit)
- pdata->phy_exit();
+ if (pdev->dev.of_node) {
+ if (dp->dp_phy_addr)
+ exynos_dp_phy_exit(dp);
+ } else {
+ if (pdata && pdata->phy_exit)
+ pdata->phy_exit();
+ }
clk_disable(dp->clock);
@@ -968,8 +1089,13 @@ static int exynos_dp_suspend(struct device *dev)
struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
struct exynos_dp_device *dp = platform_get_drvdata(pdev);
- if (pdata && pdata->phy_exit)
- pdata->phy_exit();
+ if (dev->of_node) {
+ if (dp->dp_phy_addr)
+ exynos_dp_phy_exit(dp);
+ } else {
+ if (pdata && pdata->phy_exit)
+ pdata->phy_exit();
+ }
clk_disable(dp->clock);
@@ -982,8 +1108,13 @@ static int exynos_dp_resume(struct device *dev)
struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
struct exynos_dp_device *dp = platform_get_drvdata(pdev);
- if (pdata && pdata->phy_init)
- pdata->phy_init();
+ if (dev->of_node) {
+ if (dp->dp_phy_addr)
+ exynos_dp_phy_init(dp);
+ } else {
+ if (pdata && pdata->phy_init)
+ pdata->phy_init();
+ }
clk_enable(dp->clock);
@@ -1013,6 +1144,14 @@ static const struct dev_pm_ops exynos_dp_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume)
};
+#ifdef CONFIG_OF
+static const struct of_device_id exynos_dp_match[] = {
+ { .compatible = "samsung,exynos5-dp" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, exynos_dp_match);
+#endif
+
static struct platform_driver exynos_dp_driver = {
.probe = exynos_dp_probe,
.remove = __devexit_p(exynos_dp_remove),
@@ -1020,6 +1159,7 @@ static struct platform_driver exynos_dp_driver = {
.name = "exynos-dp",
.owner = THIS_MODULE,
.pm = &exynos_dp_pm_ops,
+ .of_match_table = of_match_ptr(exynos_dp_match),
},
};
diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/video/exynos/exynos_dp_core.h
index 57b8a65..c9f8c97 100644
--- a/drivers/video/exynos/exynos_dp_core.h
+++ b/drivers/video/exynos/exynos_dp_core.h
@@ -29,6 +29,8 @@ struct exynos_dp_device {
struct clk *clock;
unsigned int irq;
void __iomem *reg_base;
+ void __iomem *dp_phy_addr;
+ unsigned int enable_bit;
struct video_info *video_info;
struct link_train link_train;
--
1.7.0.4
^ permalink raw reply related
* Re: [PATCH] video: exynos_dp: Add device tree support to DP driver
From: Ajay kumar @ 2012-09-24 12:59 UTC (permalink / raw)
To: Jingoo Han
Cc: Ajay Kumar, FlorianSchandinat, linux-samsung-soc, linux-fbdev,
thomas.ab, Leela Krishna Amudala
In-Reply-To: <008d01cd9725$a096e480$e1c4ad80$%han@samsung.com>
Hi Jingoo,
I have addressed all your comments and have sent the V3 Patch.
Regards,
Ajay Kumar
On Thu, Sep 20, 2012 at 5:16 PM, Jingoo Han <jg1.han@samsung.com> wrote:
> On Friday, September 14, 2012 3:40 AM Ajay Kumar wrote
>>
>> This patch enables device tree based discovery support for DP driver.
>> The driver is modified to handle platform data in both the cases:
>> with DT and non-DT.
>>
>> DP-PHY should be regarded as a seperate device node while
>> being passed from device tree list, and device node for
>> DP should contain DP-PHY as child node with property name "dp-phy"
>> associated with it.
>
> Hi Ajay,
>
> Thank you for sending the patch for Device Tree support.
> I tested the patch with Exynos5250.
>
> As Leela Krishna Amudala mentioned, please post the documentation
> for the bindings.
>
> Also, I added some comments for minor fix.
>
> Best regards,
> Jingoo Han
>
>>
>> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
>> ---
>> drivers/video/exynos/exynos_dp_core.c | 156 +++++++++++++++++++++++++++++++--
>> drivers/video/exynos/exynos_dp_core.h | 2 +
>> 2 files changed, 151 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
>> index f57c915..15887bd 100644
>> --- a/drivers/video/exynos/exynos_dp_core.c
>> +++ b/drivers/video/exynos/exynos_dp_core.c
>> @@ -18,6 +18,7 @@
>> #include <linux/io.h>
>> #include <linux/interrupt.h>
>> #include <linux/delay.h>
>> +#include <linux/of.h>
>>
>> #include <video/exynos_dp.h>
>>
>> @@ -856,20 +857,117 @@ static irqreturn_t exynos_dp_irq_handler(int irq, void *arg)
>> return IRQ_HANDLED;
>> }
>>
>> +#ifdef CONFIG_OF
>> +struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
>> +{
>> + struct device_node *dp_node = dev->of_node;
>> + struct exynos_dp_platdata *pd;
>> + struct video_info *dp_video_config;
>> +
>> + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
>> + if (!pd) {
>> + dev_err(dev, "memory allocation for pdata failed\n");
>> + return ERR_PTR(-ENOMEM);
>> + }
>> + dp_video_config = devm_kzalloc(dev,
>> + sizeof(*dp_video_config), GFP_KERNEL);
>> +
>> + if (!dp_video_config) {
>> + dev_err(dev, "memory allocation for video config failed\n");
>> + return ERR_PTR(-ENOMEM);
>> + }
>> + pd->video_info = dp_video_config;
>> +
>> + if (of_get_property(dp_node, "samsung,h-sync-polarity", NULL))
>> + dp_video_config->h_sync_polarity = 1;
>> +
>> + if (of_get_property(dp_node, "samsung,v-sync-polarity", NULL))
>> + dp_video_config->v_sync_polarity = 1;
>> +
>> + if (of_get_property(dp_node, "samsung,interlaced", NULL))
>> + dp_video_config->interlaced = 1;
>> +
>> + of_property_read_u32(dp_node, "samsung,color_space",
>> + &dp_video_config->color_space);
>> +
>> + of_property_read_u32(dp_node, "samsung,dynamic_range",
>> + &dp_video_config->dynamic_range);
>> +
>> + of_property_read_u32(dp_node, "samsung,ycbcr_coeff",
>> + &dp_video_config->ycbcr_coeff);
>> +
>> + of_property_read_u32(dp_node, "samsung,color_depth",
>> + &dp_video_config->color_depth);
>> +
>> + of_property_read_u32(dp_node, "samsung,link_rate",
>> + &dp_video_config->link_rate);
>> +
>> + of_property_read_u32(dp_node, "samsung,lane_count",
>> + &dp_video_config->lane_count);
>> + return pd;
>> +}
>> +
>> +void exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
>> +{
>> + struct device_node *dp_phy_node;
>> +
>> + const __be32 *parp;
>> +
>> + u32 phy_base;
>> +
>> + void *virt_phy_base;
>
> Please, remove unnecessary spaces between variables.
>
>
>> +
>> + parp = of_get_property(dp->dev->of_node, "dp_phy", NULL);
>> + if (!parp) {
>> + dp->dp_phy_addr = NULL;
>> + return;
>> + }
>> +
>> + dp_phy_node = of_find_node_by_phandle(be32_to_cpup(parp));
>> + if (!dp_phy_node) {
>> + dp->dp_phy_addr = NULL;
>> + return;
>> + }
>> +
>> + of_property_read_u32(dp_phy_node, "samsung,dptx_phy_reg", &phy_base);
>> + of_property_read_u32(dp_phy_node, "samsung,enable_bit",
>> + &dp->enable_bit);
>> + virt_phy_base = ioremap(phy_base, SZ_4);
>> + if (!virt_phy_base) {
>> + dev_err(dp->dev, "failed to ioremap dp-phy\n");
>> + dp->dp_phy_addr = NULL;
>> + return;
>> + }
>> + dp->dp_phy_addr = virt_phy_base;
>> +}
>> +
>> +void dp_phy_init(struct exynos_dp_device *dp)
>
> Use exynos_dp_phy_init.
>
>> +{
>> + u32 reg;
>> +
>> + reg = __raw_readl(dp->dp_phy_addr);
>> + reg |= dp->enable_bit;
>> + __raw_writel(reg, dp->dp_phy_addr);
>> +}
>> +
>> +void dp_phy_exit(struct exynos_dp_device *dp)
>
> Use exynos_dp_phy_exit.
>
>> +{
>> + u32 reg;
>> +
>> + reg = __raw_readl(dp->dp_phy_addr);
>> + reg &= ~(dp->enable_bit);
>> + __raw_writel(reg, dp->dp_phy_addr);
>> +}
>> +#endif /* CONFIG_OF */
>> +
>> static int __devinit exynos_dp_probe(struct platform_device *pdev)
>> {
>> struct resource *res;
>> struct exynos_dp_device *dp;
>> - struct exynos_dp_platdata *pdata;
>> + struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
>>
>> int ret = 0;
>>
>> - pdata = pdev->dev.platform_data;
>> - if (!pdata) {
>> - dev_err(&pdev->dev, "no platform data\n");
>> - return -EINVAL;
>> - }
>> -
>> dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
>> GFP_KERNEL);
>> if (!dp) {
>> @@ -879,6 +982,19 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
>>
>> dp->dev = &pdev->dev;
>>
>> + if (pdev->dev.of_node) {
>> + pdata = exynos_dp_dt_parse_pdata(&pdev->dev);
>> + if (IS_ERR(pdata))
>> + return PTR_ERR(pdata);
>> +
>> + exynos_dp_dt_parse_phydata(dp);
>> + }
>
> I would like to use the style as follows.
>
> if (pdev->dev.of_node) {
> DT case
> else
> Non-DT case
>
> Could you modify it as follows?
>
> + if (pdev->dev.of_node) {
> + pdata = exynos_dp_dt_parse_pdata(&pdev->dev);
> + if (IS_ERR(pdata))
> + return PTR_ERR(pdata);
> +
> + exynos_dp_dt_parse_phydata(dp);
> + } else {
> + pdata = pdev->dev.platform_data;
> + }
>
>
>> +
>> + if (!pdata) {
>> + dev_err(&pdev->dev, "no platform data\n");
>> + return -EINVAL;
>> + }
>> +
>> dp->clock = devm_clk_get(&pdev->dev, "dp");
>> if (IS_ERR(dp->clock)) {
>> dev_err(&pdev->dev, "failed to get clock\n");
>> @@ -909,9 +1025,13 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
>> }
>>
>> dp->video_info = pdata->video_info;
>> if (pdata->phy_init)
>> pdata->phy_init();
>>
>> + if (pdev->dev.of_node)
>> + if (dp->dp_phy_addr)
>> + dp_phy_init(dp);
>> +
>
> Could you modify it as follows?
> phy_init() and dp_phy_init(dp) cannot be used simultaneously.
> So, it seems to be clearer.
>
> - if (pdata->phy_init)
> - pdata->phy_init();
> +
> + if (pdev->dev.of_node) {
> + if (dp->dp_phy_addr)
> + dp_phy_init(dp);
> + } else {
> + if (pdata->phy_init)
> + pdata->phy_init();
> + }
>
>
>> exynos_dp_init_dp(dp);
>>
>> ret = exynos_dp_detect_hpd(dp);
>> @@ -956,6 +1077,10 @@ static int __devexit exynos_dp_remove(struct platform_device *pdev)
>> if (pdata && pdata->phy_exit)
>> pdata->phy_exit();
>>
>> + if (pdev->dev.of_node)
>> + if (dp->dp_phy_addr)
>> + dp_phy_exit(dp);
>> +
>
> Same as above.
>
>> clk_disable(dp->clock);
>>
>> return 0;
>> @@ -971,6 +1096,10 @@ static int exynos_dp_suspend(struct device *dev)
>> if (pdata && pdata->phy_exit)
>> pdata->phy_exit();
>>
>> + if (dev->of_node)
>> + if (dp->dp_phy_addr)
>> + dp_phy_exit(dp);
>> +
>
> Same as above.
>
>> clk_disable(dp->clock);
>>
>> return 0;
>> @@ -985,6 +1114,10 @@ static int exynos_dp_resume(struct device *dev)
>> if (pdata && pdata->phy_init)
>> pdata->phy_init();
>>
>> + if (dev->of_node)
>> + if (dp->dp_phy_addr)
>> + dp_phy_init(dp);
>> +
>
> Same as above.
>
>> clk_enable(dp->clock);
>>
>> exynos_dp_init_dp(dp);
>> @@ -1013,6 +1146,14 @@ static const struct dev_pm_ops exynos_dp_pm_ops = {
>> SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume)
>> };
>>
>> +#ifdef CONFIG_OF
>> +static const struct of_device_id exynos_dp_match[] = {
>> + { .compatible = "samsung,exynos5-dp" },
>> + {},
>> +};
>> +MODULE_DEVICE_TABLE(of, exynos_dp_match);
>> +#endif
>> +
>> static struct platform_driver exynos_dp_driver = {
>> .probe = exynos_dp_probe,
>> .remove = __devexit_p(exynos_dp_remove),
>> @@ -1020,6 +1161,7 @@ static struct platform_driver exynos_dp_driver = {
>> .name = "exynos-dp",
>> .owner = THIS_MODULE,
>> .pm = &exynos_dp_pm_ops,
>> + .of_match_table = of_match_ptr(exynos_dp_match),
>> },
>> };
>>
>> diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/video/exynos/exynos_dp_core.h
>> index 57b8a65..49b30cb 100644
>> --- a/drivers/video/exynos/exynos_dp_core.h
>> +++ b/drivers/video/exynos/exynos_dp_core.h
>> @@ -29,6 +29,8 @@ struct exynos_dp_device {
>> struct clk *clock;
>> unsigned int irq;
>> void __iomem *reg_base;
>> + void __iomem *dp_phy_addr;
>> + int enable_bit;
>
> How about replacing 'int' with 'unsigned int'?
> unsigned number would be better for the bit definition.
>
>>
>> struct video_info *video_info;
>> struct link_train link_train;
>> --
>> 1.7.0.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v4] of: Add videomode helper
From: Rob Herring @ 2012-09-24 13:42 UTC (permalink / raw)
To: Steffen Trumtrar
Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Laurent Pinchart,
kernel-bIcnvbaLZ9MEGnE8C9+IrQ, Sascha Hauer
In-Reply-To: <1348042843-24673-1-git-send-email-s.trumtrar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
On 09/19/2012 03:20 AM, Steffen Trumtrar wrote:
> This patch adds a helper function for parsing videomodes from the devicetree.
> The videomode can be either converted to a struct drm_display_mode or a
> struct fb_videomode.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
> ---
>
> Hi!
>
> changes since v3:
> - print error messages
> - free alloced memory
> - general cleanup
>
> Regards
> Steffen
>
> .../devicetree/bindings/video/displaymode | 74 +++++
> drivers/of/Kconfig | 5 +
> drivers/of/Makefile | 1 +
> drivers/of/of_videomode.c | 283 ++++++++++++++++++++
> include/linux/of_videomode.h | 56 ++++
> 5 files changed, 419 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/video/displaymode
> create mode 100644 drivers/of/of_videomode.c
> create mode 100644 include/linux/of_videomode.h
>
> diff --git a/Documentation/devicetree/bindings/video/displaymode b/Documentation/devicetree/bindings/video/displaymode
> new file mode 100644
> index 0000000..990ca52
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/video/displaymode
> @@ -0,0 +1,74 @@
> +videomode bindings
> +=========
> +
> +Required properties:
> + - hactive, vactive: Display resolution
> + - hfront-porch, hback-porch, hsync-len: Horizontal Display timing parameters
> + in pixels
> + vfront-porch, vback-porch, vsync-len: Vertical display timing parameters in
> + lines
> + - clock: displayclock in Hz
A major piece missing is the LCD controller to display interface width
and component ordering.
> +
> +Optional properties:
> + - width-mm, height-mm: Display dimensions in mm
> + - hsync-active-high (bool): Hsync pulse is active high
> + - vsync-active-high (bool): Vsync pulse is active high
> + - interlaced (bool): This is an interlaced mode
> + - doublescan (bool): This is a doublescan mode
> +
> +There are different ways of describing a display mode. The devicetree representation
> +corresponds to the one commonly found in datasheets for displays.
> +The description of the display and its mode is split in two parts: first the display
> +properties like size in mm and (optionally) multiple subnodes with the supported modes.
> +
> +Example:
> +
> + display@0 {
It would be useful to have a compatible string here. We may not always
know the panel type or have a fixed panel though. We could define
"generic-lcd" or something for cases where the panel type is unknown.
> + width-mm = <800>;
> + height-mm = <480>;
> + modes {
> + mode0: mode@0 {
> + /* 1920x1080p24 */
> + clock = <52000000>;
> + hactive = <1920>;
> + vactive = <1080>;
> + hfront-porch = <25>;
> + hback-porch = <25>;
> + hsync-len = <25>;
> + vback-porch = <2>;
> + vfront-porch = <2>;
> + vsync-len = <2>;
> + hsync-active-high;
> + };
> + };
> + };
> +
> +Every property also supports the use of ranges, so the commonly used datasheet
> +description with <min typ max>-tuples can be used.
> +
> +Example:
> +
> + mode1: mode@1 {
> + /* 1920x1080p24 */
> + clock = <148500000>;
> + hactive = <1920>;
> + vactive = <1080>;
> + hsync-len = <0 44 60>;
> + hfront-porch = <80 88 95>;
> + hback-porch = <100 148 160>;
> + vfront-porch = <0 4 6>;
> + vback-porch = <0 36 50>;
> + vsync-len = <0 5 6>;
> + };
> +
> +The videomode can be linked to a connector via phandles. The connector has to
> +support the display- and default-mode-property to link to and select a mode.
Could also be phandle in the lcd controller node? What are the '-' for?
Is "display-blah" a valid name or something?
"default-mode" is pretty generic. How about display-mode or
display-default-mode?
Rob
> +
> +Example:
> +
> + hdmi@00120000 {
> + status = "okay";
> + display = <&benq>;
> + default-mode = <&mode1>;
> + };
> +
> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> index dfba3e6..a3acaa3 100644
> --- a/drivers/of/Kconfig
> +++ b/drivers/of/Kconfig
> @@ -83,4 +83,9 @@ config OF_MTD
> depends on MTD
> def_bool y
>
> +config OF_VIDEOMODE
> + def_bool y
> + help
> + helper to parse videomodes from the devicetree
> +
> endmenu # OF
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index e027f44..80e6db3 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -11,3 +11,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
> obj-$(CONFIG_OF_PCI) += of_pci.o
> obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
> obj-$(CONFIG_OF_MTD) += of_mtd.o
> +obj-$(CONFIG_OF_VIDEOMODE) += of_videomode.o
> diff --git a/drivers/of/of_videomode.c b/drivers/of/of_videomode.c
> new file mode 100644
> index 0000000..52bfc74
> --- /dev/null
> +++ b/drivers/of/of_videomode.c
> @@ -0,0 +1,283 @@
> +/*
> + * OF helpers for parsing display modes
> + *
> + * Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
> + * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix
> + *
> + * This file is released under the GPLv2
> + */
> +#include <linux/of.h>
> +#include <linux/fb.h>
> +#include <linux/export.h>
> +#include <linux/slab.h>
> +#include <drm/drmP.h>
> +#include <drm/drm_crtc.h>
> +#include <linux/of_videomode.h>
> +
> +static u32 of_video_get_value(struct mode_property *prop)
> +{
> + return (prop->min >= prop->typ) ? prop->min : prop->typ;
> +}
> +
> +/* read property into new mode_property */
> +static int of_video_parse_property(struct device_node *np, char *name,
> + struct mode_property *result)
> +{
> + struct property *prop;
> + int length;
> + int cells;
> + int ret;
> +
> + prop = of_find_property(np, name, &length);
> + if (!prop) {
> + pr_err("%s: could not find property %s\n", __func__,
> + name);
> + return -EINVAL;
> + }
> +
> + cells = length / sizeof(u32);
> +
> + memset(result, 0, sizeof(*result));
> +
> + ret = of_property_read_u32_array(np, name, &result->min, cells);
> +
> + return ret;
> +}
> +
> +static int of_video_free(struct display *disp)
> +{
> + int i;
> +
> + for (i=0; i<disp->num_modes; i++)
> + kfree(disp->modes[i]);
> + kfree(disp->modes);
> +
> + return 0;
> +}
> +
> +int videomode_to_display_mode(struct display *disp, struct drm_display_mode *dmode, int index)
> +{
> + struct videomode *vm;
> +
> + memset(dmode, 0, sizeof(*dmode));
> +
> + if (index > disp->num_modes) {
> + pr_err("%s: wrong index: %d from %d\n", __func__, index, disp->num_modes);
> + return -EINVAL;
> + }
> +
> + vm = disp->modes[index];
> +
> + dmode->hdisplay = of_video_get_value(&vm->hactive);
> + dmode->hsync_start = of_video_get_value(&vm->hactive) + of_video_get_value(&vm->hfront_porch);
> + dmode->hsync_end = of_video_get_value(&vm->hactive) + of_video_get_value(&vm->hfront_porch)
> + + of_video_get_value(&vm->hsync_len);
> + dmode->htotal = of_video_get_value(&vm->hactive) + of_video_get_value(&vm->hfront_porch)
> + + of_video_get_value(&vm->hsync_len) + of_video_get_value(&vm->hback_porch);
> +
> + dmode->vdisplay = of_video_get_value(&vm->vactive);
> + dmode->vsync_start = of_video_get_value(&vm->vactive) + of_video_get_value(&vm->vfront_porch);
> + dmode->vsync_end = of_video_get_value(&vm->vactive) + of_video_get_value(&vm->vfront_porch)
> + + of_video_get_value(&vm->vsync_len);
> + dmode->vtotal = of_video_get_value(&vm->vactive) + of_video_get_value(&vm->vfront_porch) +
> + of_video_get_value(&vm->vsync_len) + of_video_get_value(&vm->vback_porch);
> +
> + dmode->width_mm = disp->width_mm;
> + dmode->height_mm = disp->height_mm;
> +
> + dmode->clock = of_video_get_value(&vm->clock) / 1000;
> +
> + if (vm->hah)
> + dmode->flags |= DRM_MODE_FLAG_PHSYNC;
> + else
> + dmode->flags |= DRM_MODE_FLAG_NHSYNC;
> + if (vm->vah)
> + dmode->flags |= DRM_MODE_FLAG_PVSYNC;
> + else
> + dmode->flags |= DRM_MODE_FLAG_NVSYNC;
> + if (vm->interlaced)
> + dmode->flags |= DRM_MODE_FLAG_INTERLACE;
> + if (vm->doublescan)
> + dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
> +
> + drm_mode_set_name(dmode);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(videomode_to_display_mode);
> +
> +int videomode_to_fb_mode(struct display *disp, struct fb_videomode *fbmode, int index)
> +{
> + struct videomode *vm;
> +
> + memset(fbmode, 0, sizeof(*fbmode));
> +
> + if (index > disp->num_modes) {
> + pr_err("%s: wrong index: %d from %d\n", __func__, index, disp->num_modes);
> + return -EINVAL;
> + }
> +
> + vm = disp->modes[index];
> +
> + fbmode->xres = of_video_get_value(&vm->hactive);
> + fbmode->left_margin = of_video_get_value(&vm->hback_porch);
> + fbmode->right_margin = of_video_get_value(&vm->hfront_porch);
> + fbmode->hsync_len = of_video_get_value(&vm->hsync_len);
> +
> + fbmode->yres = of_video_get_value(&vm->vactive);
> + fbmode->upper_margin = of_video_get_value(&vm->vback_porch);
> + fbmode->lower_margin = of_video_get_value(&vm->vfront_porch);
> + fbmode->vsync_len = of_video_get_value(&vm->vsync_len);
> +
> + fbmode->pixclock = KHZ2PICOS(of_video_get_value(&vm->clock) / 1000);
> +
> + if (vm->hah)
> + fbmode->sync |= FB_SYNC_HOR_HIGH_ACT;
> + if (vm->vah)
> + fbmode->sync |= FB_SYNC_VERT_HIGH_ACT;
> + if (vm->interlaced)
> + fbmode->vmode |= FB_VMODE_INTERLACED;
> + if (vm->doublescan)
> + fbmode->vmode |= FB_VMODE_DOUBLE;
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(videomode_to_fb_mode);
> +
> +int of_get_video_modes(struct device_node *np, struct display *disp)
> +{
> + struct device_node *display_np;
> + struct device_node *mode_np;
> + struct device_node *modes_np;
> + char *default_mode;
> +
> + int ret = 0;
> +
> + memset(disp, 0, sizeof(*disp));
> + disp->modes = kmalloc(sizeof(struct videomode*), GFP_KERNEL);
> +
> + if (!np) {
> + pr_err("%s: no node provided\n", __func__);
> + return -EINVAL;
> + }
> +
> + display_np = of_parse_phandle(np, "display", 0);
> +
> + if (!display_np) {
> + pr_err("%s: could not find display node\n", __func__);
> + return -EINVAL;
> + }
> +
> + of_property_read_u32(display_np, "width-mm", &disp->width_mm);
> + of_property_read_u32(display_np, "height-mm", &disp->height_mm);
> +
> + mode_np = of_parse_phandle(np, "default-mode", 0);
> +
> + if (!mode_np) {
> + pr_info("%s: no default-mode specified.\n", __func__);
> + mode_np = of_find_node_by_name(np, "mode");
> + }
> +
> + if (!mode_np) {
> + pr_err("%s: could not find any mode specification\n", __func__);
> + return -EINVAL;
> + }
> +
> + default_mode = (char *)mode_np->full_name;
> +
> + modes_np = of_find_node_by_name(np, "modes");
> + for_each_child_of_node(modes_np, mode_np) {
> + struct videomode *vm;
> +
> + vm = kmalloc(sizeof(struct videomode*), GFP_KERNEL);
> + disp->modes[disp->num_modes] = kmalloc(sizeof(struct videomode*), GFP_KERNEL);
> +
> + ret |= of_video_parse_property(mode_np, "hback-porch", &vm->hback_porch);
> + ret |= of_video_parse_property(mode_np, "hfront-porch", &vm->hfront_porch);
> + ret |= of_video_parse_property(mode_np, "hactive", &vm->hactive);
> + ret |= of_video_parse_property(mode_np, "hsync-len", &vm->hsync_len);
> + ret |= of_video_parse_property(mode_np, "vback-porch", &vm->vback_porch);
> + ret |= of_video_parse_property(mode_np, "vfront-porch", &vm->vfront_porch);
> + ret |= of_video_parse_property(mode_np, "vactive", &vm->vactive);
> + ret |= of_video_parse_property(mode_np, "vsync-len", &vm->vsync_len);
> + ret |= of_video_parse_property(mode_np, "clock", &vm->clock);
> +
> + if (ret)
> + return -EINVAL;
> +
> + vm->hah = of_property_read_bool(mode_np, "hsync-active-high");
> + vm->vah = of_property_read_bool(mode_np, "vsync-active-high");
> + vm->interlaced = of_property_read_bool(mode_np, "interlaced");
> + vm->doublescan = of_property_read_bool(mode_np, "doublescan");
> +
> + if (strcmp(default_mode,mode_np->full_name) = 0)
> + disp->default_mode = disp->num_modes;
> +
> + disp->modes[disp->num_modes] = vm;
> + disp->num_modes++;
> + }
> + of_node_put(display_np);
> +
> + pr_info("%s: found %d modelines. Using #%d as default\n", __func__,
> + disp->num_modes, disp->default_mode + 1);
> +
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_get_video_modes);
> +
> +int of_video_mode_exists(struct device_node *np)
> +{
> + struct device_node *display_np;
> + struct device_node *mode_np;
> +
> + if (!np)
> + return -EINVAL;
> +
> + display_np = of_parse_phandle(np, "display", 0);
> +
> + if (!display_np)
> + return -EINVAL;
> +
> + mode_np = of_parse_phandle(np, "default-mode", 0);
> +
> + if (mode_np)
> + return 0;
> +
> + return -EINVAL;
> +}
> +EXPORT_SYMBOL_GPL(of_video_mode_exists);
> +
> +int of_get_display_mode(struct device_node *np, struct drm_display_mode *dmode, int index)
> +{
> + struct display disp;
> +
> + of_get_video_modes(np, &disp);
> +
> + if (index = OF_MODE_SELECTION)
> + index = disp.default_mode;
> + if (dmode)
> + videomode_to_display_mode(&disp, dmode, index);
> +
> + of_video_free(&disp);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_get_display_mode);
> +
> +int of_get_fb_videomode(struct device_node *np, struct fb_videomode *fbmode, int index)
> +{
> + struct display disp;
> +
> + of_get_video_modes(np, &disp);
> +
> + if (index = OF_MODE_SELECTION)
> + index = disp.default_mode;
> + if (fbmode)
> + videomode_to_fb_mode(&disp, fbmode, index);
> +
> + of_video_free(&disp);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_get_fb_videomode);
> diff --git a/include/linux/of_videomode.h b/include/linux/of_videomode.h
> new file mode 100644
> index 0000000..5571ce3
> --- /dev/null
> +++ b/include/linux/of_videomode.h
> @@ -0,0 +1,56 @@
> +/*
> + * Copyright 2012 Sascha Hauer <s.hauer@pengutronix.de>
> + * Copyright 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>
> + *
> + * OF helpers for videomodes.
> + *
> + * This file is released under the GPLv2
> + */
> +
> +#ifndef __LINUX_OF_VIDEOMODE_H
> +#define __LINUX_OF_VIDEOMODE_H
> +
> +#define OF_MODE_SELECTION -1
> +
> +struct mode_property {
> + u32 min;
> + u32 typ;
> + u32 max;
> +};
> +
> +struct display {
> + u32 width_mm;
> + u32 height_mm;
> + struct videomode **modes;
> + int default_mode;
> + int num_modes;
> +};
> +
> +/* describe videomode in terms of hardware parameters */
> +struct videomode {
> + struct mode_property hback_porch;
> + struct mode_property hfront_porch;
> + struct mode_property hactive;
> + struct mode_property hsync_len;
> +
> + struct mode_property vback_porch;
> + struct mode_property vfront_porch;
> + struct mode_property vactive;
> + struct mode_property vsync_len;
> +
> + struct mode_property clock;
> +
> + bool hah;
> + bool vah;
> + bool interlaced;
> + bool doublescan;
> +};
> +
> +int of_video_mode_exists(struct device_node *np);
> +int videomode_to_display_mode(struct display *disp, struct drm_display_mode *dmode, int index);
> +int videomode_to_fb_mode(struct display *disp, struct fb_videomode *fbmode, int index);
> +int of_get_video_modes(struct device_node *np, struct display *disp);
> +int of_video_mode_exists(struct device_node *np);
> +int of_get_display_mode(struct device_node *np, struct drm_display_mode *dmode, int index);
> +int of_get_fb_videomode(struct device_node *np, struct fb_videomode *fbmode, int index);
> +#endif /* __LINUX_OF_VIDEOMODE_H */
>
^ permalink raw reply
* [PATCH 0/9] OMAPDSS: OMAP5 related patches
From: Tomi Valkeinen @ 2012-09-24 13:58 UTC (permalink / raw)
To: archit, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
Hi,
This series adds basic OMAP5 DSS functionality, mainly related to DSS core, DPI
and DSI.
Tomi
Archit Taneja (1):
OMAPDSS: Add basic omap5 features to dss and dispc
Tomi Valkeinen (8):
OMAPDSS: DSI: improve DSI clock calcs for DISPC
OMAPDSS: move dss feats to the end of dss.c
OMAPDSS: Add support for DPI source selection
OMAPDSS: DSI: Add FEAT_DSI_PLL_SELFREQDCO
OMAPDSS: DSI: Add FEAT_DSI_PLL_REFSEL
OMAPDSS: DSI: Add new linebuffer size for OMAP5
OMAPDSS: DSI: Add code to disable PHY DCC
OMAPDSS: DSI: make OMAP2_DSS_DSI depend on ARCH_OMAP5
drivers/video/omap2/dss/Kconfig | 2 +-
drivers/video/omap2/dss/dispc.c | 2 +
drivers/video/omap2/dss/dpi.c | 5 +
drivers/video/omap2/dss/dsi.c | 167 +++++++++++++++++++++++++-------
drivers/video/omap2/dss/dss.c | 121 ++++++++++++++++++-----
drivers/video/omap2/dss/dss.h | 1 +
drivers/video/omap2/dss/dss_features.c | 96 ++++++++++++++++++
drivers/video/omap2/dss/dss_features.h | 3 +
8 files changed, 337 insertions(+), 60 deletions(-)
--
1.7.9.5
^ permalink raw reply
* [PATCH 1/9] OMAPDSS: DSI: improve DSI clock calcs for DISPC
From: Tomi Valkeinen @ 2012-09-24 13:58 UTC (permalink / raw)
To: archit, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1348495119-8262-1-git-send-email-tomi.valkeinen@ti.com>
Commit ee144e645a081daad5de1ccac77f0a0e98e6a67b added
dsi_pll_calc_ddrfreq() which calculates PLL dividers based on given DSI
bus clock speed. The function works ok, but it can be improved for the
DISPC clock calc.
The current version calculates the clock going from the PLL to the DISPC
simply by setting the clock as close to DISPC maximum as possible, and
the pixel clock is calculated based on that.
This patch changes the function to calculate DISPC clock more
dynamically, iterating through different DISPC clocks and pixel clock
values, and thus we'll get more suitable pixel clocks.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dsi.c | 144 ++++++++++++++++++++++++++++++++---------
1 file changed, 113 insertions(+), 31 deletions(-)
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 8d815e3..8d47fb7 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -1454,26 +1454,17 @@ found:
}
static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev,
- unsigned long req_clk, struct dsi_clock_info *cinfo)
+ unsigned long req_clkin4ddr, struct dsi_clock_info *cinfo)
{
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
struct dsi_clock_info cur, best;
- unsigned long dss_sys_clk, max_dss_fck, max_dsi_fck;
- unsigned long req_clkin4ddr;
DSSDBG("dsi_pll_calc_ddrfreq\n");
- dss_sys_clk = clk_get_rate(dsi->sys_clk);
-
- max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
- max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK);
-
memset(&best, 0, sizeof(best));
memset(&cur, 0, sizeof(cur));
- cur.clkin = dss_sys_clk;
-
- req_clkin4ddr = req_clk * 4;
+ 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;
@@ -1503,18 +1494,107 @@ static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev,
}
}
found:
- best.regm_dispc = DIV_ROUND_UP(best.clkin4ddr, max_dss_fck);
- best.dsi_pll_hsdiv_dispc_clk = best.clkin4ddr / best.regm_dispc;
-
- best.regm_dsi = DIV_ROUND_UP(best.clkin4ddr, max_dsi_fck);
- best.dsi_pll_hsdiv_dsi_clk = best.clkin4ddr / best.regm_dsi;
-
if (cinfo)
*cinfo = best;
return 0;
}
+static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev,
+ struct dsi_clock_info *cinfo)
+{
+ unsigned long max_dsi_fck;
+
+ max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK);
+
+ cinfo->regm_dsi = DIV_ROUND_UP(cinfo->clkin4ddr, max_dsi_fck);
+ 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)
{
@@ -4188,33 +4268,35 @@ int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev,
mutex_lock(&dsi->lock);
- r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk, &cinfo);
+ /* Calculate PLL output clock */
+ r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk * 4, &cinfo);
if (r)
goto err;
- dssdev->clocks.dsi.regn = cinfo.regn;
- dssdev->clocks.dsi.regm = cinfo.regm;
- dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc;
- dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi;
+ /* Calculate PLL's DSI clock */
+ dsi_pll_calc_dsi_fck(dsidev, &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);
- dssdev->clocks.dsi.lp_clk_div = lp_clk_div;
-
- /* pck = TxByteClkHS * datalanes * 8 / bitsperpixel */
-
- pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp;
-
- DSSDBG("finding dispc dividers for pck %lu\n", pck);
+ dssdev->clocks.dsi.regn = cinfo.regn;
+ dssdev->clocks.dsi.regm = cinfo.regm;
+ dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc;
+ dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi;
- dispc_find_clk_divs(pck, cinfo.dsi_pll_hsdiv_dispc_clk, &dispc_cinfo);
+ dssdev->clocks.dsi.lp_clk_div = lp_clk_div;
dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div;
dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div;
-
dssdev->clocks.dispc.dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK;
dssdev->clocks.dispc.channel.lcd_clk_src --
1.7.9.5
^ permalink raw reply related
* [PATCH 2/9] OMAPDSS: Add basic omap5 features to dss and dispc
From: Tomi Valkeinen @ 2012-09-24 13:58 UTC (permalink / raw)
To: archit, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1348495119-8262-1-git-send-email-tomi.valkeinen@ti.com>
From: Archit Taneja <archit@ti.com>
Add basic omap5 features for dss and dispc.
Signed-off-by: Archit Taneja <archit@ti.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dispc.c | 2 +
drivers/video/omap2/dss/dss.c | 8 +++
drivers/video/omap2/dss/dss_features.c | 93 ++++++++++++++++++++++++++++++++
3 files changed, 103 insertions(+)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index d512c38..e52c5778 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -3829,6 +3829,8 @@ static int __init dispc_init_features(struct device *dev)
src = &omap34xx_rev3_0_dispc_feats;
} else if (cpu_is_omap44xx()) {
src = &omap44xx_dispc_feats;
+ } else if (soc_is_omap54xx()) {
+ src = &omap44xx_dispc_feats;
} else {
return -ENODEV;
}
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 759dbee..4524c17 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -123,6 +123,12 @@ static const struct dss_features omap44xx_dss_feats __initconst = {
.clk_name = "dpll_per_m5x2_ck",
};
+static const struct dss_features omap54xx_dss_feats __initconst = {
+ .fck_div_max = 64,
+ .dss_fck_multiplier = 1,
+ .clk_name = "dpll_per_h12x2_ck",
+};
+
static inline void dss_write_reg(const struct dss_reg idx, u32 val)
{
__raw_writel(val, dss.base + idx.idx);
@@ -740,6 +746,8 @@ static int __init dss_init_features(struct device *dev)
src = &omap3630_dss_feats;
else if (cpu_is_omap44xx())
src = &omap44xx_dss_feats;
+ else if (soc_is_omap54xx())
+ src = &omap54xx_dss_feats;
else
return -ENODEV;
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index c26fc1f..af4775a 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -106,6 +106,21 @@ static const struct dss_reg_field omap4_dss_reg_fields[] = {
[FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
};
+static const struct dss_reg_field omap5_dss_reg_fields[] = {
+ [FEAT_REG_FIRHINC] = { 12, 0 },
+ [FEAT_REG_FIRVINC] = { 28, 16 },
+ [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 },
+ [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 },
+ [FEAT_REG_FIFOSIZE] = { 15, 0 },
+ [FEAT_REG_HORIZONTALACCU] = { 10, 0 },
+ [FEAT_REG_VERTICALACCU] = { 26, 16 },
+ [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 },
+ [FEAT_REG_DSIPLL_REGN] = { 8, 1 },
+ [FEAT_REG_DSIPLL_REGM] = { 20, 9 },
+ [FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 },
+ [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
+};
+
static const enum omap_display_type omap2_dss_supported_displays[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI,
@@ -144,6 +159,19 @@ static const enum omap_display_type omap4_dss_supported_displays[] = {
OMAP_DISPLAY_TYPE_DSI,
};
+static const enum omap_display_type omap5_dss_supported_displays[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
+ OMAP_DISPLAY_TYPE_DSI,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DISPLAY_TYPE_HDMI | OMAP_DISPLAY_TYPE_DPI,
+
+ /* OMAP_DSS_CHANNEL_LCD2 */
+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
+ OMAP_DISPLAY_TYPE_DSI,
+};
+
static const enum omap_color_mode omap2_dss_supported_color_modes[] = {
/* OMAP_DSS_GFX */
OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
@@ -298,6 +326,14 @@ static const char * const omap4_dss_clk_source_names[] = {
[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "PLL2_CLK2",
};
+static const char * const omap5_dss_clk_source_names[] = {
+ [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DPLL_DSI1_A_CLK1",
+ [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DPLL_DSI1_A_CLK2",
+ [OMAP_DSS_CLK_SRC_FCK] = "DSS_CLK",
+ [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DPLL_DSI1_C_CLK1",
+ [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DPLL_DSI1_C_CLK2",
+};
+
static const struct dss_param_range omap2_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 173000000 },
[FEAT_PARAM_DSS_PCD] = { 2, 255 },
@@ -349,6 +385,22 @@ static const struct dss_param_range omap4_dss_param_range[] = {
[FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 },
};
+static const struct dss_param_range omap5_dss_param_range[] = {
+ [FEAT_PARAM_DSS_FCK] = { 0, 200000000 },
+ [FEAT_PARAM_DSS_PCD] = { 1, 255 },
+ [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 },
+ [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 },
+ [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 },
+ [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
+ [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 },
+ [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
+ [FEAT_PARAM_DSI_FCK] = { 0, 170000000 },
+ [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
+ [FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
+ [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 },
+ [FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 },
+};
+
static const enum dss_feat_id omap2_dss_feat_list[] = {
FEAT_LCDENABLEPOL,
FEAT_LCDENABLESIGNAL,
@@ -450,6 +502,25 @@ static const enum dss_feat_id omap4_dss_feat_list[] = {
FEAT_BURST_2D,
};
+static const enum dss_feat_id omap5_dss_feat_list[] = {
+ FEAT_MGR_LCD2,
+ FEAT_CORE_CLK_DIV,
+ FEAT_LCD_CLK_SRC,
+ FEAT_DSI_DCS_CMD_CONFIG_VC,
+ FEAT_DSI_VC_OCP_WIDTH,
+ FEAT_DSI_GNQ,
+ FEAT_HDMI_CTS_SWMODE,
+ FEAT_HDMI_AUDIO_USE_MCLK,
+ FEAT_HANDLE_UV_SEPARATE,
+ FEAT_ATTR2,
+ FEAT_CPR,
+ FEAT_PRELOAD,
+ FEAT_FIR_COEF_V,
+ FEAT_ALPHA_FREE_ZORDER,
+ FEAT_FIFO_MERGE,
+ FEAT_BURST_2D,
+};
+
/* OMAP2 DSS Features */
static const struct omap_dss_features omap2_dss_features = {
.reg_fields = omap2_dss_reg_fields,
@@ -570,6 +641,26 @@ static const struct omap_dss_features omap4_dss_features = {
.burst_size_unit = 16,
};
+/* OMAP5 DSS Features */
+static const struct omap_dss_features omap5_dss_features = {
+ .reg_fields = omap5_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(omap5_dss_reg_fields),
+
+ .features = omap5_dss_feat_list,
+ .num_features = ARRAY_SIZE(omap5_dss_feat_list),
+
+ .num_mgrs = 3,
+ .num_ovls = 4,
+ .supported_displays = omap5_dss_supported_displays,
+ .supported_color_modes = omap4_dss_supported_color_modes,
+ .overlay_caps = omap4_dss_overlay_caps,
+ .clksrc_names = omap5_dss_clk_source_names,
+ .dss_params = omap5_dss_param_range,
+ .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
+ .buffer_size_unit = 16,
+ .burst_size_unit = 16,
+};
+
#if defined(CONFIG_OMAP4_DSS_HDMI)
/* HDMI OMAP4 Functions*/
static const struct ti_hdmi_ip_ops omap4_hdmi_functions = {
@@ -707,6 +798,8 @@ void dss_features_init(void)
omap_current_dss_features = &omap4430_es2_0_1_2_dss_features;
else if (cpu_is_omap44xx())
omap_current_dss_features = &omap4_dss_features;
+ else if (soc_is_omap54xx())
+ omap_current_dss_features = &omap5_dss_features;
else
DSSWARN("Unsupported OMAP version");
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH 3/9] OMAPDSS: move dss feats to the end of dss.c
From: Tomi Valkeinen @ 2012-09-24 13:58 UTC (permalink / raw)
To: archit, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1348495119-8262-1-git-send-email-tomi.valkeinen@ti.com>
Move dss_features to the end of dss.c the same way they are in dispc.c,
so that we don't have to declare prototypes for static feat-related
functions.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dss.c | 60 ++++++++++++++++++++---------------------
1 file changed, 30 insertions(+), 30 deletions(-)
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 4524c17..660813b 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -99,36 +99,6 @@ static const char * const dss_generic_clk_source_names[] = {
[OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK",
};
-static const struct dss_features omap24xx_dss_feats __initconst = {
- .fck_div_max = 16,
- .dss_fck_multiplier = 2,
- .clk_name = NULL,
-};
-
-static const struct dss_features omap34xx_dss_feats __initconst = {
- .fck_div_max = 16,
- .dss_fck_multiplier = 2,
- .clk_name = "dpll4_m4_ck",
-};
-
-static const struct dss_features omap3630_dss_feats __initconst = {
- .fck_div_max = 32,
- .dss_fck_multiplier = 1,
- .clk_name = "dpll4_m4_ck",
-};
-
-static const struct dss_features omap44xx_dss_feats __initconst = {
- .fck_div_max = 32,
- .dss_fck_multiplier = 1,
- .clk_name = "dpll_per_m5x2_ck",
-};
-
-static const struct dss_features omap54xx_dss_feats __initconst = {
- .fck_div_max = 64,
- .dss_fck_multiplier = 1,
- .clk_name = "dpll_per_h12x2_ck",
-};
-
static inline void dss_write_reg(const struct dss_reg idx, u32 val)
{
__raw_writel(val, dss.base + idx.idx);
@@ -727,6 +697,36 @@ void dss_debug_dump_clocks(struct seq_file *s)
}
#endif
+static const struct dss_features omap24xx_dss_feats __initconst = {
+ .fck_div_max = 16,
+ .dss_fck_multiplier = 2,
+ .clk_name = NULL,
+};
+
+static const struct dss_features omap34xx_dss_feats __initconst = {
+ .fck_div_max = 16,
+ .dss_fck_multiplier = 2,
+ .clk_name = "dpll4_m4_ck",
+};
+
+static const struct dss_features omap3630_dss_feats __initconst = {
+ .fck_div_max = 32,
+ .dss_fck_multiplier = 1,
+ .clk_name = "dpll4_m4_ck",
+};
+
+static const struct dss_features omap44xx_dss_feats __initconst = {
+ .fck_div_max = 32,
+ .dss_fck_multiplier = 1,
+ .clk_name = "dpll_per_m5x2_ck",
+};
+
+static const struct dss_features omap54xx_dss_feats __initconst = {
+ .fck_div_max = 64,
+ .dss_fck_multiplier = 1,
+ .clk_name = "dpll_per_h12x2_ck",
+};
+
static int __init dss_init_features(struct device *dev)
{
const struct dss_features *src;
--
1.7.9.5
^ permalink raw reply related
* [PATCH 4/9] OMAPDSS: Add support for DPI source selection
From: Tomi Valkeinen @ 2012-09-24 13:58 UTC (permalink / raw)
To: archit, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen, David Anders
In-Reply-To: <1348495119-8262-1-git-send-email-tomi.valkeinen@ti.com>
We can select the video source for DPI output as follows:
OMAP2/3: always LCD1
OMAP4: LCD2 or DIGIT
OMAP5: LCD1/LCD2/LCD3/DIGIT
This patch adds support to select the source, and makes dpi.c call the
function to set the source.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Cc: David Anders <x0132446@ti.com>
---
drivers/video/omap2/dss/dpi.c | 5 ++++
drivers/video/omap2/dss/dss.c | 65 +++++++++++++++++++++++++++++++++++++++++
drivers/video/omap2/dss/dss.h | 1 +
3 files changed, 71 insertions(+)
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 5ccce9b..b723388 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -203,6 +203,10 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
if (r)
goto err_get_dispc;
+ r = dss_dpi_select_source(dssdev->channel);
+ if (r)
+ goto err_src_sel;
+
if (dpi_use_dsi_pll(dssdev)) {
r = dsi_runtime_get(dpi.dsidev);
if (r)
@@ -237,6 +241,7 @@ err_dsi_pll_init:
if (dpi_use_dsi_pll(dssdev))
dsi_runtime_put(dpi.dsidev);
err_get_dsi:
+err_src_sel:
dispc_runtime_put();
err_get_dispc:
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 660813b..2ab1c3e9 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -69,6 +69,7 @@ struct dss_features {
u8 fck_div_max;
u8 dss_fck_multiplier;
const char *clk_name;
+ int (*dpi_select_source)(enum omap_channel channel);
};
static struct {
@@ -623,6 +624,65 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
return REG_GET(DSS_CONTROL, 15, 15);
}
+static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel)
+{
+ if (channel != OMAP_DSS_CHANNEL_LCD)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int dss_dpi_select_source_omap4(enum omap_channel channel)
+{
+ int val;
+
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD2:
+ val = 0;
+ break;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ val = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ REG_FLD_MOD(DSS_CONTROL, val, 17, 17);
+
+ return 0;
+}
+
+static int dss_dpi_select_source_omap5(enum omap_channel channel)
+{
+ int val;
+
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ val = 1;
+ break;
+ case OMAP_DSS_CHANNEL_LCD2:
+ val = 2;
+ break;
+ case OMAP_DSS_CHANNEL_LCD3:
+ val = 3;
+ break;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ REG_FLD_MOD(DSS_CONTROL, val, 17, 16);
+
+ return 0;
+}
+
+int dss_dpi_select_source(enum omap_channel channel)
+{
+ return dss.feat->dpi_select_source(channel);
+}
+
static int dss_get_clocks(void)
{
struct clk *clk;
@@ -701,30 +761,35 @@ static const struct dss_features omap24xx_dss_feats __initconst = {
.fck_div_max = 16,
.dss_fck_multiplier = 2,
.clk_name = NULL,
+ .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
};
static const struct dss_features omap34xx_dss_feats __initconst = {
.fck_div_max = 16,
.dss_fck_multiplier = 2,
.clk_name = "dpll4_m4_ck",
+ .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
};
static const struct dss_features omap3630_dss_feats __initconst = {
.fck_div_max = 32,
.dss_fck_multiplier = 1,
.clk_name = "dpll4_m4_ck",
+ .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
};
static const struct dss_features omap44xx_dss_feats __initconst = {
.fck_div_max = 32,
.dss_fck_multiplier = 1,
.clk_name = "dpll_per_m5x2_ck",
+ .dpi_select_source = &dss_dpi_select_source_omap4,
};
static const struct dss_features omap54xx_dss_feats __initconst = {
.fck_div_max = 64,
.dss_fck_multiplier = 1,
.clk_name = "dpll_per_h12x2_ck",
+ .dpi_select_source = &dss_dpi_select_source_omap5,
};
static int __init dss_init_features(struct device *dev)
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 5e9fd769..2a51ae9 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -277,6 +277,7 @@ void dss_overlay_kobj_uninit(struct omap_overlay *ovl);
int dss_init_platform_driver(void) __init;
void dss_uninit_platform_driver(void);
+int dss_dpi_select_source(enum omap_channel channel);
void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void);
const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
--
1.7.9.5
^ permalink raw reply related
* [PATCH 5/9] OMAPDSS: DSI: Add FEAT_DSI_PLL_SELFREQDCO
From: Tomi Valkeinen @ 2012-09-24 13:58 UTC (permalink / raw)
To: archit, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1348495119-8262-1-git-send-email-tomi.valkeinen@ti.com>
Add FEAT_DSI_PLL_SELFREQDCO. OMAP5's DSI PLL has a new configuration
option that needs to be programmed depending on the PLL's output clock
frequency.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dsi.c | 12 ++++++++----
drivers/video/omap2/dss/dss_features.c | 1 +
drivers/video/omap2/dss/dss_features.h | 1 +
3 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 8d47fb7..0c3afc2 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -1671,18 +1671,22 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev,
BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max);
+ l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
+
if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) {
f = cinfo->fint < 1000000 ? 0x3 :
cinfo->fint < 1250000 ? 0x4 :
cinfo->fint < 1500000 ? 0x5 :
cinfo->fint < 1750000 ? 0x6 :
0x7;
- }
-
- l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
- if (dss_has_feature(FEAT_DSI_PLL_FREQSEL))
l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */
+ } else if (dss_has_feature(FEAT_DSI_PLL_SELFREQDCO)) {
+ f = cinfo->clkin4ddr < 1000000000 ? 0x2 : 0x4;
+
+ l = FLD_MOD(l, f, 4, 1); /* PLL_SELFREQDCO */
+ }
+
l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */
l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index af4775a..177f6e8 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -519,6 +519,7 @@ static const enum dss_feat_id omap5_dss_feat_list[] = {
FEAT_ALPHA_FREE_ZORDER,
FEAT_FIFO_MERGE,
FEAT_BURST_2D,
+ FEAT_DSI_PLL_SELFREQDCO,
};
/* OMAP2 DSS Features */
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
index b81d603..f9b9d28 100644
--- a/drivers/video/omap2/dss/dss_features.h
+++ b/drivers/video/omap2/dss/dss_features.h
@@ -65,6 +65,7 @@ enum dss_feat_id {
/* An unknown HW bug causing the normal FIFO thresholds not to work */
FEAT_OMAP3_DSI_FIFO_BUG,
FEAT_BURST_2D,
+ FEAT_DSI_PLL_SELFREQDCO,
};
/* DSS register field id */
--
1.7.9.5
^ permalink raw reply related
* [PATCH 6/9] OMAPDSS: DSI: Add FEAT_DSI_PLL_REFSEL
From: Tomi Valkeinen @ 2012-09-24 13:58 UTC (permalink / raw)
To: archit, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1348495119-8262-1-git-send-email-tomi.valkeinen@ti.com>
Add FEAT_DSI_PLL_REFSEL. OMAP5's DSI PLL needs configuration to select
the reference clock to be used. We always use SYSCLK.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dsi.c | 2 ++
drivers/video/omap2/dss/dss_features.c | 1 +
drivers/video/omap2/dss/dss_features.h | 1 +
3 files changed, 4 insertions(+)
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 0c3afc2..a16c8b2 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -1690,6 +1690,8 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev,
l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */
l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */
+ if (dss_has_feature(FEAT_DSI_PLL_REFSEL))
+ l = FLD_MOD(l, 3, 22, 21); /* REF_SYSCLK = sysclk */
dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index 177f6e8..4685531 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -520,6 +520,7 @@ static const enum dss_feat_id omap5_dss_feat_list[] = {
FEAT_FIFO_MERGE,
FEAT_BURST_2D,
FEAT_DSI_PLL_SELFREQDCO,
+ FEAT_DSI_PLL_REFSEL,
};
/* OMAP2 DSS Features */
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
index f9b9d28..0020bf6 100644
--- a/drivers/video/omap2/dss/dss_features.h
+++ b/drivers/video/omap2/dss/dss_features.h
@@ -66,6 +66,7 @@ enum dss_feat_id {
FEAT_OMAP3_DSI_FIFO_BUG,
FEAT_BURST_2D,
FEAT_DSI_PLL_SELFREQDCO,
+ FEAT_DSI_PLL_REFSEL,
};
/* DSS register field id */
--
1.7.9.5
^ permalink raw reply related
* [PATCH 7/9] OMAPDSS: DSI: Add new linebuffer size for OMAP5
From: Tomi Valkeinen @ 2012-09-24 13:58 UTC (permalink / raw)
To: archit, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1348495119-8262-1-git-send-email-tomi.valkeinen@ti.com>
OMAP5's DSI has a larger line buffer than earlier OMAPs. This patch adds
support for this to the DSI driver.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dsi.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index a16c8b2..0dc24f2 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -2155,6 +2155,8 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
return 1194 * 3; /* 1194x24 bits */
case 6:
return 1365 * 3; /* 1365x24 bits */
+ case 7:
+ return 1920 * 3; /* 1920x24 bits */
default:
BUG();
return 0;
--
1.7.9.5
^ permalink raw reply related
* [PATCH 8/9] OMAPDSS: DSI: Add code to disable PHY DCC
From: Tomi Valkeinen @ 2012-09-24 13:58 UTC (permalink / raw)
To: archit, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1348495119-8262-1-git-send-email-tomi.valkeinen@ti.com>
OMAP5 DSI PHY has DCC (Duty Cycle Corrector) block, and by default DCC
is enabled and thus the PLL clock is divided by 2 to get the DSI DDR
clk. This divider has been 4 for all previous OMAPs, and changing it
needs some reorganization of the code. The DCC can be disabled, and in
that case the divider is back to the old 4.
This patch adds dss feature for the DCC, and adds code to always disable
the DCC.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dsi.c | 7 +++++++
drivers/video/omap2/dss/dss_features.c | 1 +
drivers/video/omap2/dss/dss_features.h | 1 +
3 files changed, 9 insertions(+)
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 0dc24f2..497b219 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -2292,6 +2292,13 @@ static void dsi_cio_timings(struct platform_device *dsidev)
r = FLD_MOD(r, tlpx_half, 22, 16);
r = FLD_MOD(r, tclk_trail, 15, 8);
r = FLD_MOD(r, tclk_zero, 7, 0);
+
+ if (dss_has_feature(FEAT_DSI_PHY_DCC)) {
+ r = FLD_MOD(r, 0, 21, 21); /* DCCEN = disable */
+ r = FLD_MOD(r, 1, 22, 22); /* CLKINP_DIVBY2EN = enable */
+ r = FLD_MOD(r, 1, 23, 23); /* CLKINP_SEL = enable */
+ }
+
dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r);
r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index 4685531..e650a4a 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -521,6 +521,7 @@ static const enum dss_feat_id omap5_dss_feat_list[] = {
FEAT_BURST_2D,
FEAT_DSI_PLL_SELFREQDCO,
FEAT_DSI_PLL_REFSEL,
+ FEAT_DSI_PHY_DCC,
};
/* OMAP2 DSS Features */
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
index 0020bf6..aacad86 100644
--- a/drivers/video/omap2/dss/dss_features.h
+++ b/drivers/video/omap2/dss/dss_features.h
@@ -67,6 +67,7 @@ enum dss_feat_id {
FEAT_BURST_2D,
FEAT_DSI_PLL_SELFREQDCO,
FEAT_DSI_PLL_REFSEL,
+ FEAT_DSI_PHY_DCC,
};
/* DSS register field id */
--
1.7.9.5
^ permalink raw reply related
* [PATCH 9/9] OMAPDSS: DSI: make OMAP2_DSS_DSI depend on ARCH_OMAP5
From: Tomi Valkeinen @ 2012-09-24 13:58 UTC (permalink / raw)
To: archit, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1348495119-8262-1-git-send-email-tomi.valkeinen@ti.com>
Change omapdss Kconfig file to make OMAP2_DSS_DSI depend on ARCH_OMAP5.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
index b337a84..80f5390 100644
--- a/drivers/video/omap2/dss/Kconfig
+++ b/drivers/video/omap2/dss/Kconfig
@@ -84,7 +84,7 @@ config OMAP2_DSS_SDI
config OMAP2_DSS_DSI
bool "DSI support"
- depends on ARCH_OMAP3 || ARCH_OMAP4
+ depends on ARCH_OMAP3 || ARCH_OMAP4 || ARCH_OMAP5
default n
help
MIPI DSI (Display Serial Interface) support.
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH v4] of: Add videomode helper
From: Sascha Hauer @ 2012-09-24 14:12 UTC (permalink / raw)
To: Rob Herring
Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Laurent Pinchart,
kernel-bIcnvbaLZ9MEGnE8C9+IrQ, Steffen Trumtrar
In-Reply-To: <50606334.7030902-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Hi Rob,
On Mon, Sep 24, 2012 at 08:42:12AM -0500, Rob Herring wrote:
> On 09/19/2012 03:20 AM, Steffen Trumtrar wrote:
> > This patch adds a helper function for parsing videomodes from the devicetree.
> > The videomode can be either converted to a struct drm_display_mode or a
> > struct fb_videomode.
> >
> > +
> > +Required properties:
> > + - hactive, vactive: Display resolution
> > + - hfront-porch, hback-porch, hsync-len: Horizontal Display timing parameters
> > + in pixels
> > + vfront-porch, vback-porch, vsync-len: Vertical display timing parameters in
> > + lines
> > + - clock: displayclock in Hz
>
> A major piece missing is the LCD controller to display interface width
> and component ordering.
Psst. We silently skipped this for now...
I think having such a videomode helper is useful without having the
data order part. We are aware that this should be added later, but
I think currently it makes sense to concentrate on the basics.
>
> > +
> > +Optional properties:
> > + - width-mm, height-mm: Display dimensions in mm
> > + - hsync-active-high (bool): Hsync pulse is active high
> > + - vsync-active-high (bool): Vsync pulse is active high
> > + - interlaced (bool): This is an interlaced mode
> > + - doublescan (bool): This is a doublescan mode
> > +
> > +There are different ways of describing a display mode. The devicetree representation
> > +corresponds to the one commonly found in datasheets for displays.
> > +The description of the display and its mode is split in two parts: first the display
> > +properties like size in mm and (optionally) multiple subnodes with the supported modes.
> > +
> > +Example:
> > +
> > + display@0 {
>
> It would be useful to have a compatible string here. We may not always
> know the panel type or have a fixed panel though. We could define
> "generic-lcd" or something for cases where the panel type is unknown.
We expect the display nodes being subnodes of a driver (which of course
has a compatible), or maybe referred to from a driver using phandles. So
I don't see why the display node itself should have a compatible
property. The display information is only ever useful in the context of
a driver.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* Re: [PATCH v4] of: Add videomode helper
From: Rob Herring @ 2012-09-24 15:18 UTC (permalink / raw)
To: Sascha Hauer
Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Laurent Pinchart,
kernel-bIcnvbaLZ9MEGnE8C9+IrQ, Steffen Trumtrar
In-Reply-To: <20120924141233.GN1322-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
On 09/24/2012 09:12 AM, Sascha Hauer wrote:
> Hi Rob,
>
> On Mon, Sep 24, 2012 at 08:42:12AM -0500, Rob Herring wrote:
>> On 09/19/2012 03:20 AM, Steffen Trumtrar wrote:
>>> This patch adds a helper function for parsing videomodes from the devicetree.
>>> The videomode can be either converted to a struct drm_display_mode or a
>>> struct fb_videomode.
>>>
>>> +
>>> +Required properties:
>>> + - hactive, vactive: Display resolution
>>> + - hfront-porch, hback-porch, hsync-len: Horizontal Display timing parameters
>>> + in pixels
>>> + vfront-porch, vback-porch, vsync-len: Vertical display timing parameters in
>>> + lines
>>> + - clock: displayclock in Hz
>>
>> A major piece missing is the LCD controller to display interface width
>> and component ordering.
>
> Psst. We silently skipped this for now...
>
> I think having such a videomode helper is useful without having the
> data order part. We are aware that this should be added later, but
> I think currently it makes sense to concentrate on the basics.
Evolving bindings is not a good thing. We know this is needed, so we
should address it now. If Linux had a standard way to describe the
interface (it didn't a few years ago and I haven't kept up), then I
would bet it would already be part of this binding. Defining the
bindings in terms of what an OS uses or not is the wrong way around.
>>
>>> +
>>> +Optional properties:
>>> + - width-mm, height-mm: Display dimensions in mm
>>> + - hsync-active-high (bool): Hsync pulse is active high
>>> + - vsync-active-high (bool): Vsync pulse is active high
>>> + - interlaced (bool): This is an interlaced mode
>>> + - doublescan (bool): This is a doublescan mode
>>> +
>>> +There are different ways of describing a display mode. The devicetree representation
>>> +corresponds to the one commonly found in datasheets for displays.
>>> +The description of the display and its mode is split in two parts: first the display
>>> +properties like size in mm and (optionally) multiple subnodes with the supported modes.
>>> +
>>> +Example:
>>> +
>>> + display@0 {
>>
>> It would be useful to have a compatible string here. We may not always
>> know the panel type or have a fixed panel though. We could define
>> "generic-lcd" or something for cases where the panel type is unknown.
>
> We expect the display nodes being subnodes of a driver (which of course
> has a compatible), or maybe referred to from a driver using phandles. So
> I don't see why the display node itself should have a compatible
> property. The display information is only ever useful in the context of
> a driver.
A subnode or phandle will describe the h/w connection, but you need a
name to describe what is at each end of the connection.
Where would the model number of an lcd panel be captured then? The
timing parameters are a property of a specific panel, so both should be
described together. You may not have any use for the compatible string
now, but more information is better than less and adding it would not
hurt anything. For pretty much any other device sitting on a board, we
describe the manufacturer and type of device. LCD panels should be no
different.
Rob
^ permalink raw reply
* [PATCH v5] of: add display helper (was: of: add videomode helper)
From: Steffen Trumtrar @ 2012-09-24 15:35 UTC (permalink / raw)
To: devicetree-discuss
Cc: Rob Herring, linux-fbdev, dri-devel, Laurent Pinchart, kernel,
linux-media, Hans Verkuil, Tomi Valkeinen
Hi!
After the feedback I got on v4, I thought about the current state of the
videomode helper and decided to reengineer it. The most confusion seems to
stem from the fact, that a videomode does not have ranges. And that is correct.
Therefore the description of the display now uses a list of timings.
These timings support ranges, as they do in datasheets (min/typ/max).
A device driver may choose to grep a display-description from the devicetree and
directly work with that (matching parameters according to their range etc.).
Or one can use the former struct videomode to convert from the timings to a videomode
(at the moment it just grabs the typical-value from every timing-parameter).
This videomode on the other hand, can then be converted to a mode the backend wants
(drm_mode_info, fb_videomode,...).
As of now, this intermediate step is a bit, well, unnecessary. But it provides a way
to have a generic videomode and functions to possibly convert back-and-forth.
In the end, this version does the same as of_videomode, but I hope makes the whole
thing a little clearer.
Thanks to everybody who reviewed the previous versions.
Feedback is always welcome.
Regards,
Steffen
----------------------------------------------------------------
Steffen Trumtrar (2):
of: add helper to parse display specs
video: add generic videomode description
Documentation/devicetree/bindings/video/display | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
drivers/of/Kconfig | 5 +++
drivers/of/Makefile | 1 +
drivers/of/of_display.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
drivers/video/Makefile | 1 +
drivers/video/videomode.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/display.h | 85 ++++++++++++++++++++++++++++++++++++++++++
include/linux/of_display.h | 15 ++++++++
include/linux/videomode.h | 38 +++++++++++++++++++
9 files changed, 656 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/display
create mode 100644 drivers/of/of_display.c
create mode 100644 drivers/video/videomode.c
create mode 100644 include/linux/display.h
create mode 100644 include/linux/of_display.h
create mode 100644 include/linux/videomode.h
^ permalink raw reply
* [PATCH 1/2] of: add helper to parse display specs
From: Steffen Trumtrar @ 2012-09-24 15:35 UTC (permalink / raw)
To: devicetree-discuss
Cc: Rob Herring, linux-fbdev, dri-devel, Laurent Pinchart, kernel,
linux-media, Hans Verkuil, Tomi Valkeinen, Steffen Trumtrar
In-Reply-To: <1348500924-8551-1-git-send-email-s.trumtrar@pengutronix.de>
Parse a display-node with timings and hardware-specs from devictree.
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
---
Documentation/devicetree/bindings/video/display | 208 +++++++++++++++++++++++
drivers/of/Kconfig | 5 +
drivers/of/Makefile | 1 +
drivers/of/of_display.c | 157 +++++++++++++++++
include/linux/display.h | 85 +++++++++
include/linux/of_display.h | 15 ++
6 files changed, 471 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/display
create mode 100644 drivers/of/of_display.c
create mode 100644 include/linux/display.h
create mode 100644 include/linux/of_display.h
diff --git a/Documentation/devicetree/bindings/video/display b/Documentation/devicetree/bindings/video/display
new file mode 100644
index 0000000..722766a
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/display
@@ -0,0 +1,208 @@
+display bindings
+=========
+
+display-node
+------------
+
+required properties:
+ - none
+
+optional properties:
+ - default-timing: the default timing value
+ - width-mm, height-mm: Display dimensions in mm
+ - hsync-active-high (bool): Hsync pulse is active high
+ - vsync-active-high (bool): Vsync pulse is active high
+ - de-active-high (bool): Data-Enable pulse is active high
+ - pixelclk-inverted (bool): pixelclock is inverted
+ - pixel-per-clk
+ - link-width: number of channels (e.g. LVDS)
+ - bpp: bits-per-pixel
+
+timings-subnode
+---------------
+
+required properties:
+subnodes that specify
+ - hactive, vactive: Display resolution
+ - hfront-porch, hback-porch, hsync-len: Horizontal Display timing parameters
+ in pixels
+ vfront-porch, vback-porch, vsync-len: Vertical display timing parameters in
+ lines
+ - clock: displayclock in Hz
+
+There are different ways of describing a display and its capabilities. The devicetree
+representation corresponds to the one commonly found in datasheets for displays.
+The description of the display and its timing is split in two parts: first the display
+properties like size in mm and (optionally) multiple subnodes with the supported timings.
+If a display supports multiple signal timings, the default-timing can be specified.
+
+Example:
+
+ display@0 {
+ width-mm = <800>;
+ height-mm = <480>;
+ default-timing = <&timing0>;
+ timings {
+ timing0: timing@0 {
+ /* 1920x1080p24 */
+ clock = <52000000>;
+ hactive = <1920>;
+ vactive = <1080>;
+ hfront-porch = <25>;
+ hback-porch = <25>;
+ hsync-len = <25>;
+ vback-porch = <2>;
+ vfront-porch = <2>;
+ vsync-len = <2>;
+ hsync-active-high;
+ };
+ };
+ };
+
+Every property also supports the use of ranges, so the commonly used datasheet
+description with <min typ max>-tuples can be used.
+
+Example:
+
+ timing1: timing@1 {
+ /* 1920x1080p24 */
+ clock = <148500000>;
+ hactive = <1920>;
+ vactive = <1080>;
+ hsync-len = <0 44 60>;
+ hfront-porch = <80 88 95>;
+ hback-porch = <100 148 160>;
+ vfront-porch = <0 4 6>;
+ vback-porch = <0 36 50>;
+ vsync-len = <0 5 6>;
+ };
+
+The "display"-property in a connector-node (e.g. hdmi, ldb,...) is used to connect
+the display to that driver.
+of_display expects a phandle, that specifies the display-node, in that property.
+
+Example:
+
+ hdmi@00120000 {
+ status = "okay";
+ display = <&acme>;
+ };
+
+Usage in backend
+========
+
+A backend driver may choose to use the display directly and convert the timing
+ranges to a suitable mode. Or it may just use the conversion of the display timings
+to the required mode via the generic videomode struct.
+
+ dtb
+ |
+ | of_get_display
+ ↓
+ struct display
+ |
+ | videomode_from_timings
+ ↓
+ --- struct videomode ---
+ | |
+ videomode_to_displaymode | | videomode_to_fb_videomode
+ ↓ ↓
+ drm_display_mode fb_videomode
+
+
+Conversion to videomode
+===========+
+As device drivers normally work with some kind of video mode, the timings can be
+converted (may be just a simple copying of the typical value) to a generic videomode
+structure which then can be converted to the according mode used by the backend.
+
+Supported modes
+=======+
+The generic videomode read in by the driver can be converted to the following
+modes with the following parameters
+
+struct fb_videomode
+=========+
+ +----------+---------------------------------------------+----------+-------+
+ | | ↑ | | |
+ | | |upper_margin | | |
+ | | ↓ | | |
+ +----------###############################################----------+-------+
+ | # ↑ # | |
+ | # | # | |
+ | # | # | |
+ | # | # | |
+ | left # | # right | hsync |
+ | margin # | xres # margin | len |
+ |<-------->#<---------------+--------------------------->#<-------->|<----->|
+ | # | # | |
+ | # | # | |
+ | # | # | |
+ | # |yres # | |
+ | # | # | |
+ | # | # | |
+ | # | # | |
+ | # | # | |
+ | # | # | |
+ | # | # | |
+ | # | # | |
+ | # | # | |
+ | # ↓ # | |
+ +----------###############################################----------+-------+
+ | | ↑ | | |
+ | | |lower_margin | | |
+ | | ↓ | | |
+ +----------+---------------------------------------------+----------+-------+
+ | | ↑ | | |
+ | | |vsync_len | | |
+ | | ↓ | | |
+ +----------+---------------------------------------------+----------+-------+
+
+clock in nanoseconds
+
+struct drm_display_mode
+===========+
+ +----------+---------------------------------------------+----------+-------+
+ | | | | | ↑
+ | | | | | |
+ | | | | | |
+ +----------###############################################----------+-------+ |
+ | # ↑ ↑ ↑ # | | |
+ | # | | | # | | |
+ | # | | | # | | |
+ | # | | | # | | |
+ | # | | | # | | |
+ | # | | | hdisplay # | | |
+ | #<--+--------------------+-------------------># | | |
+ | # | | | # | | |
+ | # |vsync_start | # | | |
+ | # | | | # | | |
+ | # | |vsync_end | # | | |
+ | # | | |vdisplay # | | |
+ | # | | | # | | |
+ | # | | | # | | |
+ | # | | | # | | | vtotal
+ | # | | | # | | |
+ | # | | | hsync_start # | | |
+ | #<--+---------+----------+------------------------------>| | |
+ | # | | | # | | |
+ | # | | | hsync_end # | | |
+ | #<--+---------+----------+-------------------------------------->| |
+ | # | | ↓ # | | |
+ +----------####|#########|################################----------+-------+ |
+ | | | | | | | |
+ | | | | | | | |
+ | | ↓ | | | | |
+ +----------+-------------+-------------------------------+----------+-------+ |
+ | | | | | | |
+ | | | | | | |
+ | | ↓ | | | ↓
+ +----------+---------------------------------------------+----------+-------+
+ htotal
+ <------------------------------------------------------------------------->
+
+clock in kilohertz
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index dfba3e6..a4e3074 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -83,4 +83,9 @@ config OF_MTD
depends on MTD
def_bool y
+config OF_DISPLAY
+ def_bool y
+ help
+ helper to parse displays from the devicetree
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index e027f44..0756bee 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
obj-$(CONFIG_OF_PCI) += of_pci.o
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
obj-$(CONFIG_OF_MTD) += of_mtd.o
+obj-$(CONFIG_OF_DISPLAY) += of_display.o
diff --git a/drivers/of/of_display.c b/drivers/of/of_display.c
new file mode 100644
index 0000000..632a351
--- /dev/null
+++ b/drivers/of/of_display.c
@@ -0,0 +1,157 @@
+/*
+ * OF helpers for parsing display timings
+ *
+ * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix
+ *
+ * based on of_videomode.c by Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This file is released under the GPLv2
+ */
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/display.h>
+#include <linux/of_display.h>
+#include <linux/fb.h>
+
+/* every signal_timing can be specified with either
+ * just the typical value or a range consisting of
+ * min/typ/max.
+ * This function helps handling this
+ */
+static int of_display_parse_property(struct device_node *np, char *name,
+ struct timing_entry *result)
+{
+ struct property *prop;
+ int length;
+ int cells;
+ int ret;
+
+ prop = of_find_property(np, name, &length);
+ if (!prop) {
+ pr_err("%s: could not find property %s\n", __func__,
+ name);
+ return -EINVAL;
+ }
+
+ cells = length / sizeof(u32);
+
+ if (cells = 1)
+ ret = of_property_read_u32_array(np, name, &result->typ, cells);
+ else if (cells = 3)
+ ret = of_property_read_u32_array(np, name, &result->min, cells);
+ else {
+ pr_err("%s: illegal timing specification in %s\n", __func__,
+ name);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+struct display *of_get_display(struct device_node *np)
+{
+ struct device_node *display_np;
+ struct device_node *timing_np;
+ struct device_node *timings;
+ struct display *disp;
+ char *default_timing;
+
+ if (!np) {
+ pr_err("%s: no devicenode given\n", __func__);
+ return NULL;
+ }
+
+ display_np = of_parse_phandle(np, "display", 0);
+
+ if (!display_np) {
+ pr_err("%s: could not find display node\n", __func__);
+ return NULL;
+ }
+
+ disp = kmalloc(sizeof(struct display *), GFP_KERNEL);
+
+ memset(disp, 0, sizeof(struct display *));
+
+ of_property_read_u32(display_np, "width-mm", &disp->width_mm);
+ of_property_read_u32(display_np, "height-mm", &disp->height_mm);
+
+ timing_np = of_parse_phandle(display_np, "default-timing", 0);
+
+ if (!timing_np) {
+ pr_info("%s: no default-timing specified\n", __func__);
+ timing_np = of_find_node_by_name(np, "timing");
+ }
+
+ if (!timing_np) {
+ pr_info("%s: no timing specifications given\n", __func__);
+ return disp;
+ }
+
+ default_timing = (char *)timing_np->full_name;
+
+ timings = of_find_node_by_name(np, "timings");
+
+ disp->num_timings = 0;
+
+ disp->timings = kmalloc(sizeof(struct signal_timing *), GFP_KERNEL);
+
+ for_each_child_of_node(timings, timing_np) {
+ struct signal_timing *st;
+ int ret;
+
+ st = kmalloc(sizeof(struct signal_timing *), GFP_KERNEL);
+ disp->timings[disp->num_timings] = kmalloc(sizeof(struct signal_timing *), GFP_KERNEL);
+
+ ret |= of_display_parse_property(timing_np, "hback-porch", &st->hback_porch);
+ ret |= of_display_parse_property(timing_np, "hfront-porch", &st->hfront_porch);
+ ret |= of_display_parse_property(timing_np, "hactive", &st->hactive);
+ ret |= of_display_parse_property(timing_np, "hsync-len", &st->hsync_len);
+ ret |= of_display_parse_property(timing_np, "vback-porch", &st->vback_porch);
+ ret |= of_display_parse_property(timing_np, "vfront-porch", &st->vfront_porch);
+ ret |= of_display_parse_property(timing_np, "vactive", &st->vactive);
+ ret |= of_display_parse_property(timing_np, "vsync-len", &st->vsync_len);
+ ret |= of_display_parse_property(timing_np, "clock", &st->pixelclock);
+
+ if (strcmp(default_timing, timing_np->full_name) = 0)
+ disp->default_timing = disp->num_timings;
+
+ disp->timings[disp->num_timings] = st;
+ disp->num_timings++;
+ }
+
+ disp->vsync_pol_active_high = of_property_read_bool(display_np, "vsync-active-high");
+ disp->hsync_pol_active_high = of_property_read_bool(display_np, "hsync-active-high");
+ disp->de_pol_active_high = of_property_read_bool(display_np, "de-active-high");
+ disp->pixelclk_pol_inverted = of_property_read_bool(display_np, "pixelclk-inverted");
+ of_property_read_u32(display_np, "pixel-per-clk", &disp->if_pixel_per_clk);
+ of_property_read_u32(display_np, "link-width", &disp->if_link_width);
+ of_property_read_u32(display_np, "bpp", &disp->if_bpp);
+
+
+ pr_info("%s: got %d timings. Using #%d as default\n", __func__, disp->num_timings, disp->default_timing + 1);
+
+ return disp;
+}
+EXPORT_SYMBOL(of_get_display);
+
+int of_display_exists(struct device_node *np)
+{
+ struct device_node *display_np;
+ struct device_node *timing_np;
+
+ if (!np)
+ return -EINVAL;
+
+ display_np = of_parse_phandle(np, "display", 0);
+
+ if (!display_np)
+ return -EINVAL;
+
+ timing_np = of_parse_phandle(np, "default-timing", 0);
+
+ if (timing_np)
+ return 0;
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(of_display_exists);
diff --git a/include/linux/display.h b/include/linux/display.h
new file mode 100644
index 0000000..bb84ed9
--- /dev/null
+++ b/include/linux/display.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>
+ *
+ * Hardware-description of a display
+ *
+ * This file is released under the GPLv2
+ */
+
+#ifndef __LINUX_DISPLAY_H
+#define __LINUX_DISPLAY_H
+
+#include <linux/list.h>
+
+#define OF_DEFAULT_TIMING -1
+
+struct display {
+ u32 width_mm;
+ u32 height_mm;
+ unsigned int num_timings;
+ unsigned int default_timing;
+
+ struct signal_timing **timings;
+
+ bool vsync_pol_active_high;
+ bool hsync_pol_active_high;
+ bool de_pol_active_high;
+ bool pixelclk_pol_inverted;
+
+ u32 if_bpp;
+ u32 if_link_width;
+ u32 if_pixel_per_clk;
+};
+
+struct timing_entry {
+ u32 min;
+ u32 typ;
+ u32 max;
+};
+
+struct signal_timing {
+ struct timing_entry pixelclock;
+
+ struct timing_entry hactive;
+ struct timing_entry hfront_porch;
+ struct timing_entry hback_porch;
+ struct timing_entry hsync_len;
+
+ struct timing_entry vactive;
+ struct timing_entry vfront_porch;
+ struct timing_entry vback_porch;
+ struct timing_entry vsync_len;
+};
+
+/* placeholder function until ranges are really needed */
+static inline u32 signal_timing_get_value(struct timing_entry *te, int index)
+{
+ return te->typ;
+}
+
+static inline void timings_release(struct display *disp)
+{
+ int i;
+ for (i = 0; i < disp->num_timings; i++)
+ kfree(disp->timings[i]);
+}
+
+static inline void display_release(struct display *disp)
+{
+ timings_release(disp);
+ kfree(disp->timings);
+}
+
+static inline struct signal_timing *display_get_timing(struct display *disp, int index)
+{
+ if (disp->num_timings >= index)
+ return disp->timings[index];
+ else
+ return NULL;
+}
+
+
+int of_display_exists(struct device_node *np);
+struct display *of_get_display(struct device_node *np);
+
+#endif /* __LINUX_DISPLAY_H */
diff --git a/include/linux/of_display.h b/include/linux/of_display.h
new file mode 100644
index 0000000..500ff94
--- /dev/null
+++ b/include/linux/of_display.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>
+ *
+ * This file is released under the GPLv2
+ */
+
+#ifndef __LINUX_OF_DISPLAY_H
+#define __LINUX_OF_DISPALY_H
+
+#include <linux/fb.h>
+
+struct display *of_get_display(struct device_node *np);
+int of_display_exists(struct device_node *np);
+
+#endif
--
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