diff options
| author | Wengang Wu <a22350@motorola.com> | 2014-01-15 11:02:35 -0600 |
|---|---|---|
| committer | James Wylder <jwylder@motorola.com> | 2014-03-05 17:47:05 -0600 |
| commit | 06ef967840e79ae999758d7c7c74b1957e3dbae3 (patch) | |
| tree | b96f07e07cdcbeb871dd22fb3372039ff3f64e11 | |
| parent | 97610078a9318e5881b86ff7227d36c11b5de59f (diff) | |
| download | olio-linux-3.10-06ef967840e79ae999758d7c7c74b1957e3dbae3.tar.xz olio-linux-3.10-06ef967840e79ae999758d7c7c74b1957e3dbae3.zip | |
IKXCLOCK-78 Support Solomon+Orise Display Driver
Change-Id: I43a572dec6fc1d469fbf7104cb58359a2b8f87e1
Reviewed-on: http://gerrit.pcs.mot.com/603160
SLTApproved: Slta Waiver <sltawvr@motorola.com>
Tested-by: Jira Key <jirakey@motorola.com>
Reviewed-by: Jee Su Chang <w20740@motorola.com>
Submit-Approved: Jira Key <jirakey@motorola.com>
| -rw-r--r-- | arch/arm/boot/dts/omap3-minnow.dtsi | 23 | ||||
| -rw-r--r-- | arch/arm/configs/eng_minnow_defconfig | 4 | ||||
| -rw-r--r--[-rwxr-xr-x] | arch/arm/configs/minnow_defconfig | 3 | ||||
| -rw-r--r-- | arch/arm/mach-omap2/display.c | 65 | ||||
| -rw-r--r-- | drivers/video/omap2/displays/panel-minnow.c | 591 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/dsi.c | 2 | ||||
| -rw-r--r-- | drivers/video/omap2/omapfb/omapfb-main.c | 103 |
8 files changed, 648 insertions, 147 deletions
diff --git a/arch/arm/boot/dts/omap3-minnow.dtsi b/arch/arm/boot/dts/omap3-minnow.dtsi index 6256a5642a4..3466da5b9b8 100644 --- a/arch/arm/boot/dts/omap3-minnow.dtsi +++ b/arch/arm/boot/dts/omap3-minnow.dtsi @@ -15,22 +15,25 @@ compatible = "mot,minnow-panel-dsi-cm"; /* 0: MINNOW_PANEL_CM_220X176 * 1: MINNOW_PANEL_CM_220X220 + * 2: MINNOW_PANEL_CM_BRIDGE_320X320 */ - id_panel = <1>; - gpio_reset = <&gpio1 14 0>; /* RESET gpio-14 */ + id_panel = <2>; + gpio_panel_reset = <&gpio1 14 0>; /* RESET gpio-14 */ + gpio_bridge_reset = <&gpio1 23 0>; /* RESET gpio-23 */ + gpio_clk_en = <&gpio6 17 0>; /* RESET gpio-177 */ /* declare it if ext_te enable */ //gpio_te = <&gpio1 0 0>; /* EXT_TE gpio-0 */ - pins = <0 1 2 3>; /* DSI Pin config */ - esd_interval = <0>; /* ESD_INTERVAL */ - pixel_clock = <4608>; /* kHZ = 320*240*60/1000*/ + //pins = <0 1 2 3>; /* DSI Pin config */ + //esd_interval = <0>; /* ESD_INTERVAL */ + //pixel_clock = <4608>; /* kHZ = 320*240*60/1000*/ /* 0: RGB888 * 1: RGB666 * 2: RGB666_PACKED * 3: RGB565 */ - pixel_format = <1>; - hs_clk = <100000000 150000000>; /* min max*/ - lp_clk = <7000000 9000000>; /* min max*/ + //pixel_format = <1>; + //hs_clk = <90000000 150000000>; /* min max*/ + //lp_clk = <7000000 9000000>; /* min max*/ }; /* FIXME: this dummy regulator is only needed as @@ -154,6 +157,10 @@ 0x08e 0x104 /* GPMC_CLK, MODE4 | INPUT */ 0x0a0 0x002 /* GPMC_WAIT2, MODE2 | OUTPUT */ 0x0a2 0x102 /* GPMC_WAIT3, MODE2 | INPUT */ + 0x0ac 0x001 /* DSI_DX0, MODE1 | OUTPUT */ + 0x0ae 0x001 /* DSI_DY0, MODE1 | OUTPUT */ + 0x0b0 0x001 /* DSI_DX1, MODE1 | OUTPUT */ + 0x0b2 0x001 /* DSI_DY1, MODE1 | OUTPUT */ 0x0b8 0x104 /* DSS_DATA6, MODE4 | INPUT */ 0x0c0 0x004 /* DSS_DATA10, MODE4 | OUTPUT */ 0x0c2 0x004 /* DSS_DATA11, MODE4 | OUTPUT */ diff --git a/arch/arm/configs/eng_minnow_defconfig b/arch/arm/configs/eng_minnow_defconfig index 96ee2200888..c20f4ba972e 100644 --- a/arch/arm/configs/eng_minnow_defconfig +++ b/arch/arm/configs/eng_minnow_defconfig @@ -1605,7 +1605,8 @@ CONFIG_FB_MODE_HELPERS=y CONFIG_OMAP2_VRFB=y CONFIG_OMAP2_DSS=y CONFIG_OMAP2_DSS_DEBUG=y -# CONFIG_OMAP2_DSS_DEBUGFS is not set +CONFIG_OMAP2_DSS_DEBUGFS=y +# CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS is not set # CONFIG_OMAP2_DSS_DPI is not set # CONFIG_OMAP2_DSS_RFBI is not set # CONFIG_OMAP2_DSS_VENC is not set @@ -1614,6 +1615,7 @@ CONFIG_OMAP2_DSS_DEBUG=y CONFIG_OMAP2_DSS_DSI=y CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0 CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET=y +CONFIG_OMAP2_DSS_RESET=y CONFIG_FB_OMAP2=y CONFIG_FB_OMAP2_DEBUG_SUPPORT=y CONFIG_FB_OMAP2_NUM_FBS=1 diff --git a/arch/arm/configs/minnow_defconfig b/arch/arm/configs/minnow_defconfig index a32a9107d8e..83702c51654 100755..100644 --- a/arch/arm/configs/minnow_defconfig +++ b/arch/arm/configs/minnow_defconfig @@ -460,7 +460,7 @@ CONFIG_ATAGS=y CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 # CONFIG_ARM_APPENDED_DTB is not set -CONFIG_CMDLINE="rootwait earlyprintk console=ttyO2,115200n8 mem=254M@0x80000000 init=/init" +CONFIG_CMDLINE="rootwait earlyprintk console=ttyO2,115200n8 mem=254M@0x80000000 init=/init omapfb.vram=0:1M" # CONFIG_CMDLINE_FROM_BOOTLOADER is not set # CONFIG_CMDLINE_EXTEND is not set CONFIG_CMDLINE_FORCE=y @@ -1606,6 +1606,7 @@ CONFIG_OMAP2_DSS_DEBUG=y CONFIG_OMAP2_DSS_DSI=y CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0 CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET=y +CONFIG_OMAP2_DSS_RESET=y CONFIG_FB_OMAP2=y CONFIG_FB_OMAP2_DEBUG_SUPPORT=y CONFIG_FB_OMAP2_NUM_FBS=1 diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c index ff37be1f6f9..d22833a0f2a 100644 --- a/arch/arm/mach-omap2/display.c +++ b/arch/arm/mach-omap2/display.c @@ -320,6 +320,10 @@ static enum omapdss_version __init omap_display_get_version(void) return OMAPDSS_VER_UNKNOWN; } +#ifdef CONFIG_OMAP2_DSS_RESET +static int reset_omap_dss(void); +#endif + int __init omap_display_init(struct omap_dss_board_info *board_data) { int r = 0; @@ -415,7 +419,9 @@ int __init omap_display_init(struct omap_dss_board_info *board_data) return PTR_ERR(pdev); } } - +#ifdef CONFIG_OMAP2_DSS_RESET + reset_omap_dss(); +#endif return 0; } @@ -564,3 +570,60 @@ int omap_dss_reset(struct omap_hwmod *oh) return r; } + +#ifdef CONFIG_OMAP2_DSS_RESET +#define DSS_CLKS 4 +static int reset_omap_dss(void) +{ + static const char * const clkstr[DSS_CLKS] = { + "dss_ick", + "dss1_alwon_fck", + "dss2_alwon_fck", + "dss_tv_fck" + }; + struct clk *clk[DSS_CLKS]; + int i, r = 0, c = 0; + struct omap_hwmod *oh_dss = omap_hwmod_lookup("dss_core"); + struct omap_hwmod *oh_dispc = omap_hwmod_lookup("dss_dispc"); + struct omap_hwmod *oh_dsi = omap_hwmod_lookup("dss_dsi1"); + + WARN((!oh_dss || !oh_dispc || !oh_dsi), "Reset lost!"); + + for (i = 0; i < DSS_CLKS; i++) { + clk[i] = clk_get(NULL, clkstr[i]); + if (!IS_ERR(clk[i])) { + r = clk_prepare_enable(clk[i]); + if (!r) + continue; + clk_put(clk[i]); + } + pr_warn("dss_core: failed enable %s\n", clkstr[i]); + clk[i] = ERR_PTR(-ENOENT); + } + + /* + * clear DSS_CONTROL register to switch DSS clock sources to + * PRCM clock, if any + */ + omap_hwmod_write(0x0, oh_dss, DSS_CONTROL); + dispc_disable_outputs(); + omap_hwmod_write(0x0, oh_dss, DSS_SDI_CONTROL); + omap_hwmod_write(0x0, oh_dss, DSS_PLL_CONTROL); + + omap_hwmod_write(0x02, oh_dss, DSS_SYSCONFIG); + omap_test_timeout((omap_hwmod_read(oh_dss, DSS_SYSSTATUS) + & SYSS_RESETDONE_MASK), + MAX_MODULE_SOFTRESET_WAIT, c); + r = (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0; + pr_warn("dss_core: reset DSS %s\n", r ? "failed" : "done"); + + for (i = 0; i < DSS_CLKS; i++) { + if (!IS_ERR(clk[i])) { + clk_disable_unprepare(clk[i]); + clk_put(clk[i]); + } + } + + return r; +} +#endif diff --git a/drivers/video/omap2/displays/panel-minnow.c b/drivers/video/omap2/displays/panel-minnow.c index aa0a380a5da..1ac9125034d 100644 --- a/drivers/video/omap2/displays/panel-minnow.c +++ b/drivers/video/omap2/displays/panel-minnow.c @@ -36,6 +36,9 @@ #include <video/omap-panel-data.h> #include <video/mipi_display.h> +#include "../dss/dss.h" + + /* DSI Virtual channel. Hardcoded for now. */ #define TCH 0 @@ -48,102 +51,246 @@ #define DCS_GET_ID2 0xdb #define DCS_GET_ID3 0xdc +enum minnow_reset_gpios { + MINNOW_RESET_PANEL, + MINNOW_RESET_BRIDGE, + MINNOW_RESET_MAX +}; + enum minnow_panel_id { MINNOW_PANEL_CM_220X176, MINNOW_PANEL_CM_220X220, + MINNOW_PANEL_CM_BRIDGE_320X320, MINNOW_PANEL_MAX }; +enum minnow_cmd_type { + DCS_WRITE_SYNC, + GENERIC_WRITE_SYNC, + DCS_WRITE, + GENERIC_WRITE, + BTA_SYNC, + WAIT_MS, + CMD_TYPE_MAX +}; + + /* Panel Initialize DSI DCS command buffer description: * it uses compact DCS command buffer to store all DCS commands, the first * byte of each command is the command length in byte */ static u8 panel_init_220x176[] = { -/*n, data_0, data_1 ... data_n-1*/ - 3, 0xF0, 0x5A, 0x5A, - 3, 0xF1, 0x5A, 0x5A, -18, 0xF2, 0x16, 0xDC, 0x03, 0x28, 0x28, 0x10, 0x00, 0x60, 0xF8, 0x00, 0x07, 0x02, 0x00, 0x00, 0xDC, 0x28, 0x28, -15, 0xF4, 0x0A, 0x00, 0x00, 0x00, 0x77, 0x7F, 0x07, 0x22, 0x2A, 0x43, 0x07, 0x2A, 0x43, 0x07, -11, 0xF5, 0x00, 0x50, 0x28, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, -10, 0xF6, 0x07, 0x00, 0x07, 0x00, 0x0B, 0x04, 0x04, 0x04, 0x07, - 5, 0xF7, 0x00, 0x00, 0x00, 0x00, - 3, 0xF8, 0x44, 0x08, - 2, 0xF9, 0x04, -17, 0xFA, 0x0F, 0x0F, 0x1E, 0x23, 0x26, 0x2D, 0x21, 0x2B, 0x33, 0x32, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, -17, 0xFB, 0x0F, 0x0F, 0x1E, 0x23, 0x26, 0x2D, 0x21, 0x2B, 0x33, 0x32, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, - 2, 0xF9, 0x02, -17, 0xFA, 0x00, 0x00, 0x0A, 0x16, 0x1D, 0x27, 0x1C, 0x30, 0x38, 0x37, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, -17, 0xFB, 0x00, 0x00, 0x0A, 0x16, 0x1D, 0x27, 0x1C, 0x30, 0x38, 0x37, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 2, 0xF9, 0x01, -17, 0xFA, 0x00, 0x00, 0x13, 0x14, 0x19, 0x24, 0x1A, 0x31, 0x39, 0x38, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, -17, 0xFB, 0x00, 0x00, 0x13, 0x14, 0x19, 0x24, 0x1A, 0x31, 0x39, 0x38, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, - 3, 0xF0, 0x00, 0x00, - 3, 0xF1, 0x00, 0x00, - 2, 0x36, 0xD0, - 2, 0x3A, 0x06 +/*n, type, data_0, data_1 ... data_n-1*/ +1, DCS_WRITE_SYNC, MIPI_DCS_EXIT_SLEEP_MODE, +1, WAIT_MS, 5, +3, DCS_WRITE_SYNC, 0xF0, 0x5A, 0x5A, +3, DCS_WRITE_SYNC, 0xF1, 0x5A, 0x5A, +18, DCS_WRITE_SYNC, 0xF2, 0x16, 0xDC, 0x03, 0x28, 0x28, 0x10, 0x00, 0x60, 0xF8, + 0x00, 0x07, 0x02, 0x00, 0x00, 0xDC, 0x28, 0x28, +15, DCS_WRITE_SYNC, 0xF4, 0x0A, 0x00, 0x00, 0x00, 0x77, 0x7F, 0x07, 0x22, 0x2A, + 0x43, 0x07, 0x2A, 0x43, 0x07, +11, DCS_WRITE_SYNC, 0xF5, 0x00, 0x50, 0x28, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, +10, DCS_WRITE_SYNC, 0xF6, 0x07, 0x00, 0x07, 0x00, 0x0B, 0x04, 0x04, 0x04, 0x07, +5, DCS_WRITE_SYNC, 0xF7, 0x00, 0x00, 0x00, 0x00, +3, DCS_WRITE_SYNC, 0xF8, 0x44, 0x08, +2, DCS_WRITE_SYNC, 0xF9, 0x04, +17, DCS_WRITE_SYNC, 0xFA, 0x0F, 0x0F, 0x1E, 0x23, 0x26, 0x2D, 0x21, 0x2B, 0x33, + 0x32, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, +17, DCS_WRITE_SYNC, 0xFB, 0x0F, 0x0F, 0x1E, 0x23, 0x26, 0x2D, 0x21, 0x2B, 0x33, + 0x32, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, +2, DCS_WRITE_SYNC, 0xF9, 0x02, +17, DCS_WRITE_SYNC, 0xFA, 0x00, 0x00, 0x0A, 0x16, 0x1D, 0x27, 0x1C, 0x30, 0x38, + 0x37, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, +17, DCS_WRITE_SYNC, 0xFB, 0x00, 0x00, 0x0A, 0x16, 0x1D, 0x27, 0x1C, 0x30, 0x38, + 0x37, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, +2, DCS_WRITE_SYNC, 0xF9, 0x01, +17, DCS_WRITE_SYNC, 0xFA, 0x00, 0x00, 0x13, 0x14, 0x19, 0x24, 0x1A, 0x31, 0x39, + 0x38, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, +17, DCS_WRITE_SYNC, 0xFB, 0x00, 0x00, 0x13, 0x14, 0x19, 0x24, 0x1A, 0x31, 0x39, + 0x38, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, +3, DCS_WRITE_SYNC, 0xF0, 0x00, 0x00, +3, DCS_WRITE_SYNC, 0xF1, 0x00, 0x00, +2, DCS_WRITE_SYNC, 0x36, 0xD8, +2, DCS_WRITE_SYNC, 0x3A, 0x06, +0 }; static u8 panel_init_220x220[] = { -/*n, data_0, data_1 ... data_n-1*/ - 3, 0xF0, 0x5A, 0x5A, - 3, 0xF1, 0x5A, 0x5A, -18, 0xF2, 0x1C, 0xDC, 0x03, 0x28, 0x28, 0x10, 0x00, 0x60, 0xF8, 0x00, 0x07, 0x02, 0x00, 0x00, 0xDC, 0x28, 0x28, -15, 0xF4, 0x0A, 0x00, 0x00, 0x00, 0x77, 0x7F, 0x07, 0x22, 0x2A, 0x43, 0x07, 0x2A, 0x43, 0x07, -11, 0xF5, 0x00, 0x50, 0x28, 0x00, 0x00, 0x09, 0x00, 0x00, 0x01, 0x01, -10, 0xF6, 0x07, 0x00, 0x07, 0x00, 0x0B, 0x04, 0x04, 0x04, 0x07, - 5, 0xF7, 0x00, 0x00, 0x00, 0x00, - 3, 0xF8, 0x44, 0x02, - 2, 0xF9, 0x04, -17, 0xFA, 0x1E, 0x1E, 0x0D, 0x1D, 0x21, 0x2C, 0x23, 0x28, 0x2C, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, -17, 0xFB, 0x1E, 0x1E, 0x0D, 0x1D, 0x21, 0x2C, 0x23, 0x28, 0x2C, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, - 2, 0xF9, 0x02, -17, 0xFA, 0x19, 0x18, 0x08, 0x0F, 0x18, 0x26, 0x1E, 0x2C, 0x30, 0x2C, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, -17, 0xFB, 0x19, 0x18, 0x08, 0x0F, 0x18, 0x26, 0x1E, 0x2C, 0x30, 0x2C, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, - 2, 0xF9, 0x01, -17, 0xFA, 0x19, 0x19, 0x09, 0x0D, 0x12, 0x21, 0x1B, 0x2E, 0x31, 0x2E, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, -17, 0xFB, 0x19, 0x19, 0x09, 0x0D, 0x12, 0x21, 0x1B, 0x2E, 0x31, 0x2E, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, - 3, 0xF0, 0x00, 0x00, - 3, 0xF1, 0x00, 0x00, - 2, 0x36, 0xD0, - 2, 0x3A, 0x06 +/*n, type, data_0, data_1 ... data_n-1*/ +1, DCS_WRITE_SYNC, MIPI_DCS_EXIT_SLEEP_MODE, +1, WAIT_MS, 5, +3, DCS_WRITE_SYNC, 0xF0, 0x5A, 0x5A, +3, DCS_WRITE_SYNC, 0xF1, 0x5A, 0x5A, +18, DCS_WRITE_SYNC, 0xF2, 0x1C, 0xDC, 0x03, 0x28, 0x28, 0x10, 0x00, 0x60, 0xF8, + 0x00, 0x07, 0x02, 0x00, 0x00, 0xDC, 0x28, 0x28, +15, DCS_WRITE_SYNC, 0xF4, 0x0A, 0x00, 0x00, 0x00, 0x77, 0x7F, 0x07, 0x22, 0x2A, + 0x43, 0x07, 0x2A, 0x43, 0x07, +11, DCS_WRITE_SYNC, 0xF5, 0x00, 0x50, 0x28, 0x00, 0x00, 0x09, 0x00, 0x00, 0x01, + 0x01, +10, DCS_WRITE_SYNC, 0xF6, 0x07, 0x00, 0x07, 0x00, 0x0B, 0x04, 0x04, 0x04, 0x07, +5, DCS_WRITE_SYNC, 0xF7, 0x00, 0x00, 0x00, 0x00, +3, DCS_WRITE_SYNC, 0xF8, 0x44, 0x02, +2, DCS_WRITE_SYNC, 0xF9, 0x04, +17, DCS_WRITE_SYNC, 0xFA, 0x1E, 0x1E, 0x0D, 0x1D, 0x21, 0x2C, 0x23, 0x28, 0x2C, + 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, +17, DCS_WRITE_SYNC, 0xFB, 0x1E, 0x1E, 0x0D, 0x1D, 0x21, 0x2C, 0x23, 0x28, 0x2C, + 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, +2, DCS_WRITE_SYNC, 0xF9, 0x02, +17, DCS_WRITE_SYNC, 0xFA, 0x19, 0x18, 0x08, 0x0F, 0x18, 0x26, 0x1E, 0x2C, 0x30, + 0x2C, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, +17, DCS_WRITE_SYNC, 0xFB, 0x19, 0x18, 0x08, 0x0F, 0x18, 0x26, 0x1E, 0x2C, 0x30, + 0x2C, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, +2, DCS_WRITE_SYNC, 0xF9, 0x01, +17, DCS_WRITE_SYNC, 0xFA, 0x19, 0x19, 0x09, 0x0D, 0x12, 0x21, 0x1B, 0x2E, 0x31, + 0x2E, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, +17, DCS_WRITE_SYNC, 0xFB, 0x19, 0x19, 0x09, 0x0D, 0x12, 0x21, 0x1B, 0x2E, 0x31, + 0x2E, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, +3, DCS_WRITE_SYNC, 0xF0, 0x00, 0x00, +3, DCS_WRITE_SYNC, 0xF1, 0x00, 0x00, +2, DCS_WRITE_SYNC, 0x36, 0xD8, +2, DCS_WRITE_SYNC, 0x3A, 0x06, +0 +}; + +static u8 panel_init_ssd2848_320x320[] = { +/*n, type, data_0, data_1 ... data_n-1*/ +2, GENERIC_WRITE_SYNC, 0xFF, 0x00, +6, GENERIC_WRITE_SYNC, 0x00, 0x08, 0x01, 0xF4, 0x04, 0x29, +6, GENERIC_WRITE_SYNC, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0B, +6, GENERIC_WRITE_SYNC, 0x00, 0x14, 0x0C, 0x01, 0x80, 0x0F, +1, DCS_WRITE_SYNC, MIPI_DCS_EXIT_SLEEP_MODE, +1, WAIT_MS, 1, +6, GENERIC_WRITE_SYNC, 0x10, 0x08, 0x01, 0x20, 0x01, 0x45, +6, GENERIC_WRITE_SYNC, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x02, +6, GENERIC_WRITE_SYNC, 0x20, 0x10, 0x00, 0x1B, 0x00, 0x0C, +6, GENERIC_WRITE_SYNC, 0x20, 0x14, 0x01, 0x88, 0x00, 0x28, +6, GENERIC_WRITE_SYNC, 0x20, 0x18, 0x01, 0x4E, 0x00, 0x0A, +6, GENERIC_WRITE_SYNC, 0x20, 0x20, 0x01, 0x40, 0x01, 0x40, +6, GENERIC_WRITE_SYNC, 0x20, 0x24, 0x01, 0x40, 0x01, 0x40, +6, GENERIC_WRITE_SYNC, 0x20, 0x30, 0x00, 0x00, 0x00, 0x15, +6, GENERIC_WRITE_SYNC, 0x20, 0x34, 0x00, 0x00, 0x00, 0x00, +6, GENERIC_WRITE_SYNC, 0x20, 0x38, 0x01, 0x3F, 0x01, 0x3F, +6, GENERIC_WRITE_SYNC, 0x20, 0x3C, 0x01, 0x40, 0x01, 0x40, +6, GENERIC_WRITE_SYNC, 0x20, 0xA0, 0x00, 0x00, 0x05, 0x00, +5, DCS_WRITE_SYNC, 0x2A, 0x00, 0x00, 0x01, 0x3F, +5, DCS_WRITE_SYNC, 0x2B, 0x00, 0x00, 0x01, 0x3F, +6, GENERIC_WRITE_SYNC, 0x60, 0x08, 0x00, 0x02, 0x00, 0x0A, +6, GENERIC_WRITE_SYNC, 0x60, 0x0C, 0x0A, 0x2A, 0x02, 0x0A, +6, GENERIC_WRITE_SYNC, 0x60, 0x10, 0x01, 0x40, 0x02, 0x14, +6, GENERIC_WRITE_SYNC, 0x60, 0x14, 0x01, 0x00, 0x01, 0x00, +6, GENERIC_WRITE_SYNC, 0x60, 0x40, 0x3F, 0x0B, 0x23, 0x0A, +6, GENERIC_WRITE_SYNC, 0x60, 0x44, 0x1F, 0x1F, 0x07, 0x29, +6, GENERIC_WRITE_SYNC, 0x60, 0x84, 0x00, 0x00, 0x01, 0x40, +2, GENERIC_WRITE_SYNC, 0xFF, 0x01, +2, DCS_WRITE_SYNC, 0x36, 0x10, +3, DCS_WRITE_SYNC, 0xF0, 0x54, 0x47, +2, DCS_WRITE_SYNC, 0xA0, 0x00, +4, DCS_WRITE_SYNC, 0xBD, 0x00, 0x11, 0x31, +2, DCS_WRITE_SYNC, 0xE9, 0x46, +5, DCS_WRITE_SYNC, 0xBA, 0x07, 0x15, 0x3E, 0x01, +6, DCS_WRITE_SYNC, 0xB3, 0x02, 0x0A, 0x14, 0x2A, 0x2A, +5, DCS_WRITE_SYNC, 0xB5, 0x78, 0x78, 0x76, 0xF6, +18, DCS_WRITE_SYNC, 0xC0, 0x00, 0x03, 0x11, 0x12, 0x17, 0x25, 0x0D, 0x0C, 0x0A, + 0x0E, 0x0C, 0x2F, 0x09, 0x0E, 0x3D, 0x3E, 0x3F, +18, DCS_WRITE_SYNC, 0xC1, 0x00, 0x03, 0x11, 0x12, 0x17, 0x25, 0x0D, 0x0C, 0x0A, + 0x0E, 0x0C, 0x2F, 0x09, 0x0E, 0x3D, 0x3E, 0x3F, +18, DCS_WRITE_SYNC, 0xC2, 0x00, 0x03, 0x11, 0x12, 0x17, 0x25, 0x0D, 0x0C, 0x0A, + 0x0E, 0x0C, 0x2F, 0x09, 0x0E, 0x3D, 0x3E, 0x3F, +18, DCS_WRITE_SYNC, 0xC3, 0x00, 0x03, 0x11, 0x12, 0x17, 0x25, 0x0D, 0x0C, 0x0A, + 0x0E, 0x0C, 0x2F, 0x09, 0x0E, 0x3D, 0x3E, 0x3F, +18, DCS_WRITE_SYNC, 0xC4, 0x00, 0x03, 0x11, 0x12, 0x17, 0x25, 0x0D, 0x0C, 0x0A, + 0x0E, 0x0C, 0x2F, 0x09, 0x0E, 0x3D, 0x3E, 0x3F, +18, DCS_WRITE_SYNC, 0xC5, 0x00, 0x03, 0x11, 0x12, 0x17, 0x25, 0x0D, 0x0C, 0x0A, + 0x0E, 0x0C, 0x2F, 0x09, 0x0E, 0x3D, 0x3E, 0x3F, +1, DCS_WRITE_SYNC, MIPI_DCS_EXIT_SLEEP_MODE, +1, WAIT_MS, 120, +1, DCS_WRITE_SYNC, MIPI_DCS_SET_DISPLAY_ON, +2, GENERIC_WRITE_SYNC, 0xFF, 0x00, +0 +}; + +struct minnow_panel_clk_range { + int min; + int max; +}; + +struct minnow_panel_hw_reset { + int active; + int reset_ms; + int wait_ms; }; struct minnow_panel_attr { + int mode; int xres; int yres; - int rate; + int pixel_clock; + int pixel_format; int xoffset; int yoffset; int init_cmd_count; u8 *init_cmd; + struct minnow_panel_clk_range hs; + struct minnow_panel_clk_range lp; + struct minnow_panel_hw_reset panel_reset; + struct minnow_panel_hw_reset bridge_reset; }; #define INIT_CMD(buf) .init_cmd_count = sizeof(buf), .init_cmd = (buf) static struct minnow_panel_attr panel_attr_table[MINNOW_PANEL_MAX] = { [MINNOW_PANEL_CM_220X176] = { + .mode = OMAP_DSS_DSI_CMD_MODE, .xres = 220, .yres = 176, - .rate = 60, + .pixel_clock = 4608, + .pixel_format = OMAP_DSS_DSI_FMT_RGB666, .xoffset = 0x32, .yoffset = 0, - INIT_CMD(panel_init_220x176) + INIT_CMD(panel_init_220x176), + .hs = { 100000000, 150000000 }, + .lp = { 7000000, 9000000 }, + .panel_reset = { 0, 1, 5 }, + .bridge_reset = { 0, 0, 0 }, }, [MINNOW_PANEL_CM_220X220] = { + .mode = OMAP_DSS_DSI_CMD_MODE, .xres = 220, .yres = 220, - .rate = 60, + .pixel_clock = 4608, + .pixel_format = OMAP_DSS_DSI_FMT_RGB666, .xoffset = 0x32, .yoffset = 0x4, - INIT_CMD(panel_init_220x220) + INIT_CMD(panel_init_220x220), + .hs = { 100000000, 150000000 }, + .lp = { 7000000, 9000000 }, + .panel_reset = { 0, 1, 5 }, + .bridge_reset = { 0, 0, 0 }, + }, + [MINNOW_PANEL_CM_BRIDGE_320X320] = { + .mode = OMAP_DSS_DSI_CMD_MODE, + .xres = 320, + .yres = 290, /* actual display height is 290 */ + .pixel_clock = DIV_ROUND_UP(320 * 290 * 60, 1000), + .pixel_format = OMAP_DSS_DSI_FMT_RGB888, + .xoffset = 0, + .yoffset = 0, + INIT_CMD(panel_init_ssd2848_320x320), + .hs = { 100000000, 150000000 }, + .lp = { 7000000, 9000000 }, + .panel_reset = { 0, 5, 10 }, + .bridge_reset = { 0, 20, 10 } }, }; + static irqreturn_t minnow_panel_te_isr(int irq, void *data); static void minnow_panel_te_timeout_work_callback(struct work_struct *work); static int _minnow_panel_enable_te(struct omap_dss_device *dssdev, bool enable); static int minnow_panel_reset(struct omap_dss_device *dssdev); + struct minnow_panel_data { struct mutex lock; /* mutex */ @@ -157,8 +304,11 @@ struct minnow_panel_data { struct omap_dss_device *dssdev; /* panel HW configuration from DT or platform data */ - int reset_gpio; + int reset_gpio[MINNOW_RESET_MAX]; int ext_te_gpio; + int clk_en_gpio; + struct minnow_panel_hw_reset hw_reset[MINNOW_RESET_MAX]; + struct minnow_panel_hw_reset bridge_reset; bool use_dsi_backlight; @@ -167,6 +317,7 @@ struct minnow_panel_data { u8 *init_cmd_data; int init_cmd_count; + int id_panel; int x_offset; int y_offset; @@ -194,6 +345,66 @@ struct minnow_panel_data { struct delayed_work ulps_work; }; +#ifdef CONFIG_OMAP2_DSS_DEBUGFS +static void minnow_panel_dump_regs(struct seq_file *s) +{ + static struct {char name[8]; int addr; int endreg; } regs[] = { + {"SCM", 0x0000, 0x30}, + {"MIPIRX", 0x1000, 0x30}, + {"VTCM", 0x2000, 0xB4}, + {"VCU", 0x4000, 0x20}, + {"GPIO", 0x5000, 0x04}, + {"MIPITX", 0x6000, 0x54}, + {"TX-DSI0", 0x6080, 0x14}, + }; + struct omap_dss_output *out = omap_dss_get_output(OMAP_DSS_OUTPUT_DSI1); + struct platform_device *dsidev = out->pdev; + struct omap_dss_device *dssdev = out->device; + struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev); + int i, j, r; + + dsi_bus_lock(dssdev); + + if (dsi_runtime_get(dsidev)) { + seq_puts(s, "dsi_runtime_get failed!"); + goto exit1; + } + + if (mpd->dssdev != dssdev) { + seq_puts(s, "dssdev mis-matched!"); + goto exit; + } + + if (dsi_vc_set_max_rx_packet_size(dssdev, mpd->channel, 4)) { + seq_puts(s, "failed set max rx_packet_size 4"); + goto exit; + } + + for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) { + seq_printf(s, "%s Registers:\n", regs[i].name); + for (j = 0; j <= regs[i].endreg; j += 4) { + u8 reg[4]; + u16 addr = j + regs[i].addr; + seq_printf(s, " %04X: ", addr); + r = dsi_vc_generic_read_2(dssdev, mpd->channel, + addr>>8, addr&0xFF, reg, 4); + if (r) + seq_printf(s, "read failed ret = %d\n", r); + else + seq_printf(s, "%02X%02X%02X%02X\n", + reg[0], reg[1], reg[2], reg[3]); + } + } + + dsi_vc_set_max_rx_packet_size(dssdev, mpd->channel, 1); + +exit: + dsi_runtime_put(dsidev); +exit1: + dsi_bus_unlock(dssdev); +} +#endif + static void minnow_panel_esd_work(struct work_struct *work); static void minnow_panel_ulps_work(struct work_struct *work); @@ -278,10 +489,34 @@ static int minnow_panel_sleep_out(struct minnow_panel_data *mpd) return 0; } -static int minnow_panel_get_id(struct minnow_panel_data *mpd, u8 *id1, u8 *id2, u8 *id3) +static int minnow_panel_get_bridge_rev(struct minnow_panel_data *mpd, + u8 *id1, u8 *id2, u8 *id3) +{ + int r = dsi_vc_set_max_rx_packet_size(mpd->dssdev, mpd->channel, 4); + + if (!r) { + u8 reg[4]; + r = dsi_vc_generic_read_2(mpd->dssdev, + mpd->channel, 0, 0, reg, 4); + if (!r) { + *id1 = reg[0]; + *id2 = reg[1]; + *id3 = reg[3]; + } + } + dsi_vc_set_max_rx_packet_size(mpd->dssdev, mpd->channel, 1); + + return r; +} + +static int minnow_panel_get_id(struct minnow_panel_data *mpd, + u8 *id1, u8 *id2, u8 *id3) { int r; + if (mpd->id_panel == MINNOW_PANEL_CM_BRIDGE_320X320) + return minnow_panel_get_bridge_rev(mpd, id1, id2, id3); + r = minnow_panel_dcs_read_1(mpd, DCS_GET_ID1, id1); if (r) return r; @@ -292,24 +527,67 @@ static int minnow_panel_get_id(struct minnow_panel_data *mpd, u8 *id1, u8 *id2, if (r) return r; + return 0; } static int _minnow_panel_init(struct minnow_panel_data *mpd) { + u8 *data; int i, r; - for (i = 0; i < mpd->init_cmd_count; ) { - u8 *data = mpd->init_cmd_data + i; - r = *data++; - i += r + 1; - if (i > mpd->init_cmd_count) { - dev_err(&mpd->dssdev->dev, "Invalid init command data selected!\n"); - return -EINVAL; + + for (i = 0, data = mpd->init_cmd_data; *data; ) { + i += ((u32)*data + 2); + if (i >= mpd->init_cmd_count) + break; + if (data[1] >= CMD_TYPE_MAX) + break; + data += (*data + 2); + } + + /* Init command data shall end with 0 */ + if (*data) { + dev_err(&mpd->dssdev->dev, "Invalid panel initialize data\n"); + return -EINVAL; + } + + for (i = 0, data = mpd->init_cmd_data; *data; i++) { + int len = (u32)*data; + u8 cmd = data[1]; + data += 2; + switch (cmd) { + case DCS_WRITE_SYNC: + r = dsi_vc_dcs_write(mpd->dssdev, + mpd->channel, data, len); + break; + case GENERIC_WRITE_SYNC: + r = dsi_vc_generic_write(mpd->dssdev, + mpd->channel, data, len); + break; + case DCS_WRITE: + r = dsi_vc_dcs_write_nosync(mpd->dssdev, + mpd->channel, data, len); + break; + case GENERIC_WRITE: + r = dsi_vc_generic_write_nosync(mpd->dssdev, + mpd->channel, data, len); + break; + case BTA_SYNC: + r = dsi_vc_send_bta_sync(mpd->dssdev, mpd->channel); + break; + case WAIT_MS: + msleep((len == 1 ? (u32)(*data) : *(u16 *)data)); + break; } - r = dsi_vc_dcs_write(mpd->dssdev, mpd->channel, data, r); - if (r) + if (r) { + dev_err(&mpd->dssdev->dev, "Failed process initialize" + "command[%d] len=%d type=%d ret=%d\n", + i, len, cmd, r); break; + } + data += len; } + return r; } @@ -839,20 +1117,40 @@ static struct attribute_group minnow_panel_attr_group = { static void minnow_panel_hw_reset(struct omap_dss_device *dssdev) { struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev); + int i, ms_rst = -1, ms_rel = -1; - if (!gpio_is_valid(mpd->reset_gpio)) + for (i = 0; i < MINNOW_RESET_MAX; i++) { + if (!gpio_is_valid(mpd->reset_gpio[i])) + continue; + gpio_set_value(mpd->reset_gpio[i], + mpd->hw_reset[i].active ? 0 : 1); + if (ms_rst < mpd->hw_reset[i].reset_ms) + ms_rst = mpd->hw_reset[i].reset_ms; + if (ms_rel < mpd->hw_reset[i].wait_ms) + ms_rel = mpd->hw_reset[i].wait_ms; + } + if (ms_rst == -1) return; + msleep(5); - gpio_set_value(mpd->reset_gpio, 1); - udelay(10); - /* reset the panel */ - gpio_set_value(mpd->reset_gpio, 0); + /* reset the device */ + for (i = 0; i < MINNOW_RESET_MAX; i++) { + if (!gpio_is_valid(mpd->reset_gpio[i])) + continue; + gpio_set_value(mpd->reset_gpio[i], + mpd->hw_reset[i].active ? 1 : 0); + } + /* wait device reset */ + msleep(ms_rst); /* assert reset */ - udelay(10); - gpio_set_value(mpd->reset_gpio, 1); - + for (i = 0; i < MINNOW_RESET_MAX; i++) { + if (!gpio_is_valid(mpd->reset_gpio[i])) + continue; + gpio_set_value(mpd->reset_gpio[i], + mpd->hw_reset[i].active ? 0 : 1); + } /* wait after releasing reset */ - msleep(5); + msleep(ms_rel); } #define DEBUG_DT @@ -900,30 +1198,40 @@ static int minnow_panel_dt_init(struct minnow_panel_data *mpd) "Invalid id_panel = %u!\n", value); return -EINVAL; } - DTINFO("id_panel = %d\n", value); - panel_attr = &panel_attr_table[value]; + mpd->id_panel = value; + DTINFO("id_panel = %d\n", mpd->id_panel); + + panel_attr = &panel_attr_table[mpd->id_panel]; mpd->init_cmd_data = panel_attr->init_cmd; mpd->init_cmd_count = panel_attr->init_cmd_count; - mpd->x_offset = panel_attr->xoffset; - mpd->y_offset = panel_attr->yoffset; - mpd->dssdev->panel.timings.x_res = panel_attr->xres; - mpd->dssdev->panel.timings.y_res = panel_attr->yres; - mpd->dssdev->panel.timings.pixel_clock = DIV_ROUND_UP(panel_attr->xres\ - * panel_attr->yres * panel_attr->rate, 1000); - mpd->dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888; mpd->dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; - mpd->dsi_config.mode = OMAP_DSS_DSI_CMD_MODE; - mpd->dsi_config.pixel_format = OMAP_DSS_DSI_FMT_RGB888; - mpd->dsi_config.hs_clk_min = 90000000; - mpd->dsi_config.hs_clk_max = 150000000; - mpd->dsi_config.lp_clk_min = 7000000; - mpd->dsi_config.lp_clk_max = 9000000; + mpd->dssdev->panel.timings.x_res = panel_attr->xres; + mpd->dssdev->panel.timings.y_res = panel_attr->yres; + mpd->dssdev->panel.timings.pixel_clock = panel_attr->pixel_clock; + mpd->dssdev->panel.dsi_pix_fmt = panel_attr->pixel_format; + mpd->dsi_config.mode = panel_attr->mode; + mpd->dsi_config.pixel_format = panel_attr->pixel_format; + mpd->dsi_config.hs_clk_min = panel_attr->hs.min; + mpd->dsi_config.hs_clk_max = panel_attr->hs.max; + mpd->dsi_config.lp_clk_min = panel_attr->lp.min; + mpd->dsi_config.lp_clk_max = panel_attr->lp.max; + mpd->x_offset = panel_attr->xoffset; + mpd->y_offset = panel_attr->yoffset; - mpd->reset_gpio = of_get_named_gpio(dt_node, "gpio_reset", 0); - DTINFO("gpio_reset = %d\n", mpd->reset_gpio); + mpd->hw_reset[MINNOW_RESET_PANEL] = panel_attr->panel_reset; + mpd->hw_reset[MINNOW_RESET_BRIDGE] = panel_attr->bridge_reset; + mpd->reset_gpio[MINNOW_RESET_PANEL] = + of_get_named_gpio(dt_node, "gpio_panel_reset", 0); + DTINFO("gpio_panel_reset = %d\n", mpd->reset_gpio[MINNOW_RESET_PANEL]); + mpd->reset_gpio[MINNOW_RESET_BRIDGE] = + of_get_named_gpio(dt_node, "gpio_bridge_reset", 0); + DTINFO("gpio_bridge_reset = %d\n", + mpd->reset_gpio[MINNOW_RESET_BRIDGE]); mpd->ext_te_gpio = of_get_named_gpio(dt_node, "gpio_te", 0); - DTINFO("ext_te: gpio_te = %d\n", mpd->ext_te_gpio); + DTINFO("gpio_te = %d\n", mpd->ext_te_gpio); + mpd->clk_en_gpio = of_get_named_gpio(dt_node, "gpio_clk_en", 0); + DTINFO("gpio_clk_en = %d\n", mpd->clk_en_gpio); mpd->esd_interval = 0; if (!of_property_read_u32(dt_node, "esd_interval", &value)) { @@ -1021,7 +1329,7 @@ static int minnow_panel_probe(struct omap_dss_device *dssdev) struct backlight_properties props; struct minnow_panel_data *mpd; struct backlight_device *bldev = NULL; - int r; + int i, r; dev_dbg(&dssdev->dev, "probe\n"); @@ -1040,11 +1348,28 @@ static int minnow_panel_probe(struct omap_dss_device *dssdev) atomic_set(&mpd->do_update, 0); - if (gpio_is_valid(mpd->reset_gpio)) { - r = devm_gpio_request_one(&dssdev->dev, mpd->reset_gpio, - GPIOF_OUT_INIT_HIGH, "minnow-panel reset"); + if (gpio_is_valid(mpd->clk_en_gpio)) { + r = devm_gpio_request_one(&dssdev->dev, mpd->clk_en_gpio, + GPIOF_OUT_INIT_HIGH, "minnow-panel clk_en"); + if (r) { + dev_err(&dssdev->dev, "failed to request panel clk_en gpio\n"); + return r; + } + } + + for (i = 0; i < MINNOW_RESET_MAX; i++) { + static const char * const name[MINNOW_RESET_MAX] = { + "minnow-panel reset", + "minnow-bridge reset" + }; + if (!gpio_is_valid(mpd->reset_gpio[i])) + continue; + r = devm_gpio_request_one(&dssdev->dev, mpd->reset_gpio[i], + mpd->hw_reset[i].active ? GPIOF_OUT_INIT_LOW + : GPIOF_OUT_INIT_HIGH, name[i]); if (r) { - dev_err(&dssdev->dev, "failed to request reset gpio\n"); + dev_err(&dssdev->dev, + "failed to request %s gpio\n", name[i]); return r; } } @@ -1053,11 +1378,13 @@ static int minnow_panel_probe(struct omap_dss_device *dssdev) r = devm_gpio_request_one(&dssdev->dev, mpd->ext_te_gpio, GPIOF_IN, "minnow-panel irq"); if (r) { - dev_err(&dssdev->dev, "failed to request ext_te gpio\n"); + dev_err(&dssdev->dev, + "failed to request ext_te gpio\n"); return r; } - r = devm_request_irq(&dssdev->dev, gpio_to_irq(mpd->ext_te_gpio), + r = devm_request_irq(&dssdev->dev, + gpio_to_irq(mpd->ext_te_gpio), minnow_panel_te_isr, IRQF_TRIGGER_RISING, "minnow-panel vsync", dssdev); @@ -1120,6 +1447,11 @@ static int minnow_panel_probe(struct omap_dss_device *dssdev) goto err_vc_id; } +#ifdef CONFIG_OMAP2_DSS_DEBUGFS + if (mpd->id_panel == MINNOW_PANEL_CM_BRIDGE_320X320) + dss_debugfs_create_file("panel_regs", minnow_panel_dump_regs); +#endif + return 0; err_vc_id: @@ -1182,29 +1514,34 @@ static int minnow_panel_power_on(struct omap_dss_device *dssdev) goto err0; } +#ifdef CONFIG_OMAP2_DSS_RESET + minnow_panel_hw_reset(dssdev); +#else + /* Need reset display at first time as it's already enable on boot */ if (mpd->intro_printed) minnow_panel_hw_reset(dssdev); +#endif omapdss_dsi_vc_enable_hs(dssdev, mpd->channel, false); - r = minnow_panel_sleep_out(mpd); + r = _minnow_panel_init(mpd); if (r) goto err; - _minnow_panel_init(mpd); - r = minnow_panel_get_id(mpd, &id1, &id2, &id3); if (r) goto err; - r = minnow_panel_dcs_write_0(mpd, MIPI_DCS_SET_DISPLAY_ON); + r = _minnow_panel_enable_te(dssdev, mpd->te_enabled); if (r) goto err; - r = _minnow_panel_enable_te(dssdev, mpd->te_enabled); + r = minnow_panel_dcs_write_0(mpd, MIPI_DCS_SET_DISPLAY_ON); if (r) goto err; + omapdss_dsi_vc_enable_hs(dssdev, mpd->channel, true); + r = dsi_enable_video_output(dssdev, mpd->channel); if (r) goto err; @@ -1217,8 +1554,6 @@ static int minnow_panel_power_on(struct omap_dss_device *dssdev) mpd->intro_printed = true; } - omapdss_dsi_vc_enable_hs(dssdev, mpd->channel, true); - return 0; err: dev_err(&dssdev->dev, "error while enabling panel, issuing HW reset\n"); @@ -1343,7 +1678,6 @@ static irqreturn_t minnow_panel_te_isr(int irq, void *data) if (old) { cancel_delayed_work(&mpd->te_timeout_work); - r = omap_dsi_update(dssdev, mpd->channel, minnow_panel_framedone_cb, dssdev); if (r) @@ -1375,6 +1709,10 @@ static int minnow_panel_update(struct omap_dss_device *dssdev, struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev); int r; + /* for video mode, do not need manual update */ + if (mpd->dsi_config.mode == OMAP_DSS_DSI_VIDEO_MODE) + return 0; + dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h); mutex_lock(&mpd->lock); @@ -1445,9 +1783,6 @@ static int _minnow_panel_enable_te(struct omap_dss_device *dssdev, bool enable) if (!gpio_is_valid(mpd->ext_te_gpio)) omapdss_dsi_enable_te(dssdev, enable); - /* possible panel bug */ - msleep(100); - return r; } @@ -1543,12 +1878,14 @@ static int minnow_panel_memory_read(struct omap_dss_device *dssdev, u16 x, u16 y, u16 w, u16 h) { int r; - int first = 1; int plen; - unsigned buf_used = 0; + u32 buf_used = 0; struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev); + u8 dcs_cmd = MIPI_DCS_READ_MEMORY_START; - if (size < w * h * 3) + plen = dsi_get_pixel_size(mpd->dssdev->panel.dsi_pix_fmt); + plen = DIV_ROUND_UP(plen, 8); + if (size < w * h * plen) return -ENOMEM; mutex_lock(&mpd->lock); @@ -1558,9 +1895,9 @@ static int minnow_panel_memory_read(struct omap_dss_device *dssdev, goto err1; } - size = min(w * h * 3, + size = min(w * h * plen, dssdev->panel.timings.x_res * - dssdev->panel.timings.y_res * 3); + dssdev->panel.timings.y_res * plen); dsi_bus_lock(dssdev); @@ -1568,39 +1905,24 @@ static int minnow_panel_memory_read(struct omap_dss_device *dssdev, if (r) goto err2; - /* plen 1 or 2 goes into short packet. until checksum error is fixed, - * use short packets. plen 32 works, but bigger packets seem to cause - * an error. */ - if (size % 2) - plen = 1; - else - plen = 2; - minnow_panel_set_update_window(mpd, x, y, w, h); + /* each read 8 pixel as SSD2848 has minimum read pixels */ + plen *= 8; r = dsi_vc_set_max_rx_packet_size(dssdev, mpd->channel, plen); if (r) goto err2; - while (buf_used < size) { - u8 dcs_cmd = first ? 0x2e : 0x3e; - first = 0; - + size = size / plen * plen; + for (; buf_used < size; dcs_cmd = MIPI_DCS_READ_MEMORY_CONTINUE) { r = dsi_vc_dcs_read(dssdev, mpd->channel, dcs_cmd, - buf + buf_used, size - buf_used); - - if (r < 0) { - dev_err(&dssdev->dev, "read error\n"); + buf + buf_used, plen); + if (r) { + dev_err(&dssdev->dev, + "read failed at %u err=%d\n", buf_used, r); goto err3; } - - buf_used += r; - - if (r < plen) { - dev_err(&dssdev->dev, "short read\n"); - break; - } - + buf_used += plen; if (signal_pending(current)) { dev_err(&dssdev->dev, "signal pending, " "aborting memory read\n"); @@ -1608,7 +1930,6 @@ static int minnow_panel_memory_read(struct omap_dss_device *dssdev, goto err3; } } - r = buf_used; err3: diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index cb0f145c707..2bf82e2e15a 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -116,4 +116,8 @@ config OMAP2_DSS_SLEEP_AFTER_VENC_RESET This option enables the sleep, and is enabled by default. You can disable the sleep if it doesn't cause problems on your platform. +config OMAP2_DSS_RESET + bool "Reset OMAP Display Subsystem" + default n + endif diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 749aa38605a..69b44185ed1 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -4594,8 +4594,10 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) dsi_enable_pll_clock(dsidev, 1); +#ifndef CONFIG_OMAP2_DSS_RESET dsi_vc_enable(dsidev, 0, 0); dsi_vc_enable(dsidev, 1, 0); +#endif _dsi_initialize_irq(dsidev); diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index f5f57a4e9a2..27579d8f76b 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -29,6 +29,7 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/omapfb.h> +#include <linux/uaccess.h> #include <video/omapdss.h> #include <video/omapvrfb.h> @@ -906,6 +907,8 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, mirror = ofbi->mirror; info.paddr = data_start_p; + info.p_uv_addr = (u32)omapfb_get_region_vaddr(ofbi) + + (data_start_p - (u32)omapfb_get_region_paddr(ofbi)); info.screen_width = screen_width; info.width = xres; info.height = yres; @@ -1048,6 +1051,7 @@ static int omapfb_set_par(struct fb_info *fbi) static int omapfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi) { + struct omap_dss_device *display = fb2display(fbi); struct omapfb_info *ofbi = FB2OFB(fbi); struct fb_var_screeninfo new_var; int r; @@ -1070,6 +1074,12 @@ static int omapfb_pan_display(struct fb_var_screeninfo *var, omapfb_put_mem_region(ofbi->region); + if (display && display->driver->update && display->driver->sync) { + DBG("sync_update(%d, %d)\n", var->xres, var->yres); + display->driver->sync(display); + display->driver->update(display, 0, 0, var->xres, var->yres); + } + return r; } @@ -1290,6 +1300,97 @@ ssize_t omapfb_write(struct fb_info *info, const char __user *buf, } #endif +ssize_t omapfb_write(struct fb_info *info, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct omapfb_info *ofbi = FB2OFB(info); + struct omapfb2_device *fbdev = ofbi->fbdev; + struct omap_dss_device *display = fb2display(info); + struct omapfb_display_data *d; + struct fb_var_screeninfo *var = &info->var; + unsigned long p = *ppos; + u8 *buffer, *src; + u8 __iomem *dst; + int c, cnt, err = 0; + unsigned long total_size; + + DBG("omapfb_write %d, %lu\n", count, (unsigned long)*ppos); + + total_size = var->xres * var->yres * (var->bits_per_pixel>>3); + if (p > total_size) + return -EFBIG; + if (count > total_size) { + err = -EFBIG; + count = total_size; + } + if (count + p > total_size) { + if (!err) + err = -ENOSPC; + + count = total_size - p; + } + + DBG("omapfb_write %d, %lu, %lu\n", count, p, total_size); + + buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, + GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + dst = (u8 __iomem *)(info->screen_base + p); + c = var->bits_per_pixel >> 3; + cnt = var->xres_virtual * c; + dst += var->yoffset*cnt + var->xoffset*c; + DBG("omapfb_write offset = %d, scr_size = %lu\n", + (int)(dst) - (int)(info->screen_base + p), info->screen_size); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + for (cnt = 0; count; ) { + c = (count > PAGE_SIZE) ? PAGE_SIZE : count; + src = buffer; + + if (copy_from_user(src, buf, c)) { + err = -EFAULT; + break; + } + + fb_memcpy_tofb(dst, src, c); + dst += c; + src += c; + *ppos += c; + buf += c; + cnt += c; + count -= c; + } + + kfree(buffer); + + if (total_size <= *ppos && display && + display->driver->update && display->driver->sync) { + DBG("fb_var_screen info:\n"); + DBG("\txres = %u\n", var->xres); + DBG("\tyres = %u\n", var->yres); + DBG("\txres_virtual = %u\n", var->xres_virtual); + DBG("\tyres_virtual = %u\n", var->yres_virtual); + DBG("\txoffset = %u\n", var->xoffset); + DBG("\tyoffset = %u\n", var->yoffset); + DBG("\tbits_per_pixel = %u\n", var->bits_per_pixel); + omapfb_lock(fbdev); + d = get_display_data(fbdev, display); + if (d->update_mode == OMAPFB_MANUAL_UPDATE) { + DBG("sync_update(%d, %d)\n", var->xres, var->yres); + display->driver->sync(display); + display->driver->update(display, + 0, 0, var->xres, var->yres); + } + omapfb_unlock(fbdev); + } + + return (cnt) ? cnt : err; +} + static struct fb_ops omapfb_ops = { .owner = THIS_MODULE, .fb_open = omapfb_open, @@ -1305,7 +1406,7 @@ static struct fb_ops omapfb_ops = { .fb_mmap = omapfb_mmap, .fb_setcolreg = omapfb_setcolreg, .fb_setcmap = omapfb_setcmap, - /*.fb_write = omapfb_write,*/ + .fb_write = omapfb_write, }; static void omapfb_free_fbmem(struct fb_info *fbi) |