* [PATCH 2/2] video: exynos-mipi-dsi: Adding DT support to exynos mipi driver
@ 2012-11-10 11:46 Shaik Ameer Basha
2012-11-19 12:31 ` Inki Dae
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Shaik Ameer Basha @ 2012-11-10 11:46 UTC (permalink / raw)
To: linux-fbdev
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"
+
+- 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
--
1.7.0.4
^ permalink raw reply related [flat|nested] 4+ messages in thread
* RE: [PATCH 2/2] video: exynos-mipi-dsi: Adding DT support to exynos mipi driver
2012-11-10 11:46 [PATCH 2/2] video: exynos-mipi-dsi: Adding DT support to exynos mipi driver Shaik Ameer Basha
@ 2012-11-19 12:31 ` Inki Dae
2012-11-20 2:12 ` Donghwa Lee
2012-11-20 11:48 ` Shaik Ameer Basha
2 siblings, 0 replies; 4+ messages in thread
From: Inki Dae @ 2012-11-19 12:31 UTC (permalink / raw)
To: linux-fbdev
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
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 2/2] video: exynos-mipi-dsi: Adding DT support to exynos mipi driver
2012-11-10 11:46 [PATCH 2/2] video: exynos-mipi-dsi: Adding DT support to exynos mipi driver Shaik Ameer Basha
2012-11-19 12:31 ` Inki Dae
@ 2012-11-20 2:12 ` Donghwa Lee
2012-11-20 11:48 ` Shaik Ameer Basha
2 siblings, 0 replies; 4+ messages in thread
From: Donghwa Lee @ 2012-11-20 2:12 UTC (permalink / raw)
To: linux-fbdev
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
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 2/2] video: exynos-mipi-dsi: Adding DT support to exynos mipi driver
2012-11-10 11:46 [PATCH 2/2] video: exynos-mipi-dsi: Adding DT support to exynos mipi driver Shaik Ameer Basha
2012-11-19 12:31 ` Inki Dae
2012-11-20 2:12 ` Donghwa Lee
@ 2012-11-20 11:48 ` Shaik Ameer Basha
2 siblings, 0 replies; 4+ messages in thread
From: Shaik Ameer Basha @ 2012-11-20 11:48 UTC (permalink / raw)
To: linux-fbdev
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
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2012-11-20 11:48 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-11-10 11:46 [PATCH 2/2] video: exynos-mipi-dsi: Adding DT support to exynos mipi driver Shaik Ameer Basha
2012-11-19 12:31 ` Inki Dae
2012-11-20 2:12 ` Donghwa Lee
2012-11-20 11:48 ` Shaik Ameer Basha
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).