diff mbox

[2/2] video: exynos-mipi-dsi: Adding DT support to exynos mipi driver

Message ID 1352547285-12302-3-git-send-email-shaik.ameer@samsung.com (mailing list archive)
State New, archived
Headers show

Commit Message

Shaik Ameer Basha Nov. 10, 2012, 11:34 a.m. UTC
This patch adds the DT support for the exynos mipi-dsi driver.
for DT support mipi device node should supply the following
information to the mipi-dsi driver.
1] dsim_config information
2] d-phy setting information
3] lcd poweron, reset information
4] fb_videomode information

Change-Id: I93005636a7825b0c5ef4832dd17a2809d0aeda1d
Signed-off-by: Shaik Ameer Basha <shaik.ameer@samsung.com>
---
 .../devicetree/bindings/video/exynos/mipi-dsi.txt  |  185 +++++++
 drivers/video/exynos/exynos_mipi_dsi.c             |  573 +++++++++++++++++++-
 include/video/exynos_mipi_dsim.h                   |   27 +
 3 files changed, 765 insertions(+), 20 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/video/exynos/mipi-dsi.txt

Comments

Inki Dae Nov. 19, 2012, 12:31 p.m. UTC | #1
Hi,

Please, post your dts and dtsi file you used also. I think this patch should
be separated into SoC and Board-specific parts. And below is quick review.

Thanks,
Inki Dae

> -----Original Message-----
> From: Shaik Ameer Basha [mailto:shaik.ameer@samsung.com]
> Sent: Saturday, November 10, 2012 8:35 PM
> To: linux-fbdev@vger.kernel.org
> Cc: inki.dae@samsung.com; dh09.lee@samsung.com; FlorianSchandinat@gmx.de;
> s.nawrocki@samsung.com; kgene.kim@samsung.com
> Subject: [PATCH 2/2] video: exynos-mipi-dsi: Adding DT support to exynos
> mipi driver
> 
> This patch adds the DT support for the exynos mipi-dsi driver.
> for DT support mipi device node should supply the following
> information to the mipi-dsi driver.
> 1] dsim_config information
> 2] d-phy setting information
> 3] lcd poweron, reset information
> 4] fb_videomode information
> 
> Change-Id: I93005636a7825b0c5ef4832dd17a2809d0aeda1d
> Signed-off-by: Shaik Ameer Basha <shaik.ameer@samsung.com>
> ---
>  .../devicetree/bindings/video/exynos/mipi-dsi.txt  |  185 +++++++
>  drivers/video/exynos/exynos_mipi_dsi.c             |  573
> +++++++++++++++++++-
>  include/video/exynos_mipi_dsim.h                   |   27 +
>  3 files changed, 765 insertions(+), 20 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/video/exynos/mipi-
> dsi.txt
> 
> diff --git a/Documentation/devicetree/bindings/video/exynos/mipi-dsi.txt
> b/Documentation/devicetree/bindings/video/exynos/mipi-dsi.txt
> new file mode 100644
> index 0000000..6445eac
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/video/exynos/mipi-dsi.txt
> @@ -0,0 +1,185 @@
> +* Samsung Exynos MIPI-DSI bindings
> +
> +Properties for MIPI-DSI node ::
> +===============================
> +- compatible: should be "samsung,exynos5-mipi"
> +

Make sure mipi type. "samsung, exynos5250-mipi-dsi"

> +- reg: should contain mipi-dsi physical address location and length.
> +
> +- interrupts: should contain mipi-dsi interrupt number
> +
> +- enabled: Describes whether MIPI DSI got enabled in uboot
> +

Maybe board-specific.

> +- mipi-lcd: phandle to lcd specific information. It can be anything
> +	specific to lcd driver.
> +

Ditto.

