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