From mboxrd@z Thu Jan 1 00:00:00 1970 From: daeinki Date: Fri, 15 Apr 2011 02:32:02 +0000 Subject: Re: [PATCH 1/2] video: add Samsung SoC MIPI-DSI controller driver. Message-Id: <4DA7AE22.5090300@samsung.com> List-Id: References: <1302783320-31230-1-git-send-email-inki.dae@samsung.com> In-Reply-To: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit To: linux-arm-kernel@lists.infradead.org Kyungmin Park 쓴 글: > Mr. Dae, > > If only MIPI header files are used at video, just place it under video > directory. all structure and definitions included in mipi_dsim.h file should be set as machine specific data such as config data(pixel format, lane count, ..), platform data, mipi dsim device structure and so on. > > regardless this issue, how about the make a generic mipi dsi interface at video? > then other soc will be helpful also. > > e.g., one generic MIPI DSI framework and each SoCs register the > operations or override the functions or better way. > > No need to think/consider the samsung SOCs only. I agree to your opinion. common framework for mipi dsi would be helpful and also I think we could avoid duplicated codes. for this, first of all it needs open source developer's opinions related to MIPI-DSI because some mipi-dsi drivers, as I know, omap dss and ARM-shmobile, have been already applied to mainline. I guess someone who is mipi-dsi driver developer tried to propose common framework for mipi-dsi before. so Mr. Pual, have you ever been discussed about common framework for mipi-dsi before?, if not or needs it, I'd like to propose common framework for it. of course, this work would take a long time and needs many hard work and RFC. I'll look forward to your answer. thank you. > > Thank you, > Kyungmin Park > > On Thu, Apr 14, 2011 at 9:15 PM, Inki Dae wrote: >> Samsung S5PV210 and EXYNOS4 SoC platform have one or two MIPI-DSI controller. >> MIPI-DSI based LCD Panel could be used with MIPI-DSI controller driver. >> this patch adds the MIPI-DSI controller driver and also this driver would >> support both platforms. >> >> to use MIPI-DSI based LCD Panel driver, mipi_dsim_lcd_device should be >> registered to MIPI-DSI Driver through s5p_mipi_dsi_register_lcd_device() call >> in machine code or machine specific somewhere first, and mipi_dsim_lcd_driver >> should be registered when s5p_mipi_dsi_register_lcd_driver() is called at init >> function of lcd driver, and then probe() of that driver would be called by >> MIPI-DSI controller driver if lcd panel name and id of mipi_dsim_lcd_device >> are same as ones of mipi_dsim_lcd_driver. >> >> for this, you can refer to sample lcd panel driver. >> please see "Documentation/s5p_mipi_dsim/dsim_sample_lcd.c" >> >> Signed-off-by: Inki Dae >> Signed-off-by: Kyungmin Park >> --- >> arch/arm/plat-s5p/include/plat/mipi_dsim.h | 345 +++++++++++++++ >> arch/arm/plat-s5p/include/plat/regs-dsim.h | 143 ++++++ >> drivers/video/Kconfig | 7 + >> drivers/video/Makefile | 2 + >> drivers/video/s5p_mipi_dsi.c | 481 ++++++++++++++++++++ >> drivers/video/s5p_mipi_dsi_common.c | 655 ++++++++++++++++++++++++++++ >> drivers/video/s5p_mipi_dsi_common.h | 39 ++ >> drivers/video/s5p_mipi_dsi_lowlevel.c | 558 +++++++++++++++++++++++ >> drivers/video/s5p_mipi_dsi_lowlevel.h | 100 +++++ >> 9 files changed, 2330 insertions(+), 0 deletions(-) >> create mode 100644 arch/arm/plat-s5p/include/plat/mipi_dsim.h >> create mode 100644 arch/arm/plat-s5p/include/plat/regs-dsim.h >> create mode 100644 drivers/video/s5p_mipi_dsi.c >> create mode 100644 drivers/video/s5p_mipi_dsi_common.c >> create mode 100644 drivers/video/s5p_mipi_dsi_common.h >> create mode 100644 drivers/video/s5p_mipi_dsi_lowlevel.c >> create mode 100644 drivers/video/s5p_mipi_dsi_lowlevel.h >> >> diff --git a/arch/arm/plat-s5p/include/plat/mipi_dsim.h b/arch/arm/plat-s5p/include/plat/mipi_dsim.h >> new file mode 100644 >> index 0000000..0fa2d7e >> --- /dev/null >> +++ b/arch/arm/plat-s5p/include/plat/mipi_dsim.h >> @@ -0,0 +1,345 @@ >> +/* linux/arm/arch/plat-s5p/include/plat/mipi_dsim.h >> + * >> + * Platform data header for Samsung SoC MIPI-DSIM. >> + * >> + * Copyright (c) 2011 Samsung Electronics Co., Ltd >> + * >> + * InKi Dae >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License version 2 as >> + * published by the Free Software Foundation. >> +*/ >> + >> +#ifndef _DSIM_H >> +#define _DSIM_H >> + >> +#include >> +#include >> + >> +#define PANEL_NAME_SIZE (32) >> + >> +enum mipi_dsim_interface_type { >> + DSIM_COMMAND, >> + DSIM_VIDEO >> +}; >> + >> +enum mipi_dsim_virtual_ch_no { >> + DSIM_VIRTUAL_CH_0, >> + DSIM_VIRTUAL_CH_1, >> + DSIM_VIRTUAL_CH_2, >> + DSIM_VIRTUAL_CH_3 >> +}; >> + >> +enum mipi_dsim_burst_mode_type { >> + DSIM_NON_BURST_SYNC_EVENT, >> + DSIM_NON_BURST_SYNC_PULSE = 2, >> + DSIM_BURST, >> + DSIM_NON_VIDEO_MODE >> +}; >> + >> +enum mipi_dsim_no_of_data_lane { >> + DSIM_DATA_LANE_1, >> + DSIM_DATA_LANE_2, >> + DSIM_DATA_LANE_3, >> + DSIM_DATA_LANE_4 >> +}; >> + >> +enum mipi_dsim_byte_clk_src { >> + DSIM_PLL_OUT_DIV8, >> + DSIM_EXT_CLK_DIV8, >> + DSIM_EXT_CLK_BYPASS >> +}; >> + >> +enum mipi_dsim_pixel_format { >> + DSIM_CMD_3BPP, >> + DSIM_CMD_8BPP, >> + DSIM_CMD_12BPP, >> + DSIM_CMD_16BPP, >> + DSIM_VID_16BPP_565, >> + DSIM_VID_18BPP_666PACKED, >> + DSIM_18BPP_666LOOSELYPACKED, >> + DSIM_24BPP_888 >> +}; >> + >> +/** >> + * struct mipi_dsim_config - interface for configuring mipi-dsi controller. >> + * >> + * @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 variable 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 mommand mode, this variable is ignored) >> + * @hfp: specifies HFP disable mode. >> + * if this variable is set, DSI master ignores HFP area in VIDEO mode. >> + * (in command mode, this variable is ignored) >> + * @hbp: specifies HBP disable mode. >> + * if this variable is set, DSI master ignores HBP area in VIDEO mode. >> + * (in command mode, this variable is ignored) >> + * @hsa: specifies HSA disable mode. >> + * if this variable is set, DSI master ignores HSA area in VIDEO mode. >> + * (in command mode, this variable is ignored) >> + * @e_interface: specifies interface to be used.(CPU or RGB interface) >> + * @e_virtual_ch: specifies virtual channel number that main or >> + * sub diaplsy 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 ganerated >> + * 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. >> + */ >> +struct mipi_dsim_config { >> + unsigned char auto_flush; >> + unsigned char eot_disable; >> + >> + unsigned char auto_vertical_cnt; >> + unsigned char hse; >> + unsigned char hfp; >> + unsigned char hbp; >> + unsigned char hsa; >> + >> + enum mipi_dsim_interface_type e_interface; >> + enum mipi_dsim_virtual_ch_no e_virtual_ch; >> + enum mipi_dsim_pixel_format e_pixel_format; >> + enum mipi_dsim_burst_mode_type e_burst_mode; >> + enum mipi_dsim_no_of_data_lane e_no_data_lane; >> + enum mipi_dsim_byte_clk_src e_byte_clk; >> + >> + /* >> + * =====================>> + * | P | M | S | MHz | >> + * ------------------------------------------- >> + * | 3 | 100 | 3 | 100 | >> + * | 3 | 100 | 2 | 200 | >> + * | 3 | 63 | 1 | 252 | >> + * | 4 | 100 | 1 | 300 | >> + * | 4 | 110 | 1 | 330 | >> + * | 12 | 350 | 1 | 350 | >> + * | 3 | 100 | 1 | 400 | >> + * | 4 | 150 | 1 | 450 | >> + * | 3 | 118 | 1 | 472 | >> + * | 12 | 250 | 0 | 500 | >> + * | 4 | 100 | 0 | 600 | >> + * | 3 | 81 | 0 | 648 | >> + * | 3 | 88 | 0 | 704 | >> + * | 3 | 90 | 0 | 720 | >> + * | 3 | 100 | 0 | 800 | >> + * | 12 | 425 | 0 | 850 | >> + * | 4 | 150 | 0 | 900 | >> + * | 12 | 475 | 0 | 950 | >> + * | 6 | 250 | 0 | 1000 | >> + * ------------------------------------------- >> + */ >> + unsigned char p; >> + unsigned short m; >> + unsigned char s; >> + >> + unsigned int pll_stable_time; >> + unsigned long esc_clk; >> + >> + unsigned short stop_holding_cnt; >> + unsigned char bta_timeout; >> + unsigned short rx_timeout; >> +}; >> + >> +/** >> + * struct mipi_dsim_device - global interface for mipi-dsi driver. >> + * >> + * @dev: driver model representation of the device. >> + * @id: unique device id. >> + * @clock: pointer to MIPI-DSI clock of clock framework. >> + * @irq: interrupt number to MIPI-DSI controller. >> + * @reg_base: base address to memory mapped SRF of MIPI-DSI controller. >> + * (virtual address) >> + * @lock: the mutex protecting this data structure. >> + * @dsim_info: infomation for configuring mipi-dsi controller. >> + * @master_ops: callbacks to mipi-dsi operations. >> + * @dsim_lcd_dev: pointer to activated ddi device. >> + * (it would be registered by mipi-dsi driver.) >> + * @dsim_lcd_drv: pointer to activated_ddi driver. >> + * (it would be registered by mipi-dsi driver.) >> + * @lcd_info: pointer to mipi_lcd_info structure. >> + * @state: specifies status of MIPI-DSI controller. >> + * the status could be RESET, INIT, STOP, HSCLKEN and ULPS. >> + * @resume_complete: indicates whether resume operation is completed or not. >> + * @data_lane: specifiec enabled data lane number. >> + * this variable would be set by driver according to e_no_data_lane >> + * automatically. >> + * @e_clk_src: select byte clock source. >> + * @pd: pointer to MIPI-DSI driver platform data. >> + */ >> +struct mipi_dsim_device { >> + struct device *dev; >> + int id; >> + struct resource *res; >> + struct clk *clock; >> + unsigned int irq; >> + void __iomem *reg_base; >> + struct mutex lock; >> + >> + struct mipi_dsim_config *dsim_config; >> + struct mipi_dsim_master_ops *master_ops; >> + struct mipi_dsim_lcd_device *dsim_lcd_dev; >> + struct mipi_dsim_lcd_driver *dsim_lcd_drv; >> + >> + unsigned int state; >> + unsigned int resume_complete; >> + unsigned int data_lane; >> + enum mipi_dsim_byte_clk_src e_clk_src; >> + >> + struct s5p_platform_mipi_dsim *pd; >> +}; >> + >> +/** >> + * struct s5p_platform_mipi_dsim - interface to platform data >> + * for mipi-dsi driver. >> + * >> + * @lcd_panel_name: specifies lcd panel name registered to mipi-dsi driver. >> + * lcd panel driver searched would be actived. >> + * @dsim_config: pointer of structure for configuring mipi-dsi controller. >> + * @lcd_panel_info: pointer for lcd panel specific structure. >> + * this structure specifies width, height, timing and polarity and so on. >> + * @mipi_power: callback pointer for enabling or disabling mipi power. >> + * @phy_enable: pointer to a callback controlling D-PHY enable/reset >> + */ >> +struct s5p_platform_mipi_dsim { >> + char lcd_panel_name[PANEL_NAME_SIZE]; >> + >> + struct mipi_dsim_config *dsim_config; >> + void *lcd_panel_info; >> + >> + int (*mipi_power)(struct platform_device *pdev, unsigned int enable); >> + int (*phy_enable)(struct platform_device *pdev, bool on); >> +}; >> +/** >> + * struct mipi_dsim_master_ops - callbacks to mipi-dsi operations. >> + * >> + * @cmd_write: transfer command to lcd panel at LP mode. >> + * @cmd_read: read command from rx register. >> + * @get_dsim_frame_done: get the status that all screen data have been >> + * transferred to mipi-dsi. >> + * @clear_dsim_frame_done: clear frame done status. >> + * @get_fb_frame_done: get frame done status of display controller. >> + * @trigger: trigger display controller. >> + * - this one would be used only in case of CPU mode. >> + */ >> + >> +struct mipi_dsim_master_ops { >> + int (*cmd_write)(struct mipi_dsim_device *dsim, unsigned int data_id, >> + unsigned int data0, unsigned int data1); >> + int (*cmd_read)(struct mipi_dsim_device *dsim, unsigned int data_id, >> + unsigned int data0, unsigned int data1); >> + int (*get_dsim_frame_done)(struct mipi_dsim_device *dsim); >> + int (*clear_dsim_frame_done)(struct mipi_dsim_device *dsim); >> + >> + int (*get_fb_frame_done)(struct fb_info *info); >> + void (*trigger)(struct fb_info *info); >> +}; >> + >> +/** >> + * device structure for mipi-dsi based lcd panel. >> + * >> + * @name: name of the device to use with this device, or an >> + * alias for that name. >> + * @dev: driver model representation of the device. >> + * @id: id of device to be registered. >> + * @bus_id: bus id for identifing connected bus >> + * and this bus id should be same as id of mipi_dsim_device. >> + * @irq: irq number for signaling when framebuffer transfer of >> + * lcd panel module is completed. >> + * this irq would be used only for MIPI-DSI based CPU mode lcd panel. >> + * @master: pointer to mipi-dsi master device object. >> + * @platform_data: lcd panel specific platform data. >> + */ >> +struct mipi_dsim_lcd_device { >> + char *name; >> + struct device dev; >> + int id; >> + int bus_id; >> + int irq; >> + >> + struct mipi_dsim_device *master; >> + void *platform_data; >> +}; >> + >> +/** >> + * driver structure for mipi-dsi based lcd panel. >> + * >> + * this structure should be registered by lcd panel driver. >> + * mipi-dsi driver seeks lcd panel registered through name field >> + * and calls these callback functions in appropriate time. >> + * >> + * @name: name of the driver to use with this device, or an >> + * alias for that name. >> + * @id: id of driver to be registered. >> + * this id would be used for finding device object registered. >> + */ >> +struct mipi_dsim_lcd_driver { >> + char *name; >> + int id; >> + >> + int (*probe)(struct mipi_dsim_lcd_device *dsim_dev); >> + int (*remove)(struct mipi_dsim_lcd_device *dsim_dev); >> + void (*shutdown)(struct mipi_dsim_lcd_device *dsim_dev); >> + int (*suspend)(struct mipi_dsim_lcd_device *dsim_dev); >> + int (*resume)(struct mipi_dsim_lcd_device *dsim_dev); >> +}; >> + >> +/** >> + * register mipi_dsim_lcd_driver object defined by lcd panel driver >> + * to mipi-dsi driver. >> + */ >> +int s5p_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver >> + *lcd_drv); >> + >> +/** >> + * register mipi_dsim_lcd_device to mipi-dsi master. >> + */ >> +int s5p_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device >> + *lcd_dev); >> + >> +/** >> + * enable regulators to MIPI-DSI power. >> + */ >> +int s5p_mipi_dsi_dphy_power(struct mipi_dsim_device *dsim, >> + unsigned int enable); >> + >> +/** >> + * s5p_dsim_phy_enable - global MIPI-DSI receiver D-PHY control >> + * @pdev: MIPI-DSIM platform device >> + * @on: true to enable D-PHY and deassert its reset >> + * false to disable D-PHY >> + */ >> +int s5p_dsim_phy_enable(struct platform_device *pdev, bool on); >> + >> +#endif /* _DSIM_H */ >> diff --git a/arch/arm/plat-s5p/include/plat/regs-dsim.h b/arch/arm/plat-s5p/include/plat/regs-dsim.h >> new file mode 100644 >> index 0000000..5f0e4fa >> --- /dev/null >> +++ b/arch/arm/plat-s5p/include/plat/regs-dsim.h >> @@ -0,0 +1,143 @@ >> +/* linux/arch/arm/plat-s5p/include/plat/regs-dsim.h >> + * >> + * Register definition file for Samsung MIPI-DSIM driver >> + * >> + * Copyright (c) 2011 Samsung Electronics Co., Ltd >> + * >> + * InKi Dae >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License version 2 as >> + * published by the Free Software Foundation. >> +*/ >> + >> +#ifndef _REGS_DSIM_H >> +#define _REGS_DSIM_H >> + >> +#define S5P_DSIM_STATUS (0x0) /* Status register */ >> +#define S5P_DSIM_SWRST (0x4) /* Software reset register */ >> +#define S5P_DSIM_CLKCTRL (0x8) /* Clock control register */ >> +#define S5P_DSIM_TIMEOUT (0xc) /* Time out register */ >> +#define S5P_DSIM_CONFIG (0x10) /* Configuration register */ >> +#define S5P_DSIM_ESCMODE (0x14) /* Escape mode register */ >> + >> +/* Main display image resolution register */ >> +#define S5P_DSIM_MDRESOL (0x18) >> +#define S5P_DSIM_MVPORCH (0x1c) /* Main display Vporch register */ >> +#define S5P_DSIM_MHPORCH (0x20) /* Main display Hporch register */ >> +#define S5P_DSIM_MSYNC (0x24) /* Main display sync area register */ >> + >> +/* Sub display image resolution register */ >> +#define S5P_DSIM_SDRESOL (0x28) >> +#define S5P_DSIM_INTSRC (0x2c) /* Interrupt source register */ >> +#define S5P_DSIM_INTMSK (0x30) /* Interrupt mask register */ >> +#define S5P_DSIM_PKTHDR (0x34) /* Packet Header FIFO register */ >> +#define S5P_DSIM_PAYLOAD (0x38) /* Payload FIFO register */ >> +#define S5P_DSIM_RXFIFO (0x3c) /* Read FIFO register */ >> +#define S5P_DSIM_FIFOTHLD (0x40) /* FIFO threshold level register */ >> +#define S5P_DSIM_FIFOCTRL (0x44) /* FIFO status and control register */ >> + >> +/* FIFO memory AC characteristic register */ >> +#define S5P_DSIM_PLLCTRL (0x4c) /* PLL control register */ >> +#define S5P_DSIM_PLLTMR (0x50) /* PLL timer register */ >> +#define S5P_DSIM_PHYACCHR (0x54) /* D-PHY AC characteristic register */ >> +#define S5P_DSIM_PHYACCHR1 (0x58) /* D-PHY AC characteristic register1 */ >> + >> +/* DSIM_STATUS */ >> +#define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0) >> +#define DSIM_STOP_STATE_CLK (1 << 8) >> +#define DSIM_TX_READY_HS_CLK (1 << 10) >> + >> +/* DSIM_SWRST */ >> +#define DSIM_FUNCRST (1 << 16) >> +#define DSIM_SWRST (1 << 0) >> + >> +/* S5P_DSIM_TIMEOUT */ >> +#define DSIM_LPDR_TOUT_SHIFT (0) >> +#define DSIM_BTA_TOUT_SHIFT (16) >> + >> +/* S5P_DSIM_CLKCTRL */ >> +#define DSIM_LANE_ESC_CLKEN_SHIFT (19) >> +#define DSIM_BYTE_CLKEN_SHIFT (24) >> +#define DSIM_BYTE_CLK_SRC_SHIFT (25) >> +#define DSIM_PLL_BYPASS_SHIFT (27) >> +#define DSIM_ESC_CLKEN_SHIFT (28) >> +#define DSIM_TX_REQUEST_HSCLK_SHIFT (31) >> +#define DSIM_LANE_ESC_CLKEN(x) (((x) & 0x1f) << \ >> + DSIM_LANE_ESC_CLKEN_SHIFT) >> +#define DSIM_BYTE_CLK_ENABLE (1 << DSIM_BYTE_CLKEN_SHIFT) >> +#define DSIM_BYTE_CLK_DISABLE (0 << DSIM_BYTE_CLKEN_SHIFT) >> +#define DSIM_PLL_BYPASS_EXTERNAL (1 << DSIM_PLL_BYPASS_SHIFT) >> +#define DSIM_ESC_CLKEN_ENABLE (1 << DSIM_ESC_CLKEN_SHIFT) >> +#define DSIM_ESC_CLKEN_DISABLE (0 << DSIM_ESC_CLKEN_SHIFT) >> + >> +/* S5P_DSIM_CONFIG */ >> +#define DSIM_NUM_OF_DATALANE_SHIFT (5) >> +#define DSIM_HSA_MODE_SHIFT (20) >> +#define DSIM_HBP_MODE_SHIFT (21) >> +#define DSIM_HFP_MODE_SHIFT (22) >> +#define DSIM_HSE_MODE_SHIFT (23) >> +#define DSIM_AUTO_MODE_SHIFT (24) >> +#define DSIM_LANE_ENx(x) (((x) & 0x1f) << 0) >> + >> +#define DSIM_NUM_OF_DATA_LANE(x) ((x) << DSIM_NUM_OF_DATALANE_SHIFT) >> + >> +/* S5P_DSIM_ESCMODE */ >> +#define DSIM_TX_LPDT_SHIFT (6) >> +#define DSIM_CMD_LPDT_SHIFT (7) >> +#define DSIM_TX_LPDT_LP (1 << DSIM_TX_LPDT_SHIFT) >> +#define DSIM_CMD_LPDT_LP (1 << DSIM_CMD_LPDT_SHIFT) >> +#define DSIM_STOP_STATE_CNT_SHIFT (21) >> +#define DSIM_FORCE_STOP_STATE_SHIFT (20) >> + >> +/* S5P_DSIM_MDRESOL */ >> +#define DSIM_MAIN_STAND_BY (1 << 31) >> +#define DSIM_MAIN_VRESOL(x) (((x) & 0x7ff) << 16) >> +#define DSIM_MAIN_HRESOL(x) (((x) & 0X7ff) << 0) >> + >> +/* S5P_DSIM_MVPORCH */ >> +#define DSIM_CMD_ALLOW_SHIFT (28) >> +#define DSIM_STABLE_VFP_SHIFT (16) >> +#define DSIM_MAIN_VBP_SHIFT (0) >> +#define DSIM_CMD_ALLOW_MASK (0xf << DSIM_CMD_ALLOW_SHIFT) >> +#define DSIM_STABLE_VFP_MASK (0x7ff << DSIM_STABLE_VFP_SHIFT) >> +#define DSIM_MAIN_VBP_MASK (0x7ff << DSIM_MAIN_VBP_SHIFT) >> + >> +/* S5P_DSIM_MHPORCH */ >> +#define DSIM_MAIN_HFP_SHIFT (16) >> +#define DSIM_MAIN_HBP_SHIFT (0) >> +#define DSIM_MAIN_HFP_MASK ((0xffff) << DSIM_MAIN_HFP_SHIFT) >> +#define DSIM_MAIN_HBP_MASK ((0xffff) << DSIM_MAIN_HBP_SHIFT) >> + >> +/* S5P_DSIM_MSYNC */ >> +#define DSIM_MAIN_VSA_SHIFT (22) >> +#define DSIM_MAIN_HSA_SHIFT (0) >> +#define DSIM_MAIN_VSA_MASK ((0x3ff) << DSIM_MAIN_VSA_SHIFT) >> +#define DSIM_MAIN_HSA_MASK ((0xffff) << DSIM_MAIN_HSA_SHIFT) >> + >> +/* S5P_DSIM_SDRESOL */ >> +#define DSIM_SUB_STANDY_SHIFT (31) >> +#define DSIM_SUB_VRESOL_SHIFT (16) >> +#define DSIM_SUB_HRESOL_SHIFT (0) >> +#define DSIM_SUB_STANDY_MASK ((0x1) << DSIM_SUB_STANDY_SHIFT) >> +#define DSIM_SUB_VRESOL_MASK ((0x7ff) << DSIM_SUB_VRESOL_SHIFT) >> +#define DSIM_SUB_HRESOL_MASK ((0x7ff) << DSIM_SUB_HRESOL_SHIFT) >> + >> +/* S5P_DSIM_INTSRC */ >> +#define INTSRC_FRAME_DONE (1 << 24) >> +#define INTSRC_PLL_STABLE (1 << 31) >> + >> +/* S5P_DSIM_INTMSK */ >> +#define INTMSK_FRAME_DONE (1 << 24) >> + >> +/* S5P_DSIM_FIFOCTRL */ >> +#define SFR_HEADER_EMPTY (1 << 22) >> + >> +/* S5P_DSIM_PHYACCHR */ >> +#define DSIM_AFC_CTL(x) (((x) & 0x7) << 5) >> + >> +/* S5P_DSIM_PLLCTRL */ >> +#define DSIM_PLL_EN_SHIFT (23) >> +#define DSIM_FREQ_BAND_SHIFT (24) >> + >> +#endif /* _REGS_DSIM_H */ >> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig >> index e6a8d8c..1e71a54 100644 >> --- a/drivers/video/Kconfig >> +++ b/drivers/video/Kconfig >> @@ -2044,6 +2044,13 @@ config FB_S3C2410_DEBUG >> Turn on debugging messages. Note that you can set/unset at run time >> through sysfs >> >> +config S5P_MIPI_DSI >> + tristate "Samsung SoC MIPI-DSI support." >> + depends on FB_S3C && (ARCH_S5PV210 || ARCH_EXYNOS4) >> + default n >> + ---help--- >> + This enables support for MIPI-DSI device. >> + >> config FB_NUC900 >> bool "NUC900 LCD framebuffer support" >> depends on FB && ARCH_W90X900 >> diff --git a/drivers/video/Makefile b/drivers/video/Makefile >> index 2ea44b6..ee5a1d5 100644 >> --- a/drivers/video/Makefile >> +++ b/drivers/video/Makefile >> @@ -119,6 +119,8 @@ obj-$(CONFIG_FB_SH7760) += sh7760fb.o >> obj-$(CONFIG_FB_IMX) += imxfb.o >> obj-$(CONFIG_FB_S3C) += s3c-fb.o >> obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o >> +obj-$(CONFIG_S5P_MIPI_DSI) += s5p_mipi_dsi.o s5p_mipi_dsi_common.o \ >> + s5p_mipi_dsi_lowlevel.o >> obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o >> obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o >> obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/ >> diff --git a/drivers/video/s5p_mipi_dsi.c b/drivers/video/s5p_mipi_dsi.c >> new file mode 100644 >> index 0000000..50fc00e >> --- /dev/null >> +++ b/drivers/video/s5p_mipi_dsi.c >> @@ -0,0 +1,481 @@ >> +/* linux/drivers/video/s5p_mipi_dsi.c >> + * >> + * Samsung SoC MIPI-DSIM driver. >> + * >> + * Copyright (c) 2011 Samsung Electronics Co., Ltd >> + * >> + * InKi Dae, >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License version 2 as >> + * published by the Free Software Foundation. >> +*/ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include >> +#include >> + >> +#include "s5p_mipi_dsi_common.h" >> + >> +#define master_to_driver(a) (a->dsim_lcd_drv) >> +#define master_to_device(a) (a->dsim_lcd_dev) >> + >> +struct mipi_dsim_ddi { >> + int bus_id; >> + struct list_head list; >> + struct mipi_dsim_lcd_device *dsim_lcd_dev; >> + struct mipi_dsim_lcd_driver *dsim_lcd_drv; >> +}; >> + >> +static LIST_HEAD(dsim_ddi_list); >> +static LIST_HEAD(dsim_lcd_dev_list); >> + >> +static DEFINE_MUTEX(mipi_dsim_lock); >> + >> +static struct s5p_platform_mipi_dsim *to_dsim_plat(struct platform_device *pdev) >> +{ >> + return (struct s5p_platform_mipi_dsim *)pdev->dev.platform_data; >> +} >> + >> +static irqreturn_t s5p_mipi_dsi_interrupt_handler(int irq, void *dev_id) >> +{ >> + return IRQ_HANDLED; >> +} >> + >> +int s5p_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev) >> +{ >> + struct mipi_dsim_ddi *dsim_ddi; >> + >> + if (!lcd_dev) { >> + printk(KERN_ERR "mipi_dsim_lcd_device is NULL.\n"); >> + return -EFAULT; >> + } >> + >> + if (!lcd_dev->name) { >> + printk(KERN_ERR "dsim_lcd_device name is NULL.\n"); >> + return -EFAULT; >> + } >> + >> + dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL); >> + if (!dsim_ddi) { >> + printk(KERN_ERR "failed to allocate dsim_ddi object.\n"); >> + return -EFAULT; >> + } >> + >> + dsim_ddi->dsim_lcd_dev = lcd_dev; >> + >> + mutex_lock(&mipi_dsim_lock); >> + list_add_tail(&dsim_ddi->list, &dsim_ddi_list); >> + mutex_unlock(&mipi_dsim_lock); >> + >> + return 0; >> +} >> + >> +struct mipi_dsim_ddi >> + *s5p_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv) >> +{ >> + struct mipi_dsim_ddi *dsim_ddi; >> + struct mipi_dsim_lcd_device *lcd_dev; >> + >> + mutex_lock(&mipi_dsim_lock); >> + >> + list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) { >> + lcd_dev = dsim_ddi->dsim_lcd_dev; >> + if (!lcd_dev) >> + continue; >> + >> + if (lcd_drv->id >= 0) { >> + if ((strcmp(lcd_drv->name, lcd_dev->name)) = 0 && >> + lcd_drv->id = lcd_dev->id) { >> + /** >> + * bus_id would be used to identify >> + * connected bus. >> + */ >> + dsim_ddi->bus_id = lcd_dev->bus_id; >> + mutex_unlock(&mipi_dsim_lock); >> + >> + return dsim_ddi; >> + } >> + } else { >> + if ((strcmp(lcd_drv->name, lcd_dev->name)) = 0) { >> + /** >> + * bus_id would be used to identify >> + * connected bus. >> + */ >> + dsim_ddi->bus_id = lcd_dev->bus_id; >> + mutex_unlock(&mipi_dsim_lock); >> + >> + return dsim_ddi; >> + } >> + } >> + >> + kfree(dsim_ddi); >> + list_del(&dsim_ddi_list); >> + } >> + >> + mutex_unlock(&mipi_dsim_lock); >> + >> + return NULL; >> +} >> + >> +int s5p_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv) >> +{ >> + struct mipi_dsim_ddi *dsim_ddi; >> + >> + if (!lcd_drv) { >> + printk(KERN_ERR "mipi_dsim_lcd_driver is NULL.\n"); >> + return -EFAULT; >> + } >> + >> + if (!lcd_drv->name) { >> + printk(KERN_ERR "dsim_lcd_driver name is NULL.\n"); >> + return -EFAULT; >> + } >> + >> + dsim_ddi = s5p_mipi_dsi_find_lcd_device(lcd_drv); >> + if (!dsim_ddi) { >> + printk(KERN_ERR "mipi_dsim_ddi object not found.\n"); >> + return -EFAULT; >> + } >> + >> + dsim_ddi->dsim_lcd_drv = lcd_drv; >> + >> + printk(KERN_INFO "registered panel driver(%s) to mipi-dsi driver.\n", >> + lcd_drv->name); >> + >> + return 0; >> + >> +} >> + >> +struct mipi_dsim_ddi >> + *s5p_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim, >> + const char *name) >> +{ >> + struct mipi_dsim_ddi *dsim_ddi; >> + struct mipi_dsim_lcd_driver *lcd_drv; >> + struct mipi_dsim_lcd_device *lcd_dev; >> + int ret; >> + >> + mutex_lock(&dsim->lock); >> + >> + list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) { >> + lcd_drv = dsim_ddi->dsim_lcd_drv; >> + lcd_dev = dsim_ddi->dsim_lcd_dev; >> + if (!lcd_drv || !lcd_dev || >> + (dsim->id != dsim_ddi->bus_id)) >> + continue; >> + >> + dev_dbg(dsim->dev, "lcd_drv->id = %d, lcd_dev->id = %d\n", >> + lcd_drv->id, lcd_dev->id); >> + dev_dbg(dsim->dev, "lcd_dev->bus_id = %d, dsim->id = %d\n", >> + lcd_dev->bus_id, dsim->id); >> + >> + if ((strcmp(lcd_drv->name, name) = 0)) { >> + lcd_dev->master = dsim; >> + >> + lcd_dev->dev.parent = dsim->dev; >> + dev_set_name(&lcd_dev->dev, "%s", lcd_drv->name); >> + >> + ret = device_register(&lcd_dev->dev); >> + if (ret < 0) { >> + dev_err(dsim->dev, >> + "can't register %s, status %d\n", >> + dev_name(&lcd_dev->dev), ret); >> + mutex_unlock(&dsim->lock); >> + >> + return NULL; >> + } >> + >> + dsim->dsim_lcd_dev = lcd_dev; >> + dsim->dsim_lcd_drv = lcd_drv; >> + >> + mutex_unlock(&dsim->lock); >> + >> + return dsim_ddi; >> + } >> + } >> + >> + mutex_unlock(&dsim->lock); >> + >> + return NULL; >> +} >> + >> +/* define MIPI-DSI Master operations. */ >> +static struct mipi_dsim_master_ops master_ops = { >> + .cmd_write = s5p_mipi_dsi_wr_data, >> + .get_dsim_frame_done = s5p_mipi_dsi_get_frame_done_status, >> + .clear_dsim_frame_done = s5p_mipi_dsi_clear_frame_done, >> +}; >> + >> +static int s5p_mipi_dsi_probe(struct platform_device *pdev) >> +{ >> + struct resource *res; >> + struct mipi_dsim_device *dsim; >> + struct mipi_dsim_config *dsim_config; >> + struct s5p_platform_mipi_dsim *dsim_pd; >> + struct mipi_dsim_ddi *dsim_ddi; >> + int ret = -1; >> + >> + dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL); >> + if (!dsim) { >> + dev_err(&pdev->dev, "failed to allocate dsim object.\n"); >> + return -EFAULT; >> + } >> + >> + dsim->pd = to_dsim_plat(pdev); >> + dsim->dev = &pdev->dev; >> + dsim->id = pdev->id; >> + dsim->resume_complete = 0; >> + >> + /* get s5p_platform_mipi_dsim. */ >> + dsim_pd = (struct s5p_platform_mipi_dsim *)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; >> + >> + dsim->clock = clk_get(&pdev->dev, "dsim"); >> + if (IS_ERR(dsim->clock)) { >> + dev_err(&pdev->dev, "failed to get dsim clock source\n"); >> + goto err_clock_get; >> + } >> + >> + clk_enable(dsim->clock); >> + >> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); >> + if (!res) { >> + dev_err(&pdev->dev, "failed to get io memory region\n"); >> + ret = -EINVAL; >> + goto err_platform_get; >> + } >> + >> + res = request_mem_region(res->start, resource_size(res), >> + dev_name(&pdev->dev)); >> + if (!res) { >> + dev_err(&pdev->dev, "failed to request io memory region\n"); >> + ret = -EINVAL; >> + goto err_mem_region; >> + } >> + >> + dsim->res = res; >> + >> + dsim->reg_base = ioremap(res->start, resource_size(res)); >> + if (!dsim->reg_base) { >> + dev_err(&pdev->dev, "failed to remap io region\n"); >> + ret = -EINVAL; >> + goto err_mem_region; >> + } >> + >> + /* >> + * in case of MIPI Video mode, >> + * frame done interrupt handler would be used. >> + */ >> + if (dsim_config->e_interface = DSIM_VIDEO) { >> + dsim->irq = platform_get_irq(pdev, 0); >> + if (request_irq(dsim->irq, s5p_mipi_dsi_interrupt_handler, >> + IRQF_DISABLED, "mipi-dsi", dsim)) { >> + dev_err(&pdev->dev, "request_irq failed.\n"); >> + goto err_request_irq; >> + } >> + } >> + >> + mutex_init(&dsim->lock); >> + >> + if (dsim->pd->mipi_power) >> + dsim->pd->mipi_power(pdev, 1); >> + else { >> + dev_err(&pdev->dev, "mipi_power is NULL.\n"); >> + goto err_request_irq; >> + } >> + >> + /* bind lcd ddi matched with panel name. */ >> + dsim_ddi = s5p_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"); >> + goto err_bind; >> + } >> + >> + /* enable MIPI-DSI PHY. */ >> + if (dsim->pd->phy_enable) >> + dsim->pd->phy_enable(pdev, true); >> + >> + s5p_mipi_dsi_init_dsim(dsim); >> + s5p_mipi_dsi_init_link(dsim); >> + >> + s5p_mipi_dsi_set_hs_enable(dsim); >> + >> + /* set display timing. */ >> + s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config); >> + >> + platform_set_drvdata(pdev, dsim); >> + >> + /* initialize mipi-dsi client(lcd panel). */ >> + if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->probe) >> + dsim_ddi->dsim_lcd_drv->probe(dsim_ddi->dsim_lcd_dev); >> + >> + dev_dbg(&pdev->dev, "mipi-dsi driver(%s mode) has been probed.\n", >> + (dsim_config->e_interface = DSIM_COMMAND) ? >> + "CPU" : "RGB"); >> + >> + return 0; >> + >> +err_bind: >> + dsim->pd->mipi_power(pdev, 0); >> + >> +err_request_irq: >> + release_resource(dsim->res); >> + kfree(dsim->res); >> + >> + iounmap((void __iomem *) dsim->reg_base); >> + >> +err_mem_region: >> +err_platform_get: >> + clk_disable(dsim->clock); >> + >> +err_clock_get: >> + clk_put(dsim->clock); >> + kfree(dsim); >> + >> + return ret; >> + >> +} >> + >> +static int __devexit s5p_mipi_dsi_remove(struct platform_device *pdev) >> +{ >> + struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); >> + struct mipi_dsim_ddi *dsim_ddi = NULL; >> + >> + if (dsim->dsim_config->e_interface = DSIM_VIDEO) >> + free_irq(dsim->irq, dsim); >> + >> + iounmap(dsim->reg_base); >> + >> + clk_disable(dsim->clock); >> + clk_put(dsim->clock); >> + >> + release_resource(dsim->res); >> + kfree(dsim->res); >> + >> + list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) { >> + if (dsim_ddi) { >> + if (dsim->id = dsim_ddi->bus_id) { >> + kfree(dsim_ddi); >> + dsim_ddi = NULL; >> + } >> + } >> + } >> + >> + kfree(dsim); >> + >> + return 0; >> +} >> + >> +#ifdef CONFIG_PM >> +static int s5p_mipi_dsi_suspend(struct platform_device *pdev, >> + pm_message_t state) >> +{ >> + struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); >> + >> + dsim->resume_complete = 0; >> + >> + if (master_to_driver(dsim) && (master_to_driver(dsim))->suspend) >> + (master_to_driver(dsim))->suspend(master_to_device(dsim)); >> + >> + clk_disable(dsim->clock); >> + >> + if (dsim->pd->mipi_power) >> + dsim->pd->mipi_power(pdev, 0); >> + >> + return 0; >> +} >> + >> +static int s5p_mipi_dsi_resume(struct platform_device *pdev) >> +{ >> + struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); >> + >> + if (dsim->pd->mipi_power) >> + dsim->pd->mipi_power(pdev, 1); >> + >> + clk_enable(dsim->clock); >> + >> + s5p_mipi_dsi_init_dsim(dsim); >> + s5p_mipi_dsi_init_link(dsim); >> + >> + s5p_mipi_dsi_set_hs_enable(dsim); >> + >> + /* change cpu command transfer mode to hs. */ >> + s5p_mipi_dsi_set_data_transfer_mode(dsim, 0); >> + >> + if (master_to_driver(dsim) && (master_to_driver(dsim))->resume) >> + (master_to_driver(dsim))->resume(master_to_device(dsim)); >> + >> + s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config); >> + >> + /* change lcdc data transfer mode to hs. */ >> + s5p_mipi_dsi_set_data_transfer_mode(dsim, 1); >> + >> + dsim->resume_complete = 1; >> + >> + return 0; >> +} >> +#else >> +#define s5p_mipi_dsi_suspend NULL >> +#define s5p_mipi_dsi_resume NULL >> +#endif >> + >> +static struct platform_driver s5p_mipi_dsi_driver = { >> + .probe = s5p_mipi_dsi_probe, >> + .remove = __devexit_p(s5p_mipi_dsi_remove), >> + .suspend = s5p_mipi_dsi_suspend, >> + .resume = s5p_mipi_dsi_resume, >> + .driver = { >> + .name = "s5p-mipi-dsim", >> + .owner = THIS_MODULE, >> + }, >> +}; >> + >> +static int s5p_mipi_dsi_register(void) >> +{ >> + platform_driver_register(&s5p_mipi_dsi_driver); >> + >> + return 0; >> +} >> + >> +static void s5p_mipi_dsi_unregister(void) >> +{ >> + platform_driver_unregister(&s5p_mipi_dsi_driver); >> +} >> + >> +module_init(s5p_mipi_dsi_register); >> +module_exit(s5p_mipi_dsi_unregister); >> + >> +MODULE_AUTHOR("InKi Dae "); >> +MODULE_DESCRIPTION("Samusung SoC MIPI-DSI driver"); >> +MODULE_LICENSE("GPL"); >> diff --git a/drivers/video/s5p_mipi_dsi_common.c b/drivers/video/s5p_mipi_dsi_common.c >> new file mode 100644 >> index 0000000..51ee4ed >> --- /dev/null >> +++ b/drivers/video/s5p_mipi_dsi_common.c >> @@ -0,0 +1,655 @@ >> +/* linux/drivers/video/s5p_mipi_dsi_common.c >> + * >> + * Samsung SoC MIPI-DSI common driver. >> + * >> + * Copyright (c) 2011 Samsung Electronics Co., Ltd >> + * >> + * InKi Dae, >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License version 2 as >> + * published by the Free Software Foundation. >> +*/ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include