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

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

 



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@xxxxxxxxxxx]
> Sent: Saturday, November 10, 2012 8:35 PM
> To: linux-fbdev@xxxxxxxxxxxxxxx
> Cc: inki.dae@xxxxxxxxxxx; dh09.lee@xxxxxxxxxxx; FlorianSchandinat@xxxxxx;
> s.nawrocki@xxxxxxxxxxx; kgene.kim@xxxxxxxxxxx
> 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@xxxxxxxxxxx>
> ---
>  .../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@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

  Powered by Linux