> +- mipi-phy: phandle to D-PHY node.
> +
> +- mipi-config: subnode for mipi config information
> +	- auto_flush: enable or disable Auto flush of MD FIFO using VSYNC
> pulse
> +	- eot_disable: enable or disable EoT packet in HS mode
> +	- auto_vertical_cnt: specifies auto vertical count mode.
> +		In Video mode, the vertical line transition uses line
> counter
> +		configured by VSA, VBP, and Vertical resolution. If this bit
> is
> +		set to '1', the line counter does not use VSA and VBP
> registers.
> +		In command mode, this property is ignored.
> +	- hse: set horizontal sync event mode.
> +		In VSYNC pulse and Vporch area,	MIPI DSI master transfers
> only
> +		HSYNC start packet to MIPI DSI slave at MIPI DSI spec1.1r02.
> +		This bit transfers HSYNC end packet in VSYNC pulse and
> Vporch
> +		area. In command mode, this property is ignored.
> +	- hfp: specifies HFP disable mode.
> +		If this property is set, DSI master ignores HFP area in
> +		VIDEO mode. In command mode, this property is ignored.
> +	- hbp: specifies HBP disable mode.
> +		If this property is set, DSI master ignores HBP area in
> +		VIDEO mode. In command mode, this property is ignored.
> +	- hsa: specifies HSA disable mode.
> +		If this property is set, DSI master ignores HSA area in
> +		VIDEO mode. In command mode, this property is ignored.
> +	- cmd_allow: specifies the number of horizontal lines, where
> command
> +		packet transmission is allowed after Stable VFP period.
> +	- e_interface: specifies interface to be used.(CPU or RGB interface)
> +	- e_virtual_ch: specifies virtual channel number that main or
> +		sub display uses.
> +	- e_pixel_format: specifies pixel stream format for main or sub
> display.
> +	- e_burst_mode: selects Burst mode in Video mode.
> +		In Non-burst mode, RGB data area is filled with RGB data
> +		and NULL packets, according to input bandwidth of RGB
> interface.
> +		In Burst mode, RGB data area is filled with RGB data only.
> +	- e_no_data_lane: specifies data lane count to be used by Master.
> +	- e_byte_clk: select byte clock source. (it must be
> DSIM_PLL_OUT_DIV8)
> +		DSIM_EXT_CLK_DIV8 and DSIM_EXT_CLK_BYPASSS are not
supported.
> +	- pll_stable_time: specifies the PLL Timer for stability of the
> +		generated clock(System clock cycle base). If the timer value
> +		goes to 0x00000000, the clock stable bit of status and
> interrupt
> +		register is set.
> +	- esc_clk: specifies escape clock frequency for getting the escape
> clock
> +		prescaler value.
> +	- stop_holding_cnt: specifies the interval value between
> transmitting
> +		read packet(or write "set_tear_on" command) and BTA request.
> +		after transmitting read packet or write "set_tear_on"
> command,
> +		BTA requests to D-PHY automatically. this counter value
> +		specifies the interval between them.
> +	- bta_timeout: specifies the timer for BTA.
> +		this register specifies time out from BTA request to change
> +		the direction with respect to Tx escape clock.
> +	- rx_timeout: specifies the timer for LP Rx mode timeout.
> +		this register specifies time out on how long RxValid
> deasserts,
> +		after RxLpdt asserts with respect to Tx escape clock.
> +		- RxValid specifies Rx data valid indicator.
> +		- RxLpdt specifies an indicator that D-PHY is under RxLpdt
> mode.
> +		- RxValid and RxLpdt specifies signal from D-PHY.
> +
> +- display-mode: timing and resolution information of the panel used. As
> per
> +	current exynos mipi-dsi driver need, only some fields from
> +	struct fb_videomode are defined in this node.
> +	- xres: horizontal resolution (active frame width)
> +	- yres: vertical resolution (active frame height).
> +	- left_margin: Horizontal Back Porch (Number of PIXCLK pulses
> between
> +		HSYNC signal and the first valid pixel data.
> +	- right_margin: Horizontal Front Porch (Number of PIXCLK between
> +		last valid pixel data in the line and the next HSYNC pulse).
> +	- upper_margin: Vertical Back Porch (Number of lines (HSYNC pulses)
> +		from when a VSYNC signal is asserted and the first valid
> line).
> +	- lower_margin: Vertical Front Porch (Number of lines (HSYNC pulses)
> +		between last valid line of the frame and the next VSYNC
> Pulse).
> +	- hsync_len: Hsync pulse width (Number of PIXCLK pulses when a
> HSYNC
> +		signal is active).
> +	- vsync_len: Vsync pulse width (Number of HSYNC pulses when a VSYNC
> +		signal is active).
> +

All things above are specific to board.

> +Properties for D-PHY node ::
> +=============================
> +	Instead of passing D-PHY related callbacks as part of platform data,
> +we can pass the phy nodes to the mipi driver. Depending on the type of
> PHY
> +settings, we can implement multiple PHY node types and corresponding
> +enable/disable/reset callbacks in the driver itself. Currently we support
> +only one type of PHY node.
> +
> +D-PHY node type1:
> +------------------
> +- compatible: "samsung,exynos-mipi-phy-type1"
> +- reg_enable_dphy: should contain physical address location of
> +	D-PHY enable register
> +- mask_enable_dphy: should contain the mask for D-PHY enable register
> +- reg_reset_dsim: should contain physical address location of
> +	D-PHY DSIM reset register
> +- mask_reset_dsim: should contain the mask for D-PHY DSIM reset register
> +
> +MIPI-LCD node ::
> +=================
> +	Apart from the following three properties, driver specific
> +properties can be sent through this node. The following example sends
> +some more properties for driver's use.
> +
> +- lcd-name: name of the device to use with this device
> +- id: id of device to be registered (default -1 in case not specified)
> +- bus-id: bus id for identifing connected bus and this bus id should be
> +	same as id of mipi_dsim_device (default -1 incase not specified)
> +
> +Example:
> +--------
> +	mipi_lcd: mipi-lcd@toshiba {
> +		lcd-name = "tc358764";
> +		id = <0>;
> +		enabled = <1>;
> +		reset-delay = <120>;
> +		power-on-delay = <25>;
> +		power-off-delay = <200>;
> +		gpio-poweron = <&gpx1 5 0 0 0>;
> +	};
> +

Board-specific.

> +	mipi_dsim_phy: mipi-phy@exynos5250 {
> +		compatible = "samsung-exynos,mipi-phy-type1";
> +		reg_enable_dphy = <0x10040714>;
> +		mask_enable_dphy = <0x00000001>;
> +		reg_reset_dsim = <0x10040714>;
> +		mask_reset_dsim = <0x00000004>;
> +	};
> +

SoC-specific.

> +	mipi {
> +		compatible = "samsung,exynos-mipi";

mipi-dsi {
	compatible = "samsung, exynos5250-mipi-dsi";

> +		reg = <0x14500000 0x10000>;
> +		interrupts = <0 82 0>;
> +

SoC-specific.

> +		mipi-lcd = <&mipi_lcd>;

Board-specific.

> +		mipi-phy = <&mipi_dsim_phy>;

SoC-specific.

> +		enabled = <0>;
> +

Board-specific.

> +		mipi-config {
> +			e_interface = <1>;
> +			e_pixel_format = <7>;
> +			auto_flush = <0>;
> +			eot_disable = <0>;
> +			auto_vertical_cnt = <0>;
> +			hse = <0>;
> +			hfp = <0>;
> +			hbp = <0>;
> +			hsa = <0>;
> +			e_no_data_lane = <3>;
> +			e_byte_clk = <0>;
> +			e_burst_mode = <3>;
> +			p = <3>;
> +			m = <115>;
> +			s = <1>;
> +			pll_stable_time = <500>;
> +			esc_clk = <400000>;
> +			stop_holding_cnt =<0x0f>;
> +			bta_timeout = <0xff>;
> +			rx_timeout = <0xffff>;
> +			e_virtual_ch = <0>;
> +			cmd_allow = <0xf>;
> +		};
> +
> +		panel-info {
> +			left_margin = <0x4>;
> +			right_margin = <0x4>;
> +			upper_margin = <0x4>;
> +			lower_margin = <0x4>;
> +			hsync_len = <0x4>;
> +			vsync_len = <0x4>;
> +			xres = <1280>;
> +			yres = <800>;
> +		};

All things above are specific to board also.

> +	};
> diff --git a/drivers/video/exynos/exynos_mipi_dsi.c
> b/drivers/video/exynos/exynos_mipi_dsi.c
> index ae20bc3..667857b 100755
> --- a/drivers/video/exynos/exynos_mipi_dsi.c
> +++ b/drivers/video/exynos/exynos_mipi_dsi.c
> @@ -32,6 +32,7 @@
>  #include <linux/notifier.h>
>  #include <linux/regulator/consumer.h>
>  #include <linux/pm_runtime.h>
> +#include <linux/lcd.h>
> 
>  #include <video/exynos_mipi_dsim.h>
> 
> @@ -43,6 +44,8 @@
>  struct mipi_dsim_ddi {
>  	int				bus_id;
>  	struct list_head		list;
> +	struct device_node		*ofnode_dsim_lcd_dev;
> +	struct device_node		*ofnode_dsim_dphy;
>  	struct mipi_dsim_lcd_device	*dsim_lcd_dev;
>  	struct mipi_dsim_lcd_driver	*dsim_lcd_drv;
>  };
> @@ -181,6 +184,36 @@ static int exynos_mipi_dsi_blank_mode(struct
> mipi_dsim_device *dsim, int power)
>  	return 0;
>  }
> 
> +struct mipi_dsim_ddi *exynos_mipi_dsi_find_lcd_driver(
> +			struct mipi_dsim_lcd_device *lcd_dev)
> +{
> +	struct mipi_dsim_ddi *dsim_ddi, *next;
> +	struct mipi_dsim_lcd_driver *lcd_drv;
> +
> +	mutex_lock(&mipi_dsim_lock);
> +
> +	list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
> +		if (!dsim_ddi)
> +			goto out;
> +
> +		lcd_drv = dsim_ddi->dsim_lcd_drv;
> +		if (!lcd_drv)
> +			continue;
> +
> +		if ((strcmp(lcd_dev->name, lcd_drv->name)) == 0) {
> +			mutex_unlock(&mipi_dsim_lock);
> +			return dsim_ddi;
> +		}
> +
> +		list_del(&dsim_ddi->list);
> +		kfree(dsim_ddi);
> +	}
> +
> +out:
> +	mutex_unlock(&mipi_dsim_lock);
> +	return NULL;
> +}
> +
>  int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device
> *lcd_dev)
>  {
>  	struct mipi_dsim_ddi *dsim_ddi;
> @@ -190,13 +223,17 @@ int exynos_mipi_dsi_register_lcd_device(struct
> mipi_dsim_lcd_device *lcd_dev)
>  		return -EFAULT;
>  	}
> 
> -	dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
> +	dsim_ddi = exynos_mipi_dsi_find_lcd_driver(lcd_dev);
>  	if (!dsim_ddi) {
> -		pr_err("failed to allocate dsim_ddi object.\n");
> -		return -ENOMEM;
> +		dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi),
GFP_KERNEL);
> +		if (!dsim_ddi) {
> +			pr_err("failed to allocate dsim_ddi object.\n");
> +			return -ENOMEM;
> +		}
>  	}
> 
>  	dsim_ddi->dsim_lcd_dev = lcd_dev;
> +	dsim_ddi->bus_id = lcd_dev->bus_id;
> 
>  	mutex_lock(&mipi_dsim_lock);
>  	list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
> @@ -253,11 +290,26 @@ int exynos_mipi_dsi_register_lcd_driver(struct
> mipi_dsim_lcd_driver *lcd_drv)
> 
>  	dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv);
>  	if (!dsim_ddi) {
> -		pr_err("mipi_dsim_ddi object not found.\n");
> -		return -EFAULT;
> -	}
> +		/*
> +		 * If driver specific device is not registered then create a
> +		 * dsim_ddi object, fill the driver information and add to
> the
> +		 * end of the dsim_ddi_list list
> +		 */
> +		dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi),
GFP_KERNEL);
> +		if (!dsim_ddi) {
> +			pr_err("failed to allocate dsim_ddi object.\n");
> +			return -ENOMEM;
> +		}
> +
> +		dsim_ddi->dsim_lcd_drv = lcd_drv;
> 
> -	dsim_ddi->dsim_lcd_drv = lcd_drv;
> +		mutex_lock(&mipi_dsim_lock);
> +		list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
> +		mutex_unlock(&mipi_dsim_lock);
> +
> +	} else {
> +		dsim_ddi->dsim_lcd_drv = lcd_drv;
> +	}
> 
>  	pr_info("registered panel driver(%s) to mipi-dsi driver.\n",
>  		lcd_drv->name);
> @@ -329,6 +381,372 @@ static struct mipi_dsim_master_ops master_ops = {
>  	.set_blank_mode			= exynos_mipi_dsi_blank_mode,
>  };
> 
> +struct device_node *exynos_mipi_find_ofnode_dsim_phy(
> +				struct platform_device *pdev)
> +{
> +	struct device_node *dn, *dn_dphy;
> +	const __be32 *prop;
> +
> +	dn = pdev->dev.of_node;
> +	prop = of_get_property(dn, "mipi-phy", NULL);
> +	if (NULL == prop) {
> +		dev_err(&pdev->dev, "Could not find property mipi-phy\n");
> +		return NULL;
> +	}
> +
> +	dn_dphy = of_find_node_by_phandle(be32_to_cpup(prop));
> +	if (NULL == dn_dphy) {
> +		dev_err(&pdev->dev, "Could not find node\n");
> +		return NULL;
> +	}
> +
> +	return dn_dphy;
> +}
> +
> +struct device_node *exynos_mipi_find_ofnode_lcd_device(
> +			struct platform_device *pdev)
> +{
> +	struct device_node *dn, *dn_lcd_panel;
> +	const __be32 *prop;
> +
> +	dn = pdev->dev.of_node;
> +	prop = of_get_property(dn, "mipi-lcd", NULL);
> +	if (NULL == prop) {
> +		dev_err(&pdev->dev, "could not find property mipi-lcd\n");
> +		return NULL;
> +	}
> +
> +	dn_lcd_panel = of_find_node_by_phandle(be32_to_cpup(prop));
> +	if (NULL == dn_lcd_panel) {
> +		dev_err(&pdev->dev, "could not find node\n");
> +		return NULL;
> +	}
> +
> +	return dn_lcd_panel;
> +}
> +
> +static void exynos_mipi_dsim_enable_d_phy_type1(
> +			struct platform_device *pdev,
> +			bool enable)
> +{
> +	struct mipi_dsim_device *dsim = (struct mipi_dsim_device *)
> +					platform_get_drvdata(pdev);
> +	struct mipi_dsim_phy_config_type1 *dphy_cfg_type1 =
> +
&dsim->dsim_phy_config->phy_cfg_type1;
> +	u32 reg_enable;
> +
> +	reg_enable = __raw_readl(dphy_cfg_type1->reg_enable_dphy);
> +	reg_enable &= ~(dphy_cfg_type1->ctrlbit_enable_dphy);
> +
> +	if (enable)
> +		reg_enable |= dphy_cfg_type1->ctrlbit_enable_dphy;
> +
> +	__raw_writel(reg_enable, dphy_cfg_type1->reg_enable_dphy);
> +}
> +
> +static void exynos_mipi_dsim_reset_type1(
> +			struct platform_device *pdev,
> +			bool enable)
> +{
> +	struct mipi_dsim_device *dsim = (struct mipi_dsim_device *)
> +					platform_get_drvdata(pdev);
> +	struct mipi_dsim_phy_config_type1 *dphy_cfg_type1 =
> +
&dsim->dsim_phy_config->phy_cfg_type1;
> +	u32 reg_reset;
> +
> +	reg_reset = __raw_readl(dphy_cfg_type1->reg_reset_dsim);
> +	reg_reset &= ~(dphy_cfg_type1->ctrlbit_reset_dsim);
> +
> +	if (enable)
> +		reg_reset |= dphy_cfg_type1->ctrlbit_reset_dsim;
> +
> +	__raw_writel(reg_reset, dphy_cfg_type1->reg_reset_dsim);
> +}
> +
> +static int exynos_mipi_dsim_phy_init_type1(
> +			struct platform_device *pdev,
> +			bool on_off)
> +{
> +	exynos_mipi_dsim_enable_d_phy_type1(pdev, on_off);
> +	exynos_mipi_dsim_reset_type1(pdev, on_off);
> +	return 0;
> +}
> +
> +static int parse_u32_property(struct device_node *np, char *name,
> +				u32 *result)
> +{
> +	if (of_property_read_u32(np, name, result)) {
> +		pr_err("not able to find property: %s\n", name);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int exynos_mipi_parse_ofnode_dsim_phy_type1(
> +		struct platform_device *pdev,
> +		struct mipi_dsim_phy_config_type1 *dphy_cfg_type1,
> +		struct device_node *np)
> +{
> +	struct mipi_dsim_device *dsim = (struct mipi_dsim_device *)
> +					platform_get_drvdata(pdev);
> +	u32 paddr_phy_enable, paddr_dsim_reset;
> +	int ret = 0;
> +
> +	ret |= parse_u32_property(np, "reg_enable_dphy", &paddr_phy_enable);
> +	ret |= parse_u32_property(np, "reg_reset_dsim", &paddr_dsim_reset);
> +	ret |= parse_u32_property(np, "mask_enable_dphy",
> +
&dphy_cfg_type1->ctrlbit_enable_dphy);
> +	ret |= parse_u32_property(np, "mask_reset_dsim",
> +
&dphy_cfg_type1->ctrlbit_reset_dsim);
> +
> +	if (ret) {
> +		pr_err("%s: error reading phy node properties\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	dphy_cfg_type1->reg_enable_dphy = ioremap(paddr_phy_enable, SZ_4);
> +	if (!dphy_cfg_type1->reg_enable_dphy)
> +		return -EINVAL;
> +
> +	dphy_cfg_type1->reg_reset_dsim = ioremap(paddr_dsim_reset, SZ_4);
> +	if (!dphy_cfg_type1->reg_reset_dsim)
> +		goto err_ioremap;
> +
> +	dsim->pd->phy_enable = exynos_mipi_dsim_phy_init_type1;
> +
> +	return 0;
> +
> +err_ioremap:
> +	iounmap(dphy_cfg_type1->reg_enable_dphy);
> +	return -EINVAL;
> +}
> +
> +static struct mipi_dsim_phy_config *exynos_mipi_parse_ofnode_dsim_phy(
> +		struct platform_device *pdev,
> +		struct device_node *np)
> +{
> +	struct mipi_dsim_phy_config *mipi_dphy_config;
> +	const char *compatible;
> +
> +	mipi_dphy_config = devm_kzalloc(&pdev->dev,
> +			sizeof(struct mipi_dsim_phy_config), GFP_KERNEL);
> +	if (!mipi_dphy_config) {
> +		dev_err(&pdev->dev,
> +			"failed to allocate mipi_dsim_phy_config
object.\n");
> +		return NULL;
> +	}
> +
> +	if (of_property_read_string(np, "compatible", &compatible)) {
> +		dev_err(&pdev->dev, "compatible property not found");
> +		return NULL;
> +	}
> +
> +	/* try to find the phy node type from compatible string */
> +	if (!strcmp(compatible, "samsung-exynos,mipi-phy-type1"))
> +		mipi_dphy_config->type = MIPI_DSIM_PHY_CONFIG_TYPE1;
> +	else
> +		mipi_dphy_config->type = -1;
> +
> +	/* parse the phy node as per its type */
> +	switch (mipi_dphy_config->type) {
> +	case MIPI_DSIM_PHY_CONFIG_TYPE1:
> +		if (exynos_mipi_parse_ofnode_dsim_phy_type1(
> +			pdev, &mipi_dphy_config->phy_cfg_type1, np))
> +			return NULL;
> +		break;
> +	default:
> +		dev_err(&pdev->dev, "mipi phy - unknown type");
> +		return NULL;
> +	}
> +
> +	return mipi_dphy_config;
> +}
> +
> +static struct mipi_dsim_lcd_device *exynos_mipi_parse_ofnode_lcd(
> +		struct platform_device *pdev, struct device_node *np)
> +{
> +	struct mipi_dsim_lcd_device *active_mipi_dsim_lcd_device;
> +	struct lcd_platform_data *active_lcd_platform_data;
> +	const char *lcd_name;
> +
> +	active_mipi_dsim_lcd_device = devm_kzalloc(&pdev->dev,
> +			sizeof(struct mipi_dsim_lcd_device), GFP_KERNEL);
> +	if (!active_mipi_dsim_lcd_device) {
> +		dev_err(&pdev->dev,
> +		"failed to allocate active_mipi_dsim_lcd_device object.\n");
> +		return NULL;
> +	}
> +
> +	if (of_property_read_string(np, "lcd-name", &lcd_name)) {
> +		dev_err(&pdev->dev, "lcd name property not found");
> +		return NULL;
> +	}
> +
> +	active_mipi_dsim_lcd_device->name = (char *)lcd_name;
> +
> +	if (of_property_read_u32(np, "id", &active_mipi_dsim_lcd_device-
> >id))
> +		active_mipi_dsim_lcd_device->id = -1;
> +
> +	if (of_property_read_u32(np, "bus-id",
> +
&active_mipi_dsim_lcd_device->bus_id))
> +		active_mipi_dsim_lcd_device->bus_id = -1;
> +
> +	active_lcd_platform_data = devm_kzalloc(&pdev->dev,
> +				sizeof(struct lcd_platform_data),
GFP_KERNEL);
> +	if (!active_lcd_platform_data) {
> +		dev_err(&pdev->dev,
> +		"failed to allocate active_lcd_platform_data object.\n");
> +		return NULL;
> +	}
> +
> +	/* store the lcd node pointer for futher use in lcd driver */
> +	active_lcd_platform_data->pdata = (void *) np;
> +	active_mipi_dsim_lcd_device->platform_data =
> +				(void *)active_lcd_platform_data;
> +
> +	return active_mipi_dsim_lcd_device;
> +}
> +
> +static int exynos_mipi_parse_ofnode_config(struct platform_device *pdev,
> +		struct device_node *np, struct mipi_dsim_config
*dsim_config)
> +{
> +	unsigned int u32Val;
> +
> +	if (parse_u32_property(np, "e_interface", &u32Val))
> +		return -EINVAL;
> +	dsim_config->e_interface = (enum mipi_dsim_interface_type)u32Val;
> +
> +	if (parse_u32_property(np, "e_pixel_format", &u32Val))
> +		return -EINVAL;
> +	dsim_config->e_pixel_format = (enum mipi_dsim_pixel_format)u32Val;
> +
> +	if (parse_u32_property(np, "auto_flush", &u32Val))
> +		return -EINVAL;
> +	dsim_config->auto_flush = (unsigned char)u32Val;
> +
> +	if (parse_u32_property(np, "eot_disable", &u32Val))
> +		return -EINVAL;
> +	dsim_config->eot_disable = (unsigned char)u32Val;
> +
> +	if (parse_u32_property(np, "auto_vertical_cnt", &u32Val))
> +		return -EINVAL;
> +	dsim_config->auto_vertical_cnt = (unsigned char)u32Val;
> +
> +	if (parse_u32_property(np, "hse", &u32Val))
> +		return -EINVAL;
> +	dsim_config->hse = (unsigned char)u32Val;
> +
> +	if (parse_u32_property(np, "hfp", &u32Val))
> +		return -EINVAL;
> +	dsim_config->hfp = (unsigned char)u32Val;
> +
> +	if (parse_u32_property(np, "hbp", &u32Val))
> +		return -EINVAL;
> +	dsim_config->hbp = (unsigned char)u32Val;
> +
> +	if (parse_u32_property(np, "hsa", &u32Val))
> +		return -EINVAL;
> +	dsim_config->hsa = (unsigned char)u32Val;
> +
> +	if (parse_u32_property(np, "e_no_data_lane", &u32Val))
> +		return -EINVAL;
> +	dsim_config->e_no_data_lane = (enum
> mipi_dsim_no_of_data_lane)u32Val;
> +
> +	if (parse_u32_property(np, "e_byte_clk", &u32Val))
> +		return -EINVAL;
> +	dsim_config->e_byte_clk = (enum mipi_dsim_byte_clk_src)u32Val;
> +
> +	if (parse_u32_property(np, "e_burst_mode", &u32Val))
> +		return -EINVAL;
> +	dsim_config->e_burst_mode = (enum mipi_dsim_burst_mode_type)u32Val;
> +
> +	if (parse_u32_property(np, "p", &u32Val))
> +		return -EINVAL;
> +	dsim_config->p = (unsigned char)u32Val;
> +
> +	if (parse_u32_property(np, "m", &u32Val))
> +		return -EINVAL;
> +	dsim_config->m = (unsigned short)u32Val;
> +
> +	if (parse_u32_property(np, "s", &u32Val))
> +		return -EINVAL;
> +	dsim_config->s = (unsigned char)u32Val;
> +
> +	if (parse_u32_property(np, "pll_stable_time", &u32Val))
> +		return -EINVAL;
> +	dsim_config->pll_stable_time = (unsigned int)u32Val;
> +
> +	if (parse_u32_property(np, "esc_clk", &u32Val))
> +		return -EINVAL;
> +	dsim_config->esc_clk = (unsigned long)u32Val;
> +
> +	if (parse_u32_property(np, "stop_holding_cnt", &u32Val))
> +		return -EINVAL;
> +	dsim_config->stop_holding_cnt = (unsigned short)u32Val;
> +
> +	if (parse_u32_property(np, "bta_timeout", &u32Val))
> +		return -EINVAL;
> +	dsim_config->bta_timeout = (unsigned char)u32Val;
> +
> +	if (parse_u32_property(np, "rx_timeout", &u32Val))
> +		return -EINVAL;
> +	dsim_config->rx_timeout = (unsigned short)u32Val;
> +
> +	if (parse_u32_property(np, "e_virtual_ch", &u32Val))
> +		return -EINVAL;
> +	dsim_config->e_virtual_ch = (enum mipi_dsim_virtual_ch_no)u32Val;
> +
> +	if (parse_u32_property(np, "cmd_allow", &u32Val))
> +		return -EINVAL;
> +	dsim_config->cmd_allow = (unsigned char)u32Val;
> +
> +	return 0;
> +}
> +
> +static int exynos_mipi_parse_ofnode_panel_info(struct platform_device
> *pdev,
> +		struct device_node *np, struct fb_videomode *vm)
> +{
> +	int ret = 0;
> +
> +	ret |= parse_u32_property(np, "left_margin", &vm->left_margin);
> +	ret |= parse_u32_property(np, "right_margin", &vm->right_margin);
> +	ret |= parse_u32_property(np, "upper_margin", &vm->upper_margin);
> +	ret |= parse_u32_property(np, "lower_margin", &vm->lower_margin);
> +	ret |= parse_u32_property(np, "hsync_len", &vm->hsync_len);
> +	ret |= parse_u32_property(np, "vsync_len", &vm->vsync_len);
> +	ret |= parse_u32_property(np, "xres", &vm->xres);
> +	ret |= parse_u32_property(np, "yres", &vm->yres);
> +	if (ret)
> +		pr_err("%s: error reading fb_videomodeproperties\n",
> __func__);
> +
> +	return ret;
> +}
> +
> +static int exynos_mipi_parse_ofnode(struct platform_device *pdev,
> +	struct mipi_dsim_config *dsim_config, struct fb_videomode
> *panel_info)
> +{
> +	struct device_node *np_dsim_config, *np_panel_info;
> +	struct device_node *np = pdev->dev.of_node;
> +
> +	np_dsim_config = of_find_node_by_name(np, "mipi-config");
> +	if (!np_dsim_config)
> +		return -EINVAL;
> +
> +	if (exynos_mipi_parse_ofnode_config(pdev, np_dsim_config,
> dsim_config))
> +		return -EINVAL;
> +
> +	np_panel_info = of_find_node_by_name(np, "display-mode");
> +	if (!np_panel_info)
> +		return -EINVAL;
> +
> +	if (exynos_mipi_parse_ofnode_panel_info(pdev,
> +					np_panel_info, panel_info))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  static int exynos_mipi_dsi_probe(struct platform_device *pdev)
>  {
>  	struct resource *res;
> @@ -336,6 +754,12 @@ static int exynos_mipi_dsi_probe(struct
> platform_device *pdev)
>  	struct mipi_dsim_config *dsim_config;
>  	struct mipi_dsim_platform_data *dsim_pd;
>  	struct mipi_dsim_ddi *dsim_ddi;
> +	struct device_node *ofnode_lcd = NULL;
> +	struct device_node *ofnode_dphy = NULL;
> +	struct mipi_dsim_lcd_device *active_mipi_dsim_lcd_device = NULL;
> +	struct mipi_dsim_phy_config *mipi_dphy_config;
> +	struct fb_videomode *panel_info;
> +	unsigned int u32Val;
>  	int ret = -EINVAL;
> 
>  	dsim = devm_kzalloc(&pdev->dev,
> @@ -345,23 +769,87 @@ static int exynos_mipi_dsi_probe(struct
> platform_device *pdev)
>  		return -ENOMEM;
>  	}
> 
> +	if (pdev->dev.of_node) {
> +		ofnode_lcd = exynos_mipi_find_ofnode_lcd_device(pdev);
> +		if (!ofnode_lcd)
> +			return -EINVAL;
> +
> +		active_mipi_dsim_lcd_device =
> +				exynos_mipi_parse_ofnode_lcd(pdev,
ofnode_lcd);
> +
> +		if (NULL == active_mipi_dsim_lcd_device)
> +			return -EINVAL;
> +
> +		if (NULL == exynos_mipi_dsi_find_lcd_driver
> +					(active_mipi_dsim_lcd_device))
> +			return -ENXIO;
> +
> +		exynos_mipi_dsi_register_lcd_device(
> +
active_mipi_dsim_lcd_device);
> +	}
> +
>  	dsim->pd = to_dsim_plat(pdev);
>  	dsim->dev = &pdev->dev;
>  	dsim->id = pdev->id;
> 
> -	/* get mipi_dsim_platform_data. */
> -	dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
> -	if (dsim_pd == NULL) {
> -		dev_err(&pdev->dev, "failed to get platform data for
> dsim.\n");
> -		return -EFAULT;
> -	}
> -	/* get mipi_dsim_config. */
> -	dsim_config = dsim_pd->dsim_config;
> -	if (dsim_config == NULL) {
> -		dev_err(&pdev->dev, "failed to get dsim config data.\n");
> -		return -EFAULT;
> -	}
> +	if (pdev->dev.of_node) {
> +		dsim_config = devm_kzalloc(&pdev->dev,
> +			sizeof(struct mipi_dsim_config), GFP_KERNEL);
> +		if (!dsim_config) {
> +			dev_err(&pdev->dev,
> +				"failed to allocate dsim_config object.\n");
> +			return -ENOMEM;
> +		}
> 
> +		panel_info = devm_kzalloc(&pdev->dev,
> +				sizeof(struct fb_videomode), GFP_KERNEL);
> +		if (!panel_info) {
> +			dev_err(&pdev->dev,
> +				"failed to allocate fb_videomode
object.\n");
> +			return -ENOMEM;
> +		}
> +
> +		/* parse the mipi of_node for dism_config and panel info. */
> +		if (exynos_mipi_parse_ofnode(pdev, dsim_config, panel_info))
> {
> +			dev_err(&pdev->dev,
> +				"failed to read mipi-config,
display-mode\n");
> +			return -EINVAL;
> +		}
> +
> +		dsim_pd = devm_kzalloc(&pdev->dev,
> +			sizeof(struct mipi_dsim_platform_data), GFP_KERNEL);
> +		if (!dsim_pd) {
> +			dev_err(&pdev->dev,
> +				"failed to allocate
mipi_dsim_platform_data\n");
> +			return -ENOMEM;
> +		}
> +
> +		if (of_property_read_u32(pdev->dev.of_node, "enabled",
> &u32Val))
> +			dev_err(&pdev->dev, "enabled property not found\n");
> +		else
> +			dsim_pd->enabled = !(!u32Val);
> +
> +		dsim_pd->lcd_panel_info = (void *)panel_info;
> +		dsim_pd->dsim_config = dsim_config;
> +		dsim->pd = dsim_pd;
> +
> +	} else {
> +		/* get mipi_dsim_platform_data. */
> +		dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
> +		if (dsim_pd == NULL) {
> +			dev_err(&pdev->dev,
> +				"failed to get platform data for dsim.\n");
> +			return -EFAULT;
> +		}
> +
> +		/* get mipi_dsim_config. */
> +		dsim_config = dsim_pd->dsim_config;
> +		if (dsim_config == NULL) {
> +			dev_err(&pdev->dev,
> +				"failed to get dsim config data.\n");
> +			return -EFAULT;
> +		}
> +	}
>  	dsim->dsim_config = dsim_config;
>  	dsim->master_ops = &master_ops;
> 
> @@ -394,11 +882,21 @@ static int exynos_mipi_dsi_probe(struct
> platform_device *pdev)
>  	mutex_init(&dsim->lock);
> 
>  	/* bind lcd ddi matched with panel name. */
> -	dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd-
> >lcd_panel_name);
> +	if (pdev->dev.of_node) {
> +		dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim,
> +					active_mipi_dsim_lcd_device->name);
> +	} else {
> +		dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim,
> +					dsim_pd->lcd_panel_name);
> +	}
> +
>  	if (!dsim_ddi) {
>  		dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n");
>  		ret = -ENXIO;
>  		goto cleanup_clk;
> +	} else if (pdev->dev.of_node) {
> +		dsim_ddi->ofnode_dsim_lcd_dev = ofnode_lcd;
> +		dsim_ddi->ofnode_dsim_dphy = ofnode_dphy;
>  	}
> 
>  	dsim->irq = platform_get_irq(pdev, 0);
> @@ -412,6 +910,21 @@ static int exynos_mipi_dsi_probe(struct
> platform_device *pdev)
>  	init_completion(&dsim_rd_comp);
>  	platform_set_drvdata(pdev, dsim);
> 
> +	/* update dsim phy config node */
> +	if (pdev->dev.of_node) {
> +		ofnode_dphy = exynos_mipi_find_ofnode_dsim_phy(pdev);
> +		if (!ofnode_dphy)
> +			return -EINVAL;
> +
> +		mipi_dphy_config = exynos_mipi_parse_ofnode_dsim_phy(pdev,
> +
ofnode_dphy);
> +
> +		if (NULL == mipi_dphy_config)
> +			return -EINVAL;
> +
> +		dsim->dsim_phy_config = mipi_dphy_config;
> +	}
> +
>  	ret = devm_request_irq(&pdev->dev, dsim->irq,
>  			exynos_mipi_dsi_interrupt_handler,
>  			IRQF_SHARED, dev_name(&pdev->dev), dsim);
> @@ -557,13 +1070,33 @@ static const struct dev_pm_ops
> exynos_mipi_dsi_pm_ops = {
>  	SET_SYSTEM_SLEEP_PM_OPS(exynos_mipi_dsi_suspend,
> exynos_mipi_dsi_resume)
>  };
> 
> +static struct platform_device_id exynos_mipi_driver_ids[] = {
> +	{
> +		.name		= "exynos-mipi",
> +		.driver_data	= NULL,
> +	},
> +	{},
> +};
> +MODULE_DEVICE_TABLE(platform, exynos_mipi_driver_ids);
> +
> +static const struct of_device_id exynos_mipi_match[] = {
> +	{
> +		.compatible = "samsung,exynos5-mipi",
> +		.data = NULL,
> +	},
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, exynos_mipi_match);
> +
>  static struct platform_driver exynos_mipi_dsi_driver = {
>  	.probe = exynos_mipi_dsi_probe,
>  	.remove = __devexit_p(exynos_mipi_dsi_remove),
> +	.id_table = exynos_mipi_driver_ids,
>  	.driver = {
>  		   .name = "exynos-mipi-dsim",
>  		   .owner = THIS_MODULE,
>  		   .pm = &exynos_mipi_dsi_pm_ops,
> +		   .of_match_table = exynos_mipi_match,
>  	},
>  };
> 
> diff --git a/include/video/exynos_mipi_dsim.h
> b/include/video/exynos_mipi_dsim.h
> index 772c770..6d9b01d 100644
> --- a/include/video/exynos_mipi_dsim.h
> +++ b/include/video/exynos_mipi_dsim.h
> @@ -230,6 +230,7 @@ struct mipi_dsim_device {
>  	struct mipi_dsim_master_ops	*master_ops;
>  	struct mipi_dsim_lcd_device	*dsim_lcd_dev;
>  	struct mipi_dsim_lcd_driver	*dsim_lcd_drv;
> +	struct mipi_dsim_phy_config	*dsim_phy_config;
> 
>  	unsigned int			state;
>  	unsigned int			data_lane;
> @@ -295,6 +296,32 @@ struct mipi_dsim_master_ops {
>  };
> 
>  /*
> + * phy node structure for mipi-dsim.
> + *
> + * @reg_enable_dphy	: base address to memory mapped D-PHY enable
> register
> + * @ctrlbit_enable_dphy : control bit for enabling D-PHY
> + * @reg_reset_dsim	: base address to memory mapped DSIM reset register
> + * @ctrlbit_reset_dsim	: control bit for resetting DSIM
> + */
> +struct mipi_dsim_phy_config_type1 {
> +	void __iomem	*reg_enable_dphy;
> +	int		ctrlbit_enable_dphy;
> +	void __iomem	*reg_reset_dsim;
> +	int		ctrlbit_reset_dsim;
> +};
> +
> +enum mipi_dsim_phy_config_type {
> +	MIPI_DSIM_PHY_CONFIG_TYPE1,
> +};
> +
> +struct mipi_dsim_phy_config {
> +	enum mipi_dsim_phy_config_type type;
> +	union {
> +		struct mipi_dsim_phy_config_type1 phy_cfg_type1;
> +	};
> +};
> +
> +/*
>   * device structure for mipi-dsi based lcd panel.
>   *
>   * @name: name of the device to use with this device, or an
> --
> 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
Donghwa Lee Nov. 20, 2012, 2:12 a.m. UTC | #2
On 10 Nov, 2012 20:34, Shaik Ameer Basha wrote:

> This patch adds the DT support for the exynos mipi-dsi driver.
> for DT support mipi device node should supply the following
> information to the mipi-dsi driver.
> 1] dsim_config information
> 2] d-phy setting information
> 3] lcd poweron, reset information
> 4] fb_videomode information
> [...]

>  

> diff --git a/include/video/exynos_mipi_dsim.h b/include/video/exynos_mipi_dsim.h
> index 772c770..6d9b01d 100644
> --- a/include/video/exynos_mipi_dsim.h
> +++ b/include/video/exynos_mipi_dsim.h
> @@ -230,6 +230,7 @@ struct mipi_dsim_device {
>  	struct mipi_dsim_master_ops	*master_ops;
>  	struct mipi_dsim_lcd_device	*dsim_lcd_dev;
>  	struct mipi_dsim_lcd_driver	*dsim_lcd_drv;
> +	struct mipi_dsim_phy_config	*dsim_phy_config;
>  
>  	unsigned int			state;
>  	unsigned int			data_lane;
> @@ -295,6 +296,32 @@ struct mipi_dsim_master_ops {
>  };
>  
>  /*
> + * phy node structure for mipi-dsim.
> + *
> + * @reg_enable_dphy	: base address to memory mapped D-PHY enable register
> + * @ctrlbit_enable_dphy : control bit for enabling D-PHY
> + * @reg_reset_dsim	: base address to memory mapped DSIM reset register
> + * @ctrlbit_reset_dsim	: control bit for resetting DSIM
> + */
> +struct mipi_dsim_phy_config_type1 {
> +	void __iomem	*reg_enable_dphy;
> +	int		ctrlbit_enable_dphy;
> +	void __iomem	*reg_reset_dsim;
> +	int		ctrlbit_reset_dsim;
> +};
> +
> +enum mipi_dsim_phy_config_type {
> +	MIPI_DSIM_PHY_CONFIG_TYPE1,
> +};
> +
> +struct mipi_dsim_phy_config {
> +	enum mipi_dsim_phy_config_type type;
> +	union {
> +		struct mipi_dsim_phy_config_type1 phy_cfg_type1;
> +	};
> +};
> +
> +/*
>   * device structure for mipi-dsi based lcd panel.
>   *
>   * @name: name of the device to use with this device, or an


Hi,

Does mipi-phy-type1 means MIPI_PHYx_CONTROL register of PMU?
If so, why did you define only 'type1'? Even if you do not use 'type0' 
on your case, should be defined 'type0' in the 'mipi_dsim_phy_config_type'?

And Is it correct to access to the PMU registers directly in the mipi 
dsi driver to control mipi-phyx?

Thanks, 
Donghwa Lee
--
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
Shaik Ameer Basha Nov. 20, 2012, 11:36 a.m. UTC | #3
Hi Donghwa Lee,

On Tue, Nov 20, 2012 at 7:42 AM, Donghwa Lee <dh09.lee@samsung.com> wrote:
> On 10 Nov, 2012 20:34, Shaik Ameer Basha wrote:
>
>> This patch adds the DT support for the exynos mipi-dsi driver.
>> for DT support mipi device node should supply the following
>> information to the mipi-dsi driver.
>> 1] dsim_config information
>> 2] d-phy setting information
>> 3] lcd poweron, reset information
>> 4] fb_videomode information
>> [...]
>
>>
>
>> diff --git a/include/video/exynos_mipi_dsim.h b/include/video/exynos_mipi_dsim.h
>> index 772c770..6d9b01d 100644
>> --- a/include/video/exynos_mipi_dsim.h
>> +++ b/include/video/exynos_mipi_dsim.h
>> @@ -230,6 +230,7 @@ struct mipi_dsim_device {
>>       struct mipi_dsim_master_ops     *master_ops;
>>       struct mipi_dsim_lcd_device     *dsim_lcd_dev;
>>       struct mipi_dsim_lcd_driver     *dsim_lcd_drv;
>> +     struct mipi_dsim_phy_config     *dsim_phy_config;
>>
>>       unsigned int                    state;
>>       unsigned int                    data_lane;
>> @@ -295,6 +296,32 @@ struct mipi_dsim_master_ops {
>>  };
>>
>>  /*
>> + * phy node structure for mipi-dsim.
>> + *
>> + * @reg_enable_dphy  : base address to memory mapped D-PHY enable register
>> + * @ctrlbit_enable_dphy : control bit for enabling D-PHY
>> + * @reg_reset_dsim   : base address to memory mapped DSIM reset register
>> + * @ctrlbit_reset_dsim       : control bit for resetting DSIM
>> + */
>> +struct mipi_dsim_phy_config_type1 {
>> +     void __iomem    *reg_enable_dphy;
>> +     int             ctrlbit_enable_dphy;
>> +     void __iomem    *reg_reset_dsim;
>> +     int             ctrlbit_reset_dsim;
>> +};
>> +
>> +enum mipi_dsim_phy_config_type {
>> +     MIPI_DSIM_PHY_CONFIG_TYPE1,
>> +};
>> +
>> +struct mipi_dsim_phy_config {
>> +     enum mipi_dsim_phy_config_type type;
>> +     union {
>> +             struct mipi_dsim_phy_config_type1 phy_cfg_type1;
>> +     };
>> +};
>> +
>> +/*
>>   * device structure for mipi-dsi based lcd panel.
>>   *
>>   * @name: name of the device to use with this device, or an
>
>
> Hi,
>
> Does mipi-phy-type1 means MIPI_PHYx_CONTROL register of PMU?
> If so, why did you define only 'type1'? Even if you do not use 'type0'
> on your case, should be defined 'type0' in the 'mipi_dsim_phy_config_type'?

Yes, you are right.
Sorry, I should have used 'type0' as you mentioned.

>
> And Is it correct to access to the PMU registers directly in the mipi
> dsi driver to control mipi-phyx?

As the current way of controlling PHY (i.e., through callbacks from
platform data) is not acceptable,
I had only two options to choose,
1] Controlling PHY in the mipi-dsi driver itself
2] To create a seperate PHY driver for mipi-dsi.

Currently I implemented the first method to removing the PHY related
callbacks from platform data.

I thought, there should not be any issue with directly controlling PMU
registers from mipi-dsi driver.
Please suggest any better implementation for solving this problem.


Thanks,
Shaik Ameer Basha

>
> Thanks,
> Donghwa Lee
> --
> 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
--
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
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/video/exynos/mipi-dsi.txt b/Documentation/devicetree/bindings/video/exynos/mipi-dsi.txt
new file mode 100644
index 0000000..6445eac
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/exynos/mipi-dsi.txt
@@ -0,0 +1,185 @@ 
+* Samsung Exynos MIPI-DSI bindings
+
+Properties for MIPI-DSI node ::
+===============================
+- compatible: should be "samsung,exynos5-mipi"
+
+- reg: should contain mipi-dsi physical address location and length.
+
+- interrupts: should contain mipi-dsi interrupt number
+
+- enabled: Describes whether MIPI DSI got enabled in uboot
+
+- mipi-lcd: phandle to lcd specific information. It can be anything
+	specific to lcd driver.
+
+- mipi-phy: phandle to D-PHY node.
+
+- mipi-config: subnode for mipi config information
+	- auto_flush: enable or disable Auto flush of MD FIFO using VSYNC pulse
+	- eot_disable: enable or disable EoT packet in HS mode
+	- auto_vertical_cnt: specifies auto vertical count mode.
+		In Video mode, the vertical line transition uses line counter
+		configured by VSA, VBP, and Vertical resolution. If this bit is
+		set to '1', the line counter does not use VSA and VBP registers.
+		In command mode, this property is ignored.
+	- hse: set horizontal sync event mode.
+		In VSYNC pulse and Vporch area,	MIPI DSI master transfers only
+		HSYNC start packet to MIPI DSI slave at MIPI DSI spec1.1r02.
+		This bit transfers HSYNC end packet in VSYNC pulse and Vporch
+		area. In command mode, this property is ignored.
+	- hfp: specifies HFP disable mode.
+		If this property is set, DSI master ignores HFP area in
+		VIDEO mode. In command mode, this property is ignored.
+	- hbp: specifies HBP disable mode.
+		If this property is set, DSI master ignores HBP area in
+		VIDEO mode. In command mode, this property is ignored.
+	- hsa: specifies HSA disable mode.
+		If this property is set, DSI master ignores HSA area in
+		VIDEO mode. In command mode, this property is ignored.
+	- cmd_allow: specifies the number of horizontal lines, where command
+		packet transmission is allowed after Stable VFP period.
+	- e_interface: specifies interface to be used.(CPU or RGB interface)
+	- e_virtual_ch: specifies virtual channel number that main or
+		sub display uses.
+	- e_pixel_format: specifies pixel stream format for main or sub display.
+	- e_burst_mode: selects Burst mode in Video mode.
+		In Non-burst mode, RGB data area is filled with RGB data
+		and NULL packets, according to input bandwidth of RGB interface.
+		In Burst mode, RGB data area is filled with RGB data only.
+	- e_no_data_lane: specifies data lane count to be used by Master.
+	- e_byte_clk: select byte clock source. (it must be DSIM_PLL_OUT_DIV8)
+		DSIM_EXT_CLK_DIV8 and DSIM_EXT_CLK_BYPASSS are not supported.
+	- pll_stable_time: specifies the PLL Timer for stability of the
+		generated clock(System clock cycle base). If the timer value
+		goes to 0x00000000, the clock stable bit of status and interrupt
+		register is set.
+	- esc_clk: specifies escape clock frequency for getting the escape clock
+		prescaler value.
+	- stop_holding_cnt: specifies the interval value between transmitting
+		read packet(or write "set_tear_on" command) and BTA request.
+		after transmitting read packet or write "set_tear_on" command,
+		BTA requests to D-PHY automatically. this counter value
+		specifies the interval between them.
+	- bta_timeout: specifies the timer for BTA.
+		this register specifies time out from BTA request to change
+		the direction with respect to Tx escape clock.
+	- rx_timeout: specifies the timer for LP Rx mode timeout.
+		this register specifies time out on how long RxValid deasserts,
+		after RxLpdt asserts with respect to Tx escape clock.
+		- RxValid specifies Rx data valid indicator.
+		- RxLpdt specifies an indicator that D-PHY is under RxLpdt mode.
+		- RxValid and RxLpdt specifies signal from D-PHY.
+
+- display-mode: timing and resolution information of the panel used. As per
+	current exynos mipi-dsi driver need, only some fields from
+	struct fb_videomode are defined in this node.
+	- xres: horizontal resolution (active frame width)
+	- yres: vertical resolution (active frame height).
+	- left_margin: Horizontal Back Porch (Number of PIXCLK pulses between
+		HSYNC signal and the first valid pixel data.
+	- right_margin: Horizontal Front Porch (Number of PIXCLK between
+		last valid pixel data in the line and the next HSYNC pulse).
+	- upper_margin: Vertical Back Porch (Number of lines (HSYNC pulses)
+		from when a VSYNC signal is asserted and the first valid line).
+	- lower_margin: Vertical Front Porch (Number of lines (HSYNC pulses)
+		between last valid line of the frame and the next VSYNC Pulse).
+	- hsync_len: Hsync pulse width (Number of PIXCLK pulses when a HSYNC
+		signal is active).
+	- vsync_len: Vsync pulse width (Number of HSYNC pulses when a VSYNC
+		signal is active).
+
+Properties for D-PHY node ::
+=============================
+	Instead of passing D-PHY related callbacks as part of platform data,
+we can pass the phy nodes to the mipi driver. Depending on the type of PHY
+settings, we can implement multiple PHY node types and corresponding
+enable/disable/reset callbacks in the driver itself. Currently we support
+only one type of PHY node.
+
+D-PHY node type1:
+------------------
+- compatible: "samsung,exynos-mipi-phy-type1"
+- reg_enable_dphy: should contain physical address location of
+	D-PHY enable register
+- mask_enable_dphy: should contain the mask for D-PHY enable register
+- reg_reset_dsim: should contain physical address location of
+	D-PHY DSIM reset register
+- mask_reset_dsim: should contain the mask for D-PHY DSIM reset register
+
+MIPI-LCD node ::
+=================
+	Apart from the following three properties, driver specific
+properties can be sent through this node. The following example sends
+some more properties for driver's use.
+
+- lcd-name: name of the device to use with this device
+- id: id of device to be registered (default -1 in case not specified)
+- bus-id: bus id for identifing connected bus and this bus id should be
+	same as id of mipi_dsim_device (default -1 incase not specified)
+
+Example:
+--------
+	mipi_lcd: mipi-lcd@toshiba {
+		lcd-name = "tc358764";
+		id = <0>;
+		enabled = <1>;
+		reset-delay = <120>;
+		power-on-delay = <25>;
+		power-off-delay = <200>;
+		gpio-poweron = <&gpx1 5 0 0 0>;
+	};
+
+	mipi_dsim_phy: mipi-phy@exynos5250 {
+		compatible = "samsung-exynos,mipi-phy-type1";
+		reg_enable_dphy = <0x10040714>;
+		mask_enable_dphy = <0x00000001>;
+		reg_reset_dsim = <0x10040714>;
+		mask_reset_dsim = <0x00000004>;
+	};
+
+	mipi {
+		compatible = "samsung,exynos-mipi";
+		reg = <0x14500000 0x10000>;
+		interrupts = <0 82 0>;
+
+		mipi-lcd = <&mipi_lcd>;
+		mipi-phy = <&mipi_dsim_phy>;
+		enabled = <0>;
+
+		mipi-config {
+			e_interface = <1>;
+			e_pixel_format = <7>;
+			auto_flush = <0>;
+			eot_disable = <0>;
+			auto_vertical_cnt = <0>;
+			hse = <0>;
+			hfp = <0>;
+			hbp = <0>;
+			hsa = <0>;
+			e_no_data_lane = <3>;
+			e_byte_clk = <0>;
+			e_burst_mode = <3>;
+			p = <3>;
+			m = <115>;
+			s = <1>;
+			pll_stable_time = <500>;
+			esc_clk = <400000>;
+			stop_holding_cnt =<0x0f>;
+			bta_timeout = <0xff>;
+			rx_timeout = <0xffff>;
+			e_virtual_ch = <0>;
+			cmd_allow = <0xf>;
+		};
+
+		panel-info {
+			left_margin = <0x4>;
+			right_margin = <0x4>;
+			upper_margin = <0x4>;
+			lower_margin = <0x4>;
+			hsync_len = <0x4>;
+			vsync_len = <0x4>;
+			xres = <1280>;
+			yres = <800>;
+		};
+	};
diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c
index ae20bc3..667857b 100755
--- a/drivers/video/exynos/exynos_mipi_dsi.c
+++ b/drivers/video/exynos/exynos_mipi_dsi.c
@@ -32,6 +32,7 @@ 
 #include <linux/notifier.h>
 #include <linux/regulator/consumer.h>
 #include <linux/pm_runtime.h>
+#include <linux/lcd.h>
 
 #include <video/exynos_mipi_dsim.h>
 
@@ -43,6 +44,8 @@ 
 struct mipi_dsim_ddi {
 	int				bus_id;
 	struct list_head		list;
+	struct device_node		*ofnode_dsim_lcd_dev;
+	struct device_node		*ofnode_dsim_dphy;
 	struct mipi_dsim_lcd_device	*dsim_lcd_dev;
 	struct mipi_dsim_lcd_driver	*dsim_lcd_drv;
 };
@@ -181,6 +184,36 @@  static int exynos_mipi_dsi_blank_mode(struct mipi_dsim_device *dsim, int power)
 	return 0;
 }
 
+struct mipi_dsim_ddi *exynos_mipi_dsi_find_lcd_driver(
+			struct mipi_dsim_lcd_device *lcd_dev)
+{
+	struct mipi_dsim_ddi *dsim_ddi, *next;
+	struct mipi_dsim_lcd_driver *lcd_drv;
+
+	mutex_lock(&mipi_dsim_lock);
+
+	list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
+		if (!dsim_ddi)
+			goto out;
+
+		lcd_drv = dsim_ddi->dsim_lcd_drv;
+		if (!lcd_drv)
+			continue;
+
+		if ((strcmp(lcd_dev->name, lcd_drv->name)) == 0) {
+			mutex_unlock(&mipi_dsim_lock);
+			return dsim_ddi;
+		}
+
+		list_del(&dsim_ddi->list);
+		kfree(dsim_ddi);
+	}
+
+out:
+	mutex_unlock(&mipi_dsim_lock);
+	return NULL;
+}
+
 int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
 {
 	struct mipi_dsim_ddi *dsim_ddi;
@@ -190,13 +223,17 @@  int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
 		return -EFAULT;
 	}
 
-	dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
+	dsim_ddi = exynos_mipi_dsi_find_lcd_driver(lcd_dev);
 	if (!dsim_ddi) {
-		pr_err("failed to allocate dsim_ddi object.\n");
-		return -ENOMEM;
+		dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
+		if (!dsim_ddi) {
+			pr_err("failed to allocate dsim_ddi object.\n");
+			return -ENOMEM;
+		}
 	}
 
 	dsim_ddi->dsim_lcd_dev = lcd_dev;
+	dsim_ddi->bus_id = lcd_dev->bus_id;
 
 	mutex_lock(&mipi_dsim_lock);
 	list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
@@ -253,11 +290,26 @@  int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
 
 	dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv);
 	if (!dsim_ddi) {
-		pr_err("mipi_dsim_ddi object not found.\n");
-		return -EFAULT;
-	}
+		/*
+		 * If driver specific device is not registered then create a
+		 * dsim_ddi object, fill the driver information and add to the
+		 * end of the dsim_ddi_list list
+		 */
+		dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
+		if (!dsim_ddi) {
+			pr_err("failed to allocate dsim_ddi object.\n");
+			return -ENOMEM;
+		}
+
+		dsim_ddi->dsim_lcd_drv = lcd_drv;
 
-	dsim_ddi->dsim_lcd_drv = lcd_drv;
+		mutex_lock(&mipi_dsim_lock);
+		list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
+		mutex_unlock(&mipi_dsim_lock);
+
+	} else {
+		dsim_ddi->dsim_lcd_drv = lcd_drv;
+	}
 
 	pr_info("registered panel driver(%s) to mipi-dsi driver.\n",
 		lcd_drv->name);
@@ -329,6 +381,372 @@  static struct mipi_dsim_master_ops master_ops = {
 	.set_blank_mode			= exynos_mipi_dsi_blank_mode,
 };
 
+struct device_node *exynos_mipi_find_ofnode_dsim_phy(
+				struct platform_device *pdev)
+{
+	struct device_node *dn, *dn_dphy;
+	const __be32 *prop;
+
+	dn = pdev->dev.of_node;
+	prop = of_get_property(dn, "mipi-phy", NULL);
+	if (NULL == prop) {
+		dev_err(&pdev->dev, "Could not find property mipi-phy\n");
+		return NULL;
+	}
+
+	dn_dphy = of_find_node_by_phandle(be32_to_cpup(prop));
+	if (NULL == dn_dphy) {
+		dev_err(&pdev->dev, "Could not find node\n");
+		return NULL;
+	}
+
+	return dn_dphy;
+}
+
+struct device_node *exynos_mipi_find_ofnode_lcd_device(
+			struct platform_device *pdev)
+{
+	struct device_node *dn, *dn_lcd_panel;
+	const __be32 *prop;
+
+	dn = pdev->dev.of_node;
+	prop = of_get_property(dn, "mipi-lcd", NULL);
+	if (NULL == prop) {
+		dev_err(&pdev->dev, "could not find property mipi-lcd\n");
+		return NULL;
+	}
+
+	dn_lcd_panel = of_find_node_by_phandle(be32_to_cpup(prop));
+	if (NULL == dn_lcd_panel) {
+		dev_err(&pdev->dev, "could not find node\n");
+		return NULL;
+	}
+
+	return dn_lcd_panel;
+}
+
+static void exynos_mipi_dsim_enable_d_phy_type1(
+			struct platform_device *pdev,
+			bool enable)
+{
+	struct mipi_dsim_device *dsim = (struct mipi_dsim_device *)
+					platform_get_drvdata(pdev);
+	struct mipi_dsim_phy_config_type1 *dphy_cfg_type1 =
+					&dsim->dsim_phy_config->phy_cfg_type1;
+	u32 reg_enable;
+
+	reg_enable = __raw_readl(dphy_cfg_type1->reg_enable_dphy);
+	reg_enable &= ~(dphy_cfg_type1->ctrlbit_enable_dphy);
+
+	if (enable)
+		reg_enable |= dphy_cfg_type1->ctrlbit_enable_dphy;
+
+	__raw_writel(reg_enable, dphy_cfg_type1->reg_enable_dphy);
+}
+
+static void exynos_mipi_dsim_reset_type1(
+			struct platform_device *pdev,
+			bool enable)
+{
+	struct mipi_dsim_device *dsim = (struct mipi_dsim_device *)
+					platform_get_drvdata(pdev);
+	struct mipi_dsim_phy_config_type1 *dphy_cfg_type1 =
+					&dsim->dsim_phy_config->phy_cfg_type1;
+	u32 reg_reset;
+
+	reg_reset = __raw_readl(dphy_cfg_type1->reg_reset_dsim);
+	reg_reset &= ~(dphy_cfg_type1->ctrlbit_reset_dsim);
+
+	if (enable)
+		reg_reset |= dphy_cfg_type1->ctrlbit_reset_dsim;
+
+	__raw_writel(reg_reset, dphy_cfg_type1->reg_reset_dsim);
+}
+
+static int exynos_mipi_dsim_phy_init_type1(
+			struct platform_device *pdev,
+			bool on_off)
+{
+	exynos_mipi_dsim_enable_d_phy_type1(pdev, on_off);
+	exynos_mipi_dsim_reset_type1(pdev, on_off);
+	return 0;
+}
+
+static int parse_u32_property(struct device_node *np, char *name,
+				u32 *result)
+{
+	if (of_property_read_u32(np, name, result)) {
+		pr_err("not able to find property: %s\n", name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int exynos_mipi_parse_ofnode_dsim_phy_type1(
+		struct platform_device *pdev,
+		struct mipi_dsim_phy_config_type1 *dphy_cfg_type1,
+		struct device_node *np)
+{
+	struct mipi_dsim_device *dsim = (struct mipi_dsim_device *)
+					platform_get_drvdata(pdev);
+	u32 paddr_phy_enable, paddr_dsim_reset;
+	int ret = 0;
+
+	ret |= parse_u32_property(np, "reg_enable_dphy", &paddr_phy_enable);
+	ret |= parse_u32_property(np, "reg_reset_dsim", &paddr_dsim_reset);
+	ret |= parse_u32_property(np, "mask_enable_dphy",
+					&dphy_cfg_type1->ctrlbit_enable_dphy);
+	ret |= parse_u32_property(np, "mask_reset_dsim",
+					&dphy_cfg_type1->ctrlbit_reset_dsim);
+
+	if (ret) {
+		pr_err("%s: error reading phy node properties\n", __func__);
+		return -EINVAL;
+	}
+
+	dphy_cfg_type1->reg_enable_dphy = ioremap(paddr_phy_enable, SZ_4);
+	if (!dphy_cfg_type1->reg_enable_dphy)
+		return -EINVAL;
+
+	dphy_cfg_type1->reg_reset_dsim = ioremap(paddr_dsim_reset, SZ_4);
+	if (!dphy_cfg_type1->reg_reset_dsim)
+		goto err_ioremap;
+
+	dsim->pd->phy_enable = exynos_mipi_dsim_phy_init_type1;
+
+	return 0;
+
+err_ioremap:
+	iounmap(dphy_cfg_type1->reg_enable_dphy);
+	return -EINVAL;
+}
+
+static struct mipi_dsim_phy_config *exynos_mipi_parse_ofnode_dsim_phy(
+		struct platform_device *pdev,
+		struct device_node *np)
+{
+	struct mipi_dsim_phy_config *mipi_dphy_config;
+	const char *compatible;
+
+	mipi_dphy_config = devm_kzalloc(&pdev->dev,
+			sizeof(struct mipi_dsim_phy_config), GFP_KERNEL);
+	if (!mipi_dphy_config) {
+		dev_err(&pdev->dev,
+			"failed to allocate mipi_dsim_phy_config object.\n");
+		return NULL;
+	}
+
+	if (of_property_read_string(np, "compatible", &compatible)) {
+		dev_err(&pdev->dev, "compatible property not found");
+		return NULL;
+	}
+
+	/* try to find the phy node type from compatible string */
+	if (!strcmp(compatible, "samsung-exynos,mipi-phy-type1"))
+		mipi_dphy_config->type = MIPI_DSIM_PHY_CONFIG_TYPE1;
+	else
+		mipi_dphy_config->type = -1;
+
+	/* parse the phy node as per its type */
+	switch (mipi_dphy_config->type) {
+	case MIPI_DSIM_PHY_CONFIG_TYPE1:
+		if (exynos_mipi_parse_ofnode_dsim_phy_type1(
+			pdev, &mipi_dphy_config->phy_cfg_type1, np))
+			return NULL;
+		break;
+	default:
+		dev_err(&pdev->dev, "mipi phy - unknown type");
+		return NULL;
+	}
+
+	return mipi_dphy_config;
+}
+
+static struct mipi_dsim_lcd_device *exynos_mipi_parse_ofnode_lcd(
+		struct platform_device *pdev, struct device_node *np)
+{
+	struct mipi_dsim_lcd_device *active_mipi_dsim_lcd_device;
+	struct lcd_platform_data *active_lcd_platform_data;
+	const char *lcd_name;
+
+	active_mipi_dsim_lcd_device = devm_kzalloc(&pdev->dev,
+			sizeof(struct mipi_dsim_lcd_device), GFP_KERNEL);
+	if (!active_mipi_dsim_lcd_device) {
+		dev_err(&pdev->dev,
+		"failed to allocate active_mipi_dsim_lcd_device object.\n");
+		return NULL;
+	}
+
+	if (of_property_read_string(np, "lcd-name", &lcd_name)) {
+		dev_err(&pdev->dev, "lcd name property not found");
+		return NULL;
+	}
+
+	active_mipi_dsim_lcd_device->name = (char *)lcd_name;
+
+	if (of_property_read_u32(np, "id", &active_mipi_dsim_lcd_device->id))
+		active_mipi_dsim_lcd_device->id = -1;
+
+	if (of_property_read_u32(np, "bus-id",
+					&active_mipi_dsim_lcd_device->bus_id))
+		active_mipi_dsim_lcd_device->bus_id = -1;
+
+	active_lcd_platform_data = devm_kzalloc(&pdev->dev,
+				sizeof(struct lcd_platform_data), GFP_KERNEL);
+	if (!active_lcd_platform_data) {
+		dev_err(&pdev->dev,
+		"failed to allocate active_lcd_platform_data object.\n");
+		return NULL;
+	}
+
+	/* store the lcd node pointer for futher use in lcd driver */
+	active_lcd_platform_data->pdata = (void *) np;
+	active_mipi_dsim_lcd_device->platform_data =
+				(void *)active_lcd_platform_data;
+
+	return active_mipi_dsim_lcd_device;
+}
+
+static int exynos_mipi_parse_ofnode_config(struct platform_device *pdev,
+		struct device_node *np, struct mipi_dsim_config *dsim_config)
+{
+	unsigned int u32Val;
+
+	if (parse_u32_property(np, "e_interface", &u32Val))
+		return -EINVAL;
+	dsim_config->e_interface = (enum mipi_dsim_interface_type)u32Val;
+
+	if (parse_u32_property(np, "e_pixel_format", &u32Val))
+		return -EINVAL;
+	dsim_config->e_pixel_format = (enum mipi_dsim_pixel_format)u32Val;
+
+	if (parse_u32_property(np, "auto_flush", &u32Val))
+		return -EINVAL;
+	dsim_config->auto_flush = (unsigned char)u32Val;
+
+	if (parse_u32_property(np, "eot_disable", &u32Val))
+		return -EINVAL;
+	dsim_config->eot_disable = (unsigned char)u32Val;
+
+	if (parse_u32_property(np, "auto_vertical_cnt", &u32Val))
+		return -EINVAL;
+	dsim_config->auto_vertical_cnt = (unsigned char)u32Val;
+
+	if (parse_u32_property(np, "hse", &u32Val))
+		return -EINVAL;
+	dsim_config->hse = (unsigned char)u32Val;
+
+	if (parse_u32_property(np, "hfp", &u32Val))
+		return -EINVAL;
+	dsim_config->hfp = (unsigned char)u32Val;
+
+	if (parse_u32_property(np, "hbp", &u32Val))
+		return -EINVAL;
+	dsim_config->hbp = (unsigned char)u32Val;
+
+	if (parse_u32_property(np, "hsa", &u32Val))
+		return -EINVAL;
+	dsim_config->hsa = (unsigned char)u32Val;
+
+	if (parse_u32_property(np, "e_no_data_lane", &u32Val))
+		return -EINVAL;
+	dsim_config->e_no_data_lane = (enum mipi_dsim_no_of_data_lane)u32Val;
+
+	if (parse_u32_property(np, "e_byte_clk", &u32Val))
+		return -EINVAL;
+	dsim_config->e_byte_clk = (enum mipi_dsim_byte_clk_src)u32Val;
+
+	if (parse_u32_property(np, "e_burst_mode", &u32Val))
+		return -EINVAL;
+	dsim_config->e_burst_mode = (enum mipi_dsim_burst_mode_type)u32Val;
+
+	if (parse_u32_property(np, "p", &u32Val))
+		return -EINVAL;
+	dsim_config->p = (unsigned char)u32Val;
+
+	if (parse_u32_property(np, "m", &u32Val))
+		return -EINVAL;
+	dsim_config->m = (unsigned short)u32Val;
+
+	if (parse_u32_property(np, "s", &u32Val))
+		return -EINVAL;
+	dsim_config->s = (unsigned char)u32Val;
+
+	if (parse_u32_property(np, "pll_stable_time", &u32Val))
+		return -EINVAL;
+	dsim_config->pll_stable_time = (unsigned int)u32Val;
+
+	if (parse_u32_property(np, "esc_clk", &u32Val))
+		return -EINVAL;
+	dsim_config->esc_clk = (unsigned long)u32Val;
+
+	if (parse_u32_property(np, "stop_holding_cnt", &u32Val))
+		return -EINVAL;
+	dsim_config->stop_holding_cnt = (unsigned short)u32Val;
+
+	if (parse_u32_property(np, "bta_timeout", &u32Val))
+		return -EINVAL;
+	dsim_config->bta_timeout = (unsigned char)u32Val;
+
+	if (parse_u32_property(np, "rx_timeout", &u32Val))
+		return -EINVAL;
+	dsim_config->rx_timeout = (unsigned short)u32Val;
+
+	if (parse_u32_property(np, "e_virtual_ch", &u32Val))
+		return -EINVAL;
+	dsim_config->e_virtual_ch = (enum mipi_dsim_virtual_ch_no)u32Val;
+
+	if (parse_u32_property(np, "cmd_allow", &u32Val))
+		return -EINVAL;
+	dsim_config->cmd_allow = (unsigned char)u32Val;
+
+	return 0;
+}
+
+static int exynos_mipi_parse_ofnode_panel_info(struct platform_device *pdev,
+		struct device_node *np, struct fb_videomode *vm)
+{
+	int ret = 0;
+
+	ret |= parse_u32_property(np, "left_margin", &vm->left_margin);
+	ret |= parse_u32_property(np, "right_margin", &vm->right_margin);
+	ret |= parse_u32_property(np, "upper_margin", &vm->upper_margin);
+	ret |= parse_u32_property(np, "lower_margin", &vm->lower_margin);
+	ret |= parse_u32_property(np, "hsync_len", &vm->hsync_len);
+	ret |= parse_u32_property(np, "vsync_len", &vm->vsync_len);
+	ret |= parse_u32_property(np, "xres", &vm->xres);
+	ret |= parse_u32_property(np, "yres", &vm->yres);
+	if (ret)
+		pr_err("%s: error reading fb_videomodeproperties\n", __func__);
+
+	return ret;
+}
+
+static int exynos_mipi_parse_ofnode(struct platform_device *pdev,
+	struct mipi_dsim_config *dsim_config, struct fb_videomode *panel_info)
+{
+	struct device_node *np_dsim_config, *np_panel_info;
+	struct device_node *np = pdev->dev.of_node;
+
+	np_dsim_config = of_find_node_by_name(np, "mipi-config");
+	if (!np_dsim_config)
+		return -EINVAL;
+
+	if (exynos_mipi_parse_ofnode_config(pdev, np_dsim_config, dsim_config))
+		return -EINVAL;
+
+	np_panel_info = of_find_node_by_name(np, "display-mode");
+	if (!np_panel_info)
+		return -EINVAL;
+
+	if (exynos_mipi_parse_ofnode_panel_info(pdev,
+					np_panel_info, panel_info))
+		return -EINVAL;
+
+	return 0;
+}
+
 static int exynos_mipi_dsi_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -336,6 +754,12 @@  static int exynos_mipi_dsi_probe(struct platform_device *pdev)
 	struct mipi_dsim_config *dsim_config;
 	struct mipi_dsim_platform_data *dsim_pd;
 	struct mipi_dsim_ddi *dsim_ddi;
+	struct device_node *ofnode_lcd = NULL;
+	struct device_node *ofnode_dphy = NULL;
+	struct mipi_dsim_lcd_device *active_mipi_dsim_lcd_device = NULL;
+	struct mipi_dsim_phy_config *mipi_dphy_config;
+	struct fb_videomode *panel_info;
+	unsigned int u32Val;
 	int ret = -EINVAL;
 
 	dsim = devm_kzalloc(&pdev->dev,
@@ -345,23 +769,87 @@  static int exynos_mipi_dsi_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
+	if (pdev->dev.of_node) {
+		ofnode_lcd = exynos_mipi_find_ofnode_lcd_device(pdev);
+		if (!ofnode_lcd)
+			return -EINVAL;
+
+		active_mipi_dsim_lcd_device =
+				exynos_mipi_parse_ofnode_lcd(pdev, ofnode_lcd);
+
+		if (NULL == active_mipi_dsim_lcd_device)
+			return -EINVAL;
+
+		if (NULL == exynos_mipi_dsi_find_lcd_driver
+					(active_mipi_dsim_lcd_device))
+			return -ENXIO;
+
+		exynos_mipi_dsi_register_lcd_device(
+						active_mipi_dsim_lcd_device);
+	}
+
 	dsim->pd = to_dsim_plat(pdev);
 	dsim->dev = &pdev->dev;
 	dsim->id = pdev->id;
 
-	/* get mipi_dsim_platform_data. */
-	dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
-	if (dsim_pd == NULL) {
-		dev_err(&pdev->dev, "failed to get platform data for dsim.\n");
-		return -EFAULT;
-	}
-	/* get mipi_dsim_config. */
-	dsim_config = dsim_pd->dsim_config;
-	if (dsim_config == NULL) {
-		dev_err(&pdev->dev, "failed to get dsim config data.\n");
-		return -EFAULT;
-	}
+	if (pdev->dev.of_node) {
+		dsim_config = devm_kzalloc(&pdev->dev,
+			sizeof(struct mipi_dsim_config), GFP_KERNEL);
+		if (!dsim_config) {
+			dev_err(&pdev->dev,
+				"failed to allocate dsim_config object.\n");
+			return -ENOMEM;
+		}
 
+		panel_info = devm_kzalloc(&pdev->dev,
+				sizeof(struct fb_videomode), GFP_KERNEL);
+		if (!panel_info) {
+			dev_err(&pdev->dev,
+				"failed to allocate fb_videomode object.\n");
+			return -ENOMEM;
+		}
+
+		/* parse the mipi of_node for dism_config and panel info. */
+		if (exynos_mipi_parse_ofnode(pdev, dsim_config, panel_info)) {
+			dev_err(&pdev->dev,
+				"failed to read mipi-config, display-mode\n");
+			return -EINVAL;
+		}
+
+		dsim_pd = devm_kzalloc(&pdev->dev,
+			sizeof(struct mipi_dsim_platform_data), GFP_KERNEL);
+		if (!dsim_pd) {
+			dev_err(&pdev->dev,
+				"failed to allocate mipi_dsim_platform_data\n");
+			return -ENOMEM;
+		}
+
+		if (of_property_read_u32(pdev->dev.of_node, "enabled", &u32Val))
+			dev_err(&pdev->dev, "enabled property not found\n");
+		else
+			dsim_pd->enabled = !(!u32Val);
+
+		dsim_pd->lcd_panel_info = (void *)panel_info;
+		dsim_pd->dsim_config = dsim_config;
+		dsim->pd = dsim_pd;
+
+	} else {
+		/* get mipi_dsim_platform_data. */
+		dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
+		if (dsim_pd == NULL) {
+			dev_err(&pdev->dev,
+				"failed to get platform data for dsim.\n");
+			return -EFAULT;
+		}
+
+		/* get mipi_dsim_config. */
+		dsim_config = dsim_pd->dsim_config;
+		if (dsim_config == NULL) {
+			dev_err(&pdev->dev,
+				"failed to get dsim config data.\n");
+			return -EFAULT;
+		}
+	}
 	dsim->dsim_config = dsim_config;
 	dsim->master_ops = &master_ops;
 
@@ -394,11 +882,21 @@  static int exynos_mipi_dsi_probe(struct platform_device *pdev)
 	mutex_init(&dsim->lock);
 
 	/* bind lcd ddi matched with panel name. */
-	dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name);
+	if (pdev->dev.of_node) {
+		dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim,
+					active_mipi_dsim_lcd_device->name);
+	} else {
+		dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim,
+					dsim_pd->lcd_panel_name);
+	}
+
 	if (!dsim_ddi) {
 		dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n");
 		ret = -ENXIO;
 		goto cleanup_clk;
+	} else if (pdev->dev.of_node) {
+		dsim_ddi->ofnode_dsim_lcd_dev = ofnode_lcd;
+		dsim_ddi->ofnode_dsim_dphy = ofnode_dphy;
 	}
 
 	dsim->irq = platform_get_irq(pdev, 0);
@@ -412,6 +910,21 @@  static int exynos_mipi_dsi_probe(struct platform_device *pdev)
 	init_completion(&dsim_rd_comp);
 	platform_set_drvdata(pdev, dsim);
 
+	/* update dsim phy config node */
+	if (pdev->dev.of_node) {
+		ofnode_dphy = exynos_mipi_find_ofnode_dsim_phy(pdev);
+		if (!ofnode_dphy)
+			return -EINVAL;
+
+		mipi_dphy_config = exynos_mipi_parse_ofnode_dsim_phy(pdev,
+								ofnode_dphy);
+
+		if (NULL == mipi_dphy_config)
+			return -EINVAL;
+
+		dsim->dsim_phy_config = mipi_dphy_config;
+	}
+
 	ret = devm_request_irq(&pdev->dev, dsim->irq,
 			exynos_mipi_dsi_interrupt_handler,
 			IRQF_SHARED, dev_name(&pdev->dev), dsim);
@@ -557,13 +1070,33 @@  static const struct dev_pm_ops exynos_mipi_dsi_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(exynos_mipi_dsi_suspend, exynos_mipi_dsi_resume)
 };
 
+static struct platform_device_id exynos_mipi_driver_ids[] = {
+	{
+		.name		= "exynos-mipi",
+		.driver_data	= NULL,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(platform, exynos_mipi_driver_ids);
+
+static const struct of_device_id exynos_mipi_match[] = {
+	{
+		.compatible = "samsung,exynos5-mipi",
+		.data = NULL,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, exynos_mipi_match);
+
 static struct platform_driver exynos_mipi_dsi_driver = {
 	.probe = exynos_mipi_dsi_probe,
 	.remove = __devexit_p(exynos_mipi_dsi_remove),
+	.id_table = exynos_mipi_driver_ids,
 	.driver = {
 		   .name = "exynos-mipi-dsim",
 		   .owner = THIS_MODULE,
 		   .pm = &exynos_mipi_dsi_pm_ops,
+		   .of_match_table = exynos_mipi_match,
 	},
 };
 
diff --git a/include/video/exynos_mipi_dsim.h b/include/video/exynos_mipi_dsim.h
index 772c770..6d9b01d 100644
--- a/include/video/exynos_mipi_dsim.h
+++ b/include/video/exynos_mipi_dsim.h
@@ -230,6 +230,7 @@  struct mipi_dsim_device {
 	struct mipi_dsim_master_ops	*master_ops;
 	struct mipi_dsim_lcd_device	*dsim_lcd_dev;
 	struct mipi_dsim_lcd_driver	*dsim_lcd_drv;
+	struct mipi_dsim_phy_config	*dsim_phy_config;
 
 	unsigned int			state;
 	unsigned int			data_lane;
@@ -295,6 +296,32 @@  struct mipi_dsim_master_ops {
 };
 
 /*
+ * phy node structure for mipi-dsim.
+ *
+ * @reg_enable_dphy	: base address to memory mapped D-PHY enable register
+ * @ctrlbit_enable_dphy : control bit for enabling D-PHY
+ * @reg_reset_dsim	: base address to memory mapped DSIM reset register
+ * @ctrlbit_reset_dsim	: control bit for resetting DSIM
+ */
+struct mipi_dsim_phy_config_type1 {
+	void __iomem	*reg_enable_dphy;
+	int		ctrlbit_enable_dphy;
+	void __iomem	*reg_reset_dsim;
+	int		ctrlbit_reset_dsim;
+};
+
+enum mipi_dsim_phy_config_type {
+	MIPI_DSIM_PHY_CONFIG_TYPE1,
+};
+
+struct mipi_dsim_phy_config {
+	enum mipi_dsim_phy_config_type type;
+	union {
+		struct mipi_dsim_phy_config_type1 phy_cfg_type1;
+	};
+};
+
+/*
  * device structure for mipi-dsi based lcd panel.
  *
  * @name: name of the device to use with this device, or an