summaryrefslogtreecommitdiff
path: root/drivers/video/sprdfb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/sprdfb')
-rw-r--r--drivers/video/sprdfb/Kconfig363
-rw-r--r--drivers/video/sprdfb/Makefile35
-rw-r--r--drivers/video/sprdfb/dsi_1_10a/Makefile2
-rw-r--r--drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.c1216
-rw-r--r--drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.h113
-rw-r--r--drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.c1031
-rw-r--r--drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.h55
-rw-r--r--drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.c529
-rw-r--r--drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.h242
-rw-r--r--drivers/video/sprdfb/dsi_1_10a/mipi_dsih_local.h227
-rw-r--r--drivers/video/sprdfb/dsi_1_21a/Makefile12
-rw-r--r--drivers/video/sprdfb/dsi_1_21a/mipi_dsih_api.c1750
-rw-r--r--drivers/video/sprdfb/dsi_1_21a/mipi_dsih_api.h134
-rw-r--r--drivers/video/sprdfb/dsi_1_21a/mipi_dsih_dphy.c1080
-rw-r--r--drivers/video/sprdfb/dsi_1_21a/mipi_dsih_dphy.h61
-rw-r--r--drivers/video/sprdfb/dsi_1_21a/mipi_dsih_dphy_megacores.c1166
-rw-r--r--drivers/video/sprdfb/dsi_1_21a/mipi_dsih_hal.c1114
-rw-r--r--drivers/video/sprdfb/dsi_1_21a/mipi_dsih_hal.h1807
-rw-r--r--drivers/video/sprdfb/dsi_1_21a/mipi_dsih_local.h361
-rw-r--r--drivers/video/sprdfb/lcd/Makefile50
-rw-r--r--drivers/video/sprdfb/lcd/lcd_dummy.c104
-rw-r--r--drivers/video/sprdfb/lcd/lcd_fl10802_mipi.c364
-rw-r--r--drivers/video/sprdfb/lcd/lcd_hx8363_mcu.c406
-rw-r--r--drivers/video/sprdfb/lcd/lcd_hx8363_rgb_spi.c445
-rw-r--r--drivers/video/sprdfb/lcd/lcd_hx8363_rgb_spi_viva.c442
-rw-r--r--drivers/video/sprdfb/lcd/lcd_hx8369.c391
-rwxr-xr-xdrivers/video/sprdfb/lcd/lcd_hx8369b_grandneo_mipi.c338
-rw-r--r--drivers/video/sprdfb/lcd/lcd_hx8369b_mipi.c348
-rw-r--r--drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_coreprimelite.c348
-rw-r--r--drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_coreprimelite_marlin.c348
-rw-r--r--drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_kiran3g.c384
-rw-r--r--drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_sharkls_z3lte.c348
-rw-r--r--drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_vivaltoVE.c283
-rwxr-xr-xdrivers/video/sprdfb/lcd/lcd_hx8369b_tshark2_j3_mipi.c290
-rw-r--r--drivers/video/sprdfb/lcd/lcd_hx8379a_mipi.c312
-rwxr-xr-xdrivers/video/sprdfb/lcd/lcd_hx8389c_mipi.c318
-rw-r--r--drivers/video/sprdfb/lcd/lcd_hx8394a_mipi.c295
-rw-r--r--drivers/video/sprdfb/lcd/lcd_hx8394d_mipi.c430
-rw-r--r--drivers/video/sprdfb/lcd/lcd_ili6150_lvds.c81
-rw-r--r--drivers/video/sprdfb/lcd/lcd_ili9341.c428
-rw-r--r--drivers/video/sprdfb/lcd/lcd_ili9486.c434
-rw-r--r--drivers/video/sprdfb/lcd/lcd_ili9486_rgb_spi.c397
-rw-r--r--drivers/video/sprdfb/lcd/lcd_ili9486s1_mipi.c268
-rw-r--r--drivers/video/sprdfb/lcd/lcd_ili9806e_2_mipi.c487
-rw-r--r--drivers/video/sprdfb/lcd/lcd_ili9806e_mipi.c632
-rw-r--r--drivers/video/sprdfb/lcd/lcd_jd9161_mipi.c380
-rwxr-xr-xdrivers/video/sprdfb/lcd/lcd_nt35502_mipi.c300
-rw-r--r--drivers/video/sprdfb/lcd/lcd_nt35510_mipi.c291
-rw-r--r--drivers/video/sprdfb/lcd/lcd_nt35512_mipi.c183
-rw-r--r--drivers/video/sprdfb/lcd/lcd_nt35516_mcu.c585
-rw-r--r--drivers/video/sprdfb/lcd/lcd_nt35516_mipi.c441
-rw-r--r--drivers/video/sprdfb/lcd/lcd_nt35516_rgb_i2c.c623
-rwxr-xr-xdrivers/video/sprdfb/lcd/lcd_nt35516_rgb_spi.c624
-rw-r--r--drivers/video/sprdfb/lcd/lcd_nt35596h_mipi.c841
-rwxr-xr-xdrivers/video/sprdfb/lcd/lcd_nt51017_goyal_mipi.c296
-rw-r--r--drivers/video/sprdfb/lcd/lcd_nt51017_mipi_lvds.c589
-rw-r--r--drivers/video/sprdfb/lcd/lcd_otm1283a_mipi.c560
-rw-r--r--drivers/video/sprdfb/lcd/lcd_otm8019a_mipi.c516
-rw-r--r--drivers/video/sprdfb/lcd/lcd_otm_8018b_mipi.c296
-rw-r--r--drivers/video/sprdfb/lcd/lcd_rm68180_mipi.c383
-rw-r--r--drivers/video/sprdfb/lcd/lcd_s6d0139.c244
-rw-r--r--drivers/video/sprdfb/lcd/lcd_s6d77a1_pikeA_mipi.c330
-rw-r--r--drivers/video/sprdfb/lcd/lcd_s6d7aa0x62_t8_mipi.c350
-rwxr-xr-xdrivers/video/sprdfb/lcd/lcd_sc7798_rgb_spi.c561
-rwxr-xr-xdrivers/video/sprdfb/lcd/lcd_sd7798d_mipi.c261
-rwxr-xr-xdrivers/video/sprdfb/lcd/lcd_sd7798d_mipi_sharkls_z3lte.c261
-rw-r--r--drivers/video/sprdfb/lcd/lcd_ssd2075_mipi.c375
-rw-r--r--drivers/video/sprdfb/lcd/lcd_st7789v_mcu.c336
-rw-r--r--drivers/video/sprdfb/lcd/lcd_t8861_mipi.c485
-rwxr-xr-xdrivers/video/sprdfb/lcd/lcd_vx5b3d_mipi.c965
-rw-r--r--drivers/video/sprdfb/spi/Makefile7
-rw-r--r--drivers/video/sprdfb/spi/spi_simple_drv.c358
-rw-r--r--drivers/video/sprdfb/spi/spi_simple_drv.h178
-rw-r--r--drivers/video/sprdfb/sprdfb.h289
-rw-r--r--drivers/video/sprdfb/sprdfb_attr.c429
-rwxr-xr-xdrivers/video/sprdfb/sprdfb_chip_7715.c35
-rwxr-xr-xdrivers/video/sprdfb/sprdfb_chip_7715.h116
-rw-r--r--drivers/video/sprdfb/sprdfb_chip_8830.c80
-rw-r--r--drivers/video/sprdfb/sprdfb_chip_8830.h135
-rw-r--r--drivers/video/sprdfb/sprdfb_chip_9630.c58
-rw-r--r--drivers/video/sprdfb/sprdfb_chip_9630.h129
-rw-r--r--drivers/video/sprdfb/sprdfb_chip_common.c23
-rw-r--r--drivers/video/sprdfb/sprdfb_chip_common.h58
-rw-r--r--drivers/video/sprdfb/sprdfb_dispc.c2446
-rw-r--r--drivers/video/sprdfb/sprdfb_dispc_reg.h169
-rw-r--r--drivers/video/sprdfb/sprdfb_dsi.c1010
-rw-r--r--drivers/video/sprdfb/sprdfb_gpio2spi.c199
-rw-r--r--drivers/video/sprdfb/sprdfb_i2c.c333
-rw-r--r--drivers/video/sprdfb/sprdfb_main.c888
-rw-r--r--drivers/video/sprdfb/sprdfb_mcu.c563
-rw-r--r--drivers/video/sprdfb/sprdfb_mipi.c231
-rw-r--r--drivers/video/sprdfb/sprdfb_panel.c683
-rw-r--r--drivers/video/sprdfb/sprdfb_panel.h324
-rwxr-xr-xdrivers/video/sprdfb/sprdfb_rgb.c277
-rw-r--r--drivers/video/sprdfb/sprdfb_spi.c153
95 files changed, 40516 insertions, 0 deletions
diff --git a/drivers/video/sprdfb/Kconfig b/drivers/video/sprdfb/Kconfig
new file mode 100644
index 00000000..21a034e5
--- /dev/null
+++ b/drivers/video/sprdfb/Kconfig
@@ -0,0 +1,363 @@
+if FB
+config FB_SCX35
+ boolean "SC8830 frame buffer support "
+ depends on FB && ARCH_SCX35 && (!ARCH_SCX30G) && (!ARCH_SCX35L)
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ Frame buffer driver for sc8830 based boards.
+
+config FB_SCX30G
+ boolean "SC8830G frame buffer support "
+ depends on FB && ARCH_SCX30G
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ Frame buffer driver for sc8830G based boards.
+
+config FB_SCX35L
+ boolean "SharkL frame buffer support "
+ depends on FB && ARCH_SCX35L
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ Frame buffer driver for SharkL based boards.
+
+config FB_SCX15
+ boolean "SC7715 frame buffer support "
+ depends on FB && ARCH_SCX15
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ Frame buffer driver for sc7715 based boards.
+
+config SPRD_FB_SIZE
+ int "MB size for frame buffer, should larger or equal lcd_w*lcd_h*4*2"
+ range 1 16
+ default 8
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX15 || FB_SCX30G || FB_SCX35L
+
+config FB_LCD_HX8363_MCU
+ boolean "support HX8363 panel mcu"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX15
+ default n
+
+config FB_LCD_HX8363_RGB_SPI
+ boolean "support HX8363 panel rgb spi"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX15
+ default n
+
+config FB_LCD_VIVA_RGB_SPI
+ boolean "support VIVA panel rgb spi"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX15
+ default n
+
+config FB_LCD_HX8369
+ boolean "support HX8369 panel"
+ depends on FB_SC8825 || FB_SCX35
+ default n
+
+config FB_LCD_HX8369B_MIPI_COREPRIMELITE
+ boolean "support HX8369B coreprimelite MIPI panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G || FB_SCX35L
+ default n
+
+config FB_LCD_SD7798D_MIPI_COREPRIMELITE
+ boolean "support SD7798D coreprimelite MIPI panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G || FB_SCX35L
+ default n
+
+config FB_LCD_HX8369B_MIPI_SHARKLS_Z3LTE
+ boolean "support HX8369B sharkls_z3lte panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G || FB_SCX35L
+ default n
+
+config FB_LCD_SD7798D_MIPI_SHARKLS_Z3LTE
+ boolean "support SD7798D sharkls_z3lte MIPI panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G || FB_SCX35L
+ default n
+
+config FB_LCD_HX8369B_MIPI_COREPRIMELITE_MARLIN
+ boolean "support HX8369B coreprimelite_marlin MIPI panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G || FB_SCX35L
+ default n
+
+config FB_LCD_HX8369B_MIPI
+ boolean "support HX8369B MIPI panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G
+ default n
+
+config FB_LCD_TSHARK2_J3_MIPI
+ boolean "support TSHARK2 J3 MIPI panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G
+ default n
+
+config FB_LCD_SD7798D_MIPI
+ boolean "support SD7798D MIPI panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G
+ default n
+
+config FB_LCD_GRANDNEO_MIPI
+ boolean "support GRAND NEO MIPI panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G
+ default n
+
+config FB_LCD_NT51017_MIPI
+ boolean "support TSHARK2 TABE MIPI panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G || FB_SCX30G2
+ default n
+
+config FB_LCD_SD7798D_MIPI_COREPRIMELITE
+ boolean "support SD7798D coreprimelite MIPI panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G || FB_SCX35L
+ default n
+
+config FB_LCD_HX8369B_MIPI_COREPRIMELITE_MARLIN
+ boolean "support HX8369B coreprimelite_marlin MIPI panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G || FB_SCX35L
+ default n
+
+config FB_LCD_HX8369B_MIPI
+ boolean "support HX8369B MIPI panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G
+ default n
+
+config FB_LCD_VX5B3D_MIPI
+ boolean "support VX5B3D mipi panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G
+ default n
+
+config FB_LCD_HX8369B_MIPI_VIVALTO_VE
+ boolean "support HX8369B Vivalto VE mipi panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G
+ default n
+
+config FB_LCD_HX8369B_MIPI_KIRAN3G
+ boolean "support HX8369B MIPI panel for KIRAN3G"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G
+ default n
+
+config FB_LCD_S6D77A1_MIPI_PIKEA_J1
+ boolean "support s6d77a1 MIPI panel for PikeA J1"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G
+ default n
+
+config FB_LCD_S6D0139
+ boolean "support S6D0139 panel"
+ depends on FB_SC8825 || FB_SCX35
+ default n
+
+config FB_LCD_NT35516_MIPI
+ boolean "support NT35516 mipi panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G || FB_SCX35L
+ default n
+
+config FB_LCD_NT35596H_MIPI
+ boolean "support NT35596H mipi panel"
+ default n
+
+config FB_LCD_FL10802_MIPI
+ boolean "support FL10802 mipi panel"
+ default n
+
+config FB_LCD_JD9161_MIPI
+ boolean "support JD9161 mipi panel"
+ default n
+
+config FB_LCD_ILI6150_LVDS
+ boolean "support ILI6150 lvds panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G || FB_SCX35L
+ default n
+
+config FB_LCD_RM68180_MIPI
+ boolean "support rm68180 mipi panel"
+ depends on FB_SCX35 || FB_SCX35L || FB_SCX30G
+ default n
+
+config FB_LCD_HX8394D_MIPI
+ boolean "support HX8394D mipi panel"
+ default n
+
+config FB_LCD_DUMMY
+ boolean "support DUMMY panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G || FB_SCX35L
+ default y
+
+config FB_LCD_NT35502_MIPI
+ boolean "support NT35502 mipi panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G
+ default n
+
+config FB_LCD_ILI9486S1_MIPI
+ boolean "support ILI9486S1 mipi panel"
+ depends on FB_SCX35 || FB_SCX15 || FB_SCX30G
+ default n
+
+config FB_LCD_NT35516_RGB_I2C
+ boolean "support NT35516 rgb (i2c) panel"
+ depends on FB_SC8825 || FB_SCX35
+ default n
+
+config FB_LCD_NT35516_RGB_SPI
+ boolean "support NT35516 rgb (spi) panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX15
+ default n
+
+config FB_LCD_NT35516_MCU
+ boolean "support NT35516 mcu panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX15 || FB_SCX30G || FB_SCX35L
+ default n
+
+config FB_LCD_NT35510_MIPI
+ boolean "support NT35510 mipi panel"
+ depends on FB_SC8825 || FB_SCX35
+ default n
+
+config FB_LCD_NT35512_MIPI
+ boolean "support NT35512 mipi panel"
+ depends on FB_SC8825 || FB_SCX35
+ default n
+
+config FB_LCD_OTM8018B_MIPI
+ boolean "support otm 8018b mipi panel"
+ depends on FB_SC8825 || FB_SCX35
+ default n
+
+config FB_LCD_SSD2075_MIPI
+ boolean "support ssd2075 mipi panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G
+ default n
+
+config FB_LCD_ILI9486
+ boolean "support ILI9486 mcu panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX15
+ default n
+
+config FB_LCD_ILI9486_RGB_SPI
+ boolean "support ILI9486 rgb spi panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX15
+ default n
+
+config FB_LCD_SC7798_RGB_SPI
+ boolean "support SC7798 rgb spi panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX15
+ default n
+
+config FB_LCD_ILI9341
+ boolean "support ILI9341 mcu panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX15
+ default n
+
+config FB_LCD_ST7789V_MCU
+ boolean "support ST7789V mcu panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX15
+ default n
+
+config FB_LCD_NT51017_MIPI_LVDS
+ boolean "support nt51017 lvds panel"
+ depends on FB_SC8825 || FB_SCX35
+ default n
+
+config FB_LCD_HX8369B_MIPI
+ boolean "support hx8369b mipi panel"
+ depends on FB_SC8825 || FB_SCX35
+ default n
+
+config FB_LCD_OTM1283A_MIPI
+ boolean "support otm 1283a mipi panel"
+ depends on FB_SC8825 || FB_SCX35
+ default n
+
+config FB_LCD_ILI9806E_MIPI
+ boolean "support ili9806e mipi panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX35L
+ default n
+
+config FB_LCD_ILI9806E_2_MIPI
+ boolean "support ili9806e_2 mipi panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX35L || FB_SCX30G
+ default n
+
+config FB_LCD_T8861_MIPI
+ boolean "support t8861 mipi panel"
+ depends on FB_SC8825 || FB_SCX35
+ default n
+
+config FB_LCD_HX8379A_MIPI
+ boolean "support hx8379a mipi panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G
+ default n
+
+config FB_LCD_HX8389C_MIPI
+ boolean "support hx8389c mipi panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G
+ default n
+
+config FB_LCD_S6D7AA0X62_MIPI
+ boolean "support S6D7AA0X62 mipi panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G || FB_SCX35L
+ default n
+
+config FB_LCD_OTM8019A_MIPI
+ boolean "support otm8019a mipi panel"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G || FB_SCX35L
+ default n
+
+config FB_LCD_HX8394A_MIPI
+ boolean "support hx8394a mipi panel"
+ default n
+
+config FB_LCD_RESERVE_MEM
+ boolean "support FB reserve mem"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX15 || FB_SCX30G || FB_SCX35L
+ default n
+
+config FB_LCD_OVERLAY_SUPPORT
+ boolean "support lcd overlay"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX15 || FB_SCX30G || FB_SCX35L
+ default n
+
+config FB_VSYNC_SUPPORT
+ boolean "support wait for vsync io"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX15 || FB_SCX30G || FB_SCX35L
+ default y
+
+config FB_ESD_SUPPORT
+ boolean "support esd check"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G || FB_SCX35L
+ default n
+
+config FB_DYNAMIC_CLK_SUPPORT
+ boolean "support close clk dynamically"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX30G || FB_SCX35L
+ default n
+
+config FB_DYNAMIC_FREQ_SCALING
+ boolean "support change mipi clk/fps/dpi clk dynamically"
+ depends on FB_SC8825 || FB_SCX35 || FB_SCX15 || FB_SCX30G || FB_SCX35L
+ default y
+
+config FB_USE_MEGACORES_MIPI_DPHY
+ boolean "support megacores mipi dphy"
+ depends on FB
+ default n
+
+config FB_MMAP_CACHED
+ boolean "support fb_mmap with cach"
+ depends on FB_SC8825 || FB_SCX35 ||FB_SCX15
+ default n
+
+config FB_LOW_RES_SIMU
+ boolean "support low resolution simulator"
+ depends on FB_SC8825 || FB_SCX35 ||FB_SCX15 || FB_SCX30G || FB_SCX35L
+ default n
+
+config FB_TRIPLE_FRAMEBUFFER
+ boolean "support triple buffer"
+ depends on FB_SC8825 || FB_SCX35 ||FB_SCX15 || FB_SCX30G || FB_SCX35L
+ default y
+endif
diff --git a/drivers/video/sprdfb/Makefile b/drivers/video/sprdfb/Makefile
new file mode 100644
index 00000000..f54afdcc
--- /dev/null
+++ b/drivers/video/sprdfb/Makefile
@@ -0,0 +1,35 @@
+obj-$(CONFIG_FB_SCX35) := sprdfb_main.o sprdfb_panel.o sprdfb_dispc.o sprdfb_mcu.o sprdfb_rgb.o sprdfb_mipi.o sprdfb_i2c.o sprdfb_spi.o sprdfb_dsi.o sprdfb_chip_common.o sprdfb_chip_8830.o
+obj-$(CONFIG_FB_SCX35) += dsi_1_10a/
+obj-$(CONFIG_FB_SCX35) += spi/
+obj-$(CONFIG_FB_SCX35) += lcd/
+
+obj-$(CONFIG_FB_SCX30G) := sprdfb_main.o sprdfb_panel.o sprdfb_dispc.o sprdfb_mcu.o sprdfb_rgb.o sprdfb_mipi.o sprdfb_i2c.o sprdfb_spi.o sprdfb_dsi.o sprdfb_chip_common.o sprdfb_chip_8830.o
+obj-$(CONFIG_FB_SCX30G) += dsi_1_21a/
+obj-$(CONFIG_FB_SCX30G) += spi/
+obj-$(CONFIG_FB_SCX30G) += lcd/
+obj-$(CONFIG_FB_SCX15) := sprdfb_main.o sprdfb_panel.o sprdfb_dispc.o sprdfb_mcu.o sprdfb_rgb.o sprdfb_i2c.o sprdfb_spi.o sprdfb_chip_common.o sprdfb_chip_7715.o
+obj-$(CONFIG_FB_SCX15) += spi/
+obj-$(CONFIG_FB_SCX15) += lcd/
+obj-$(CONFIG_FB_DYNAMIC_FPS_SUPPORT) += sprdfb_notifier.o
+
+# ========== SharkL/TSharkL configuration begin ===========
+ifeq ($(CONFIG_FB_SCX35L), y)
+obj-y := sprdfb_main.o sprdfb_panel.o sprdfb_dispc.o
+obj-y += sprdfb_dsi.o sprdfb_mipi.o sprdfb_rgb.o sprdfb_mcu.o
+obj-y += sprdfb_chip_common.o sprdfb_chip_9630.o
+obj-$(CONFIG_I2C) += sprdfb_i2c.o
+obj-$(CONFIG_SPI) += sprdfb_spi.o
+endif
+
+ifeq ($(CONFIG_SC_FPGA), y)
+obj-$(CONFIG_FB_SCX35L) += sprdfb_gpio2spi.o
+endif
+
+obj-$(CONFIG_FB_SCX35L) += dsi_1_21a/
+obj-$(CONFIG_FB_SCX35L) += spi/
+obj-$(CONFIG_FB_SCX35L) += lcd/
+# ========== SharkL/TSharkL configuration end ============
+
+# This file is used for creating file node
+obj-y += sprdfb_attr.o
+
diff --git a/drivers/video/sprdfb/dsi_1_10a/Makefile b/drivers/video/sprdfb/dsi_1_10a/Makefile
new file mode 100644
index 00000000..f5970668
--- /dev/null
+++ b/drivers/video/sprdfb/dsi_1_10a/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_FB_SC8825) := mipi_dsih_api.o mipi_dsih_dphy.o mipi_dsih_hal.o
+obj-$(CONFIG_FB_SCX35) := mipi_dsih_api.o mipi_dsih_dphy.o mipi_dsih_hal.o
diff --git a/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.c b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.c
new file mode 100644
index 00000000..4747338c
--- /dev/null
+++ b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.c
@@ -0,0 +1,1216 @@
+
+#include "mipi_dsih_api.h"
+#include "mipi_dsih_hal.h"
+#include "mipi_dsih_dphy.h"
+#include "../sprdfb.h"
+#include <linux/delay.h>
+
+/* whether to get debug messages (1) or not (0) */
+#define DEBUG 0
+
+#define PRECISION_FACTOR 1000
+#define VIDEO_PACKET_OVERHEAD 6
+#define NULL_PACKET_OVERHEAD 6
+#define SHORT_PACKET 4
+#define BLANKING_PACKET 6
+#define MAX_NULL_SIZE 1023
+
+static const uint32_t mipi_dsih_supported_versions[] = {0x3130302A, 0x3130312A, 0x3131302A};
+static const uint32_t mipi_dsih_no_of_versions = sizeof(mipi_dsih_supported_versions) / sizeof(uint32_t);
+
+/*
+func:mipi_dsih_set_lp_clock
+desc:in low-power mode, max PHY frequency should smaller than 20MHz,
+ in synopsys IP, low-power clock divide from high-speed clock,
+ this function is designed to adapt low-power clock to various high-speed clock.
+arithmetic:
+ Fhs : high-speed frequence
+ Flp : low-power frequence
+ div : mipi_dsih_hal_tx_escape_division() param, byte clock unit.
+ because of the 20MHz demand, Flp == Fhs/(div*8) <= 20 MHz, here 500000 present 500MHz, so MHz equal 1000
+ so div >= { Fhs/(20Mhz*8) == Fhs/(20000*8) == (Fhs>>4)/10000 }
+*/
+static void mipi_dsih_set_lp_clock(dsih_ctrl_t * instance)
+{
+ uint32_t tx_escape_division = 1;
+ tx_escape_division = (instance->phy_feq>>4);
+ tx_escape_division = (tx_escape_division+9999)/10000;//ceiling calc
+ printk("sprdfb: [%s]: lp frequence div:%d\n", __func__, tx_escape_division);
+ mipi_dsih_hal_tx_escape_division(instance, (uint8_t)tx_escape_division);
+}
+
+dsih_error_t mipi_dsih_open(dsih_ctrl_t * instance)
+{
+ dsih_error_t err = OK;
+ uint32_t version = 0;
+ int i = 0;
+
+ if (instance == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ else if ((instance->core_read_function == 0) || (instance->core_write_function == 0))
+ {
+ return ERR_DSI_INVALID_IO;
+ }
+ else if (instance->status == INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ else if (mipi_dsih_dphy_open(&(instance->phy_instance)))
+ {
+ return ERR_DSI_PHY_INVALID;
+ }
+ else
+ {
+ instance->status = NOT_INITIALIZED;
+ version = mipi_dsih_hal_get_version(instance);
+ for (i = 0; i < mipi_dsih_no_of_versions; i++)
+ {
+ if (version == mipi_dsih_supported_versions[i])
+ {
+ break;
+ }
+ }
+ /* no matching supported version has been found*/
+ if (i >= mipi_dsih_no_of_versions)
+ {
+ if (instance->log_info != 0)
+ {
+ instance->log_info("sprdfb: driver does not support this core version 0x%lX", version);
+ }
+ return ERR_DSI_CORE_INCOMPATIBLE;
+ }
+ }
+ //mipi_dsih_hal_power(instance, 0);//Jessica
+ //mipi_dsih_hal_power(instance, 1);//Jessica
+ mipi_dsih_hal_dpi_color_mode_pol(instance, !instance->color_mode_polarity);
+ mipi_dsih_hal_dpi_shut_down_pol(instance, !instance->shut_down_polarity);
+ err = mipi_dsih_phy_hs2lp_config(instance, instance->max_hs_to_lp_cycles);
+ err |= mipi_dsih_phy_lp2hs_config(instance, instance->max_lp_to_hs_cycles);
+ err |= mipi_dsih_phy_bta_time(instance, instance->max_bta_cycles);
+ if (err)
+ {
+ return ERR_DSI_OVERFLOW;
+ }
+ /* by default, return to LP during ALL, unless otherwise specified*/
+ mipi_dsih_hal_dpi_lp_during_hfp(instance, 1);
+ mipi_dsih_hal_dpi_lp_during_hbp(instance, 1);
+ mipi_dsih_hal_dpi_lp_during_vactive(instance, 1);
+ mipi_dsih_hal_dpi_lp_during_vfp(instance, 1);
+ mipi_dsih_hal_dpi_lp_during_vbp(instance, 1);
+ mipi_dsih_hal_dpi_lp_during_vsync(instance, 1);
+ /* by default, all commands are sent in LP */
+ mipi_dsih_hal_dcs_wr_tx_type(instance, 0, 1);
+ mipi_dsih_hal_dcs_wr_tx_type(instance, 1, 1);
+ mipi_dsih_hal_dcs_wr_tx_type(instance, 3, 1); /* long packet*/
+ mipi_dsih_hal_dcs_rd_tx_type(instance, 0, 1);
+ /*Jessica add to support max rd packet size command*/
+ mipi_dsih_hal_max_rd_packet_size_type(instance, 1);
+ mipi_dsih_hal_gen_wr_tx_type(instance, 0, 1);
+ mipi_dsih_hal_gen_wr_tx_type(instance, 1, 1);
+ mipi_dsih_hal_gen_wr_tx_type(instance, 2, 1);
+ mipi_dsih_hal_gen_wr_tx_type(instance, 3, 1); /* long packet*/
+ mipi_dsih_hal_gen_rd_tx_type(instance, 0, 1);
+ mipi_dsih_hal_gen_rd_tx_type(instance, 1, 1);
+ mipi_dsih_hal_gen_rd_tx_type(instance, 2, 1);
+ /* by default, RX_VC = 0, NO EOTp, EOTn, BTA, ECC rx and CRC rx */
+ mipi_dsih_hal_gen_rd_vc(instance, 0);
+ mipi_dsih_hal_gen_eotp_rx_en(instance, 0);
+ mipi_dsih_hal_gen_eotp_tx_en(instance, 0);
+ mipi_dsih_hal_bta_en(instance, 0);
+ mipi_dsih_hal_gen_ecc_rx_en(instance, 0);
+ mipi_dsih_hal_gen_crc_rx_en(instance, 0);
+ mipi_dsih_hal_power(instance, 0);//Jessica
+ mipi_dsih_hal_power(instance, 1);//Jessica
+ /* initialize pll so escape clocks could be generated at 864MHz, 1 lane */
+ /* however the high speed clock will not be requested */
+ //err = mipi_dsih_dphy_configure(&(instance->phy_instance), 1, DEFAULT_BYTE_CLOCK);
+#if 0
+ err = mipi_dsih_dphy_configure(&(instance->phy_instance), instance->max_lanes, 190*1000);
+ if (err)
+ {
+ return err; /* ERR_DSI_PHY_POWERUP; */
+ }
+#endif
+ /* dividing by 6 is aimed for max PHY frequency, 1GHz */
+ //mipi_dsih_hal_tx_escape_division(instance, 4); //6 //Jessica
+ mipi_dsih_set_lp_clock(instance);
+ instance->status = INITIALIZED;
+ return OK;
+}
+dsih_error_t mipi_dsih_close(dsih_ctrl_t * instance)
+{
+ if (instance == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ mipi_dsih_dphy_close(&(instance->phy_instance));
+ mipi_dsih_hal_power(instance, 0);
+ return OK;
+}
+void mipi_dsih_allow_return_to_lp(dsih_ctrl_t * instance, int hfp, int hbp, int vactive, int vfp, int vbp, int vsync)
+{
+ if(0 == instance)
+ {
+ return;
+ }
+
+ if (instance->status == INITIALIZED)
+ {
+ mipi_dsih_hal_dpi_lp_during_hfp(instance, hfp);
+ mipi_dsih_hal_dpi_lp_during_hbp(instance, hbp);
+ mipi_dsih_hal_dpi_lp_during_vactive(instance, vactive);
+ mipi_dsih_hal_dpi_lp_during_vfp(instance, vfp);
+ mipi_dsih_hal_dpi_lp_during_vbp(instance, vbp);
+ mipi_dsih_hal_dpi_lp_during_vsync(instance, vsync);
+ return;
+ }
+
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: invalid instance");
+ }
+}
+void mipi_dsih_dcs_cmd_lp_transmission(dsih_ctrl_t * instance, int long_write, int short_write, int short_read)
+{
+ if(0 == instance)
+ {
+ return;
+ }
+
+ if (instance->status == INITIALIZED)
+ {
+ mipi_dsih_hal_dcs_wr_tx_type(instance, 0, short_write);
+ mipi_dsih_hal_dcs_wr_tx_type(instance, 1, short_write);
+ mipi_dsih_hal_dcs_wr_tx_type(instance, 3, long_write); /* long packet*/
+ mipi_dsih_hal_dcs_rd_tx_type(instance, 0, short_read);
+ return;
+ }
+
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: invalid instance");
+ }
+}
+void mipi_dsih_gen_cmd_lp_transmission(dsih_ctrl_t * instance, int long_write, int short_write, int short_read)
+{
+ if(0 == instance)
+ {
+ return;
+ }
+
+ if (instance->status == INITIALIZED)
+ {
+ mipi_dsih_hal_gen_wr_tx_type(instance, 0, short_write);
+ mipi_dsih_hal_gen_wr_tx_type(instance, 1, short_write);
+ mipi_dsih_hal_gen_wr_tx_type(instance, 2, short_write);
+ mipi_dsih_hal_gen_wr_tx_type(instance, 3, long_write); /* long packet*/
+ mipi_dsih_hal_gen_rd_tx_type(instance, 0, short_read);
+ mipi_dsih_hal_gen_rd_tx_type(instance, 1, short_read);
+ mipi_dsih_hal_gen_rd_tx_type(instance, 2, short_read);
+ return;
+ }
+
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: invalid instance");
+ }
+}
+/* packet handling */
+dsih_error_t mipi_dsih_enable_rx(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_hal_bta_en(instance, enable);
+ return OK;
+}
+dsih_error_t mipi_dsih_peripheral_ack(dsih_ctrl_t * instance, int enable)
+{
+ if (instance != 0)
+ {
+ if (instance->status == INITIALIZED)
+ {
+ mipi_dsih_hal_cmd_ack_en(instance, enable);
+ if (enable)
+ {
+ mipi_dsih_hal_bta_en(instance, 1);
+ }
+ return OK;
+ }
+ }
+ return ERR_DSI_INVALID_INSTANCE;
+}
+dsih_error_t mipi_dsih_tear_effect_ack(dsih_ctrl_t * instance, int enable)
+{
+ if (instance != 0)
+ {
+ if (instance->status == INITIALIZED)
+ {
+ mipi_dsih_hal_tear_effect_ack_en(instance, enable);
+ if (enable)
+ {
+ mipi_dsih_hal_bta_en(instance, 1);
+ }
+ return OK;
+ }
+ }
+ return ERR_DSI_INVALID_INSTANCE;
+}
+dsih_error_t mipi_dsih_eotp_rx(dsih_ctrl_t * instance, int enable)
+{
+ if (instance != 0)
+ {
+ if (instance->status == INITIALIZED)
+ {
+ mipi_dsih_hal_gen_eotp_rx_en(instance, enable);
+ if (enable)
+ {
+ mipi_dsih_hal_bta_en(instance, 1);
+ }
+ return OK;
+ }
+ }
+ return ERR_DSI_INVALID_INSTANCE;
+}
+dsih_error_t mipi_dsih_ecc_rx(dsih_ctrl_t * instance, int enable)
+{
+ if (instance != 0)
+ {
+ if (instance->status == INITIALIZED)
+ {
+ mipi_dsih_hal_gen_ecc_rx_en(instance, enable);
+ if (enable)
+ {
+ mipi_dsih_hal_bta_en(instance, 1);
+ }
+ return OK;
+ }
+ }
+ return ERR_DSI_INVALID_INSTANCE;
+}
+dsih_error_t mipi_dsih_eotp_tx(dsih_ctrl_t * instance, int enable)
+{
+ if (instance != 0)
+ {
+ if (instance->status == INITIALIZED)
+ {
+ mipi_dsih_hal_gen_eotp_tx_en(instance, enable);
+ return OK;
+ }
+ }
+ return ERR_DSI_INVALID_INSTANCE;
+}
+dsih_error_t mipi_dsih_dpi_video(dsih_ctrl_t * instance, dsih_dpi_video_t * video_params)
+{
+ dsih_error_t err_code = OK;
+ uint16_t bytes_per_pixel_x100 = 0; /* bpp x 100 because it can be 2.25 */
+ uint16_t video_size = 0;
+ uint32_t ratio_clock_xPF = 0; /* holds dpi clock/byte clock times precision factor */
+ uint16_t null_packet_size = 0;
+ uint8_t video_size_step = 1;
+ uint32_t hs_timeout = 0;
+ uint32_t total_bytes = 0;
+ uint32_t bytes_per_chunk = 0;
+ uint32_t no_of_chunks = 0;
+ uint32_t bytes_left = 0;
+ uint32_t chunk_overhead = 0;
+ int counter = 0;
+ /* check DSI controller instance */
+ if ((instance == 0) || (video_params == 0))
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ /* set up phy pll to required lane clock */
+ //begin--frank
+ //err_code = mipi_dsih_dphy_configure(&(instance->phy_instance), video_params->no_of_lanes, video_params->byte_clock * 8);
+ //if (err_code)
+ //{
+ // return err_code;
+ //}
+ //end--frank
+ ratio_clock_xPF = (video_params->byte_clock * PRECISION_FACTOR) / (video_params->pixel_clock);
+ video_size = video_params->h_active_pixels;
+ /* set up ACKs and error reporting */
+ mipi_dsih_hal_dpi_frame_ack_en(instance, video_params->receive_ack_packets);
+ if (video_params->receive_ack_packets)
+ { /* if ACK is requested, enable BTA, otherwise leave as is */
+ mipi_dsih_hal_bta_en(instance, 1);
+ }
+ mipi_dsih_hal_gen_cmd_mode_en(instance, 0);
+ mipi_dsih_hal_dpi_video_mode_en(instance, 1);
+ /* get bytes per pixel and video size step (depending if loosely or not */
+ switch (video_params->color_coding)
+ {
+ case COLOR_CODE_16BIT_CONFIG1:
+ case COLOR_CODE_16BIT_CONFIG2:
+ case COLOR_CODE_16BIT_CONFIG3:
+ bytes_per_pixel_x100 = 200;
+ video_size_step = 1;
+ break;
+ case COLOR_CODE_18BIT_CONFIG1:
+ case COLOR_CODE_18BIT_CONFIG2:
+ mipi_dsih_hal_dpi_18_loosely_packet_en(instance, video_params->is_18_loosely);
+ bytes_per_pixel_x100 = 225;
+ if (!video_params->is_18_loosely)
+ { /* 18bits per pixel and NOT loosely, packets should be multiples of 4 */
+ video_size_step = 4;
+ /* round up active H pixels to a multiple of 4 */
+ for (; (video_size % 4) != 0; video_size++)
+ {
+ ;
+ }
+ }
+ else
+ {
+ video_size_step = 1;
+ }
+ break;
+ case COLOR_CODE_24BIT:
+ bytes_per_pixel_x100 = 300;
+ video_size_step = 1;
+ break;
+ default:
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: invalid color coding");
+ }
+ err_code = ERR_DSI_COLOR_CODING;
+ break;
+ }
+ if (err_code == OK)
+ {
+ err_code = mipi_dsih_hal_dpi_color_coding(instance, video_params->color_coding);
+ }
+ if (err_code != OK)
+ {
+ return err_code;
+ }
+ mipi_dsih_hal_dpi_video_mode_type(instance, video_params->video_mode);
+ mipi_dsih_hal_dpi_hline(instance, (uint16_t)(((video_params->h_total_pixels) * ratio_clock_xPF) / PRECISION_FACTOR));
+ mipi_dsih_hal_dpi_hbp(instance, ((video_params->h_back_porch_pixels * ratio_clock_xPF) / PRECISION_FACTOR));
+ mipi_dsih_hal_dpi_hsa(instance, ((video_params->h_sync_pixels * ratio_clock_xPF) / PRECISION_FACTOR));
+ mipi_dsih_hal_dpi_vactive(instance, video_params->v_active_lines);
+ mipi_dsih_hal_dpi_vfp(instance, video_params->v_total_lines - (video_params->v_back_porch_lines + video_params->v_sync_lines + video_params->v_active_lines));
+ mipi_dsih_hal_dpi_vbp(instance, video_params->v_back_porch_lines);
+ mipi_dsih_hal_dpi_vsync(instance, video_params->v_sync_lines);
+ mipi_dsih_hal_dpi_hsync_pol(instance, !video_params->h_polarity);
+ mipi_dsih_hal_dpi_vsync_pol(instance, !video_params->v_polarity);
+ mipi_dsih_hal_dpi_dataen_pol(instance, !video_params->data_en_polarity);
+ /* HS timeout */
+ hs_timeout = ((video_params->h_total_pixels * video_params->v_active_lines) + (DSIH_PIXEL_TOLERANCE * bytes_per_pixel_x100) / 100);
+ for (counter = 0x80; (counter < hs_timeout) && (counter > 2); counter--)
+ {
+ if ((hs_timeout % counter) == 0)
+ {
+ mipi_dsih_hal_timeout_clock_division(instance, counter);
+ mipi_dsih_hal_lp_rx_timeout(instance, (uint16_t)(hs_timeout / counter));
+ mipi_dsih_hal_hs_tx_timeout(instance, (uint16_t)(hs_timeout / counter));
+ break;
+ }
+ }
+ /* TX_ESC_CLOCK_DIV must be less than 20000KHz */
+ //mipi_dsih_hal_tx_escape_division(instance, 4); //6 //Jessia
+ mipi_dsih_set_lp_clock(instance);
+ /* video packetisation */
+ if (video_params->video_mode == VIDEO_BURST_WITH_SYNC_PULSES)
+ { /* BURST */
+ mipi_dsih_hal_dpi_null_packet_en(instance, 0);
+ mipi_dsih_hal_dpi_multi_packet_en(instance, 0);
+ err_code = mipi_dsih_hal_dpi_null_packet_size(instance, 0);
+ err_code = err_code? err_code: mipi_dsih_hal_dpi_chunks_no(instance, 1);
+ err_code = err_code? err_code: mipi_dsih_hal_dpi_video_packet_size(instance, video_size);
+ if (err_code != OK)
+ {
+ return err_code;
+ }
+ /* BURST by default, returns to LP during ALL empty periods - energy saving */
+ mipi_dsih_hal_dpi_lp_during_hfp(instance, 1);
+#if defined(CONFIG_FB_LCD_SSD2075_MIPI)
+ mipi_dsih_hal_dpi_lp_during_hbp(instance, 0);
+#else
+ mipi_dsih_hal_dpi_lp_during_hbp(instance, 1);
+#endif
+ mipi_dsih_hal_dpi_lp_during_vactive(instance, 1);
+ mipi_dsih_hal_dpi_lp_during_vfp(instance, 1);
+ mipi_dsih_hal_dpi_lp_during_vbp(instance, 1);
+ mipi_dsih_hal_dpi_lp_during_vsync(instance, 1);
+#if DEBUG
+ /* D E B U G */
+ if (instance->log_info != 0)
+ {
+ instance->log_info("sprdfb: burst video");
+ instance->log_info("sprdfb: h line time %ld", (uint16_t)((video_params->h_total_pixels * ratio_clock_xPF) / PRECISION_FACTOR));
+ instance->log_info("sprdfb: video_size %ld", video_size);
+ }
+#endif
+ }
+ else
+ { /* non burst transmission */
+ null_packet_size = 0;
+ /* bytes to be sent - first as one chunk*/
+ bytes_per_chunk = (bytes_per_pixel_x100 * video_params->h_active_pixels) / 100 + VIDEO_PACKET_OVERHEAD;
+ /* bytes being received through the DPI interface per byte clock cycle */
+ total_bytes = (ratio_clock_xPF * video_params->no_of_lanes * (video_params->h_total_pixels - video_params->h_back_porch_pixels - video_params->h_sync_pixels)) / PRECISION_FACTOR;
+ /* check if the in pixels actually fit on the DSI link */
+ if (total_bytes >= bytes_per_chunk)
+ {
+ chunk_overhead = total_bytes - bytes_per_chunk;
+ /* overhead higher than 1 -> enable multi packets */
+ if (chunk_overhead > 1)
+ { /* MULTI packets */
+ for (video_size = video_size_step; video_size < video_params->h_active_pixels; video_size += video_size_step)
+ { /* determine no of chunks */
+ if ((((video_params->h_active_pixels * PRECISION_FACTOR) / video_size) % PRECISION_FACTOR) == 0)
+ {
+ no_of_chunks = video_params->h_active_pixels / video_size;
+ bytes_per_chunk = (bytes_per_pixel_x100 * video_size) / 100 + VIDEO_PACKET_OVERHEAD;
+ if (total_bytes >= (bytes_per_chunk * no_of_chunks))
+ {
+ bytes_left = total_bytes - (bytes_per_chunk * no_of_chunks);
+ break;
+ }
+ }
+ }
+ /* prevent overflow (unsigned - unsigned) */
+ if (bytes_left > (NULL_PACKET_OVERHEAD * no_of_chunks))
+ {
+ null_packet_size = (bytes_left - (NULL_PACKET_OVERHEAD * no_of_chunks)) / no_of_chunks;
+ if (null_packet_size > MAX_NULL_SIZE)
+ { /* avoid register overflow */
+ null_packet_size = MAX_NULL_SIZE;
+ }
+ }
+ }
+ else
+ { /* no multi packets */
+ no_of_chunks = 1;
+#if DEBUG
+ /* D E B U G */
+ if (instance->log_info != 0)
+ {
+ instance->log_info("sprdfb: no multi no null video");
+ instance->log_info("sprdfb: h line time %ld", (uint16_t)((video_params->h_total_pixels * ratio_clock_xPF) / PRECISION_FACTOR));
+ instance->log_info("sprdfb: video_size %ld", video_size);
+ }
+ /************************/
+#endif
+ /* video size must be a multiple of 4 when not 18 loosely */
+ for (video_size = video_params->h_active_pixels; (video_size % video_size_step) != 0; video_size++)
+ {
+ ;
+ }
+ }
+ }
+ else
+ {
+ instance->log_error("sprdfb: resolution cannot be sent to display through current settings");
+ err_code = ERR_DSI_OVERFLOW;
+ }
+ }
+ err_code = err_code? err_code: mipi_dsih_hal_dpi_chunks_no(instance, no_of_chunks);
+ err_code = err_code? err_code: mipi_dsih_hal_dpi_video_packet_size(instance, video_size);
+ err_code = err_code? err_code: mipi_dsih_hal_dpi_null_packet_size(instance, null_packet_size);
+ mipi_dsih_hal_dpi_null_packet_en(instance, null_packet_size > 0? 1: 0);
+ mipi_dsih_hal_dpi_multi_packet_en(instance, (no_of_chunks > 1)? 1: 0);
+#if DEBUG
+ /* D E B U G */
+ if (instance->log_info != 0)
+ {
+ instance->log_info("sprdfb: total_bytes %d", total_bytes);
+ instance->log_info("sprdfb: bytes_per_chunk %d", bytes_per_chunk);
+ instance->log_info("sprdfb: bytes left %d", bytes_left);
+ instance->log_info("sprdfb: null packets %d", null_packet_size);
+ instance->log_info("sprdfb: chunks %ld", no_of_chunks);
+ instance->log_info("sprdfb: video_size %ld", video_size);
+ }
+ /************************/
+#endif
+ mipi_dsih_hal_dpi_video_vc(instance, video_params->virtual_channel);
+ mipi_dsih_dphy_no_of_lanes(&(instance->phy_instance), video_params->no_of_lanes);
+ /* enable high speed clock */
+// mipi_dsih_dphy_enable_hs_clk(&(instance->phy_instance), 1);
+ return err_code;
+}
+dsih_error_t mipi_dsih_dcs_wr_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t* params, uint16_t param_length)
+{
+ uint8_t packet_type = 0;
+// int i = 0;
+ if (params == 0)
+ {
+ return ERR_DSI_OUT_OF_BOUND;
+ }
+#if 0
+ if (param_length > 2)
+ {
+ i = 2;
+ }
+ switch (params[i])
+ {
+ case 0x39:
+ case 0x38:
+ case 0x34:
+ case 0x29:
+ case 0x28:
+ case 0x21:
+ case 0x20:
+ case 0x13:
+ case 0x12:
+ case 0x11:
+ case 0x10:
+ case 0x01:
+ case 0x00:
+ packet_type = 0x05; /* DCS short write no param */
+ break;
+ case 0x3A:
+ case 0x36:
+ case 0x35:
+ case 0x26:
+ packet_type = 0x15; /* DCS short write 1 param */
+ break;
+ case 0x44:
+ case 0x3C:
+ case 0x37:
+ case 0x33:
+ case 0x30:
+ case 0x2D:
+ case 0x2C:
+ case 0x2B:
+ case 0x2A:
+ packet_type = 0x39; /* DCS long write/write_LUT command packet */
+ break;
+ default:
+ if (instance->log_error != 0)
+ {
+ instance->log_error("invalid DCS command");
+ }
+ return ERR_DSI_INVALID_COMMAND;
+ }
+#endif
+ switch(param_length)
+ {
+ case 1:
+ packet_type = 0x05; /* DCS short write no param */
+ break;
+ case 2:
+ packet_type = 0x15; /* DCS short write 1 param */
+ break;
+ default:
+ packet_type = 0x39; /* DCS long write/write_LUT command packet */
+ break;
+ }
+
+ return mipi_dsih_gen_wr_packet(instance, vc, packet_type, params, param_length);
+}
+void mipi_dsih_cmd_mode(dsih_ctrl_t * instance, int en)
+{
+ if(0 == instance)
+ {
+ return;
+ }
+
+ if (instance->status == INITIALIZED)
+ {
+ if ((!mipi_dsih_hal_gen_is_cmd_mode(instance)) && en)
+ { /* disable video mode first */
+ mipi_dsih_hal_dpi_video_mode_en(instance, 0);
+ mipi_dsih_hal_gen_cmd_mode_en(instance, 1);
+ }
+ else if ((mipi_dsih_hal_gen_is_cmd_mode(instance)) && !en)
+ {
+ mipi_dsih_hal_gen_cmd_mode_en(instance, 0);
+ }
+ return;
+ }
+
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: invalid instance");
+ }
+}
+
+void mipi_dsih_video_mode(dsih_ctrl_t * instance, int en)
+{
+ if(0 == instance)
+ {
+ return;
+ }
+
+ if (instance->status == INITIALIZED)
+ {
+ if ((!mipi_dsih_hal_dpi_is_video_mode(instance)) && en)
+ { /* disable cmd mode first */
+ mipi_dsih_hal_gen_cmd_mode_en(instance, 0);
+ mipi_dsih_hal_dpi_video_mode_en(instance, 1);
+ }
+ else if ((!mipi_dsih_hal_dpi_is_video_mode(instance)) && !en)
+ {
+ mipi_dsih_hal_dpi_video_mode_en(instance, 0);
+ }
+ return;
+ }
+
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: invalid instance");
+ }
+}
+
+int mipi_dsih_active_mode(dsih_ctrl_t * instance)
+{
+ int ret_val=0;
+ if (mipi_dsih_hal_gen_is_cmd_mode(instance))
+ {
+ ret_val=ret_val|0x1;
+ }
+ if (mipi_dsih_hal_dpi_is_video_mode(instance))
+ {
+ ret_val=ret_val|0x2;
+ }
+ return ret_val;
+}
+
+dsih_error_t mipi_dsih_gen_wr_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t* params, uint16_t param_length)
+{
+ uint8_t data_type = 0;
+ switch(param_length)
+ {
+ case 0:
+ data_type = 0x03;
+ break;
+ case 1:
+ data_type = 0x13;
+ break;
+ case 2:
+ data_type = 0x23;
+ break;
+ default:
+ data_type = 0x29;
+ break;
+ }
+ return mipi_dsih_gen_wr_packet(instance, vc, data_type, params, param_length);
+}
+dsih_error_t mipi_dsih_gen_wr_packet(dsih_ctrl_t * instance, uint8_t vc, uint8_t data_type, uint8_t* params, uint16_t param_length)
+{
+ dsih_error_t err_code = OK;
+ /* active delay iterator */
+ int timeout = 0;
+ /* iterators */
+ int i = 0;
+ int j = 0;
+ /* holds padding bytes needed */
+ int compliment_counter = 0;
+ uint8_t* payload = 0;
+ /* temporary variable to arrange bytes into words */
+ uint32_t temp = 0;
+ uint16_t word_count = 0;
+ if (instance == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if ((params == 0) && (param_length != 0)) /* pointer NULL */
+ {
+ return ERR_DSI_OUT_OF_BOUND;
+ }
+ if (param_length > 2)
+ { /* long packet - write word count to header, and the rest to payload */
+ payload = params + (2 * sizeof(params[0]));
+ word_count = (params[1] << 8) | params[0];
+ if ((param_length - 2) < word_count)
+ {
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: sent > input payload. complemented with zeroes");
+ }
+ compliment_counter = (param_length - 2) - word_count;
+ }
+ else if ((param_length - 2) > word_count)
+ {
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: Overflow - input > sent. payload truncated");
+ }
+ }
+ for (i = 0; i < (param_length - 2); i += j)
+ {
+ temp = 0;
+ for (j = 0; (j < 4) && ((j + i) < (param_length - 2)); j++)
+ { /* temp = (payload[i + 3] << 24) | (payload[i + 2] << 16) | (payload[i + 1] << 8) | payload[i]; */
+ temp |= payload[i + j] << (j * 8);
+ }
+ /* check if payload Tx fifo is not full */
+ for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++)
+ {
+ if (!mipi_dsih_hal_gen_packet_payload(instance, temp))
+ {
+ break;
+ }
+ }
+ if (!(timeout < DSIH_FIFO_ACTIVE_WAIT))
+ {
+ return ERR_DSI_TIMEOUT;
+ }
+ }
+ /* if word count entered by the user more than actual parameters received
+ * fill with zeroes - a fail safe mechanism, otherwise controller will
+ * want to send data from an empty buffer */
+ for (i = 0; i < compliment_counter; i++)
+ {
+ /* check if payload Tx fifo is not full */
+ for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++)
+ {
+ if (!mipi_dsih_hal_gen_packet_payload(instance, 0x00))
+ {
+ break;
+ }
+ }
+ if (!(timeout < DSIH_FIFO_ACTIVE_WAIT))
+ {
+ return ERR_DSI_TIMEOUT;
+ }
+ }
+ }
+ for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++)
+ {
+ /* check if payload Tx fifo is not full */
+ if (!mipi_dsih_hal_gen_cmd_fifo_full(instance))
+ {
+ if (param_length == 0)
+ {
+ err_code |= mipi_dsih_hal_gen_packet_header(instance, vc, data_type, 0x0, 0x0);
+ }
+ else if (param_length == 1)
+ {
+ err_code |= mipi_dsih_hal_gen_packet_header(instance, vc, data_type, 0x0, params[0]);
+ }
+ else
+ {
+ err_code |= mipi_dsih_hal_gen_packet_header(instance, vc, data_type, params[1], params[0]);
+ }
+ break;
+ }
+ }
+ if (!(timeout < DSIH_FIFO_ACTIVE_WAIT))
+ {
+ err_code = ERR_DSI_TIMEOUT;
+ }
+ return err_code;
+}
+uint16_t mipi_dsih_dcs_rd_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t command, uint8_t bytes_to_read, uint8_t* read_buffer)
+{
+ if (instance == 0)
+ {
+ return 0;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return 0;
+ }
+ switch (command)
+ {
+ case 0xA8:
+ case 0xA1:
+ case 0x45:
+ case 0x3E:
+ case 0x2E:
+ case 0x0F:
+ case 0x0E:
+ case 0x0D:
+ case 0x0C:
+ case 0x0B:
+ case 0x0A:
+ case 0x08:
+ case 0x07:
+ case 0x06:
+ /* COMMAND_TYPE 0x06 - DCS Read no params refer to DSI spec p.47 */
+ return mipi_dsih_gen_rd_packet(instance, vc, 0x06, 0x0, command, bytes_to_read, read_buffer);
+ default:
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: invalid DCS command");
+ }
+ return 0;
+ }
+ return 0;
+}
+uint16_t mipi_dsih_gen_rd_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t* params, uint16_t param_length, uint8_t bytes_to_read, uint8_t* read_buffer)
+{
+ uint8_t data_type = 0;
+ if (instance == 0)
+ {
+ return 0;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return 0;
+ }
+ switch(param_length)
+ {
+ case 0:
+ data_type = 0x04;
+ return mipi_dsih_gen_rd_packet(instance, vc, data_type, 0x00, 0x00, bytes_to_read, read_buffer);
+ case 1:
+ data_type = 0x14;
+ return mipi_dsih_gen_rd_packet(instance, vc, data_type, 0x00, params[0], bytes_to_read, read_buffer);
+ case 2:
+ data_type = 0x24;
+ return mipi_dsih_gen_rd_packet(instance, vc, data_type, params[1], params[0], bytes_to_read, read_buffer);
+ default:
+ return 0;
+ }
+}
+uint16_t mipi_dsih_gen_rd_packet(dsih_ctrl_t * instance, uint8_t vc, uint8_t data_type, uint8_t msb_byte, uint8_t lsb_byte, uint8_t bytes_to_read, uint8_t* read_buffer)
+{
+ dsih_error_t err_code = OK;
+ int timeout = 0;
+ int counter = 0;
+ int i = 0;
+ int last_count = 0;
+ uint32_t temp[1] = {0};
+ if (instance == 0)
+ {
+ return 0;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return 0;
+ }
+ if (bytes_to_read < 1)
+ {
+ return 0;
+ }
+ if (read_buffer == 0)
+ {
+ return 0;
+ }
+#ifndef FB_CHECK_ESD_IN_VFP
+ /* make sure command mode is on */
+ mipi_dsih_cmd_mode(instance, 1);
+#endif
+ /* make sure receiving is enabled */
+ mipi_dsih_hal_bta_en(instance, 1);
+ /* listen to the same virtual channel as the one sent to */
+ mipi_dsih_hal_gen_rd_vc(instance, vc);
+ for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++)
+ { /* check if payload Tx fifo is not full */
+ if (!mipi_dsih_hal_gen_cmd_fifo_full(instance))
+ {
+ mipi_dsih_hal_gen_packet_header(instance, vc, data_type, msb_byte, lsb_byte);
+ break;
+ }
+ }
+ if (!(timeout < DSIH_FIFO_ACTIVE_WAIT))
+ {
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: tx rd command timed out\n");
+ }
+ return 0;
+ }
+ /* loop for the number of words to be read */
+ for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++)
+ { /* check if command transaction is done */
+ if (!mipi_dsih_hal_gen_rd_cmd_busy(instance))
+ {
+ if (!mipi_dsih_hal_gen_read_fifo_empty(instance))
+ {
+ for (counter = 0; (!mipi_dsih_hal_gen_read_fifo_empty(instance)); counter += 4)
+ {
+ err_code = mipi_dsih_hal_gen_read_payload(instance, temp);
+ if (err_code)
+ {
+ return 0;
+ }
+ if (counter < bytes_to_read)
+ {
+ for (i = 0; i < 4; i++)
+ {
+ if ((counter + i) < bytes_to_read)
+ {
+ /* put 32 bit temp in 4 bytes of buffer passed by user*/
+ read_buffer[counter + i] = (uint8_t)(temp[0] >> (i * 8));
+ last_count = i + counter;
+ }
+ else
+ {
+ if ((uint8_t)(temp[0] >> (i * 8)) != 0x00)
+ {
+ last_count = i + counter;
+ }
+ }
+ }
+ }
+ else
+ {
+ last_count = counter;
+ for (i = 0; i < 4; i++)
+ {
+ if ((uint8_t)(temp[0] >> (i * 8)) != 0x00)
+ {
+ last_count = i + counter;
+ }
+ }
+ }
+ }
+ return last_count + 1;
+ }
+#ifdef FB_CHECK_ESD_IN_VFP
+ else if(timeout == (DSIH_FIFO_ACTIVE_WAIT - 1))//else
+#else
+ else
+#endif
+ {
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: rx buffer empty\n");
+ }
+ return 0;
+ }
+ }
+//#ifdef FB_CHECK_ESD_IN_VFP
+ udelay(5);
+//#endif
+ }
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: rx command timed out\n");
+ }
+ return 0;
+}
+uint32_t mipi_dsih_dump_register_configuration(dsih_ctrl_t * instance, int all, register_config_t *config, uint16_t config_length)
+{
+ uint32_t current0 = 0;
+ uint16_t count = 0;
+ if (instance == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (all)
+ { /* dump all registers */
+ for (current0 = R_DSI_HOST_VERSION; current0 <= R_DSI_HOST_ERROR_MSK1; count++, current0 += (R_DSI_HOST_PWR_UP - R_DSI_HOST_VERSION))
+ {
+ if ((config_length == 0) || (config == 0) || count >= config_length)
+ { /* no place to write - write to STD IO */
+ if (instance->log_info != 0)
+ {
+ instance->log_info("sprdfb: DSI 0x%lX:0x%lX", current0, mipi_dsih_read_word(instance, current0));
+ }
+ }
+ else
+ {
+ config[count].addr = current0;
+ config[count].data = mipi_dsih_read_word(instance, current0);
+ }
+ }
+ }
+ else
+ {
+ if(config == 0)
+ {
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: invalid buffer");
+ }
+ }
+ else
+ {
+ for (count = 0; count < config_length; count++)
+ {
+ config[count].data = mipi_dsih_read_word(instance, config[count].addr);
+ }
+ }
+ }
+ return count;
+}
+uint32_t mipi_dsih_write_register_configuration(dsih_ctrl_t * instance, register_config_t *config, uint16_t config_length)
+{
+ uint16_t count = 0;
+ if (instance == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ for (count = 0; count < config_length; count++)
+ {
+ mipi_dsih_write_word(instance, config[count].addr, config[count].data);
+ }
+ return count;
+}
+dsih_error_t mipi_dsih_register_event(dsih_ctrl_t * instance, dsih_event_t event, void (*handler)(dsih_ctrl_t *, void *))
+{
+ uint32_t mask = 1;
+ uint32_t temp = 0;
+ if (event >= DSI_MAX_EVENT)
+ {
+ return ERR_DSI_INVALID_EVENT;
+ }
+ if (handler == 0)
+ {
+ return ERR_DSI_INVALID_HANDLE;
+ }
+ if (instance == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ instance->event_registry[event] = handler;
+ if (event < HS_CONTENTION)
+ {
+ temp = mipi_dsih_hal_get_error_mask_0(instance, 0xffffffff);
+ temp &= ~(mask << event);
+ temp |= (0 & mask) << event;
+ mipi_dsih_hal_error_mask_0(instance, temp);
+ }
+ else
+ {
+ temp = mipi_dsih_hal_get_error_mask_1(instance, 0xffffffff);
+ temp &= ~(mask << (event - HS_CONTENTION));
+ temp |= (0 & mask) << (event - HS_CONTENTION);
+ mipi_dsih_hal_error_mask_1(instance, temp);
+ if (event == RX_CRC_ERR)
+ { /* automatically enable CRC reporting */
+ mipi_dsih_hal_gen_crc_rx_en(instance, 1);
+ }
+ }
+ return OK;
+}
+dsih_error_t mipi_dsih_unregister_event(dsih_ctrl_t * instance, dsih_event_t event)
+{
+ uint32_t mask = 1;
+ uint32_t temp = 0;
+ if (event >= DSI_MAX_EVENT)
+ {
+ return ERR_DSI_INVALID_EVENT;
+ }
+ if (instance == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ instance->event_registry[event] = 0;
+ if (event < HS_CONTENTION)
+ {
+ temp = mipi_dsih_hal_get_error_mask_0(instance, 0xffffffff);
+ temp &= ~(mask << event);
+ temp |= (1 & mask) << event;
+ mipi_dsih_hal_error_mask_0(instance, temp);
+ }
+ else
+ {
+ temp = mipi_dsih_hal_get_error_mask_1(instance, 0xffffffff);
+ temp &= ~(mask << (event - HS_CONTENTION));
+ temp |= (1 & mask) << (event - HS_CONTENTION);
+ mipi_dsih_hal_error_mask_1(instance, temp);
+ if (event == RX_CRC_ERR)
+ { /* automatically disable CRC reporting */
+ mipi_dsih_hal_gen_crc_rx_en(instance, 0);
+ }
+ }
+ return OK;
+}
+dsih_error_t mipi_dsih_unregister_all_events(dsih_ctrl_t * instance)
+{
+ int i = 0;
+ if (instance == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ for (i = 0; i < DSI_MAX_EVENT; i++)
+ {
+ instance->event_registry[i] = 0;
+ }
+ mipi_dsih_hal_error_mask_0(instance, 0xffffff);
+ mipi_dsih_hal_error_mask_1(instance, 0xffffff);
+ /* automatically disable CRC reporting */
+ mipi_dsih_hal_gen_crc_rx_en(instance, 0);
+ return OK;
+}
+void mipi_dsih_event_handler(void * param)
+{
+ dsih_ctrl_t * instance = (dsih_ctrl_t *)(param);
+ uint8_t i = 0;
+ uint32_t status_0;
+ uint32_t status_1;
+
+ if (instance == 0)
+ {
+ return;
+ }
+
+ status_0 = mipi_dsih_hal_error_status_0(instance, 0xffffffff);
+ status_1 = mipi_dsih_hal_error_status_1(instance, 0xffffffff);
+
+ for (i = 0; i < DSI_MAX_EVENT; i++)
+ {
+ if (instance->event_registry[i] != 0)
+ {
+ if (i < HS_CONTENTION)
+ {
+ if ((status_0 & (1 << i)) != 0)
+ {
+ instance->event_registry[i](instance, &i);
+ }
+ }
+ else
+ {
+ if ((status_1 & (1 << (i - HS_CONTENTION))) != 0)
+ {
+ instance->event_registry[i](instance, &i);
+ }
+ }
+ }
+ }
+}
+void mipi_dsih_reset_controller(dsih_ctrl_t * instance)
+{
+ mipi_dsih_hal_power(instance, 0);
+ mipi_dsih_hal_power(instance, 1);
+}
+void mipi_dsih_shutdown_controller(dsih_ctrl_t * instance, int shutdown)
+{
+ mipi_dsih_hal_power(instance, !shutdown);
+}
+void mipi_dsih_reset_phy(dsih_ctrl_t * instance)
+{
+ mipi_dsih_dphy_reset(&(instance->phy_instance), 0);
+ mipi_dsih_dphy_reset(&(instance->phy_instance), 1);
+}
+void mipi_dsih_shutdown_phy(dsih_ctrl_t * instance, int shutdown)
+{
+ mipi_dsih_dphy_shutdown(&(instance->phy_instance), !shutdown);
+}
+
+void mipi_dsih_ulps_mode(dsih_ctrl_t * instance, int en)
+{
+ mipi_dsih_dphy_ulps_data_lanes(&(instance->phy_instance),en);
+ mipi_dsih_dphy_ulps_clk_lane(&(instance->phy_instance),en);
+}
+
+
diff --git a/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.h b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.h
new file mode 100644
index 00000000..5004c55c
--- /dev/null
+++ b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.h
@@ -0,0 +1,113 @@
+
+/*
+ The Synopsys Software Driver and documentation (hereinafter "Software")
+ is an unsupported work of Synopsys, Inc. unless otherwise
+ expressly agreed to in writing between Synopsys and you.
+
+ The Software IS NOT an item of Licensed Software or Licensed Product under
+ any End User Software License Agreement or Agreement for Licensed Product
+ with Synopsys or any supplement thereto. Permission is hereby granted,
+ free of charge, to any person obtaining a copy of this software annotated
+ with this license and the Software, to deal in the Software without
+ restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so, subject
+ to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
+ */
+#ifndef MIPI_DSIH_API_H_
+#define MIPI_DSIH_API_H_
+
+#include "mipi_dsih_local.h"
+
+/* general configuration functions */
+
+dsih_error_t mipi_dsih_open(dsih_ctrl_t * instance);
+
+dsih_error_t mipi_dsih_close(dsih_ctrl_t * instance);
+
+void mipi_dsih_reset_controller(dsih_ctrl_t * instance);
+
+void mipi_dsih_shutdown_controller(dsih_ctrl_t * instance, int shutdown);
+
+void mipi_dsih_reset_phy(dsih_ctrl_t * instance);
+
+void mipi_dsih_shutdown_phy(dsih_ctrl_t * instance, int shutdown);
+
+void mipi_dsih_ulps_mode(dsih_ctrl_t * instance, int en);
+
+/* packet handling */
+
+dsih_error_t mipi_dsih_enable_rx(dsih_ctrl_t * instance, int enable);
+
+dsih_error_t mipi_dsih_peripheral_ack(dsih_ctrl_t * instance, int enable);
+
+dsih_error_t mipi_dsih_tear_effect_ack(dsih_ctrl_t * instance, int enable);
+
+dsih_error_t mipi_dsih_eotp_rx(dsih_ctrl_t * instance, int enable);
+
+dsih_error_t mipi_dsih_ecc_rx(dsih_ctrl_t * instance, int enable);
+
+
+dsih_error_t mipi_dsih_eotp_tx(dsih_ctrl_t * instance, int enable);
+
+/* video mode functions */
+
+dsih_error_t mipi_dsih_dpi_video(dsih_ctrl_t * instance, dsih_dpi_video_t * video_params);
+
+void mipi_dsih_allow_return_to_lp(dsih_ctrl_t * instance, int hfp, int hbp, int vactive, int vfp, int vbp, int vsync);
+
+/* command mode functions */
+
+dsih_error_t mipi_dsih_dcs_wr_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t* params, uint16_t param_length);
+
+dsih_error_t mipi_dsih_gen_wr_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t* params, uint16_t param_length);
+
+dsih_error_t mipi_dsih_gen_wr_packet(dsih_ctrl_t * instance, uint8_t vc, uint8_t data_type, uint8_t* params, uint16_t param_length);
+
+uint16_t mipi_dsih_dcs_rd_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t command, uint8_t bytes_to_read, uint8_t* read_buffer);
+
+uint16_t mipi_dsih_gen_rd_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t* params, uint16_t param_length, uint8_t bytes_to_read, uint8_t* read_buffer);
+
+uint16_t mipi_dsih_gen_rd_packet(dsih_ctrl_t * instance, uint8_t vc, uint8_t data_type, uint8_t msb_byte, uint8_t lsb_byte, uint8_t bytes_to_read, uint8_t* read_buffer);
+
+void mipi_dsih_cmd_mode(dsih_ctrl_t * instance, int en);
+
+void mipi_dsih_video_mode(dsih_ctrl_t * instance, int en);
+
+int mipi_dsih_active_mode(dsih_ctrl_t * instance);
+
+void mipi_dsih_dcs_cmd_lp_transmission(dsih_ctrl_t * instance, int long_write, int short_write, int short_read);
+
+void mipi_dsih_gen_cmd_lp_transmission(dsih_ctrl_t * instance, int long_write, int short_write, int short_read);
+
+/* event handling functions */
+
+dsih_error_t mipi_dsih_register_event(dsih_ctrl_t * instance, dsih_event_t event, void (*handler)(dsih_ctrl_t *, void *));
+
+dsih_error_t mipi_dsih_unregister_event(dsih_ctrl_t * instance, dsih_event_t event);
+
+dsih_error_t mipi_dsih_unregister_all_events(dsih_ctrl_t * instance);
+
+void mipi_dsih_event_handler(void * param);
+
+uint32_t mipi_dsih_dump_register_configuration(dsih_ctrl_t * instance, int all, register_config_t *config, uint16_t config_length);
+
+uint32_t mipi_dsih_write_register_configuration(dsih_ctrl_t * instance, register_config_t *config, uint16_t config_length);
+
+
+#endif /* MIPI_DSIH_API_H_ */
diff --git a/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.c b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.c
new file mode 100644
index 00000000..ab68b9e2
--- /dev/null
+++ b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.c
@@ -0,0 +1,1031 @@
+
+#include "mipi_dsih_dphy.h"
+
+#define PRECISION_FACTOR (1000)
+/* Reference clock frequency divided by Input Frequency Division Ratio LIMITS */
+#define DPHY_DIV_UPPER_LIMIT (40000)
+#ifdef GEN_2
+#define DPHY_DIV_LOWER_LIMIT (5000)
+#else
+#define DPHY_DIV_LOWER_LIMIT (1000)
+#endif
+#if ((defined DWC_MIPI_DPHY_BIDIR_TSMC40LP) || (defined GEN_2))
+#define MIN_OUTPUT_FREQ (80)
+#elif defined DPHY2Btql
+#define MIN_OUTPUT_FREQ (200)
+#undef GEN_2
+#endif
+/**
+ * Initialise D-PHY module and power up
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @return error code
+ */
+dsih_error_t mipi_dsih_dphy_open(dphy_t * phy)
+{
+ if (phy == 0)
+ {
+ return ERR_DSI_PHY_INVALID;
+ }
+ else if ((phy->core_read_function == 0) || (phy->core_write_function == 0))
+ {
+ return ERR_DSI_INVALID_IO;
+ }
+ else if (phy->status == INITIALIZED)
+ {
+ return ERR_DSI_PHY_INVALID;
+ }
+ phy->status = NOT_INITIALIZED;
+#if 0
+ mipi_dsih_dphy_reset(phy, 0);
+ mipi_dsih_dphy_stop_wait_time(phy, 0x1C);
+ mipi_dsih_dphy_no_of_lanes(phy, 1);
+ mipi_dsih_dphy_clock_en(phy, 1);
+ mipi_dsih_dphy_shutdown(phy, 1);
+ mipi_dsih_dphy_reset(phy, 1);
+#endif
+ phy->status = INITIALIZED;
+ return OK;
+}
+uint8_t mipi_dsih_dphy_test_data_read(dphy_t * instance, uint8_t address)
+{
+ uint32_t i = 0;
+ mipi_dsih_dphy_test_clock(instance, 1);
+ /* set the desired test code in the input 8-bit bus TESTDIN[7:0] */
+ mipi_dsih_dphy_test_data_in(instance, address);
+ /* set TESTEN input high */
+ mipi_dsih_dphy_test_en(instance, 1);
+ /* drive the TESTCLK input low; the falling edge captures the chosen test code into the transceiver */
+ mipi_dsih_dphy_test_clock(instance, 0);
+ /* set TESTEN input low to disable further test mode code latching */
+ mipi_dsih_dphy_test_en(instance, 0);
+
+// udelay(1);
+ for(i=0;i<1000;i++)
+ ;
+ return mipi_dsih_dphy_test_data_out(instance);
+}
+
+/**
+ * Configure D-PHY and PLL module to desired operation mode
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @param no_of_lanes active
+ * @param output_freq desired high speed frequency
+ * @return error code
+ */
+
+ #ifdef GEN_2
+dsih_error_t mipi_dsih_dphy_configure(dphy_t * phy, uint8_t no_of_lanes, uint32_t output_freq)
+{
+ uint32_t loop_divider = 0; /* (M) */
+ uint32_t input_divider = 1; /* (N) */
+ uint8_t data[4]; /* maximum data for now are 4 bytes per test mode*/
+ uint8_t no_of_bytes = 0;
+ uint8_t i = 0;
+ uint8_t n=0;/* iterator */
+ uint8_t range = 0; /* ranges iterator */
+ int flag = 0;
+ struct
+ {
+ uint32_t loop_div; /* upper limit of loop divider range */
+ uint8_t cp_current; /* icpctrl */
+ uint8_t lpf_resistor; /* lpfctrl */
+ }
+ loop_bandwidth[] =
+
+ { /* gen 2 associates the charge pump current and LPF resistor with the
+ output frequency ranges (and thus we simplify here to use the
+ counter/pointer of the following structure) */
+ { 90, 0x02, 0x02}, { 100, 0x02, 0x02}, { 110, 0x02, 0x02},
+ { 130, 0x02, 0x01}, { 140, 0x02, 0x01}, { 150, 0x02, 0x01},
+ { 170, 0x09, 0x00}, { 180, 0x09, 0x01}, { 200, 0x09, 0x01},
+ { 220, 0x09, 0x04}, { 240, 0x09, 0x04}, { 250, 0x09, 0x04},
+ { 270, 0x06, 0x04}, { 300, 0x06, 0x04}, { 330, 0x09, 0x04},
+ { 360, 0x09, 0x04}, { 400, 0x09, 0x04}, { 450, 0x06, 0x04},
+ { 500, 0x06, 0x04}, { 550, 0x06, 0x04}, { 600, 0x06, 0x04},
+ { 650, 0x0A, 0x04}, { 700, 0x0A, 0x04}, { 750, 0x0A, 0x04},
+ { 800, 0x0A, 0x04}, { 850, 0x0A, 0x04}, { 900, 0x0A, 0x04},
+ { 950, 0x0B, 0x08}, {1000, 0x0B, 0x08}, {1050, 0x0B, 0x08},
+ {1100, 0x0B, 0x08}, {1150, 0x0B, 0x08}, {1200, 0x0B, 0x08},
+ {1250, 0x0B, 0x08}, {1300, 0x0B, 0x08}, {1350, 0x0B, 0x08},
+ {1400, 0x0B, 0x08}, {1450, 0x0B, 0x08}, {1500, 0x0B, 0x08}
+ };
+ uint32_t delta = 0;
+ uint32_t tmp_loop_divider = 0;
+ unsigned step = 0;
+
+ struct
+ {
+ uint32_t freq; /* upper margin of frequency range */
+ uint8_t hs_freq; /* hsfreqrange */
+ uint8_t vco_range; /* vcorange */
+ }
+ ranges[] =
+ {
+ { 90, 0x00, 0x00}, { 100, 0x10, 0x00}, { 110, 0x20, 0x00},
+ { 130, 0x01, 0x00}, { 140, 0x11, 0x00}, { 150, 0x21, 0x00},
+ { 170, 0x02, 0x00}, { 180, 0x12, 0x00}, { 200, 0x22, 0x00},
+ { 220, 0x03, 0x01}, { 240, 0x13, 0x01}, { 250, 0x23, 0x01},
+ { 270, 0x04, 0x01}, { 300, 0x14, 0x01}, { 330, 0x05, 0x02},
+ { 360, 0x15, 0x02}, { 400, 0x25, 0x02}, { 450, 0x06, 0x02},
+ { 500, 0x16, 0x02}, { 550, 0x07, 0x03}, { 600, 0x17, 0x03},
+ { 650, 0x08, 0x03}, { 700, 0x18, 0x03}, { 750, 0x09, 0x04},
+ { 800, 0x19, 0x04}, { 850, 0x29, 0x04}, { 900, 0x39, 0x04},
+ { 950, 0x0A, 0x05}, {1000, 0x1A, 0x05}, {1050, 0x2A, 0x05},
+ {1100, 0x3A, 0x05}, {1150, 0x0B, 0x06}, {1200, 0x1B, 0x06},
+ {1250, 0x2B, 0x06}, {1300, 0x3B, 0x06}, {1350, 0x0C, 0x07},
+ {1400, 0x1C, 0x07}, {1450, 0x2C, 0x07}, {1500, 0x3C, 0x07}
+ };
+
+ if (phy == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (phy->status < INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (output_freq < MIN_OUTPUT_FREQ)
+ {
+ return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;
+ }
+
+ loop_divider = ((output_freq * (phy->reference_freq / DPHY_DIV_LOWER_LIMIT)) / phy->reference_freq);
+ /* here delta will account for the rounding */
+ delta = ((loop_divider * phy->reference_freq) / (phy->reference_freq / DPHY_DIV_LOWER_LIMIT)) - output_freq;
+ for (input_divider = 1 + (phy->reference_freq / DPHY_DIV_UPPER_LIMIT); ((phy->reference_freq / input_divider) >= DPHY_DIV_LOWER_LIMIT) && (!flag); input_divider++)
+ {
+ tmp_loop_divider = ((output_freq * input_divider) / (phy->reference_freq));
+ if ((tmp_loop_divider % 2) == 0)
+ { /* if even */
+ if (output_freq == (tmp_loop_divider * (phy->reference_freq / input_divider)))
+ { /* exact values found */
+ flag = 1;
+ loop_divider = tmp_loop_divider;
+ delta = output_freq - (tmp_loop_divider * (phy->reference_freq / input_divider));
+ /* variable was incremented before exiting the loop */
+ input_divider--;
+ }
+ if ((output_freq - (tmp_loop_divider * (phy->reference_freq / input_divider))) < delta)
+ { /* values found with smaller delta */
+ loop_divider = tmp_loop_divider;
+ delta = output_freq - (tmp_loop_divider * (phy->reference_freq / input_divider));
+ step = 1;
+ }
+ }
+ else
+ {
+ tmp_loop_divider += 1;
+ if (output_freq == (tmp_loop_divider * (phy->reference_freq / input_divider)))
+ { /* exact values found */
+ flag = 1;
+ loop_divider = tmp_loop_divider;
+ delta = (tmp_loop_divider * (phy->reference_freq / input_divider)) - output_freq;
+ /* variable was incremented before exiting the loop */
+ input_divider--;
+ }
+ if (((tmp_loop_divider * (phy->reference_freq / input_divider)) - output_freq) < delta)
+ { /* values found with smaller delta */
+ loop_divider = tmp_loop_divider;
+ delta = (tmp_loop_divider * (phy->reference_freq / input_divider)) - output_freq;
+ step = 0;
+ }
+ }
+ }
+ if (!flag)
+ {
+ input_divider = step + (loop_divider * phy->reference_freq) / output_freq;
+// phy->log_info("D-PHY: Approximated Frequency: %d KHz", (loop_divider * (phy->reference_freq / input_divider)));
+ }
+#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING
+ if (phy->phy_keep_work != true)
+#endif
+ {
+ /* get the PHY in power down mode (shutdownz=0) and reset it (rstz=0) to
+ avoid transient periods in PHY operation during re-configuration procedures. */
+ mipi_dsih_dphy_reset(phy, 0);
+ mipi_dsih_dphy_clock_en(phy, 0);
+ mipi_dsih_dphy_shutdown(phy, 0);
+ /* provide an initial active-high test clear pulse in TESTCLR */
+ mipi_dsih_dphy_test_clear(phy, 1);
+ mipi_dsih_dphy_test_clear(phy, 0);
+ for(n=0;n<100;n++){
+ ;
+ }
+ }
+ /* find ranges */
+ for (range = 0; (range < (sizeof(ranges)/sizeof(ranges[0]))) && ((output_freq / 1000) > ranges[range].freq); range++)
+ {
+ ;
+ }
+ if (range >= (sizeof(ranges)/sizeof(ranges[0])))
+ {
+ return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;
+ }
+ /* set up board depending on environment if any */
+ if (phy->bsp_pre_config != 0)
+ {
+ phy->bsp_pre_config(phy, 0);
+ }
+
+ /* Jessica add - begin*/
+ data[0] = 0x83;//0x44;//0x44;//0x40; //0x40: ok for 200 clock lane lpx /*about 52ns*/
+ mipi_dsih_dphy_write(phy, 0x60, data, 1);
+// data[0] = 0x0; //0xA6;//0xC6;//0xC6;//0x86; //0x48: ok for 200 prepare time
+// mipi_dsih_dphy_write(phy, 0x61, data, 1);
+
+// data[0] = 0x0;//0x6a;//0x6a;//0x4a; //0x4a: ok for 200 zero time
+// mipi_dsih_dphy_write(phy, 0x62, data, 1);
+
+ data[0] = 0x83;//0x44;//0x40;//0x40; // 0x40: ok for 200 data lane lpx /*about 52ns*/
+ mipi_dsih_dphy_write(phy, 0x70, data, 1);
+
+// data[0] = 0x0;// 0x84;//0x96;//0x96;//0x86; //0x48: ok for 200 prepare time
+// mipi_dsih_dphy_write(phy, 0x71, data, 1);
+
+// data[0] = 0x0;//0x44;//0x44;//0x40; //0x4a: ok for 200 zero time
+// mipi_dsih_dphy_write(phy, 0x72, data, 1);
+
+ //data[0] = 0x44;
+ //mipi_dsih_dphy_write(phy, 0x73, data, 1);
+
+ //data[0] = 0x7F;
+ //mipi_dsih_dphy_write(phy, 0x74, data, 1);
+
+ /* Jessica add - end*/
+
+ data[0] = 0x70;
+ mipi_dsih_dphy_write(phy, 0x16, data, 1);
+
+ /* setup digital part */
+ /* hs frequency range [7]|[6:1]|[0]*/
+ data[0] = (0 << 7) | (ranges[range].hs_freq << 1) | 0;
+ //data[0] = (0 << 7) | (0x23 << 1) | 0;
+ /*From ASIC, we need unmask this code to make the frequency correct*/
+ mipi_dsih_dphy_write(phy, 0x44, data, 1); //Jessica remove for more accurate frequency
+ /* setup PLL */
+ /* vco range [7]|[6:3]|[2:1]|[0] */
+ data[0] = (1 << 7) | (ranges[range].vco_range << 3) | (0 << 1) | 0;
+ mipi_dsih_dphy_write(phy, 0x10, data, 1); //Jessica
+#ifdef TESTCHIP
+ /* for all Gen2 testchips, bypass LP TX enable idle low power */
+ data[0] = 0x80;
+ mipi_dsih_dphy_write(phy, 0x32, data, 1);
+ mipi_dsih_dphy_write(phy, 0x42, data, 1);
+ mipi_dsih_dphy_write(phy, 0x52, data, 1);
+ mipi_dsih_dphy_write(phy, 0x82, data, 1);
+ mipi_dsih_dphy_write(phy, 0x92, data, 1);
+#endif
+ if ((loop_divider % 2) != 0)
+ { /* only odd integers are allowed (1 will be subtracted upon writing,
+ see below) */
+ loop_divider -= 1;
+
+ }
+ /* gen 2 associates the charge pump current and LPF resistor with the
+ output frequency ranges (and thus we simplify here to use the
+ counter/pointer of the following structure) */
+ i = range;
+ data[0] = (0x00 << 6) | (0x01 << 5) | (0x01 << 4);
+
+ mipi_dsih_dphy_write(phy, 0x19, data, 1); //Jessica
+
+ /* PLL Lock bypass|charge pump current [7:4]|[3:0] */
+ data[0] = (0x00 << 4) | (loop_bandwidth[i].cp_current << 0);
+ mipi_dsih_dphy_write(phy, 0x11, data, 1); //Jessica
+ /* bypass CP default|bypass LPF default| LPF resistor [7]|[6]|[5:0] */
+ data[0] = (0x01 << 7) | (0x01 << 6) |(loop_bandwidth[i].lpf_resistor << 0);
+ mipi_dsih_dphy_write(phy, 0x12, data, 1);
+ /* PLL input divider ratio [7:0] */
+ data[0] = input_divider - 1;
+ mipi_dsih_dphy_write(phy, 0x17, data, 1); //Jessica
+
+// data[0] = 1;
+// mipi_dsih_dphy_write(phy, 0xB0, data, 1);
+
+ data[0] = 0x04; //short the delay time before BTA
+ mipi_dsih_dphy_write(phy, 0x07, data, 1);
+
+ data[0] = 0x8B;
+ mipi_dsih_dphy_write(phy, 0x22, data, 1);
+// data[1] = mipi_dsih_dphy_test_data_out(phy);
+// printk("sprdfb:mipi dphy config-->0x22 write:%x,read:%x \n",data[0],data[1]);
+
+ no_of_bytes = 2; /* pll loop divider (code 0x18) takes only 2 bytes (10 bits in data) */
+ for (i = 0; i < no_of_bytes; i++)
+ {
+ data[i] = ((uint8_t)((((loop_divider - 1) >> (5 * i)) & 0x1F) | (i << 7) ));
+ /* 7 is dependent on no_of_bytes
+ make sure 5 bits only of value are written at a time */
+ }
+ /* PLL loop divider ratio - SET no|reserved|feedback divider [7]|[6:5]|[4:0] */
+ mipi_dsih_dphy_write(phy, 0x18, data, no_of_bytes);
+ mipi_dsih_dphy_no_of_lanes(phy, no_of_lanes);
+#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING
+ if (phy->phy_keep_work != true)
+#endif
+ {
+ mipi_dsih_dphy_stop_wait_time(phy, 0x1C);
+ mipi_dsih_dphy_clock_en(phy, 1);
+ for(n=0;n<100;n++){
+ ;
+ }
+ mipi_dsih_dphy_shutdown(phy, 1);
+ for(n=0;n<100;n++){
+ ;
+ }
+ mipi_dsih_dphy_reset(phy, 1);
+ }
+ return OK;
+}
+#else
+dsih_error_t mipi_dsih_dphy_configure(dphy_t * phy, uint8_t no_of_lanes, uint32_t output_freq)
+{
+ uint32_t loop_divider = 0; /* (M) */
+ uint32_t input_divider = 1; /* (N) */
+ uint8_t data[4]; /* maximum data for now are 4 bytes per test mode*/
+ uint8_t no_of_bytes = 0;
+ uint8_t i = 0; /* iterator */
+ uint8_t n=0;/* iterator */
+ uint8_t range = 0; /* ranges iterator */
+ int flag = 0;
+#ifdef DWC_MIPI_DPHY_BIDIR_TSMC40LP
+ struct
+ {
+ uint32_t freq; /* upper margin of frequency range */
+ uint8_t hs_freq; /* hsfreqrange */
+ uint8_t vco_range; /* vcorange */
+ }
+ ranges[] =
+ {
+ {90, 0x00, 0x01}, {100, 0x10, 0x01}, {110, 0x20, 0x01},
+ {125, 0x01, 0x01}, {140, 0x11, 0x01}, {150, 0x21, 0x01},
+ {160, 0x02, 0x01}, {180, 0x12, 0x03}, {200, 0x22, 0x03},
+ {210, 0x03, 0x03}, {240, 0x13, 0x03}, {250, 0x23, 0x03},
+ {270, 0x04, 0x07}, {300, 0x14, 0x07}, {330, 0x24, 0x07},
+ {360, 0x15, 0x07}, {400, 0x25, 0x07}, {450, 0x06, 0x07},
+ {500, 0x16, 0x07}, {550, 0x07, 0x0f}, {600, 0x17, 0x0f},
+ {650, 0x08, 0x0f}, {700, 0x18, 0x0f}, {750, 0x09, 0x0f},
+ {800, 0x19, 0x0f}, {850, 0x0A, 0x0f}, {900, 0x1A, 0x0f},
+ {950, 0x2A, 0x0f}, {1000, 0x3A, 0x0f}
+ };
+ struct
+ {
+ uint32_t loop_div; /* upper limit of loop divider range */
+ uint8_t cp_current; /* icpctrl */
+ uint8_t lpf_resistor; /* lpfctrl */
+ }
+ loop_bandwidth[] =
+ {
+ {32, 0x06, 0x10}, {64, 0x06, 0x10}, {128, 0x0C, 0x08},
+ {256, 0x04, 0x04}, {512, 0x00, 0x01}, {768, 0x01, 0x01},
+ {1000, 0x02, 0x01}
+ };
+#elif defined DPHY2Btql
+ struct
+ {
+ uint32_t loop_div; /* upper limit of loop divider range */
+ uint8_t cp_current; /* icpctrl */
+ uint8_t lpf_resistor; /* lpfctrl */
+ }
+ loop_bandwidth[] =
+ {
+ {32, 0x0B, 0x00}, {64, 0x0A, 0x00}, {128, 0x09, 0x01},
+ {256, 0x08, 0x03}, {512, 0x08, 0x07}, {768, 0x08, 0x0F},
+ {1000, 0x08, 0x1F}
+ };
+#endif
+ if (phy == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (phy->status < INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (output_freq < MIN_OUTPUT_FREQ)
+ {
+ return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;
+ }
+ /* find M and N dividers */
+ for (input_divider = 1 + (phy->reference_freq / DPHY_DIV_UPPER_LIMIT); ((phy->reference_freq / input_divider) >= DPHY_DIV_LOWER_LIMIT) && (!flag); input_divider++)
+ { /* here the >= DPHY_DIV_LOWER_LIMIT is a phy constraint, formula should be above 1 MHz */
+ if (((output_freq * input_divider) % (phy->reference_freq )) == 0)
+ { /* values found */
+ loop_divider = ((output_freq * input_divider) / (phy->reference_freq ));
+ if (loop_divider >= 12)
+ {
+ flag = 1;
+ }
+ }
+ }
+ if ((!flag) || ((phy->reference_freq / input_divider) < DPHY_DIV_LOWER_LIMIT))
+ { /* no exact value found in previous for loop */
+ /* this solution is not favourable as jitter would be maximum */
+ loop_divider = output_freq / DPHY_DIV_LOWER_LIMIT;
+ input_divider = phy->reference_freq / DPHY_DIV_LOWER_LIMIT;
+ }
+ else
+ { /* variable was incremented before exiting the loop */
+ input_divider--;
+ }
+ for (i = 0; (i < (sizeof(loop_bandwidth)/sizeof(loop_bandwidth[0]))) && (loop_divider > loop_bandwidth[i].loop_div); i++)
+ {
+ ;
+ }
+ if (i >= (sizeof(loop_bandwidth)/sizeof(loop_bandwidth[0])))
+ {
+ return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;
+ }
+ printk("sprdfb: Gen1 D-PHY: Approximated Frequency: %d KHz\n", (loop_divider * (phy->reference_freq / input_divider)));
+#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING
+ if (phy->phy_keep_work != true)
+#endif
+ {
+ /* get the PHY in power down mode (shutdownz=0) and reset it (rstz=0) to
+ avoid transient periods in PHY operation during re-configuration procedures. */
+ mipi_dsih_dphy_reset(phy, 0);
+ mipi_dsih_dphy_clock_en(phy, 0);
+ mipi_dsih_dphy_shutdown(phy, 0);
+ /* provide an initial active-high test clear pulse in TESTCLR */
+ mipi_dsih_dphy_test_clear(phy, 1);
+ mipi_dsih_dphy_test_clear(phy, 0);
+ }
+#ifdef DWC_MIPI_DPHY_BIDIR_TSMC40LP
+ /* find ranges */
+ for (range = 0; (range < (sizeof(ranges)/sizeof(ranges[0]))) && ((output_freq / 1000) > ranges[range].freq); range++)
+ {
+ ;
+ }
+ if (range >= (sizeof(ranges)/sizeof(ranges[0])))
+ {
+ return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;
+ }
+ /* set up board depending on environment if any */
+ if (phy->bsp_pre_config != 0)
+ {
+ phy->bsp_pre_config(phy, 0);
+ }
+
+ /* Jessica add - begin*/
+ data[0] = 0x42;//0x44;//0x44;//0x40; //0x40: ok for 200 clock lane lpx /*about 52ns*/
+ mipi_dsih_dphy_write(phy, 0x60, data, 1);
+ data[0] = 0x0; //0xA6;//0xC6;//0xC6;//0x86; //0x48: ok for 200 prepare time
+ mipi_dsih_dphy_write(phy, 0x61, data, 1);
+
+ data[0] = 0x0;//0x6a;//0x6a;//0x4a; //0x4a: ok for 200 zero time
+ mipi_dsih_dphy_write(phy, 0x62, data, 1);
+
+ data[0] = 0x42;//0x44;//0x40;//0x40; // 0x40: ok for 200 data lane lpx /*about 52ns*/
+ mipi_dsih_dphy_write(phy, 0x70, data, 1);
+
+ data[0] = 0x0;// 0x84;//0x96;//0x96;//0x86; //0x48: ok for 200 prepare time
+ mipi_dsih_dphy_write(phy, 0x71, data, 1);
+
+ data[0] = 0x0;//0x44;//0x44;//0x40; //0x4a: ok for 200 zero time
+ mipi_dsih_dphy_write(phy, 0x72, data, 1);
+
+ //data[0] = 0x44;
+ //mipi_dsih_dphy_write(phy, 0x73, data, 1);
+
+ //data[0] = 0x7F;
+ //mipi_dsih_dphy_write(phy, 0x74, data, 1);
+
+ /* Jessica add - end*/
+
+ /* setup digital part */
+ /* hs frequency range [7]|[6:1]|[0]*/
+ data[0] = (0 << 7) | (ranges[range].hs_freq << 1) | 0;
+ //data[0] = (0 << 7) | (0x23 << 1) | 0;
+ /*From ASIC, we need unmask this code to make the frequency correct*/
+ mipi_dsih_dphy_write(phy, 0x44, data, 1); //Jessica remove for more accurate frequency
+ /* setup PLL */
+ /* vco range [7]|[6:3]|[2:1]|[0] */
+ data[0] = (1 << 7) | (ranges[range].vco_range << 3) | (0 << 1) | 0;
+ mipi_dsih_dphy_write(phy, 0x10, data, 1); //Jessica
+ /* PLL reserved|Input divider control|Loop Divider Control|Post Divider Ratio [7:6]|[5]|[4]|[3:0] */
+ data[0] = (0x00 << 6) | (0x01 << 5) | (0x01 << 4) | (0x03 << 0); /* post divider default = 0x03 - it is only used for clock out 2*/
+ mipi_dsih_dphy_write(phy, 0x19, data, 1); //Jessica
+#elif defined DPHY2Btql
+ /* vco range [7:5]|[4]|[3]|[2:1]|[0] */
+ data[0] = ((((output_freq / 1000) > 500 )? 1: 0) << 4) | (1 << 3) | (0 << 1) | 0;
+ mipi_dsih_dphy_write(phy, 0x10, data, 1);
+#endif
+ /* PLL Lock bypass|charge pump current [7:4]|[3:0] */
+ data[0] = (0x00 << 4) | (loop_bandwidth[i].cp_current << 0);
+ mipi_dsih_dphy_write(phy, 0x11, data, 1); //Jessica
+ /* bypass CP default|bypass LPF default| LPF resistor [7]|[6]|[5:0] */
+ data[0] = (0x01 << 7) | (0x01 << 6) |(loop_bandwidth[i].lpf_resistor << 0);
+ mipi_dsih_dphy_write(phy, 0x12, data, 1);
+ /* PLL input divider ratio [7:0] */
+ data[0] = input_divider - 1;
+ mipi_dsih_dphy_write(phy, 0x17, data, 1); //Jessica
+
+ data[0] = 0x04; //short the delay time before BTA
+ mipi_dsih_dphy_write(phy, 0x07, data, 1);
+
+// data[0] = 1;
+// mipi_dsih_dphy_write(phy, 0xB0, data, 1);
+
+ data[0] = 0x8B;
+ mipi_dsih_dphy_write(phy, 0x22, data, 1);
+ // data[1] = mipi_dsih_dphy_test_data_out(phy);
+// printk("sprdfb:mipi dphy config-->0x22 write:%x,read:%x \n",data[0],data[1]);
+
+ no_of_bytes = 2; /* pll loop divider (code 0x18) takes only 2 bytes (10 bits in data) */
+ for (i = 0; i < no_of_bytes; i++)
+ {
+ data[i] = ((uint8_t)((((loop_divider - 1) >> (5 * i)) & 0x1F) | (i << 7) ));
+ /* 7 is dependent on no_of_bytes
+ make sure 5 bits only of value are written at a time */
+ }
+ /* PLL loop divider ratio - SET no|reserved|feedback divider [7]|[6:5]|[4:0] */
+ mipi_dsih_dphy_write(phy, 0x18, data, no_of_bytes);
+ mipi_dsih_dphy_no_of_lanes(phy, no_of_lanes);
+#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING
+ if (phy->phy_keep_work != true)
+#endif
+ {
+ mipi_dsih_dphy_stop_wait_time(phy, 0x1C);
+ mipi_dsih_dphy_clock_en(phy, 1);
+ for(n=0;n<100;n++){
+ ;
+ }
+ mipi_dsih_dphy_shutdown(phy, 1);
+ for(n=0;n<100;n++){
+ ;
+ }
+ mipi_dsih_dphy_reset(phy, 1);
+ }
+ return OK;
+}
+#endif
+/**
+ * Close and power down D-PHY module
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @return error code
+ */
+
+dsih_error_t mipi_dsih_dphy_close(dphy_t * phy)
+{
+ if (phy == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ else if ((phy->core_read_function == 0) || (phy->core_write_function == 0))
+ {
+ return ERR_DSI_INVALID_IO;
+ }
+ if (phy->status < NOT_INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ mipi_dsih_dphy_reset(phy, 0);
+ mipi_dsih_dphy_reset(phy, 1);
+ mipi_dsih_dphy_shutdown(phy, 0);
+ phy->status = NOT_INITIALIZED;
+ return OK;
+}
+/**
+ * Enable clock lane module
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param en
+ */
+void mipi_dsih_dphy_clock_en(dphy_t * instance, int en)
+{
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_RSTZ, en, 2, 1);
+}
+/**
+ * Reset D-PHY module
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param reset
+ */
+void mipi_dsih_dphy_reset(dphy_t * instance, int reset)
+{
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_RSTZ, reset, 1, 1);
+}
+/**
+ * Power up/down D-PHY module
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param powerup (1) shutdown (0)
+ */
+void mipi_dsih_dphy_shutdown(dphy_t * instance, int powerup)
+{
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_RSTZ, powerup, 0, 1);
+}
+/**
+ * Configure minimum wait period for HS transmission request after a stop state
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param no_of_byte_cycles [in byte (lane) clock cycles]
+ */
+void mipi_dsih_dphy_stop_wait_time(dphy_t * instance, uint8_t no_of_byte_cycles)
+{
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CFG, no_of_byte_cycles, 2, 8);
+}
+/**
+ * Set number of active lanes
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param no_of_lanes
+ */
+void mipi_dsih_dphy_no_of_lanes(dphy_t * instance, uint8_t no_of_lanes)
+{
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CFG, no_of_lanes - 1, 0, 2);
+}
+/**
+ * Get number of currently active lanes
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @return number of active lanes
+ */
+uint8_t mipi_dsih_dphy_get_no_of_lanes(dphy_t * instance)
+{
+ return mipi_dsih_dphy_read_part(instance, R_DSI_HOST_PHY_IF_CFG, 0, 2);
+}
+/**
+ * Request the PHY module to start transmission of high speed clock.
+ * This causes the clock lane to start transmitting DDR clock on the
+ * lane interconnect.
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param enable
+ * @note this function should be called explicitly by user always except for
+ * transmitting
+ */
+void mipi_dsih_dphy_enable_hs_clk(dphy_t * instance, int enable)
+{
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, enable, 0, 1);
+}
+/**
+ * One bit is asserted in the trigger_request (4bits) to cause the lane module
+ * to cause the associated trigger to be sent across the lane interconnect.
+ * The trigger request is synchronous with the rising edge of the clock.
+ * @note: Only one bit of the trigger_request is asserted at any given time, the
+ * remaining must be left set to 0, and only when not in LPDT or ULPS modes
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param trigger_request 4 bit request
+ */
+dsih_error_t mipi_dsih_dphy_escape_mode_trigger(dphy_t * instance, uint8_t trigger_request)
+{
+ uint8_t sum = 0;
+ int i = 0;
+ for (i = 0; i < 4; i++)
+ {
+ sum += ((trigger_request >> i) & 1);
+ }
+ if (sum == 1)
+ { /* clear old trigger */
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0x00, 5, 4);
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, trigger_request, 5, 4);
+ for (i = 0; i < DSIH_PHY_ACTIVE_WAIT; i++)
+ {
+ if(mipi_dsih_dphy_status(instance, 0x0010))
+ {
+ break;
+ }
+ }
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0x00, 5, 4);
+ if (i >= DSIH_PHY_ACTIVE_WAIT)
+ {
+ return ERR_DSI_TIMEOUT;
+ }
+ return OK;
+ }
+ return ERR_DSI_INVALID_COMMAND;
+}
+/**
+ * ULPS mode request/exit on all active data lanes.
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param enable (request 1/ exit 0)
+ * @return error code
+ * @note this is a blocking function. wait upon exiting the ULPS will exceed 1ms
+ */
+#ifdef GEN_2
+dsih_error_t mipi_dsih_dphy_ulps_data_lanes(dphy_t * instance, int enable)
+{
+ int timeout;
+ /* mask 1 0101 0010 0000 */
+ uint16_t data_lanes_mask = 0;
+ if (enable)
+ {
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 3, 1);
+ return OK;
+ }
+ else
+ {
+ if (mipi_dsih_dphy_status(instance, 0x1) == 0)
+ {
+ return ERR_DSI_PHY_PLL_NOT_LOCKED;
+ }
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 4, 1);
+ switch (mipi_dsih_dphy_get_no_of_lanes(instance))
+ {
+ case 3:
+ data_lanes_mask |= (1 << 12);
+ case 2:
+ data_lanes_mask |= (1 << 10);
+ case 1:
+ data_lanes_mask |= (1 << 8);
+ case 0:
+ data_lanes_mask |= (1 << 5);
+ break;
+ default:
+ data_lanes_mask = 0;
+ break;
+ }
+ for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++)
+ { /* verify that the DPHY has left ULPM */
+ /* mask 1010100100000 */
+ if (mipi_dsih_dphy_status(instance, data_lanes_mask) == data_lanes_mask)
+ {
+ break;
+ }
+ /* wait at least 1ms */
+ for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)
+ {
+ ;
+ }
+ }
+ if (mipi_dsih_dphy_status(instance, data_lanes_mask) != data_lanes_mask)
+ {
+ instance->log_info("sprdfb: stat %x, mask %x", mipi_dsih_dphy_status(instance, data_lanes_mask), data_lanes_mask);
+ return ERR_DSI_TIMEOUT;
+ }
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 3, 1);
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 4, 1);
+ }
+ return OK;
+}
+#else
+void mipi_dsih_dphy_ulps_data_lanes(dphy_t * instance, int enable)
+{
+ int timeout;
+ if (enable)
+ {
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 3, 1);
+ }
+ else
+ {
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 4, 1);
+ for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++)
+ { /* verify that the DPHY has left ULPM */
+ /* mask 1010100100000 */
+ if (mipi_dsih_dphy_status(instance, 0x1520) == 0)
+ { /* wait at least 1ms */
+ for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)
+ {
+ ;
+ }
+ break;
+ }
+ }
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 3, 1);
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 4, 1);
+ }
+}
+#endif
+/**
+ * ULPS mode request/exit on Clock Lane.
+ * @param instance pointer to structure which holds information about the
+ * d-phy module
+ * @param enable 1 or disable 0 of the Ultra Low Power State of the clock lane
+ * @return error code
+ * @note this is a blocking function. wait upon exiting the ULPS will exceed 1ms
+ */
+#ifdef GEN_2
+dsih_error_t mipi_dsih_dphy_ulps_clk_lane(dphy_t * instance, int enable)
+{
+ int timeout;
+ /* mask 1000 */
+ uint16_t clk_lane_mask = 0x0008;
+ if (enable)
+ {
+// mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 0, 1);
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 1, 1);
+ }
+ else
+ {
+ if (mipi_dsih_dphy_status(instance, 0x1) == 0)
+ {
+ return ERR_DSI_PHY_PLL_NOT_LOCKED;
+ }
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 2, 1);
+ for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++)
+ { /* verify that the DPHY has left ULPM */
+ /* mask 1010100100000 */
+ if (mipi_dsih_dphy_status(instance, clk_lane_mask) == clk_lane_mask)
+ { /* wait at least 1ms */
+ instance->log_info("sprdfb: stat %x, mask %x", mipi_dsih_dphy_status(instance, clk_lane_mask), clk_lane_mask);
+ break;
+ }
+ /* wait at least 1ms */
+ for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)
+ {
+ enable = mipi_dsih_dphy_status(instance, clk_lane_mask);
+ }
+ }
+ if (mipi_dsih_dphy_status(instance, clk_lane_mask) != clk_lane_mask)
+ {
+ return ERR_DSI_TIMEOUT;
+ }
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 1, 1);
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 2, 1);
+ }
+ return OK;
+}
+#else
+void mipi_dsih_dphy_ulps_clk_lane(dphy_t * instance, int enable)
+{
+ int timeout;
+ if (enable)
+ {
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 0, 1);
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 1, 1);
+ }
+ else
+ {
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 2, 1);
+ for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++)
+ { /* verify that the DPHY has left ULPM */
+ /* mask 1010100100000 */
+ if (mipi_dsih_dphy_status(instance, 0x0004) == 0)
+ { /* wait at least 1ms */
+ for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)
+ {
+ ;
+ }
+ break;
+ }
+ }
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 1, 1);
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 2, 1);
+ }
+}
+#endif
+/**
+ * Get D-PHY PPI status
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param mask
+ * @return status
+ */
+uint32_t mipi_dsih_dphy_status(dphy_t * instance, uint16_t mask)
+{
+ return mipi_dsih_dphy_read_word(instance, R_DSI_HOST_PHY_STATUS) & mask;
+}
+/**
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param value
+ */
+void mipi_dsih_dphy_test_clock(dphy_t * instance, int value)
+{
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_TST_CRTL0, value, 1, 1);
+}
+/**
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param value
+ */
+void mipi_dsih_dphy_test_clear(dphy_t * instance, int value)
+{
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_TST_CRTL0, value, 0, 1);
+}
+/**
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param on_falling_edge
+ */
+void mipi_dsih_dphy_test_en(dphy_t * instance, uint8_t on_falling_edge)
+{
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_TST_CRTL1, on_falling_edge, 16, 1);
+}
+/**
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ */
+uint8_t mipi_dsih_dphy_test_data_out(dphy_t * instance)
+{
+ return mipi_dsih_dphy_read_part(instance, R_DSI_HOST_PHY_TST_CRTL1, 8, 8);
+}
+/**
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param test_data
+ */
+void mipi_dsih_dphy_test_data_in(dphy_t * instance, uint8_t test_data)
+{
+ mipi_dsih_dphy_write_word(instance, R_DSI_HOST_PHY_TST_CRTL1, test_data);
+}
+/**
+ * Write to D-PHY module (encapsulating the digital interface)
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param address offset inside the D-PHY digital interface
+ * @param data array of bytes to be written to D-PHY
+ * @param data_length of the data array
+ */
+void mipi_dsih_dphy_write(dphy_t * instance, uint8_t address, uint8_t * data, uint8_t data_length)
+{
+ unsigned i = 0;
+ if (data != 0)
+ {
+#if ((defined DWC_MIPI_DPHY_BIDIR_TSMC40LP) || (defined DPHY2Btql) || (defined GEN_2))
+ /* set the TESTCLK input high in preparation to latch in the desired test mode */
+ mipi_dsih_dphy_test_clock(instance, 1);
+ /* set the desired test code in the input 8-bit bus TESTDIN[7:0] */
+ mipi_dsih_dphy_test_data_in(instance, address);
+ /* set TESTEN input high */
+ mipi_dsih_dphy_test_en(instance, 1);
+ /* drive the TESTCLK input low; the falling edge captures the chosen test code into the transceiver */
+ mipi_dsih_dphy_test_clock(instance, 0);
+ /* set TESTEN input low to disable further test mode code latching */
+ mipi_dsih_dphy_test_en(instance, 0);
+ /* start writing MSB first */
+ for (i = data_length; i > 0; i--)
+ { /* set TESTDIN[7:0] to the desired test data appropriate to the chosen test mode */
+ mipi_dsih_dphy_test_data_in(instance, data[i - 1]);
+ /* pulse TESTCLK high to capture this test data into the macrocell; repeat these two steps as necessary */
+ mipi_dsih_dphy_test_clock(instance, 1);
+ mipi_dsih_dphy_test_clock(instance, 0);
+ }
+#endif
+ }
+}
+
+
+
+/* abstracting BSP */
+/**
+ * Write to whole register to D-PHY module (encapsulating the bus interface)
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param reg_address offset
+ * @param data 32-bit word
+ */
+void mipi_dsih_dphy_write_word(dphy_t * instance, uint32_t reg_address, uint32_t data)
+{
+ if (instance->core_write_function != 0)
+ {
+ instance->core_write_function(instance->address, reg_address, data);
+ }
+}
+/**
+ * Write bit field to D-PHY module (encapsulating the bus interface)
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param reg_address offset
+ * @param data bits to be written to D-PHY
+ * @param shift from the right hand side of the register (big endian)
+ * @param width of the bit field
+ */
+void mipi_dsih_dphy_write_part(dphy_t * instance, uint32_t reg_address, uint32_t data, uint8_t shift, uint8_t width)
+{
+ uint32_t mask = 0;
+ uint32_t temp = 0;
+ if (instance->core_read_function != 0)
+ {
+ mask = (1 << width) - 1;
+ temp = mipi_dsih_dphy_read_word(instance, reg_address);
+ temp &= ~(mask << shift);
+ temp |= (data & mask) << shift;
+ mipi_dsih_dphy_write_word(instance, reg_address, temp);
+ }
+}
+/**
+ * Read whole register from D-PHY module (encapsulating the bus interface)
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param reg_address offset
+ * @return data 32-bit word
+ */
+uint32_t mipi_dsih_dphy_read_word(dphy_t * instance, uint32_t reg_address)
+{
+ if (instance->core_read_function == 0)
+ {
+ return ERR_DSI_INVALID_IO;
+ }
+ return instance->core_read_function(instance->address, reg_address);
+}
+/**
+ * Read bit field from D-PHY module (encapsulating the bus interface)
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param reg_address offset
+ * @param shift from the right hand side of the register (big endian)
+ * @param width of the bit field
+ * @return data bits to be written to D-PHY
+ */
+uint32_t mipi_dsih_dphy_read_part(dphy_t * instance, uint32_t reg_address, uint8_t shift, uint8_t width)
+{
+ return (mipi_dsih_dphy_read_word(instance, reg_address) >> shift) & ((1 << width) - 1);
+}
+
diff --git a/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.h b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.h
new file mode 100644
index 00000000..4d457db2
--- /dev/null
+++ b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.h
@@ -0,0 +1,55 @@
+/*
+ * @file mipi_dsih_dphy.h
+ *
+ * Synopsys Inc.
+ * SG DWC PT02
+ */
+
+#ifndef MIPI_DSIH_DPHY_H_
+#define MIPI_DSIH_DPHY_H_
+
+#include "mipi_dsih_local.h"
+
+#define R_DSI_HOST_PHY_RSTZ 0x54UL
+#define R_DSI_HOST_PHY_IF_CFG 0x58UL
+#define R_DSI_HOST_PHY_IF_CTRL 0x5CUL
+#define R_DSI_HOST_PHY_STATUS 0x60UL
+#define R_DSI_HOST_PHY_TST_CRTL0 0x64UL
+#define R_DSI_HOST_PHY_TST_CRTL1 0x68UL
+
+/* obligatory functions - code can be changed for different phys*/
+dsih_error_t mipi_dsih_dphy_open(dphy_t * phy);
+dsih_error_t mipi_dsih_dphy_configure(dphy_t * phy, uint8_t no_of_lanes, uint32_t output_freq);
+dsih_error_t mipi_dsih_dphy_close(dphy_t * phy);
+
+void mipi_dsih_dphy_clock_en(dphy_t * instance, int en);
+void mipi_dsih_dphy_reset(dphy_t * instance, int reset);
+void mipi_dsih_dphy_shutdown(dphy_t * instance, int powerup);
+
+void mipi_dsih_dphy_stop_wait_time(dphy_t * instance, uint8_t no_of_byte_cycles);
+void mipi_dsih_dphy_no_of_lanes(dphy_t * instance, uint8_t no_of_lanes);
+uint8_t mipi_dsih_dphy_get_no_of_lanes(dphy_t * instance);
+void mipi_dsih_dphy_enable_hs_clk(dphy_t * instance, int enable);
+dsih_error_t mipi_dsih_dphy_escape_mode_trigger(dphy_t * instance, uint8_t trigger_request);
+#ifdef GEN_2
+dsih_error_t mipi_dsih_dphy_ulps_data_lanes(dphy_t * instance, int enable);
+dsih_error_t mipi_dsih_dphy_ulps_clk_lane(dphy_t * instance, int enable);
+#else
+void mipi_dsih_dphy_ulps_data_lanes(dphy_t * instance, int enable);
+void mipi_dsih_dphy_ulps_clk_lane(dphy_t * instance, int enable);
+#endif
+uint32_t mipi_dsih_dphy_status(dphy_t * instance, uint16_t mask);
+/* end of obligatory functions*/
+void mipi_dsih_dphy_test_clock(dphy_t * instance, int value);
+void mipi_dsih_dphy_test_clear(dphy_t * instance, int value);
+void mipi_dsih_dphy_test_en(dphy_t * instance, uint8_t on_falling_edge);
+uint8_t mipi_dsih_dphy_test_data_out(dphy_t * instance);
+void mipi_dsih_dphy_test_data_in(dphy_t * instance, uint8_t test_data);
+
+void mipi_dsih_dphy_write(dphy_t * instance, uint8_t address, uint8_t * data, uint8_t data_length);
+
+void mipi_dsih_dphy_write_word(dphy_t * instance, uint32_t reg_address, uint32_t data);
+void mipi_dsih_dphy_write_part(dphy_t * instance, uint32_t reg_address, uint32_t data, uint8_t shift, uint8_t width);
+uint32_t mipi_dsih_dphy_read_word(dphy_t * instance, uint32_t reg_address);
+uint32_t mipi_dsih_dphy_read_part(dphy_t * instance, uint32_t reg_address, uint8_t shift, uint8_t width);
+#endif /* MIPI_DSIH_DPHY_H_ */
diff --git a/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.c b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.c
new file mode 100644
index 00000000..cf87836d
--- /dev/null
+++ b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.c
@@ -0,0 +1,529 @@
+
+#include "mipi_dsih_hal.h"
+
+void mipi_dsih_write_word(dsih_ctrl_t * instance, uint32_t reg_address, uint32_t data)
+{
+
+ instance->core_write_function(instance->address, reg_address, data);
+}
+void mipi_dsih_write_part(dsih_ctrl_t * instance, uint32_t reg_address, uint32_t data, uint8_t shift, uint8_t width)
+{
+ uint32_t mask = (1 << width) - 1;
+ uint32_t temp = mipi_dsih_read_word(instance, reg_address);
+
+ temp &= ~(mask << shift);
+ temp |= (data & mask) << shift;
+ mipi_dsih_write_word(instance, reg_address, temp);
+}
+uint32_t mipi_dsih_read_word(dsih_ctrl_t * instance, uint32_t reg_address)
+{
+ return instance->core_read_function(instance->address, reg_address);
+}
+uint32_t mipi_dsih_read_part(dsih_ctrl_t * instance, uint32_t reg_address, uint8_t shift, uint8_t width)
+{
+ return (mipi_dsih_read_word(instance, reg_address) >> shift) & ((1 << width) - 1);
+}
+uint32_t mipi_dsih_hal_get_version(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_word(instance, R_DSI_HOST_VERSION);
+}
+void mipi_dsih_hal_power(dsih_ctrl_t * instance, int on)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_PWR_UP, on, 0, 1);
+}
+int mipi_dsih_hal_get_power(dsih_ctrl_t * instance)
+{
+ return (int)(mipi_dsih_read_word(instance, R_DSI_HOST_PWR_UP));
+}
+void mipi_dsih_hal_tx_escape_division(dsih_ctrl_t * instance, uint8_t tx_escape_division)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_CLK_MGR, tx_escape_division, 0, 8);
+}
+void mipi_dsih_hal_dpi_video_vc(dsih_ctrl_t * instance, uint8_t vc)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG, (uint32_t)(vc), 0, 2);
+}
+uint8_t mipi_dsih_hal_dpi_get_video_vc(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_DPI_CFG, 0, 2);
+}
+dsih_error_t mipi_dsih_hal_dpi_color_coding(dsih_ctrl_t * instance, dsih_color_coding_t color_coding)
+{
+ dsih_error_t err = OK;
+ if (color_coding > 7)
+ {
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: invalid colour configuration");
+ }
+ err = ERR_DSI_COLOR_CODING;
+ }
+ else
+ {
+ mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG, color_coding, 2, 3);
+ }
+ return err;
+}
+dsih_color_coding_t mipi_dsih_hal_dpi_get_color_coding(dsih_ctrl_t * instance)
+{
+ return (dsih_color_coding_t)(mipi_dsih_read_part(instance, R_DSI_HOST_DPI_CFG, 2, 3));
+}
+uint8_t mipi_dsih_hal_dpi_get_color_depth(dsih_ctrl_t * instance)
+{
+ uint8_t color_depth = 0;
+ switch (mipi_dsih_read_part(instance, R_DSI_HOST_DPI_CFG, 2, 3))
+ {
+ case 0:
+ case 1:
+ case 2:
+ color_depth = 16;
+ break;
+ case 3:
+ case 4:
+ color_depth = 18;
+ break;
+ default:
+ color_depth = 24;
+ break;
+ }
+ return color_depth;
+}
+uint8_t mipi_dsih_hal_dpi_get_color_config(dsih_ctrl_t * instance)
+{
+ uint8_t color_config = 0;
+ switch (mipi_dsih_read_part(instance, R_DSI_HOST_DPI_CFG, 2, 3))
+ {
+ case 0:
+ color_config = 1;
+ break;
+ case 1:
+ color_config = 2;
+ break;
+ case 2:
+ color_config = 3;
+ break;
+ case 3:
+ color_config = 1;
+ break;
+ case 4:
+ color_config = 2;
+ break;
+ default:
+ color_config = 0;
+ break;
+ }
+ return color_config;
+}
+void mipi_dsih_hal_dpi_18_loosely_packet_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG, enable, 10, 1);
+}
+void mipi_dsih_hal_dpi_color_mode_pol(dsih_ctrl_t * instance, int active_low)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG, active_low, 9, 1);
+}
+void mipi_dsih_hal_dpi_shut_down_pol(dsih_ctrl_t * instance, int active_low)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG, active_low, 8, 1);
+}
+void mipi_dsih_hal_dpi_hsync_pol(dsih_ctrl_t * instance, int active_low)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG, active_low, 7, 1);
+}
+void mipi_dsih_hal_dpi_vsync_pol(dsih_ctrl_t * instance, int active_low)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG, active_low, 6, 1);
+}
+void mipi_dsih_hal_dpi_dataen_pol(dsih_ctrl_t * instance, int active_low)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG, active_low, 5, 1);
+}
+void mipi_dsih_hal_dpi_frame_ack_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 11, 1);
+}
+void mipi_dsih_hal_dpi_null_packet_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 10, 1);
+}
+void mipi_dsih_hal_dpi_multi_packet_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 9, 1);
+}
+void mipi_dsih_hal_dpi_lp_during_hfp(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 8, 1);
+}
+void mipi_dsih_hal_dpi_lp_during_hbp(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 7, 1);
+}
+void mipi_dsih_hal_dpi_lp_during_vactive(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 6, 1);
+}
+void mipi_dsih_hal_dpi_lp_during_vfp(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 5, 1);
+}
+void mipi_dsih_hal_dpi_lp_during_vbp(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 4, 1);
+}
+void mipi_dsih_hal_dpi_lp_during_vsync(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 3, 1);
+}
+dsih_error_t mipi_dsih_hal_dpi_video_mode_type(dsih_ctrl_t * instance, dsih_video_mode_t type)
+{
+ if (type < 3)
+ {
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, type, 1, 2);
+ return OK;
+ }
+ else
+ {
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: undefined type");
+ }
+ return ERR_DSI_OUT_OF_BOUND;
+ }
+}
+void mipi_dsih_hal_dpi_video_mode_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 0, 1);
+}
+int mipi_dsih_hal_dpi_is_video_mode(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_VID_MODE_CFG, 0, 1);
+}
+dsih_error_t mipi_dsih_hal_dpi_null_packet_size(dsih_ctrl_t * instance, uint16_t size)
+{
+ if (size < 0x3ff) /* 10-bit field */
+ {
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_PKT_CFG, size, 21, 10);
+ return OK;
+ }
+ else
+ {
+ return ERR_DSI_OUT_OF_BOUND;
+ }
+}
+dsih_error_t mipi_dsih_hal_dpi_chunks_no(dsih_ctrl_t * instance, uint16_t no)
+{
+ if (no < 0x3ff)
+ {
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_PKT_CFG, no, 11, 10);
+ return OK;
+ }
+ else
+ {
+ return ERR_DSI_OUT_OF_BOUND;
+ }
+}
+dsih_error_t mipi_dsih_hal_dpi_video_packet_size(dsih_ctrl_t * instance, uint16_t size)
+{
+ if (size < 0x7ff) /* 11-bit field */
+ {
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_PKT_CFG, size, 0, 11);
+ return OK;
+ }
+ else
+ {
+ return ERR_DSI_OUT_OF_BOUND;
+ }
+}
+void mipi_dsih_hal_tear_effect_ack_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, enable, 14, 1);
+}
+void mipi_dsih_hal_cmd_ack_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, enable, 13, 1);
+}
+dsih_error_t mipi_dsih_hal_dcs_wr_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp)
+{
+ switch (no_of_param)
+ {
+ case 0:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 7, 1);
+ break;
+ case 1:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 8, 1);
+ break;
+ default:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 12, 1);
+ break;
+ }
+ return OK;
+}
+dsih_error_t mipi_dsih_hal_dcs_rd_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp)
+{
+ dsih_error_t err = OK;
+ switch (no_of_param)
+ {
+ case 0:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 9, 1);
+ break;
+ default:
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: undefined DCS Read packet type");
+ }
+ err = ERR_DSI_OUT_OF_BOUND;
+ break;
+ }
+ return err;
+}
+
+/*Jessica add begin: to support max read packet size command */
+dsih_error_t mipi_dsih_hal_max_rd_packet_size_type(dsih_ctrl_t * instance, int lp)
+{
+ dsih_error_t err = OK;
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 10, 1);
+ return err;
+}
+/*Jessica add end*/
+
+dsih_error_t mipi_dsih_hal_gen_wr_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp)
+{
+ switch (no_of_param)
+ {
+ case 0:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 1, 1);
+ break;
+ case 1:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 2, 1);
+ break;
+ case 2:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 3, 1);
+ break;
+ default:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 11, 1);
+ break;
+ }
+ return OK;
+}
+dsih_error_t mipi_dsih_hal_gen_rd_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp)
+{
+ dsih_error_t err = OK;
+ switch (no_of_param)
+ {
+ case 0:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 4, 1);
+ break;
+ case 1:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 5, 1);
+ break;
+ case 2:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 6, 1);
+ break;
+ default:
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: undefined Generic Read packet type");
+ }
+ err = ERR_DSI_OUT_OF_BOUND;
+ break;
+ }
+ return err;
+}
+void mipi_dsih_hal_max_rd_size_tx_type(dsih_ctrl_t * instance, int lp)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 10, 1);
+}
+void mipi_dsih_hal_gen_cmd_mode_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, enable, 0, 1);
+}
+int mipi_dsih_hal_gen_is_cmd_mode(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_MODE_CFG, 0, 1);
+}
+void mipi_dsih_hal_dpi_hline(dsih_ctrl_t * instance, uint16_t time)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_TMR_LINE_CFG, time, 18, 14);
+}
+void mipi_dsih_hal_dpi_hbp(dsih_ctrl_t * instance, uint16_t time)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_TMR_LINE_CFG, time, 9, 9);
+}
+void mipi_dsih_hal_dpi_hsa(dsih_ctrl_t * instance, uint16_t time)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_TMR_LINE_CFG, time, 0, 9);
+}
+void mipi_dsih_hal_dpi_vactive(dsih_ctrl_t * instance, uint16_t lines)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VTIMING_CFG, lines, 16, 11);
+}
+void mipi_dsih_hal_dpi_vfp(dsih_ctrl_t * instance, uint16_t lines)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VTIMING_CFG, lines, 10, 6);
+}
+void mipi_dsih_hal_dpi_vbp(dsih_ctrl_t * instance, uint16_t lines)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VTIMING_CFG, lines, 4, 6);
+}
+void mipi_dsih_hal_dpi_vsync(dsih_ctrl_t * instance, uint16_t lines)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VTIMING_CFG, lines, 0, 4);
+}
+void mipi_dsih_hal_timeout_clock_division(dsih_ctrl_t * instance, uint8_t byte_clk_division_factor)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_CLK_MGR, byte_clk_division_factor, 8, 8);
+}
+void mipi_dsih_hal_lp_rx_timeout(dsih_ctrl_t * instance, uint16_t count)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_TO_CNT_CFG, count, 16, 16);
+}
+void mipi_dsih_hal_hs_tx_timeout(dsih_ctrl_t * instance, uint16_t count)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_TO_CNT_CFG, count, 0, 16);
+}
+uint32_t mipi_dsih_hal_error_status_0(dsih_ctrl_t * instance, uint32_t mask)
+{
+ return (mipi_dsih_read_word(instance, R_DSI_HOST_ERROR_ST0) & mask);
+}
+uint32_t mipi_dsih_hal_error_status_1(dsih_ctrl_t * instance, uint32_t mask)
+{
+ return (mipi_dsih_read_word(instance, R_DSI_HOST_ERROR_ST1) & mask);
+}
+void mipi_dsih_hal_error_mask_0(dsih_ctrl_t * instance, uint32_t mask)
+{
+ mipi_dsih_write_word(instance, R_DSI_HOST_ERROR_MSK0, mask);
+}
+uint32_t mipi_dsih_hal_get_error_mask_0(dsih_ctrl_t * instance, uint32_t mask)
+{
+ return (mipi_dsih_read_word(instance, R_DSI_HOST_ERROR_MSK0) & mask);
+}
+void mipi_dsih_hal_error_mask_1(dsih_ctrl_t * instance, uint32_t mask)
+{
+ mipi_dsih_write_word(instance, R_DSI_HOST_ERROR_MSK1, mask);
+}
+uint32_t mipi_dsih_hal_get_error_mask_1(dsih_ctrl_t * instance, uint32_t mask)
+{
+ return (mipi_dsih_read_word(instance, R_DSI_HOST_ERROR_MSK1) & mask);
+}
+/* DBI NOT IMPLEMENTED */
+void mipi_dsih_hal_dbi_out_color_coding(dsih_ctrl_t * instance, uint8_t color_depth, uint8_t option);
+void mipi_dsih_hal_dbi_in_color_coding(dsih_ctrl_t * instance, uint8_t color_depth, uint8_t option);
+void mipi_dsih_hal_dbi_lut_size(dsih_ctrl_t * instance, uint8_t size);
+void mipi_dsih_hal_dbi_partitioning_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dbi_dcs_vc(dsih_ctrl_t * instance, uint8_t vc);
+void mipi_dsih_hal_dbi_max_cmd_size(dsih_ctrl_t * instance, uint16_t size);
+void mipi_dsih_hal_dbi_cmd_size(dsih_ctrl_t * instance, uint16_t size);
+void mipi_dsih_hal_dbi_max_cmd_size(dsih_ctrl_t * instance, uint16_t size);
+int mipi_dsih_hal_dbi_rd_cmd_busy(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_read_fifo_full(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_read_fifo_empty(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_write_fifo_full(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_write_fifo_empty(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_cmd_fifo_full(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_cmd_fifo_empty(dsih_ctrl_t * instance);
+
+dsih_error_t mipi_dsih_hal_gen_packet_header(dsih_ctrl_t * instance, uint8_t vc, uint8_t packet_type, uint8_t ms_byte, uint8_t ls_byte)
+{
+ if (vc < 4)
+ {
+ mipi_dsih_write_part(instance, R_DSI_HOST_GEN_HDR, (ms_byte << 16) | (ls_byte << 8 ) | ((vc << 6) | packet_type), 0, 24);
+ return OK;
+ }
+ return ERR_DSI_OVERFLOW;
+}
+dsih_error_t mipi_dsih_hal_gen_packet_payload(dsih_ctrl_t * instance, uint32_t payload)
+{
+ if (mipi_dsih_hal_gen_write_fifo_full(instance))
+ {
+ return ERR_DSI_OVERFLOW;
+ }
+ mipi_dsih_write_word(instance, R_DSI_HOST_GEN_PLD_DATA, payload);
+ return OK;
+
+}
+dsih_error_t mipi_dsih_hal_gen_read_payload(dsih_ctrl_t * instance, uint32_t* payload)
+{
+ *payload = mipi_dsih_read_word(instance, R_DSI_HOST_GEN_PLD_DATA);
+ return OK;
+}
+
+void mipi_dsih_hal_gen_rd_vc(dsih_ctrl_t * instance, uint8_t vc)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_PCKHDL_CFG, vc, 5, 2);
+}
+void mipi_dsih_hal_gen_eotp_rx_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_PCKHDL_CFG, enable, 1, 1);
+}
+void mipi_dsih_hal_gen_eotp_tx_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_PCKHDL_CFG, enable, 0, 1);
+}
+void mipi_dsih_hal_bta_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_PCKHDL_CFG, enable, 2, 1);
+}
+void mipi_dsih_hal_gen_ecc_rx_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_PCKHDL_CFG, enable, 3, 1);
+}
+void mipi_dsih_hal_gen_crc_rx_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_PCKHDL_CFG, enable, 4, 1);
+}
+int mipi_dsih_hal_gen_rd_cmd_busy(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 6, 1);
+}
+int mipi_dsih_hal_gen_read_fifo_full(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 5, 1);
+}
+int mipi_dsih_hal_gen_read_fifo_empty(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 4, 1);
+}
+int mipi_dsih_hal_gen_write_fifo_full(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 3, 1);
+}
+int mipi_dsih_hal_gen_write_fifo_empty(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 2, 1);
+}
+int mipi_dsih_hal_gen_cmd_fifo_full(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 1, 1);
+}
+int mipi_dsih_hal_gen_cmd_fifo_empty(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 0, 1);
+}
+/* only if DPI */
+dsih_error_t mipi_dsih_phy_hs2lp_config(dsih_ctrl_t * instance, uint8_t no_of_byte_cycles)
+{
+ //mipi_dsih_write_part(instance, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 20, 8);
+ mipi_dsih_write_part(instance, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 24, 8);
+ return OK;
+}
+dsih_error_t mipi_dsih_phy_lp2hs_config(dsih_ctrl_t * instance, uint8_t no_of_byte_cycles)
+{
+ //mipi_dsih_write_part(instance, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 12, 8);
+ mipi_dsih_write_part(instance, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 16, 8);
+ return OK;
+}
+dsih_error_t mipi_dsih_phy_bta_time(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles)
+{
+ /*Jessica modified: From ASIC, the second table in spec is correct, this 15 bits are max rd time*/
+ if (no_of_byte_cycles < 0x8000) /* 15-bit field */
+ {
+ //mipi_dsih_write_part(instance, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 0, 12);
+ mipi_dsih_write_part(instance, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 0, 15);
+ }
+ else
+ {
+ return ERR_DSI_OVERFLOW;
+ }
+ return OK;
+}
+/* */ \ No newline at end of file
diff --git a/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.h b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.h
new file mode 100644
index 00000000..4524f9f7
--- /dev/null
+++ b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.h
@@ -0,0 +1,242 @@
+/*
+ * @file mipi_dsih_hal.h
+ *
+ * Synopsys Inc.
+ * SG DWC PT02
+ */
+/*
+ The Synopsys Software Driver and documentation (hereinafter "Software")
+ is an unsupported work of Synopsys, Inc. unless otherwise
+ expressly agreed to in writing between Synopsys and you.
+
+ The Software IS NOT an item of Licensed Software or Licensed Product under
+ any End User Software License Agreement or Agreement for Licensed Product
+ with Synopsys or any supplement thereto. Permission is hereby granted,
+ free of charge, to any person obtaining a copy of this software annotated
+ with this license and the Software, to deal in the Software without
+ restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so, subject
+ to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
+ */
+
+#ifndef MIPI_DSIH_HAL_H_
+#define MIPI_DSIH_HAL_H_
+
+#include "mipi_dsih_local.h"
+
+#define R_DSI_HOST_VERSION 0x00UL
+#define R_DSI_HOST_PWR_UP 0x04UL
+#define R_DSI_HOST_CLK_MGR 0x08UL
+#define R_DSI_HOST_DPI_CFG 0x0CUL
+#define R_DSI_HOST_DBI_CFG 0x10UL
+#define R_DSI_HOST_DBI_CMDSIZE 0x14UL
+#define R_DSI_HOST_PCKHDL_CFG 0x18UL
+#define R_DSI_HOST_VID_MODE_CFG 0x1CUL
+#define R_DSI_HOST_VID_PKT_CFG 0x20UL
+#define R_DSI_HOST_CMD_MODE_CFG 0x24UL
+#define R_DSI_HOST_TMR_LINE_CFG 0x28UL
+#define R_DSI_HOST_VTIMING_CFG 0x2CUL
+#define R_DSI_HOST_PHY_TMR_CFG 0x30UL
+#define R_DSI_HOST_GEN_HDR 0x34UL
+#define R_DSI_HOST_GEN_PLD_DATA 0x38UL
+#define R_DSI_HOST_CMD_PKT_STATUS 0x3CUL
+#define R_DSI_HOST_TO_CNT_CFG 0x40UL
+#define R_DSI_HOST_ERROR_ST0 0x44UL
+#define R_DSI_HOST_ERROR_ST1 0x48UL
+#define R_DSI_HOST_ERROR_MSK0 0x4CUL
+#define R_DSI_HOST_ERROR_MSK1 0x50UL
+
+#ifdef CONFIG_OF
+extern uint32_t g_dsi_base_addr;
+#endif
+
+typedef enum _Dsi_Int0_Type_ {
+ ack_with_err_0,
+ ack_with_err_1,
+ ack_with_err_2,
+ ack_with_err_3,
+ ack_with_err_4,
+ ack_with_err_5,
+ ack_with_err_6,
+ ack_with_err_7,
+ ack_with_err_8,
+ ack_with_err_9,
+ ack_with_err_10,
+ ack_with_err_11,
+ ack_with_err_12,
+ ack_with_err_13,
+ ack_with_err_14,
+ ack_with_err_15,
+ dphy_errors_0,
+ dphy_errors_1,
+ dphy_errors_2,
+ dphy_errors_3,
+ dphy_errors_4,
+ DSI_INT0_MAX,
+}Dsi_Int0_Type;
+
+typedef enum _Dsi_Int1_Type_ {
+ to_hs_tx,
+ to_lp_rx,
+ ecc_single_err,
+ ecc_multi_err,
+ crc_err,
+ pkt_size_err,
+ eopt_err,
+ dpi_pld_wr_err,
+ gen_cmd_wr_err,
+ gen_pld_wr_err,
+ gen_pld_send_err,
+ gen_pld_rd_err,
+ gen_pld_recv_err,
+ dbi_cmd_wr_err,
+ dbi_pld_wr_err,
+ dbi_pld_rd_err,
+ dbi_pld_recv_err,
+ dbi_illegal_comm_err,
+ DSI_INT1_MAX,
+}Dsi_Int1_Type;
+#define DSI_INT_MASK0_SET(bit,val)\
+{\
+ uint32_t reg_val = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK0);\
+ reg_val = (val == 1)?(reg_val | (1UL<<bit)):(reg_val & (~(1UL<<bit)));\
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK0, reg_val);\
+}
+
+#define DSI_INT_MASK1_SET(bit,val)\
+{\
+ uint32_t reg_val = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK1);\
+ reg_val = (val == 1)?(reg_val | (1UL<<bit)):(reg_val & (~(1UL<<bit)));\
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK1, reg_val);\
+}
+
+
+uint32_t mipi_dsih_hal_get_version(dsih_ctrl_t * instance);
+void mipi_dsih_hal_power(dsih_ctrl_t * instance, int on);
+int mipi_dsih_hal_get_power(dsih_ctrl_t * instance);
+void mipi_dsih_hal_tx_escape_division(dsih_ctrl_t * instance, uint8_t tx_escape_division);
+void mipi_dsih_hal_dpi_video_vc(dsih_ctrl_t * instance, uint8_t vc);
+uint8_t mipi_dsih_hal_dpi_get_video_vc(dsih_ctrl_t * instance);
+
+dsih_error_t mipi_dsih_hal_dpi_color_coding(dsih_ctrl_t * instance, dsih_color_coding_t color_coding);
+dsih_color_coding_t mipi_dsih_hal_dpi_get_color_coding(dsih_ctrl_t * instance);
+uint8_t mipi_dsih_hal_dpi_get_color_depth(dsih_ctrl_t * instance);
+uint8_t mipi_dsih_hal_dpi_get_color_config(dsih_ctrl_t * instance);
+void mipi_dsih_hal_dpi_18_loosely_packet_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dpi_color_mode_pol(dsih_ctrl_t * instance, int active_low);
+void mipi_dsih_hal_dpi_shut_down_pol(dsih_ctrl_t * instance, int active_low);
+void mipi_dsih_hal_dpi_hsync_pol(dsih_ctrl_t * instance, int active_low);
+void mipi_dsih_hal_dpi_vsync_pol(dsih_ctrl_t * instance, int active_low);
+void mipi_dsih_hal_dpi_dataen_pol(dsih_ctrl_t * instance, int active_low);
+void mipi_dsih_hal_dpi_frame_ack_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dpi_null_packet_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dpi_multi_packet_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dpi_lp_during_hfp(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dpi_lp_during_hbp(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dpi_lp_during_vactive(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dpi_lp_during_vfp(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dpi_lp_during_vbp(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dpi_lp_during_vsync(dsih_ctrl_t * instance, int enable);
+
+dsih_error_t mipi_dsih_hal_dpi_video_mode_type(dsih_ctrl_t * instance, dsih_video_mode_t type);
+void mipi_dsih_hal_dpi_video_mode_en(dsih_ctrl_t * instance, int enable);
+int mipi_dsih_hal_dpi_is_video_mode(dsih_ctrl_t * instance);
+dsih_error_t mipi_dsih_hal_dpi_null_packet_size(dsih_ctrl_t * instance, uint16_t size);
+dsih_error_t mipi_dsih_hal_dpi_chunks_no(dsih_ctrl_t * instance, uint16_t no);
+dsih_error_t mipi_dsih_hal_dpi_video_packet_size(dsih_ctrl_t * instance, uint16_t size);
+
+void mipi_dsih_hal_tear_effect_ack_en(dsih_ctrl_t * instance, int enable);
+
+void mipi_dsih_hal_cmd_ack_en(dsih_ctrl_t * instance, int enable);
+dsih_error_t mipi_dsih_hal_dcs_wr_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp);
+dsih_error_t mipi_dsih_hal_dcs_rd_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp);
+/*Jessica add to support max rd packet size command*/
+dsih_error_t mipi_dsih_hal_max_rd_packet_size_type(dsih_ctrl_t * instance, int lp);
+dsih_error_t mipi_dsih_hal_gen_wr_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp);
+dsih_error_t mipi_dsih_hal_gen_rd_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp);
+void mipi_dsih_hal_max_rd_size_type(dsih_ctrl_t * instance, int lp);
+void mipi_dsih_hal_gen_cmd_mode_en(dsih_ctrl_t * instance, int enable);
+int mipi_dsih_hal_gen_is_cmd_mode(dsih_ctrl_t * instance);
+
+void mipi_dsih_hal_dpi_hline(dsih_ctrl_t * instance, uint16_t time);
+void mipi_dsih_hal_dpi_hbp(dsih_ctrl_t * instance, uint16_t time);
+void mipi_dsih_hal_dpi_hsa(dsih_ctrl_t * instance, uint16_t time);
+void mipi_dsih_hal_dpi_vactive(dsih_ctrl_t * instance, uint16_t lines);
+void mipi_dsih_hal_dpi_vfp(dsih_ctrl_t * instance, uint16_t lines);
+void mipi_dsih_hal_dpi_vbp(dsih_ctrl_t * instance, uint16_t lines);
+void mipi_dsih_hal_dpi_vsync(dsih_ctrl_t * instance, uint16_t lines);
+dsih_error_t mipi_dsih_hal_gen_packet_header(dsih_ctrl_t * instance, uint8_t vc, uint8_t packet_type, uint8_t ms_byte, uint8_t ls_byte);
+/*dsih_error_t mipi_dsih_hal_gen_packet_payload(dsih_ctrl_t * instance, uint32_t* payload, uint16_t payload_size);*/
+dsih_error_t mipi_dsih_hal_gen_packet_payload(dsih_ctrl_t * instance, uint32_t payload);
+dsih_error_t mipi_dsih_hal_gen_read_payload(dsih_ctrl_t * instance, uint32_t* payload);
+
+void mipi_dsih_hal_timeout_clock_division(dsih_ctrl_t * instance, uint8_t byte_clk_division_factor);
+void mipi_dsih_hal_lp_rx_timeout(dsih_ctrl_t * instance, uint16_t count);
+void mipi_dsih_hal_hs_tx_timeout(dsih_ctrl_t * instance, uint16_t count);
+
+uint32_t mipi_dsih_hal_error_status_0(dsih_ctrl_t * instance, uint32_t mask);
+uint32_t mipi_dsih_hal_error_status_1(dsih_ctrl_t * instance, uint32_t mask);
+void mipi_dsih_hal_error_mask_0(dsih_ctrl_t * instance, uint32_t mask);
+void mipi_dsih_hal_error_mask_1(dsih_ctrl_t * instance, uint32_t mask);
+uint32_t mipi_dsih_hal_get_error_mask_0(dsih_ctrl_t * instance, uint32_t mask);
+uint32_t mipi_dsih_hal_get_error_mask_1(dsih_ctrl_t * instance, uint32_t mask);
+
+void mipi_dsih_hal_dbi_out_color_coding(dsih_ctrl_t * instance, uint8_t color_depth, uint8_t option);
+void mipi_dsih_hal_dbi_in_color_coding(dsih_ctrl_t * instance, uint8_t color_depth, uint8_t option);
+void mipi_dsih_hal_dbi_lut_size(dsih_ctrl_t * instance, uint8_t size);
+void mipi_dsih_hal_dbi_partitioning_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dbi_dcs_vc(dsih_ctrl_t * instance, uint8_t vc);
+
+void mipi_dsih_hal_dbi_cmd_size(dsih_ctrl_t * instance, uint16_t size);
+void mipi_dsih_hal_dbi_max_cmd_size(dsih_ctrl_t * instance, uint16_t size);
+int mipi_dsih_hal_dbi_rd_cmd_busy(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_read_fifo_full(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_read_fifo_empty(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_write_fifo_full(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_write_fifo_empty(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_cmd_fifo_full(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_cmd_fifo_empty(dsih_ctrl_t * instance);
+
+void mipi_dsih_hal_gen_rd_vc(dsih_ctrl_t * instance, uint8_t vc);
+void mipi_dsih_hal_gen_eotp_rx_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_gen_eotp_tx_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_bta_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_gen_ecc_rx_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_gen_crc_rx_en(dsih_ctrl_t * instance, int enable);
+int mipi_dsih_hal_gen_rd_cmd_busy(dsih_ctrl_t * instance);
+int mipi_dsih_hal_gen_read_fifo_full(dsih_ctrl_t * instance);
+int mipi_dsih_hal_gen_read_fifo_empty(dsih_ctrl_t * instance);
+int mipi_dsih_hal_gen_write_fifo_full(dsih_ctrl_t * instance);
+int mipi_dsih_hal_gen_write_fifo_empty(dsih_ctrl_t * instance);
+int mipi_dsih_hal_gen_cmd_fifo_full(dsih_ctrl_t * instance);
+int mipi_dsih_hal_gen_cmd_fifo_empty(dsih_ctrl_t * instance);
+
+/* only if DPI */
+dsih_error_t mipi_dsih_phy_hs2lp_config(dsih_ctrl_t * instance, uint8_t no_of_byte_cycles);
+dsih_error_t mipi_dsih_phy_lp2hs_config(dsih_ctrl_t * instance, uint8_t no_of_byte_cycles);
+dsih_error_t mipi_dsih_phy_bta_time(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles);
+/* */
+
+void mipi_dsih_write_word(dsih_ctrl_t * instance, uint32_t reg_address, uint32_t data);
+void mipi_dsih_write_part(dsih_ctrl_t * instance, uint32_t reg_address, uint32_t data, uint8_t shift, uint8_t width);
+uint32_t mipi_dsih_read_word(dsih_ctrl_t * instance, uint32_t reg_address);
+uint32_t mipi_dsih_read_part(dsih_ctrl_t * instance, uint32_t reg_address, uint8_t shift, uint8_t width);
+
+#endif /* MIPI_DSI_API_H_ */
+
diff --git a/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_local.h b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_local.h
new file mode 100644
index 00000000..6c0fa3be
--- /dev/null
+++ b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_local.h
@@ -0,0 +1,227 @@
+
+/*
+ The Synopsys Software Driver and documentation (hereinafter "Software")
+ is an unsupported work of Synopsys, Inc. unless otherwise
+ expressly agreed to in writing between Synopsys and you.
+
+ The Software IS NOT an item of Licensed Software or Licensed Product under
+ any End User Software License Agreement or Agreement for Licensed Product
+ with Synopsys or any supplement thereto. Permission is hereby granted,
+ free of charge, to any person obtaining a copy of this software annotated
+ with this license and the Software, to deal in the Software without
+ restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so, subject
+ to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
+ */
+
+#ifndef MIPI_DSIH_LOCAL_H_
+#define MIPI_DSIH_LOCAL_H_
+
+//#include <stdint.h>
+#include <linux/kernel.h>
+#include "../sprdfb_chip_common.h"
+
+
+//typedef unsigned char uint8_t;
+//typedef unsigned short uint16_t;
+//typedef unsigned int uint32_t;
+
+#define DSIH_PIXEL_TOLERANCE 2
+#define DSIH_FIFO_ACTIVE_WAIT 5000 /* no of tries to access the fifo*/
+#define DSIH_PHY_ACTIVE_WAIT 200
+#define ONE_MS_ACTIVE_WAIT 50000 /* 50MHz processor */
+#define DEFAULT_BYTE_CLOCK 864000 /* a value to start PHY PLL - random */
+
+/** Define D-PHY type */
+
+#ifdef SPRD_MIPI_DPHY_GEN1
+/** DWC_MIPI_DPHY_BIDIR_TSMC40LP 4 Lanes Gen 1 1GHz */
+#define DWC_MIPI_DPHY_BIDIR_TSMC40LP
+#endif
+#ifdef SPRD_MIPI_DPHY_GEN2
+/** DWC_MIPI_DPHY_BIDIR_TSMC40LP / GF28LP 4 Lanes Gen 2 1.5GHz */
+#define GEN_2
+#endif
+/** 4 Lanes Gen 2 1.5GHz testchips */
+//#define TESTCHIP
+/** TQL 2 Lane test chip */
+/* #define DPHY2Btql */
+typedef enum
+{
+ OK = 0,
+ ERR_DSI_COLOR_CODING,
+ ERR_DSI_OUT_OF_BOUND,
+ ERR_DSI_OVERFLOW,
+ ERR_DSI_INVALID_INSTANCE,
+ ERR_DSI_INVALID_IO,
+ ERR_DSI_CORE_INCOMPATIBLE,
+ ERR_DSI_VIDEO_MODE,
+ ERR_DSI_INVALID_COMMAND,
+ ERR_DSI_INVALID_EVENT,
+ ERR_DSI_INVALID_HANDLE,
+ ERR_DSI_PHY_POWERUP,
+ ERR_DSI_PHY_INVALID,
+ ERR_DSI_PHY_FREQ_OUT_OF_BOUND,
+#ifdef GEN_2
+ ERR_DSI_PHY_PLL_NOT_LOCKED,
+#endif
+ ERR_DSI_TIMEOUT
+}
+dsih_error_t;
+typedef enum
+{
+ VIDEO_NON_BURST_WITH_SYNC_PULSES = 0,
+ VIDEO_NON_BURST_WITH_SYNC_EVENTS,
+ VIDEO_BURST_WITH_SYNC_PULSES
+}
+dsih_video_mode_t;
+typedef enum
+{
+ COLOR_CODE_16BIT_CONFIG1,
+ COLOR_CODE_16BIT_CONFIG2,
+ COLOR_CODE_16BIT_CONFIG3,
+ COLOR_CODE_18BIT_CONFIG1,
+ COLOR_CODE_18BIT_CONFIG2,
+ COLOR_CODE_24BIT
+}
+dsih_color_coding_t;
+typedef enum
+{
+ ACK_SOT_ERR = 0,
+ ACK_SOT_SYNC,
+ ACK_EOT_SYNC,
+ ACK_ESCAPE_CMD_ERR,
+ ACK_LP_TX_SYNC_ERR,
+ ACK_HS_RX_TIMEOUT_ERR,
+ ACK_FALSE_CONTROL_ERR,
+ ACK_RSVD_DEVICE_ERR_7,
+ ACK_ECC_SINGLE_BIT_ERR,
+ ACK_ECC_MULTI_BIT_ERR,
+ ACK_CHECKSUM_ERR,
+ ACK_DSI_TYPE_NOT_RECOGNIZED_ERR,
+ ACK_VC_ID_INVALID_ERR,
+ ACK_INVALID_TX_LENGTH_ERR,
+ ACK_RSVD_DEVICE_ERR_14,
+ ACK_DSI_PROTOCOL_ERR,
+
+ DPHY_ESC_ENTRY_ERR,
+ DPHY_SYNC_ESC_LP_ERR,
+ DPHY_CONTROL_LANE0_ERR,
+ DPHY_CONTENTION_LP0_ERR,
+ DPHY_CONTENTION_LP1_ERR,
+ /* start of st1*/
+ HS_CONTENTION,
+ LP_CONTENTION,
+ RX_ECC_SINGLE_ERR,
+ RX_ECC_MULTI_ERR,
+ RX_CRC_ERR,
+ RX_PKT_SIZE_ERR,
+ RX_EOTP_ERR,
+ DPI_PLD_FIFO_FULL_ERR,
+ GEN_TX_CMD_FIFO_FULL_ERR,
+ GEN_TX_PLD_FIFO_FULL_ERR,
+ GEN_TX_PLD_FIFO_EMPTY_ERR,
+ GEN_RX_PLD_FIFO_EMPTY_ERR,
+ GEN_RX_PLD_FIFO_FULL_ERR,
+
+ DBI_TX_CMD_FIFO_FULL_ERR,
+ DBI_TX_PLD_FIFO_FULL_ERR,
+ DBI_RX_PLD_FIFO_EMPTY_ERR,
+ DBI_RX_PLD_FIFO_FULL_ERR,
+ DBI_ILLEGAL_CMD_ERR,
+ DSI_MAX_EVENT
+}
+dsih_event_t;
+typedef enum
+{
+ NOT_INITIALIZED = 0,
+ INITIALIZED,
+ ON,
+ OFF
+}
+dsih_state_t;
+
+typedef struct dphy_t
+{
+ uint32_t address;
+ uint32_t reference_freq;
+#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING
+ /** mark if D-PHY should keep work or not */
+ uint32_t phy_keep_work;
+#endif
+ dsih_state_t status;
+ void (*bsp_pre_config)(struct dphy_t *instance, void* param);
+ uint32_t (*core_read_function)(uint32_t addr, uint32_t offset);
+ void (*core_write_function)(uint32_t addr, uint32_t offset, uint32_t data);
+ void (*log_error)(const char * string);
+ void (*log_info)(const char *fmt, ...);
+}
+dphy_t;
+
+typedef struct dsih_ctrl_t
+{
+ uint32_t address;
+ dphy_t phy_instance;
+ uint32_t phy_feq;
+ uint8_t max_lanes;
+ uint8_t max_hs_to_lp_cycles;
+ uint8_t max_lp_to_hs_cycles;
+ uint16_t max_bta_cycles;
+ int color_mode_polarity;
+ int shut_down_polarity;
+ dsih_state_t status;
+ uint32_t (*core_read_function)(uint32_t addr, uint32_t offset);
+ void (*core_write_function)(uint32_t addr, uint32_t offset, uint32_t data);
+ void (*log_error)(const char * string);
+ void (*log_info)(const char *fmt, ...);
+ void (*event_registry[DSI_MAX_EVENT])(struct dsih_ctrl_t *instance, void *handler);
+}
+dsih_ctrl_t;
+typedef struct
+{
+ uint8_t no_of_lanes;
+ uint8_t virtual_channel;
+ dsih_video_mode_t video_mode;
+ int receive_ack_packets;
+ uint32_t byte_clock;
+ uint32_t pixel_clock;
+ dsih_color_coding_t color_coding;
+ int is_18_loosely;
+ int data_en_polarity;
+ int h_polarity;
+ uint16_t h_active_pixels; /* hadr*/
+ uint16_t h_sync_pixels;
+ uint16_t h_back_porch_pixels; /* hbp */
+ uint16_t h_total_pixels; /* h_total */
+ int v_polarity;
+ uint16_t v_active_lines; /* vadr*/
+ uint16_t v_sync_lines;
+ uint16_t v_back_porch_lines; /* vbp */
+ uint16_t v_total_lines; /* v_total */
+}
+dsih_dpi_video_t;
+typedef struct
+{
+ uint32_t addr;
+ uint32_t data;
+}
+register_config_t;
+
+#endif /* MIPI_DSIH_LOCAL_H_ */
+
diff --git a/drivers/video/sprdfb/dsi_1_21a/Makefile b/drivers/video/sprdfb/dsi_1_21a/Makefile
new file mode 100644
index 00000000..8e96888d
--- /dev/null
+++ b/drivers/video/sprdfb/dsi_1_21a/Makefile
@@ -0,0 +1,12 @@
+obj-$(CONFIG_FB_SC8825) := mipi_dsih_api.o mipi_dsih_dphy.o mipi_dsih_hal.o
+obj-$(CONFIG_FB_SCX35) := mipi_dsih_api.o mipi_dsih_dphy.o mipi_dsih_hal.o
+
+# ========== Pike configuration begin =======
+obj-$(CONFIG_FB_SCX30G) := mipi_dsih_api.o mipi_dsih_hal.o
+ifeq ($(CONFIG_FB_USE_MEGACORES_MIPI_DPHY), y)
+obj-$(CONFIG_FB_SCX30G) += mipi_dsih_dphy_megacores.o
+else
+obj-$(CONFIG_FB_SCX30G) += mipi_dsih_dphy.o
+endif
+# ========== Pike configuration end =========
+obj-$(CONFIG_FB_SCX35L) := mipi_dsih_api.o mipi_dsih_dphy.o mipi_dsih_hal.o
diff --git a/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_api.c b/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_api.c
new file mode 100644
index 00000000..1862be63
--- /dev/null
+++ b/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_api.c
@@ -0,0 +1,1750 @@
+/**
+ * @file mipi_dsih_api.c
+ * @brief DWC MIPI DSI Host driver
+ *
+ * Synopsys Inc.
+ * SG DWC PT02
+ */
+
+#include "mipi_dsih_api.h"
+#include "mipi_dsih_hal.h"
+#include "mipi_dsih_dphy.h"
+#include "../sprdfb.h"
+#include <linux/delay.h>
+
+/* whether to get debug messages (1) or not (0) */
+#define DEBUG 0
+
+#define PRECISION_FACTOR 1000
+#define VIDEO_PACKET_OVERHEAD 6
+#define NULL_PACKET_OVERHEAD 6
+#define SHORT_PACKET 4
+#define BLANKING_PACKET 6
+
+#define SPRDFB_MIPI_READ_COUNT_MAX 100
+
+/** Version supported by this driver */
+static const uint32_t mipi_dsih_supported_versions[] = {0x3132302A, 0x3132312A};
+static const uint32_t mipi_dsih_no_of_versions = sizeof(mipi_dsih_supported_versions) / sizeof(uint32_t);
+
+/*
+func:mipi_dsih_set_lp_clock
+desc:in low-power mode, max PHY frequency should smaller than 20MHz,
+ in synopsys IP, low-power clock divide from high-speed clock,
+ this function is designed to adapt low-power clock to various high-speed clock.
+arithmetic:
+ Fhs : high-speed frequence
+ Flp : low-power frequence
+ div : mipi_dsih_hal_tx_escape_division() param, byte clock unit.
+ because of the 20MHz demand, Flp == Fhs/(div*8) <= 20 MHz, here 500000 present 500MHz, so MHz equal 1000
+ so div >= { Fhs/(20Mhz*8) == Fhs/(20000*8) == (Fhs>>4)/10000 }
+*/
+static void mipi_dsih_set_lp_clock(dsih_ctrl_t * instance)
+{
+ uint32_t tx_escape_division = 1;
+ tx_escape_division = (instance->phy_feq>>4);
+ tx_escape_division = (tx_escape_division+9999)/10000;//ceiling calc
+ printk("sprdfb: [%s]: lp frequence div:%d\n", __func__, tx_escape_division);
+ mipi_dsih_hal_tx_escape_division(instance, (uint8_t)tx_escape_division);
+}
+
+/**
+ * Open controller instance
+ * - Check if driver is compatible with core version
+ * - Check if instance context data structure is not NULL
+ * - Bring up PHY for any transmissions in low power
+ * + Includes programming PLL to DEFAULT_BYTE_CLOCK
+ * - Bring up controller and perform initial configuration
+ * + Includes start all commands transmision in LP
+ * + Controller will not turn the bus around after commands
+ * + program counters
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return dsih_error_t
+ * @note this function must be called before any other function in this API
+ */
+dsih_error_t mipi_dsih_open(dsih_ctrl_t * instance)
+{
+ dsih_error_t err = OK;
+ uint32_t version = 0;
+ int i = 0;
+
+ if (instance == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ else if ((instance->core_read_function == 0) || (instance->core_write_function == 0))
+ {
+ return ERR_DSI_INVALID_IO;
+ }
+ else if (instance->status == INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ else if (mipi_dsih_dphy_open(&(instance->phy_instance)))
+ {
+ return ERR_DSI_PHY_INVALID;
+ }
+ else
+ {
+ instance->status = NOT_INITIALIZED;
+ version = mipi_dsih_hal_get_version(instance);
+ for (i = 0; i < mipi_dsih_no_of_versions; i++)
+ {
+ if (version == mipi_dsih_supported_versions[i])
+ {
+ break;
+ }
+ }
+ /* no matching supported version has been found*/
+ if (i >= mipi_dsih_no_of_versions)
+ {
+ if (instance->log_info != 0)
+ {
+ instance->log_info("sprdfb: driver does not support this core version 0x%lX", version);
+ }
+ return ERR_DSI_CORE_INCOMPATIBLE;
+ }
+ }
+ mipi_dsih_hal_power(instance, 0);
+ //mipi_dsih_hal_power(instance, 0);//Jessica
+ //mipi_dsih_hal_power(instance, 1);//Jessica
+ mipi_dsih_hal_dpi_color_mode_pol(instance, !instance->color_mode_polarity);
+ mipi_dsih_hal_dpi_shut_down_pol(instance, !instance->shut_down_polarity);
+ //err = mipi_dsih_phy_hs2lp_config(instance, instance->max_hs_to_lp_cycles);
+ //err |= mipi_dsih_phy_lp2hs_config(instance, instance->max_lp_to_hs_cycles);
+ mipi_dsih_hal_int_mask_0(instance, 0xffffff);
+ mipi_dsih_hal_int_mask_1(instance, 0xffffff);
+ err = mipi_dsih_phy_bta_time(instance, instance->max_bta_cycles);
+ if (err)
+ {
+ return ERR_DSI_OVERFLOW;
+ }
+ /* by default, return to LP during ALL, unless otherwise specified*/
+ mipi_dsih_hal_dpi_lp_during_hfp(instance, 1);
+ mipi_dsih_hal_dpi_lp_during_hbp(instance, 1);
+ mipi_dsih_hal_dpi_lp_during_vactive(instance, 1);
+ mipi_dsih_hal_dpi_lp_during_vfp(instance, 1);
+ mipi_dsih_hal_dpi_lp_during_vbp(instance, 1);
+ mipi_dsih_hal_dpi_lp_during_vsync(instance, 1);
+ /* by default, all commands are sent in LP */
+ mipi_dsih_hal_dcs_wr_tx_type(instance, 0, 1);
+ mipi_dsih_hal_dcs_wr_tx_type(instance, 1, 1);
+ mipi_dsih_hal_dcs_wr_tx_type(instance, 3, 1); /* long packet*/
+ mipi_dsih_hal_dcs_rd_tx_type(instance, 0, 1);
+ /*Jessica add to support max rd packet size command*/
+ mipi_dsih_hal_max_rd_packet_size_type(instance, 1);
+ mipi_dsih_hal_gen_wr_tx_type(instance, 0, 1);
+ mipi_dsih_hal_gen_wr_tx_type(instance, 1, 1);
+ mipi_dsih_hal_gen_wr_tx_type(instance, 2, 1);
+ mipi_dsih_hal_gen_wr_tx_type(instance, 3, 1); /* long packet*/
+ mipi_dsih_hal_gen_rd_tx_type(instance, 0, 1);
+ mipi_dsih_hal_gen_rd_tx_type(instance, 1, 1);
+ mipi_dsih_hal_gen_rd_tx_type(instance, 2, 1);
+ /* by default, RX_VC = 0, NO EOTp, EOTn, BTA, ECC rx and CRC rx */
+ mipi_dsih_hal_gen_rd_vc(instance, 0);
+ mipi_dsih_hal_gen_eotp_rx_en(instance, 0);
+ mipi_dsih_hal_gen_eotp_tx_en(instance, 0);
+ mipi_dsih_hal_bta_en(instance, 0);
+ mipi_dsih_hal_gen_ecc_rx_en(instance, 0);
+ mipi_dsih_hal_gen_crc_rx_en(instance, 0);
+ //mipi_dsih_hal_power(instance, 0);//Jessica
+ mipi_dsih_hal_power(instance, 1);//Jessica
+
+ /* dividing by 6 is aimed for max PHY frequency, 1GHz */
+// mipi_dsih_hal_tx_escape_division(instance, 4); //6 //Jessica
+ mipi_dsih_set_lp_clock(instance);
+ instance->status = INITIALIZED;
+ /* initialize pll so escape clocks could be generated at 864MHz, 1 lane */
+ /* however the high speed clock will not be requested */
+ //err = mipi_dsih_dphy_configure(&(instance->phy_instance), 1, DEFAULT_BYTE_CLOCK);
+ return err;
+}
+/**
+ * Close DSI Host driver
+ * - Free up resources and shutdown host controller and PHY
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return dsih_error_t
+ */
+dsih_error_t mipi_dsih_close(dsih_ctrl_t * instance)
+{
+ if (instance == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ mipi_dsih_hal_int_mask_0(instance, 0xffffff);
+ mipi_dsih_hal_int_mask_1(instance, 0xffffff);
+ mipi_dsih_dphy_close(&(instance->phy_instance));
+ mipi_dsih_hal_power(instance, 0);
+ instance->status = NOT_INITIALIZED;
+ return OK;
+}
+/**
+ * Enable return to low power mode inside video periods when timing allows
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param hfp allow to return to lp inside horizontal front porch pixels
+ * @param hbp allow to return to lp inside horizontal back porch pixels
+ * @param vactive allow to return to lp inside vertical active lines
+ * @param vfp allow to return to lp inside vertical front porch lines
+ * @param vbp allow to return to lp inside vertical back porch lines
+ * @param vsync allow to return to lp inside vertical sync lines
+ */
+void mipi_dsih_allow_return_to_lp(dsih_ctrl_t * instance, int hfp, int hbp, int vactive, int vfp, int vbp, int vsync)
+{
+ if(0 == instance)
+ {
+ return;
+ }
+
+ if (instance->status == INITIALIZED)
+ {
+ mipi_dsih_hal_dpi_lp_during_hfp(instance, hfp);
+ mipi_dsih_hal_dpi_lp_during_hbp(instance, hbp);
+ mipi_dsih_hal_dpi_lp_during_vactive(instance, vactive);
+ mipi_dsih_hal_dpi_lp_during_vfp(instance, vfp);
+ mipi_dsih_hal_dpi_lp_during_vbp(instance, vbp);
+ mipi_dsih_hal_dpi_lp_during_vsync(instance, vsync);
+ return;
+ }
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: [mipi_dsih_allow_return_to_lp] invalid instance");
+ }
+
+}
+/**
+ * Set DCS command packet transmission to low power
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param long_write command packets
+ * @param short_write command packets with none and one parameters
+ * @param short_read command packets with none parameters
+ */
+void mipi_dsih_dcs_cmd_lp_transmission(dsih_ctrl_t * instance, int long_write, int short_write, int short_read)
+{
+ if(0 == instance)
+ {
+ return;
+ }
+
+ if (instance->status == INITIALIZED)
+ {
+ mipi_dsih_hal_dcs_wr_tx_type(instance, 0, short_write);
+ mipi_dsih_hal_dcs_wr_tx_type(instance, 1, short_write);
+ mipi_dsih_hal_dcs_wr_tx_type(instance, 3, long_write); /* long packet*/
+ mipi_dsih_hal_dcs_rd_tx_type(instance, 0, short_read);
+ return;
+ }
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: [mipi_dsih_dcs_cmd_lp_transmission] invalid instance");
+ }
+
+}
+/**
+ * Set Generic interface packet transmission to low power
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param long_write command packets
+ * @param short_write command packets with none, one and two parameters
+ * @param short_read command packets with none, one and two parameters
+ */
+void mipi_dsih_gen_cmd_lp_transmission(dsih_ctrl_t * instance, int long_write, int short_write, int short_read)
+{
+ if(0 == instance)
+ {
+ return;
+ }
+
+ if (instance->status == INITIALIZED)
+ {
+ mipi_dsih_hal_gen_wr_tx_type(instance, 0, short_write);
+ mipi_dsih_hal_gen_wr_tx_type(instance, 1, short_write);
+ mipi_dsih_hal_gen_wr_tx_type(instance, 2, short_write);
+ mipi_dsih_hal_gen_wr_tx_type(instance, 3, long_write); /* long packet*/
+ mipi_dsih_hal_gen_rd_tx_type(instance, 0, short_read);
+ mipi_dsih_hal_gen_rd_tx_type(instance, 1, short_read);
+ mipi_dsih_hal_gen_rd_tx_type(instance, 2, short_read);
+ return;
+ }
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: [mipi_dsih_gen_cmd_lp_transmission] invalid instance");
+ }
+
+}
+/* packet handling */
+/**
+ * Enable all receiving activities (applying a Bus Turn Around).
+ * - Disabling using this function will stop all acknowledges by the
+ * peripherals and no interrupts from low-level protocol error reporting
+ * will be able to rise.
+ * - Enabling any receiving function (command or frame ACKs, ECC,
+ * tear effect ACK or EoTp receiving) will enable this automatically,
+ * but it must be EXPLICITLY be disabled to disabled all kinds of
+ * receiving functionality.
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable or disable
+ * @return error code
+ */
+dsih_error_t mipi_dsih_enable_rx(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_hal_bta_en(instance, enable);
+ return OK;
+}
+/**
+ * Enable command packet acknowledges by the peripherals
+ * - For interrupts to rise the monitored event must be registered
+ * using the event_register function
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable or disable
+ * @return error code
+ */
+dsih_error_t mipi_dsih_peripheral_ack(dsih_ctrl_t * instance, int enable)
+{
+ if (instance != 0)
+ {
+ if (instance->status == INITIALIZED)
+ {
+ mipi_dsih_hal_cmd_ack_en(instance, enable);
+ if (enable)
+ {
+ mipi_dsih_hal_bta_en(instance, 1);
+ }
+ return OK;
+ }
+ }
+ return ERR_DSI_INVALID_INSTANCE;
+}
+/**
+ * Enable tearing effect acknowledges by the peripherals (wait for TE)
+ * - It enables the following from the DSI specification
+ * "Since the timing of a TE event is, by definition, unknown to the host
+ * processor, the host processor shall give bus possession to the display
+ * module and then wait for up to one video frame period for the TE response.
+ * During this time, the host processor cannot send new commands, or requests
+ * to the display module, because it does not have bus possession."
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable or disable
+ * @return error code
+ */
+dsih_error_t mipi_dsih_tear_effect_ack(dsih_ctrl_t * instance, int enable)
+{
+ if (instance != 0)
+ {
+ if (instance->status == INITIALIZED)
+ {
+ mipi_dsih_hal_tear_effect_ack_en(instance, enable);
+ if (enable)
+ {
+ mipi_dsih_hal_bta_en(instance, 1);
+ }
+ return OK;
+ }
+ }
+ return ERR_DSI_INVALID_INSTANCE;
+}
+/**
+ * Enable the receiving of EoT packets at the end of LS transmission.
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable or disable
+ * @return error code
+ */
+dsih_error_t mipi_dsih_eotp_rx(dsih_ctrl_t * instance, int enable)
+{
+ if (instance != 0)
+ {
+ if (instance->status == INITIALIZED)
+ {
+ mipi_dsih_hal_gen_eotp_rx_en(instance, enable);
+ if (enable)
+ {
+ mipi_dsih_hal_bta_en(instance, 1);
+ }
+ return OK;
+ }
+ }
+ return ERR_DSI_INVALID_INSTANCE;
+}
+/**
+ * Enable the listening to ECC bytes. This allows for recovering from
+ * 1 bit errors. To report ECC events, the ECC events should be registered
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable or disable
+ * @return error code
+ */
+dsih_error_t mipi_dsih_ecc_rx(dsih_ctrl_t * instance, int enable)
+{
+ if (instance != 0)
+ {
+ if (instance->status == INITIALIZED)
+ {
+ mipi_dsih_hal_gen_ecc_rx_en(instance, enable);
+ if (enable)
+ {
+ mipi_dsih_hal_bta_en(instance, 1);
+ }
+ return OK;
+ }
+ }
+ return ERR_DSI_INVALID_INSTANCE;
+}
+/**
+ * Enable the sending of EoT (End of Transmission) packets at the end of HS
+ * transmission. It was made optional in the DSI spec. for retro-compatibility.
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable or disable
+ * @return error code
+ */
+dsih_error_t mipi_dsih_eotp_tx(dsih_ctrl_t * instance, int enable)
+{
+ if (instance != 0)
+ {
+ if (instance->status == INITIALIZED)
+ {
+ mipi_dsih_hal_gen_eotp_tx_en(instance, enable);
+ return OK;
+ }
+ }
+ return ERR_DSI_INVALID_INSTANCE;
+}
+/**
+ * Configure DPI video interface
+ * - If not in burst mode, it will compute the video and null packet sizes
+ * according to necessity
+ * - Configure timers for data lanes and/or clock lane to return to LP when
+ * bandwidth is not filled by data
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param video_params pointer to video stream-to-send information
+ * @return error code
+ */
+dsih_error_t mipi_dsih_dpi_video(dsih_ctrl_t * instance, dsih_dpi_video_t * video_params)
+{
+ dsih_error_t err_code = OK;
+ uint16_t bytes_per_pixel_x100 = 0; /* bpp x 100 because it can be 2.25 */
+ uint16_t video_size = 0;
+ uint32_t ratio_clock_xPF = 0; /* holds dpi clock/byte clock times precision factor */
+ uint16_t null_packet_size = 0;
+ uint8_t video_size_step = 1;
+ uint32_t hs_timeout = 0;
+ uint32_t total_bytes = 0;
+ uint32_t bytes_per_chunk = 0;
+ uint32_t no_of_chunks = 0;
+ uint32_t bytes_left = 0;
+ uint32_t chunk_overhead = 0;
+ int counter = 0;
+ /* check DSI controller instance */
+ if ((instance == 0) || (video_params == 0))
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (video_params->no_of_lanes > instance->max_lanes)
+ {
+ return ERR_DSI_OUT_OF_BOUND;
+ }
+ /* set up phy pll to required lane clock */
+ err_code = mipi_dsih_phy_hs2lp_config(instance, video_params->max_hs_to_lp_cycles);
+ err_code |= mipi_dsih_phy_lp2hs_config(instance, video_params->max_lp_to_hs_cycles);
+ err_code = mipi_dsih_phy_clk_hs2lp_config(instance, video_params->max_clk_hs_to_lp_cycles);
+ err_code |= mipi_dsih_phy_clk_lp2hs_config(instance, video_params->max_clk_lp_to_hs_cycles);
+ video_params->non_continuous_clock = 0; // 1.21a new feature, set 1 result in half-bottom snow screen , disbale it
+ mipi_dsih_non_continuous_clock(instance,video_params->non_continuous_clock);
+ //begin--frank
+ //err_code = mipi_dsih_dphy_configure(&(instance->phy_instance), video_params->no_of_lanes, video_params->byte_clock * 8);
+ //if (err_code)
+ //{
+ // return err_code;
+ //}
+ //end--frank
+ ratio_clock_xPF = (video_params->byte_clock * PRECISION_FACTOR) / (video_params->pixel_clock);
+ video_size = video_params->h_active_pixels;
+ /* set up ACKs and error reporting */
+ mipi_dsih_hal_dpi_frame_ack_en(instance, video_params->receive_ack_packets);
+ if (video_params->receive_ack_packets)
+ { /* if ACK is requested, enable BTA, otherwise leave as is */
+ mipi_dsih_hal_bta_en(instance, 1);
+ }
+ /* mipi_dsih_hal_gen_cmd_mode_en(instance, 0); */
+ mipi_dsih_hal_dpi_video_mode_en(instance, 1);
+ /* get bytes per pixel and video size step (depending if loosely or not */
+ switch (video_params->color_coding)
+ {
+ case COLOR_CODE_16BIT_CONFIG1:
+ case COLOR_CODE_16BIT_CONFIG2:
+ case COLOR_CODE_16BIT_CONFIG3:
+ bytes_per_pixel_x100 = 200;
+ video_size_step = 1;
+ break;
+ case COLOR_CODE_18BIT_CONFIG1:
+ case COLOR_CODE_18BIT_CONFIG2:
+ mipi_dsih_hal_dpi_18_loosely_packet_en(instance, video_params->is_18_loosely);
+ bytes_per_pixel_x100 = 225;
+ if (!video_params->is_18_loosely)
+ { /* 18bits per pixel and NOT loosely, packets should be multiples of 4 */
+ video_size_step = 4;
+ /* round up active H pixels to a multiple of 4 */
+ for (; (video_size % 4) != 0; video_size++)
+ {
+ ;
+ }
+ }
+ else
+ {
+ video_size_step = 1;
+ }
+ break;
+ case COLOR_CODE_24BIT:
+ bytes_per_pixel_x100 = 300;
+ video_size_step = 1;
+ break;
+ case COLOR_CODE_20BIT_YCC422_LOOSELY:
+ bytes_per_pixel_x100 = 250;
+ video_size_step = 2;
+ /* round up active H pixels to a multiple of 2 */
+ if ((video_size % 2) != 0)
+ {
+ video_size += 1;
+ }
+ break;
+ case COLOR_CODE_24BIT_YCC422:
+ bytes_per_pixel_x100 = 300;
+ video_size_step = 2;
+ /* round up active H pixels to a multiple of 2 */
+ if ((video_size % 2) != 0)
+ {
+ video_size += 1;
+ }
+ break;
+ case COLOR_CODE_16BIT_YCC422:
+ bytes_per_pixel_x100 = 200;
+ video_size_step = 2;
+ /* round up active H pixels to a multiple of 2 */
+ if ((video_size % 2) != 0)
+ {
+ video_size += 1;
+ }
+ break;
+ case COLOR_CODE_30BIT:
+ bytes_per_pixel_x100 = 375;
+ video_size_step = 2;
+ break;
+ case COLOR_CODE_36BIT:
+ bytes_per_pixel_x100 = 450;
+ video_size_step = 2;
+ break;
+ case COLOR_CODE_12BIT_YCC420:
+ bytes_per_pixel_x100 = 150;
+ video_size_step = 2;
+ /* round up active H pixels to a multiple of 2 */
+ if ((video_size % 2) != 0)
+ {
+ video_size += 1;
+ }
+ break;
+ default:
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: invalid color coding");
+ }
+ err_code = ERR_DSI_COLOR_CODING;
+ break;
+ }
+ if (err_code == OK)
+ {
+ err_code = mipi_dsih_hal_dpi_color_coding(instance, video_params->color_coding);
+ }
+ if (err_code != OK)
+ {
+ return err_code;
+ }
+ mipi_dsih_hal_dpi_video_mode_type(instance, video_params->video_mode);
+ mipi_dsih_hal_dpi_hline(instance, (uint16_t)((video_params->h_total_pixels * ratio_clock_xPF) / PRECISION_FACTOR));
+ mipi_dsih_hal_dpi_hbp(instance, ((video_params->h_back_porch_pixels * ratio_clock_xPF) / PRECISION_FACTOR));
+ mipi_dsih_hal_dpi_hsa(instance, ((video_params->h_sync_pixels * ratio_clock_xPF) / PRECISION_FACTOR));
+ mipi_dsih_hal_dpi_vactive(instance, video_params->v_active_lines);
+ mipi_dsih_hal_dpi_vfp(instance, video_params->v_total_lines - (video_params->v_back_porch_lines + video_params->v_sync_lines + video_params->v_active_lines));
+ mipi_dsih_hal_dpi_vbp(instance, video_params->v_back_porch_lines);
+ mipi_dsih_hal_dpi_vsync(instance, video_params->v_sync_lines);
+ mipi_dsih_hal_dpi_hsync_pol(instance, !video_params->h_polarity);
+ mipi_dsih_hal_dpi_vsync_pol(instance, !video_params->v_polarity);
+ mipi_dsih_hal_dpi_dataen_pol(instance, !video_params->data_en_polarity);
+ /* HS timeout */
+ hs_timeout = ((video_params->h_total_pixels * video_params->v_active_lines) + (DSIH_PIXEL_TOLERANCE * bytes_per_pixel_x100) / 100);
+ for (counter = 0x80; (counter < hs_timeout) && (counter > 2); counter--)
+ {
+ if ((hs_timeout % counter) == 0)
+ {
+ mipi_dsih_hal_timeout_clock_division(instance, counter);
+ mipi_dsih_hal_lp_rx_timeout(instance, (uint16_t)(hs_timeout / counter));
+ mipi_dsih_hal_hs_tx_timeout(instance, (uint16_t)(hs_timeout / counter));
+ break;
+ }
+ }
+ /* TX_ESC_CLOCK_DIV must be less than 20000KHz */
+ // mipi_dsih_hal_tx_escape_division(instance, 4); //6 //Jessia
+ mipi_dsih_set_lp_clock(instance);
+ /* video packetisation */
+ if (video_params->video_mode == VIDEO_BURST_WITH_SYNC_PULSES)
+ { /* BURST */
+ mipi_dsih_hal_dpi_null_packet_en(instance, 0);
+ mipi_dsih_hal_dpi_multi_packet_en(instance, 0);
+ err_code = mipi_dsih_hal_dpi_null_packet_size(instance, 0);
+ err_code = err_code? err_code: mipi_dsih_hal_dpi_chunks_no(instance, 1);
+ err_code = err_code? err_code: mipi_dsih_hal_dpi_video_packet_size(instance, video_size);
+ if (err_code != OK)
+ {
+ return err_code;
+ }
+ /* BURST by default, returns to LP during ALL empty periods - energy saving */
+ mipi_dsih_hal_dpi_lp_during_hfp(instance, 1);
+#if defined(CONFIG_FB_LCD_SSD2075_MIPI)
+ mipi_dsih_hal_dpi_lp_during_hbp(instance, 0);//forbit return to lp during hbp
+#else
+ mipi_dsih_hal_dpi_lp_during_hbp(instance, 1);
+#endif
+ mipi_dsih_hal_dpi_lp_during_vactive(instance, 1);
+ mipi_dsih_hal_dpi_lp_during_vfp(instance, 1);
+ mipi_dsih_hal_dpi_lp_during_vbp(instance, 1);
+ mipi_dsih_hal_dpi_lp_during_vsync(instance, 1);
+#if DEBUG
+ /* D E B U G */
+ if (instance->log_info != 0)
+ {
+ instance->log_info("sprdfb: burst video");
+ instance->log_info("sprdfb: h line time %ld", (uint16_t)((video_params->h_total_pixels * ratio_clock_xPF) / PRECISION_FACTOR));
+ instance->log_info("sprdfb: video_size %ld", video_size);
+ }
+#endif
+ }
+ else
+ { /* non burst transmission */
+ null_packet_size = 0;
+ /* bytes to be sent - first as one chunk */
+ bytes_per_chunk = (bytes_per_pixel_x100 * video_params->h_active_pixels) / 100 + VIDEO_PACKET_OVERHEAD;
+ /* bytes being received through the DPI interface per byte clock cycle */
+ total_bytes = (ratio_clock_xPF * video_params->no_of_lanes * (video_params->h_total_pixels - video_params->h_back_porch_pixels - video_params->h_sync_pixels)) / PRECISION_FACTOR;
+ /* check if the in pixels actually fit on the DSI link */
+ if (total_bytes >= bytes_per_chunk)
+ {
+ chunk_overhead = total_bytes - bytes_per_chunk;
+ /* overhead higher than 1 -> enable multi packets */
+ if (chunk_overhead > 1)
+ { /* MULTI packets */
+ for (video_size = video_size_step; video_size < video_params->h_active_pixels; video_size += video_size_step)
+ { /* determine no of chunks */
+ if ((((video_params->h_active_pixels * PRECISION_FACTOR) / video_size) % PRECISION_FACTOR) == 0)
+ {
+ no_of_chunks = video_params->h_active_pixels / video_size;
+ bytes_per_chunk = (bytes_per_pixel_x100 * video_size) / 100 + VIDEO_PACKET_OVERHEAD;
+ if (total_bytes >= (bytes_per_chunk * no_of_chunks))
+ {
+ bytes_left = total_bytes - (bytes_per_chunk * no_of_chunks);
+ break;
+ }
+ }
+ }
+ /* prevent overflow (unsigned - unsigned) */
+ if (bytes_left > (NULL_PACKET_OVERHEAD * no_of_chunks))
+ {
+ null_packet_size = (bytes_left - (NULL_PACKET_OVERHEAD * no_of_chunks)) / no_of_chunks;
+ if (null_packet_size > MAX_NULL_SIZE)
+ { /* avoid register overflow */
+ null_packet_size = MAX_NULL_SIZE;
+ }
+ }
+ }
+ else
+ { /* no multi packets */
+ no_of_chunks = 1;
+#if DEBUG
+ /* D E B U G */
+ if (instance->log_info != 0)
+ {
+ instance->log_info("sprdfb: no multi no null video");
+ instance->log_info("sprdfb: h line time %ld", (uint16_t)((video_params->h_total_pixels * ratio_clock_xPF) / PRECISION_FACTOR));
+ instance->log_info("sprdfb: video_size %ld", video_size);
+ }
+ /************************/
+#endif
+ /* video size must be a multiple of 4 when not 18 loosely */
+ for (video_size = video_params->h_active_pixels; (video_size % video_size_step) != 0; video_size++)
+ {
+ ;
+ }
+ }
+ }
+ else
+ {
+ instance->log_error("sprdfb: resolution cannot be sent to display through current settings");
+ err_code = ERR_DSI_OVERFLOW;
+ }
+ }
+ err_code = err_code? err_code: mipi_dsih_hal_dpi_chunks_no(instance, no_of_chunks);
+ err_code = err_code? err_code: mipi_dsih_hal_dpi_video_packet_size(instance, video_size);
+ err_code = err_code? err_code: mipi_dsih_hal_dpi_null_packet_size(instance, null_packet_size);
+ mipi_dsih_hal_dpi_null_packet_en(instance, null_packet_size > 0? 1: 0);
+ mipi_dsih_hal_dpi_multi_packet_en(instance, (no_of_chunks > 1)? 1: 0);
+#if DEBUG
+ /* D E B U G */
+ if (instance->log_info != 0)
+ {
+ instance->log_info("sprdfb: total_bytes %d", total_bytes);
+ instance->log_info("sprdfb: bytes_per_chunk %d", bytes_per_chunk);
+ instance->log_info("sprdfb: bytes left %d", bytes_left);
+ instance->log_info("sprdfb: null packets %d", null_packet_size);
+ instance->log_info("sprdfb: chunks %ld", no_of_chunks);
+ instance->log_info("sprdfb: video_size %ld", video_size);
+ }
+ /************************/
+#endif
+ mipi_dsih_hal_dpi_video_vc(instance, video_params->virtual_channel);
+ mipi_dsih_dphy_no_of_lanes(&(instance->phy_instance), video_params->no_of_lanes);
+ /* enable high speed clock */
+ //mipi_dsih_dphy_enable_hs_clk(&(instance->phy_instance), 1);//jessica, panel not init yet, could not set to hs, or result in err to some panel
+ return err_code;
+}
+/**
+ * Send a DCS write command
+ * It sends the User Command Set commands listed in the DCS specification and
+ * not the Manufacturer Command Set. To send the Manufacturer Commands use the
+ * packet on the generic packets sending function
+ * function sets the packet data type automatically
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param vc destination virtual channel
+ * @param params byte-addressed array of command parameters, including the
+ * command itself
+ * @param param_length length of the above array
+ * @return error code
+ * @note this function has an active delay to wait for the buffer to clear.
+ * The delay is limited to DSIH_FIFO_ACTIVE_WAIT x register access time
+ */
+dsih_error_t mipi_dsih_dcs_wr_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t* params, uint16_t param_length)
+{
+ uint8_t packet_type = 0;
+// int i = 0;
+ if (params == 0)
+ {
+ return ERR_DSI_OUT_OF_BOUND;
+ }
+#if 0
+ if (param_length > 2)
+ {
+ i = 2;
+ }
+ switch (params[i])
+ {
+ case 0x39:
+ case 0x38:
+ case 0x34:
+ case 0x29:
+ case 0x28:
+ case 0x21:
+ case 0x20:
+ case 0x13:
+ case 0x12:
+ case 0x11:
+ case 0x10:
+ case 0x01:
+ case 0x00:
+ packet_type = 0x05; /* DCS short write no param */
+ break;
+ case 0x3A:
+ case 0x36:
+ case 0x35:
+ case 0x26:
+ packet_type = 0x15; /* DCS short write 1 param */
+ break;
+ case 0x44:
+ case 0x3C:
+ case 0x37:
+ case 0x33:
+ case 0x30:
+ case 0x2D:
+ case 0x2C:
+ case 0x2B:
+ case 0x2A:
+ packet_type = 0x39; /* DCS long write/write_LUT command packet */
+ break;
+ default:
+ if (instance->log_error != 0)
+ {
+ instance->log_error("invalid DCS command");
+ }
+ return ERR_DSI_INVALID_COMMAND;
+ }
+#else
+ switch(param_length)
+ {
+ case 1:
+ packet_type = 0x05; /* DCS short write no param */
+ break;
+ case 2:
+ packet_type = 0x15; /* DCS short write 1 param */
+ break;
+ default:
+ packet_type = 0x39; /* DCS long write/write_LUT command packet */
+ break;
+ }
+#endif
+ return mipi_dsih_gen_wr_packet(instance, vc, packet_type, params, param_length);
+}
+/**
+ * Enable command mode
+ * - This function shall be explicitly called before commands are send if they
+ * are to be sent in command mode and not interlaced with video
+ * - If video mode is ON, it will be turned off automatically
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param en enable/disable
+ */
+void mipi_dsih_cmd_mode(dsih_ctrl_t * instance, int en)
+{
+ if(0 == instance)
+ {
+ return;
+ }
+
+ if (instance->status == INITIALIZED)
+ {
+ mipi_dsih_hal_gen_cmd_mode_en(instance, en);
+ return;
+ }
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: [mipi_dsih_cmd_mode] invalid instance");
+ }
+
+}
+/**
+ * Enable video mode
+ * - If command mode is ON, it will be turned off automatically
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param en enable/disable
+ */
+void mipi_dsih_video_mode(dsih_ctrl_t * instance, int en)
+{
+ if(0 == instance)
+ {
+ return;
+ }
+
+ if (instance->status == INITIALIZED)
+ {
+ mipi_dsih_hal_dpi_video_mode_en(instance, en);
+ return;
+ }
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: [mipi_dsih_video_mode] invalid instance");
+ }
+
+}
+
+/**
+ * Get the current active mode
+ * - 1 command mode
+ * - 2 DPI video mode
+ */
+int mipi_dsih_active_mode(dsih_ctrl_t * instance)
+{
+ if (mipi_dsih_hal_gen_is_cmd_mode(instance))
+ {
+ return 1;
+ }
+ else if (mipi_dsih_hal_dpi_is_video_mode(instance))
+ {
+ return 2;
+ }
+ return 0;
+}
+/**
+ * Send a generic write command
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param vc destination virtual channel
+ * @param params byte-addressed array of command parameters
+ * @param param_length length of the above array
+ * @return error code
+ * @note this function has an active delay to wait for the buffer to clear.
+ * The delay is limited to DSIH_FIFO_ACTIVE_WAIT x register access time
+ */
+dsih_error_t mipi_dsih_gen_wr_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t* params, uint16_t param_length)
+{
+ uint8_t data_type = 0;
+ switch(param_length)
+ {
+ case 0:
+ data_type = 0x03;
+ break;
+ case 1:
+ data_type = 0x13;
+ break;
+ case 2:
+ data_type = 0x23;
+ break;
+ default:
+ data_type = 0x29;
+ break;
+ }
+ return mipi_dsih_gen_wr_packet(instance, vc, data_type, params, param_length);
+}
+/**
+ * Send a packet on the generic interface
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param vc destination virtual channel
+ * @param data_type type of command, inserted in first byte of header
+ * @param params byte array of command parameters
+ * @param param_length length of the above array
+ * @return error code
+ * @note this function has an active delay to wait for the buffer to clear.
+ * The delay is limited to:
+ * (param_length / 4) x DSIH_FIFO_ACTIVE_WAIT x register access time
+ * @note the controller restricts the sending of .
+ * This function will not be able to send Null and Blanking packets due to
+ * controller restriction
+ */
+dsih_error_t mipi_dsih_gen_wr_packet(dsih_ctrl_t * instance, uint8_t vc, uint8_t data_type, uint8_t* params, uint16_t param_length)
+{
+ dsih_error_t err_code = OK;
+ /* active delay iterator */
+ int timeout = 0;
+ /* iterators */
+ int i = 0;
+ int j = 0;
+ /* holds padding bytes needed */
+ int compliment_counter = 0;
+ uint8_t* payload = 0;
+ /* temporary variable to arrange bytes into words */
+ uint32_t temp = 0;
+ uint16_t word_count = 0;
+ if (instance == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if ((params == 0) && (param_length != 0)) /* pointer NULL */
+ {
+ return ERR_DSI_OUT_OF_BOUND;
+ }
+ if (param_length > 2)
+ { /* long packet - write word count to header, and the rest to payload */
+ payload = params + (2 * sizeof(params[0]));
+ word_count = (params[1] << 8) | params[0];
+ if ((param_length - 2) < word_count)
+ {
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: sent > input payload. complemented with zeroes");
+ }
+ compliment_counter = (param_length - 2) - word_count;
+ }
+ else if ((param_length - 2) > word_count)
+ {
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: Overflow - input > sent. payload truncated");
+ }
+ }
+ for (i = 0; i < (param_length - 2); i += j)
+ {
+ temp = 0;
+ for (j = 0; (j < 4) && ((j + i) < (param_length - 2)); j++)
+ { /* temp = (payload[i + 3] << 24) | (payload[i + 2] << 16) | (payload[i + 1] << 8) | payload[i]; */
+ temp |= payload[i + j] << (j * 8);
+ }
+ /* check if payload Tx fifo is not full */
+ for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++)
+ {
+ if (!mipi_dsih_hal_gen_packet_payload(instance, temp))
+ {
+ break;
+ }
+ }
+ if (!(timeout < DSIH_FIFO_ACTIVE_WAIT))
+ {
+ return ERR_DSI_TIMEOUT;
+ }
+ }
+ /* if word count entered by the user more than actual parameters received
+ * fill with zeroes - a fail safe mechanism, otherwise controller will
+ * want to send data from an empty buffer */
+ for (i = 0; i < compliment_counter; i++)
+ {
+ /* check if payload Tx fifo is not full */
+ for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++)
+ {
+ if (!mipi_dsih_hal_gen_packet_payload(instance, 0x00))
+ {
+ break;
+ }
+ }
+ if (!(timeout < DSIH_FIFO_ACTIVE_WAIT))
+ {
+ return ERR_DSI_TIMEOUT;
+ }
+ }
+ }
+ for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++)
+ {
+ /* check if payload Tx fifo is not full */
+ if (!mipi_dsih_hal_gen_cmd_fifo_full(instance))
+ {
+ if (param_length == 0)
+ {
+ err_code |= mipi_dsih_hal_gen_packet_header(instance, vc, data_type, 0x0, 0x0);
+ }
+ else if (param_length == 1)
+ {
+ err_code |= mipi_dsih_hal_gen_packet_header(instance, vc, data_type, 0x0, params[0]);
+ }
+ else
+ {
+ err_code |= mipi_dsih_hal_gen_packet_header(instance, vc, data_type, params[1], params[0]);
+ }
+ break;
+ }
+ }
+ if (!(timeout < DSIH_FIFO_ACTIVE_WAIT))
+ {
+ err_code = ERR_DSI_TIMEOUT;
+ }
+ return err_code;
+}
+/**
+ * Send a DCS READ command to peripheral
+ * function sets the packet data type automatically
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param vc destination virtual channel
+ * @param command DCS code
+ * @param bytes_to_read no of bytes to read (expected to arrive at buffer)
+ * @param read_buffer pointer to 8-bit array to hold the read buffer words
+ * return read_buffer_length
+ * @note this function has an active delay to wait for the buffer to clear.
+ * The delay is limited to 2 x DSIH_FIFO_ACTIVE_WAIT
+ * (waiting for command buffer, and waiting for receiving)
+ * @note this function will enable BTA
+ */
+uint16_t mipi_dsih_dcs_rd_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t command, uint8_t bytes_to_read, uint8_t* read_buffer)
+{
+ if (instance == 0)
+ {
+ return 0;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return 0;
+ }
+ switch (command)
+ {
+ case 0xA8:
+ case 0xA1:
+ case 0x45:
+ case 0x3E:
+ case 0x2E:
+ case 0x0F:
+ case 0x0E:
+ case 0x0D:
+ case 0x0C:
+ case 0x0B:
+ case 0x0A:
+ case 0x08:
+ case 0x07:
+ case 0x06:
+ /* COMMAND_TYPE 0x06 - DCS Read no params refer to DSI spec p.47 */
+ return mipi_dsih_gen_rd_packet(instance, vc, 0x06, 0x0, command, bytes_to_read, read_buffer);
+ default:
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: invalid DCS command");
+ }
+ return 0;
+ }
+ return 0;
+}
+/**
+ * Send Generic READ command to peripheral
+ * - function sets the packet data type automatically
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param vc destination virtual channel
+ * @param params byte array of command parameters
+ * @param param_length length of the above array
+ * @param bytes_to_read no of bytes to read (expected to arrive at buffer)
+ * @param read_buffer pointer to 8-bit array to hold the read buffer words
+ * return read_buffer_length
+ * @note this function has an active delay to wait for the buffer to clear.
+ * The delay is limited to 2 x DSIH_FIFO_ACTIVE_WAIT
+ * (waiting for command buffer, and waiting for receiving)
+ * @note this function will enable BTA
+ */
+uint16_t mipi_dsih_gen_rd_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t* params, uint16_t param_length, uint8_t bytes_to_read, uint8_t* read_buffer)
+{
+ uint8_t data_type = 0;
+ if (instance == 0)
+ {
+ return 0;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return 0;
+ }
+ switch(param_length)
+ {
+ case 0:
+ data_type = 0x04;
+ return mipi_dsih_gen_rd_packet(instance, vc, data_type, 0x00, 0x00, bytes_to_read, read_buffer);
+ case 1:
+ data_type = 0x14;
+ return mipi_dsih_gen_rd_packet(instance, vc, data_type, 0x00, params[0], bytes_to_read, read_buffer);
+ case 2:
+ data_type = 0x24;
+ return mipi_dsih_gen_rd_packet(instance, vc, data_type, params[1], params[0], bytes_to_read, read_buffer);
+ default:
+ return 0;
+ }
+}
+/**
+ * Send READ packet to peripheral using the generic interface
+ * This will force command mode and stop video mode (because of BTA)
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param vc destination virtual channel
+ * @param data_type generic command type
+ * @param lsb_byte first command parameter
+ * @param msb_byte second command parameter
+ * @param bytes_to_read no of bytes to read (expected to arrive at buffer)
+ * @param read_buffer pointer to 8-bit array to hold the read buffer words
+ * return read_buffer_length
+ * @note this function has an active delay to wait for the buffer to clear.
+ * The delay is limited to 2 x DSIH_FIFO_ACTIVE_WAIT
+ * (waiting for command buffer, and waiting for receiving)
+ * @note this function will enable BTA
+ */
+uint16_t mipi_dsih_gen_rd_packet(dsih_ctrl_t * instance, uint8_t vc, uint8_t data_type, uint8_t msb_byte, uint8_t lsb_byte, uint8_t bytes_to_read, uint8_t* read_buffer)
+{
+ dsih_error_t err_code = OK;
+ int timeout = 0;
+ int counter = 0;
+ int i = 0;
+ int last_count = 0;
+ uint32_t temp[1] = {0};
+ if (instance == 0)
+ {
+ return 0;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return 0;
+ }
+ if (bytes_to_read < 1)
+ {
+ return 0;
+ }
+ if (read_buffer == 0)
+ {
+ return 0;
+ }
+
+#ifndef FB_CHECK_ESD_IN_VFP
+ /* make sure command mode is on */
+ mipi_dsih_cmd_mode(instance, 1);
+#endif
+ /* make sure receiving is enabled */
+ mipi_dsih_hal_bta_en(instance, 1);
+ /* listen to the same virtual channel as the one sent to */
+ mipi_dsih_hal_gen_rd_vc(instance, vc);
+ for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++)
+ { /* check if payload Tx fifo is not full */
+ if (!mipi_dsih_hal_gen_cmd_fifo_full(instance))
+ {
+ mipi_dsih_hal_gen_packet_header(instance, vc, data_type, msb_byte, lsb_byte);
+ break;
+ }
+ }
+ if (!(timeout < DSIH_FIFO_ACTIVE_WAIT))
+ {
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: tx rd command timed out");
+ }
+ return 0;
+ }
+ /* loop for the number of words to be read */
+ for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++)
+ { /* check if command transaction is done */
+ if (!mipi_dsih_hal_gen_rd_cmd_busy(instance))
+ {
+ if (!mipi_dsih_hal_gen_read_fifo_empty(instance))
+ {
+ for (counter = 0; (!mipi_dsih_hal_gen_read_fifo_empty(instance) && (counter < SPRDFB_MIPI_READ_COUNT_MAX)); counter += 4)
+ //for (counter = 0; (!mipi_dsih_hal_gen_read_fifo_empty(instance)); counter += 4)
+ {
+ err_code = mipi_dsih_hal_gen_read_payload(instance, temp);
+ if (err_code)
+ {
+ return 0;
+ }
+ if (counter < bytes_to_read)
+ {
+ for (i = 0; i < 4; i++)
+ {
+ if ((counter + i) < bytes_to_read)
+ {
+ /* put 32 bit temp in 4 bytes of buffer passed by user*/
+ read_buffer[counter + i] = (uint8_t)(temp[0] >> (i * 8));
+ last_count = i + counter;
+ }
+ else
+ {
+ if ((uint8_t)(temp[0] >> (i * 8)) != 0x00)
+ {
+ last_count = i + counter;
+ }
+ }
+ }
+ }
+ else
+ {
+ last_count = counter;
+ for (i = 0; i < 4; i++)
+ {
+ if ((uint8_t)(temp[0] >> (i * 8)) != 0x00)
+ {
+ last_count = i + counter;
+ }
+ }
+ }
+ }
+
+ if(counter >= SPRDFB_MIPI_READ_COUNT_MAX){
+ printk("sprdfb: read too many buffers!\n");
+ }
+
+ return last_count + 1;
+ }
+#ifdef FB_CHECK_ESD_IN_VFP
+ else if(timeout == (DSIH_FIFO_ACTIVE_WAIT - 1))//else
+#else
+ else
+#endif
+ {
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: rx buffer empty");
+ }
+ return 0;
+ }
+ }
+#ifdef FB_CHECK_ESD_IN_VFP
+ udelay(5);
+#endif
+ }
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: rx command timed out");
+ }
+ return 0;
+}
+/**
+ * Dump values stored in the DSI host core registers
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param all whether to dump all the registers, no register_config array need
+ * be provided if dump is to standard IO
+ * @param config array of register_config_t type where addresses and values are
+ * stored
+ * @param config_length the length of the config array
+ * @return the number of the registers that were read
+ */
+uint32_t mipi_dsih_dump_register_configuration(dsih_ctrl_t * instance, int all, register_config_t *config, uint16_t config_length)
+{
+ uint32_t current0 = 0;
+ uint16_t count = 0;
+ if (instance == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (all)
+ { /* dump all registers */
+ for (current0 = R_DSI_HOST_VERSION; current0 <= R_DSI_HOST_PHY_TMR_LPCLK_CFG; count++, current0 += (R_DSI_HOST_PWR_UP - R_DSI_HOST_VERSION))
+ {
+ if ((config_length == 0) || (config == 0) || count >= config_length)
+ { /* no place to write - write to STD IO */
+ if (instance->log_info != 0)
+ {
+ instance->log_info("sprdfb: DSI 0x%lX:0x%lX", current0, mipi_dsih_read_word(instance, current0));
+ }
+ }
+ else
+ {
+ config[count].addr = current0;
+ config[count].data = mipi_dsih_read_word(instance, current0);
+ }
+ }
+ }
+ else
+ {
+ if(config == 0)
+ {
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: invalid buffer");
+ }
+ }
+ else
+ {
+ for (count = 0; count < config_length; count++)
+ {
+ config[count].data = mipi_dsih_read_word(instance, config[count].addr);
+ }
+ }
+ }
+ return count;
+}
+/**
+ * Write values to DSI host core registers
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param config array of register_config_t type where register addresses and
+ * their new values are stored
+ * @param config_length the length of the config array
+ * @return the number of the registers that were written to
+ */
+uint32_t mipi_dsih_write_register_configuration(dsih_ctrl_t * instance, register_config_t *config, uint16_t config_length)
+{
+ uint16_t count = 0;
+ if (instance == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ for (count = 0; count < config_length; count++)
+ {
+ mipi_dsih_write_word(instance, config[count].addr, config[count].data);
+ }
+ return count;
+}
+/**
+ * Register a handler for a specific event
+ * - The handler will be called when this specific event occurs
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param event enum
+ * @param handler call back to handler function to handle the event
+ * @return error code
+ */
+dsih_error_t mipi_dsih_register_event(dsih_ctrl_t * instance, dsih_event_t event, void (*handler)(dsih_ctrl_t *, void *))
+{
+ uint32_t mask = 1;
+ uint32_t temp = 0;
+ if (event >= DSI_MAX_EVENT)
+ {
+ return ERR_DSI_INVALID_EVENT;
+ }
+ if (handler == 0)
+ {
+ return ERR_DSI_INVALID_HANDLE;
+ }
+ if (instance == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ instance->event_registry[event] = handler;
+ if (event < HS_CONTENTION)
+ {
+ temp = mipi_dsih_hal_int_get_mask_0(instance, 0xffffffff);
+ temp &= ~(mask << event);
+ temp |= (0 & mask) << event;
+ mipi_dsih_hal_int_mask_0(instance, temp);
+ }
+ else
+ {
+ temp = mipi_dsih_hal_int_get_mask_1(instance, 0xffffffff);
+ temp &= ~(mask << (event - HS_CONTENTION));
+ temp |= (0 & mask) << (event - HS_CONTENTION);
+ mipi_dsih_hal_int_mask_1(instance, temp);
+ if (event == RX_CRC_ERR)
+ { /* automatically enable CRC reporting */
+ mipi_dsih_hal_gen_crc_rx_en(instance, 1);
+ }
+ }
+ return OK;
+}
+/**
+ * Clear an already registered event
+ * - Callback of the handler will be removed
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param event enum
+ * @return error code
+ */
+dsih_error_t mipi_dsih_unregister_event(dsih_ctrl_t * instance, dsih_event_t event)
+{
+ uint32_t mask = 1;
+ uint32_t temp = 0;
+ if (event >= DSI_MAX_EVENT)
+ {
+ return ERR_DSI_INVALID_EVENT;
+ }
+ if (instance == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ instance->event_registry[event] = 0;
+ if (event < HS_CONTENTION)
+ {
+ temp = mipi_dsih_hal_int_get_mask_0(instance, 0xffffffff);
+ temp &= ~(mask << event);
+ temp |= (1 & mask) << event;
+ mipi_dsih_hal_int_mask_0(instance, temp);
+ }
+ else
+ {
+ temp = mipi_dsih_hal_int_get_mask_1(instance, 0xffffffff);
+ temp &= ~(mask << (event - HS_CONTENTION));
+ temp |= (1 & mask) << (event - HS_CONTENTION);
+ mipi_dsih_hal_int_mask_1(instance, temp);
+ if (event == RX_CRC_ERR)
+ { /* automatically disable CRC reporting */
+ mipi_dsih_hal_gen_crc_rx_en(instance, 0);
+ }
+ }
+ return OK;
+}
+/**
+ * Clear all registered events at once
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return error code
+ */
+dsih_error_t mipi_dsih_unregister_all_events(dsih_ctrl_t * instance)
+{
+ int i = 0;
+ if (instance == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (instance->status != INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ for (i = 0; i < DSI_MAX_EVENT; i++)
+ {
+ instance->event_registry[i] = 0;
+ }
+ mipi_dsih_hal_int_mask_0(instance, 0xffffff);
+ mipi_dsih_hal_int_mask_1(instance, 0xffffff);
+ /* automatically disable CRC reporting */
+ mipi_dsih_hal_gen_crc_rx_en(instance, 0);
+ return OK;
+}
+/**
+ * This event handler shall be called upon receiving any event
+ * it will call the specific callback (handler) registered for the invoking
+ * event. Registration is done beforehand using mipi_dsih_register_event
+ * its signature is void * so it could be OS agnostic (for it to be
+ * registered in any OS/Interrupt controller)
+ * @param param pointer to structure holding the DSI Host core information
+ * @note This function must be registered with the DSI IRQs
+ */
+void mipi_dsih_event_handler(void * param)
+{
+ dsih_ctrl_t * instance = (dsih_ctrl_t *)(param);
+ uint8_t i = 0;
+ uint32_t status_0;
+ uint32_t status_1;
+
+ if (instance == 0)
+ {
+ return;
+ }
+
+ status_0 = mipi_dsih_hal_int_status_0(instance, 0xffffffff);
+ status_1 = mipi_dsih_hal_int_status_1(instance, 0xffffffff);
+
+ for (i = 0; i < DSI_MAX_EVENT; i++)
+ {
+ if (instance->event_registry[i] != 0)
+ {
+ if (i < HS_CONTENTION)
+ {
+ if ((status_0 & (1 << i)) != 0)
+ {
+ instance->event_registry[i](instance, &i);
+ }
+ }
+ else
+ {
+ if ((status_1 & (1 << (i - HS_CONTENTION))) != 0)
+ {
+ instance->event_registry[i](instance, &i);
+ }
+ }
+ }
+ }
+}
+/**
+ * Reset the DSI Host controller
+ * - Sends a pulse to the shut down register
+ * @param instance pointer to structure holding the DSI Host core information
+ */
+void mipi_dsih_reset_controller(dsih_ctrl_t * instance)
+{
+ mipi_dsih_hal_power(instance, 0);
+ mipi_dsih_hal_power(instance, 1);
+}
+/**
+ * Shut down the DSI Host controller
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param shutdown (1) power up (0)
+ */
+void mipi_dsih_shutdown_controller(dsih_ctrl_t * instance, int shutdown)
+{
+ mipi_dsih_hal_power(instance, !shutdown);
+}
+/**
+ * Reset the PHY module being controlled by the DSI Host controller
+ * - Sends a pulse to the PPI reset signal
+ * @param instance pointer to structure holding the DSI Host core information
+ */
+void mipi_dsih_reset_phy(dsih_ctrl_t * instance)
+{
+ mipi_dsih_dphy_reset(&(instance->phy_instance), 0);
+ mipi_dsih_dphy_reset(&(instance->phy_instance), 1);
+}
+/**
+ * Shut down the PHY module being controlled by the DSI Host controller
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param shutdown (1) power up (0)
+ */
+void mipi_dsih_shutdown_phy(dsih_ctrl_t * instance, int shutdown)
+{
+ mipi_dsih_dphy_shutdown(&(instance->phy_instance), !shutdown);
+}
+
+/*
+sprd Aoke added for power saving while suspend
+*/
+void mipi_dsih_ulps_mode(dsih_ctrl_t * instance, int en)
+{
+ mipi_dsih_dphy_ulps_data_lanes(&(instance->phy_instance),en);
+ mipi_dsih_dphy_ulps_clk_lane(&(instance->phy_instance),en);
+}
+/**
+ * Configure the eDPI interface
+ * - Programs the controller to receive pixels on the DPI interface and send them
+ * as commands (write memory start and write memory continue) instead of a
+ * video stream.
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param video_params pointer to the command mode video parameters context
+ * @param send_setup_packets whether to send the setup packets from given info. These are: 1 - set pixel format; 2 - set column address; 3 - set page address
+ * @return error code
+ */
+dsih_error_t mipi_dsih_edpi_video(dsih_ctrl_t * instance, dsih_cmd_mode_video_t *video_params, int send_setup_packets)
+{
+ dsih_error_t err_code = OK;
+ uint8_t buf[7] = {0};
+ uint32_t bytes_per_pixel_x100 = 0;
+ mipi_dsih_hal_dpi_video_vc(instance, video_params->virtual_channel);
+ mipi_dsih_cmd_mode(instance, 1);
+ err_code = mipi_dsih_hal_dpi_color_coding(instance, video_params->color_coding);
+ /* define whether write memory commands will be sent in LP or HS */
+ err_code = err_code? err_code: mipi_dsih_hal_dcs_wr_tx_type(instance, 3, video_params->lp); /* long packet*/
+ if (send_setup_packets)
+ {
+ /* define pixel packing format - 1 param */
+ buf[0] = 0x3A;
+ /* colour depth: table 6 DCS spec. 3:1| 8:2| 12:3| 16:5| 18:6| 24:7*/
+ switch (video_params->color_coding)
+ {
+ case 0:
+ case 1:
+ case 2:
+ buf[1] = 5;
+ break;
+ case 3:
+ case 4:
+ buf[1] = 6;
+ break;
+ default:
+ buf[1] = 7;
+ break;
+ }
+ err_code = err_code? err_code: mipi_dsih_dcs_wr_cmd(instance, video_params->virtual_channel, buf, 2);
+ if (err_code)
+ {
+ instance->log_error("sprdfb: error setting up command video - colour depth");
+ }
+ /* set column address (left to right) - 4 param */
+ buf[0] = 0x05; /* cmd length */
+ buf[1] = 0x00;
+ buf[2] = 0x2A; /* cmd opcode */
+ buf[3] = (uint8_t)(video_params->h_start >> 8); /* payload start */
+ buf[4] = (uint8_t)(video_params->h_start);
+ buf[5] = (uint8_t)(video_params->h_active_pixels >> 8);
+ buf[6] = (uint8_t)(video_params->h_active_pixels);
+ err_code = err_code? err_code: mipi_dsih_dcs_wr_cmd(instance, video_params->virtual_channel, buf, 7);
+ if (err_code)
+ {
+ instance->log_error("sprdfb: error setting up command video - set column address");
+ }
+ /* set page address (top to bottom) 4 - param*/
+ buf[0] = 0x05; /* cmd length */
+ buf[1] = 0x00;
+ buf[2] = 0x2B; /* cmd opcode */
+ buf[3] = (uint8_t)(video_params->v_start >> 8); /* payload start */
+ buf[4] = (uint8_t)(video_params->v_start);
+ buf[5] = (uint8_t)(video_params->v_active_lines >> 8);
+ buf[6] = (uint8_t)(video_params->v_active_lines);
+ err_code = err_code? err_code: mipi_dsih_dcs_wr_cmd(instance, video_params->virtual_channel, buf, 7);
+ if (err_code)
+ {
+ instance->log_error("sprdfb: error setting up command video - set page address");
+ }
+ }
+ switch (video_params->color_coding)
+ {
+ case COLOR_CODE_16BIT_CONFIG1:
+ case COLOR_CODE_16BIT_CONFIG2:
+ case COLOR_CODE_16BIT_CONFIG3:
+ bytes_per_pixel_x100 = 200;
+ break;
+ case COLOR_CODE_18BIT_CONFIG1:
+ case COLOR_CODE_18BIT_CONFIG2:
+ bytes_per_pixel_x100 = 225;
+ break;
+ case COLOR_CODE_24BIT:
+ bytes_per_pixel_x100 = 300;
+ break;
+ case COLOR_CODE_20BIT_YCC422_LOOSELY:
+ bytes_per_pixel_x100 = 250;
+ break;
+ case COLOR_CODE_24BIT_YCC422:
+ bytes_per_pixel_x100 = 300;
+ break;
+ case COLOR_CODE_16BIT_YCC422:
+ bytes_per_pixel_x100 = 200;
+ break;
+ case COLOR_CODE_30BIT:
+ bytes_per_pixel_x100 = 375;
+ break;
+ case COLOR_CODE_36BIT:
+ bytes_per_pixel_x100 = 450;
+ break;
+ case COLOR_CODE_12BIT_YCC420:
+ bytes_per_pixel_x100 = 150;
+ break;
+ default:
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: invalid color coding");
+ }
+ err_code = ERR_DSI_COLOR_CODING;
+ break;
+ }
+ if (video_params->te)
+ {
+ mipi_dsih_hal_bta_en(instance, video_params->te);
+ /* enable tearing effect */
+ mipi_dsih_tear_effect_ack(instance, video_params->te);
+ buf[0] = 0x35;
+ err_code = mipi_dsih_dcs_wr_cmd(instance, video_params->virtual_channel, buf, 1);
+ }
+ mipi_dsih_dphy_enable_hs_clk(&(instance->phy_instance), 1);
+ if ((((WORD_LENGTH * FIFO_DEPTH) * 100) / bytes_per_pixel_x100) > video_params->h_active_pixels)
+ {
+ mipi_dsih_hal_edpi_max_allowed_size(instance, video_params->h_active_pixels);
+ }
+ else
+ {
+ mipi_dsih_hal_edpi_max_allowed_size(instance, (((WORD_LENGTH * FIFO_DEPTH) * 100) / bytes_per_pixel_x100));
+ }
+ return err_code;
+}
+
+/* PRESP Time outs */
+/**
+ * Timeout for peripheral (for controller to stay still) after LP data
+ * transmission write requests
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_byte_cycles period for which the DWC_mipi_dsi_host keeps the
+ * link still, after sending a low power write operation. This period is
+ * measured in cycles of lanebyteclk
+ */
+void mipi_dsih_presp_timeout_low_power_write(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles)
+{
+ mipi_dsih_hal_presp_timeout_low_power_write(instance, no_of_byte_cycles);
+}
+/**
+ * Timeout for peripheral (for controller to stay still) after LP data
+ * transmission read requests
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_byte_cycles period for which the DWC_mipi_dsi_host keeps the
+ * link still, after sending a low power read operation. This period is
+ * measured in cycles of lanebyteclk
+ */
+void mipi_dsih_presp_timeout_low_power_read(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles)
+{
+ mipi_dsih_hal_presp_timeout_low_power_read(instance, no_of_byte_cycles);
+}
+/**
+ * Timeout for peripheral (for controller to stay still) after HS data
+ * transmission write requests
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_byte_cycles period for which the DWC_mipi_dsi_host keeps the
+ * link still, after sending a high-speed write operation. This period is
+ * measured in cycles of lanebyteclk
+ */
+void mipi_dsih_presp_timeout_high_speed_write(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles)
+{
+ mipi_dsih_hal_presp_timeout_high_speed_write(instance, no_of_byte_cycles);
+}
+/**
+ * Timeout for peripheral between HS data transmission read requests
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_byte_cycles period for which the DWC_mipi_dsi_host keeps the
+ * link still, after sending a high-speed read operation. This period is
+ * measured in cycles of lanebyteclk
+ */
+void mipi_dsih_presp_timeout_high_speed_read(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles)
+{
+ mipi_dsih_hal_presp_timeout_high_speed_read(instance, no_of_byte_cycles);
+}
+/**
+ * Timeout for peripheral (for controller to stay still) after bus turn around
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_byte_cycles period for which the DWC_mipi_dsi_host keeps the
+ * link still, after sending a BTA operation. This period is
+ * measured in cycles of lanebyteclk
+ */
+void mipi_dsih_presp_timeout_bta(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles)
+{
+ mipi_dsih_hal_presp_timeout_bta(instance, no_of_byte_cycles);
+}
+uint16_t mipi_dsih_check_dbi_fifos_state(dsih_ctrl_t * instance)
+{
+ uint16_t cnt = 0;
+ while( cnt < 5000 && mipi_dsih_read_word(instance, R_DSI_HOST_CMD_PKT_STATUS) != 0x15)
+ {
+ cnt ++;
+ }
+ return (mipi_dsih_read_word(instance, R_DSI_HOST_CMD_PKT_STATUS) != 0x15) ? -1 : 1;
+}
+uint16_t mipi_dsih_check_ulpm_mode(dsih_ctrl_t * instance)
+{
+ return (mipi_dsih_read_word(instance, R_DSI_HOST_PHY_STATUS) != 0x1528) ? -1 : 1;
+}
diff --git a/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_api.h b/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_api.h
new file mode 100644
index 00000000..73ae5efc
--- /dev/null
+++ b/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_api.h
@@ -0,0 +1,134 @@
+/**
+ * @file mipi_dsih_api.h
+ *
+ * Synopsys Inc.
+ * SG DWC PT02
+ */
+/*
+ The Synopsys Software Driver and documentation (hereinafter "Software")
+ is an unsupported work of Synopsys, Inc. unless otherwise
+ expressly agreed to in writing between Synopsys and you.
+
+ The Software IS NOT an item of Licensed Software or Licensed Product under
+ any End User Software License Agreement or Agreement for Licensed Product
+ with Synopsys or any supplement thereto. Permission is hereby granted,
+ free of charge, to any person obtaining a copy of this software annotated
+ with this license and the Software, to deal in the Software without
+ restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so, subject
+ to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
+ */
+#ifndef MIPI_DSIH_API_H_
+#define MIPI_DSIH_API_H_
+
+#include "mipi_dsih_local.h"
+
+/* general configuration functions */
+
+dsih_error_t mipi_dsih_open(dsih_ctrl_t * instance);
+
+dsih_error_t mipi_dsih_close(dsih_ctrl_t * instance);
+
+void mipi_dsih_reset_controller(dsih_ctrl_t * instance);
+
+void mipi_dsih_shutdown_controller(dsih_ctrl_t * instance, int shutdown);
+
+void mipi_dsih_reset_phy(dsih_ctrl_t * instance);
+
+void mipi_dsih_shutdown_phy(dsih_ctrl_t * instance, int shutdown);
+
+void mipi_dsih_ulps_mode(dsih_ctrl_t * instance, int en);//Aoke add
+/* packet handling */
+
+dsih_error_t mipi_dsih_enable_rx(dsih_ctrl_t * instance, int enable);
+
+dsih_error_t mipi_dsih_peripheral_ack(dsih_ctrl_t * instance, int enable);
+
+dsih_error_t mipi_dsih_tear_effect_ack(dsih_ctrl_t * instance, int enable);
+
+dsih_error_t mipi_dsih_eotp_rx(dsih_ctrl_t * instance, int enable);
+
+dsih_error_t mipi_dsih_ecc_rx(dsih_ctrl_t * instance, int enable);
+
+
+dsih_error_t mipi_dsih_eotp_tx(dsih_ctrl_t * instance, int enable);
+
+/* video mode functions */
+
+dsih_error_t mipi_dsih_dpi_video(dsih_ctrl_t * instance, dsih_dpi_video_t * video_params);
+
+void mipi_dsih_allow_return_to_lp(dsih_ctrl_t * instance, int hfp, int hbp, int vactive, int vfp, int vbp, int vsync);
+
+void mipi_dsih_video_mode(dsih_ctrl_t * instance, int en);
+
+/* command mode functions */
+
+dsih_error_t mipi_dsih_dcs_wr_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t* params, uint16_t param_length);
+
+dsih_error_t mipi_dsih_gen_wr_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t* params, uint16_t param_length);
+
+dsih_error_t mipi_dsih_gen_wr_packet(dsih_ctrl_t * instance, uint8_t vc, uint8_t data_type, uint8_t* params, uint16_t param_length);
+
+uint16_t mipi_dsih_dcs_rd_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t command, uint8_t bytes_to_read, uint8_t* read_buffer);
+
+uint16_t mipi_dsih_gen_rd_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t* params, uint16_t param_length, uint8_t bytes_to_read, uint8_t* read_buffer);
+
+uint16_t mipi_dsih_gen_rd_packet(dsih_ctrl_t * instance, uint8_t vc, uint8_t data_type, uint8_t msb_byte, uint8_t lsb_byte, uint8_t bytes_to_read, uint8_t* read_buffer);
+
+void mipi_dsih_cmd_mode(dsih_ctrl_t * instance, int en);
+
+int mipi_dsih_active_mode(dsih_ctrl_t * instance);
+
+void mipi_dsih_dcs_cmd_lp_transmission(dsih_ctrl_t * instance, int long_write, int short_write, int short_read);
+
+void mipi_dsih_gen_cmd_lp_transmission(dsih_ctrl_t * instance, int long_write, int short_write, int short_read);
+
+dsih_error_t mipi_dsih_edpi_video(dsih_ctrl_t * instance, dsih_cmd_mode_video_t *video_params, int send_setup_packets);
+
+/* event handling functions */
+
+dsih_error_t mipi_dsih_register_event(dsih_ctrl_t * instance, dsih_event_t event, void (*handler)(dsih_ctrl_t *, void *));
+
+dsih_error_t mipi_dsih_unregister_event(dsih_ctrl_t * instance, dsih_event_t event);
+
+dsih_error_t mipi_dsih_unregister_all_events(dsih_ctrl_t * instance);
+
+void mipi_dsih_event_handler(void * param);
+
+/* PRESP Time outs */
+void mipi_dsih_presp_timeout_low_power_write(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles);
+
+void mipi_dsih_presp_timeout_low_power_read(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles);
+
+void mipi_dsih_presp_timeout_high_speed_write(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles);
+
+void mipi_dsih_presp_timeout_high_speed_read(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles);
+
+void mipi_dsih_presp_timeout_bta(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles);
+
+/* read/write register functions */
+uint32_t mipi_dsih_dump_register_configuration(dsih_ctrl_t * instance, int all, register_config_t *config, uint16_t config_length);
+
+uint32_t mipi_dsih_write_register_configuration(dsih_ctrl_t * instance, register_config_t *config, uint16_t config_length);
+
+uint16_t mipi_dsih_check_dbi_fifos_state(dsih_ctrl_t * instance);
+
+uint16_t mipi_dsih_check_ulpm_mode(dsih_ctrl_t * instance);
+
+#endif /* MIPI_DSIH_API_H_ */
diff --git a/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_dphy.c b/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_dphy.c
new file mode 100644
index 00000000..0b0d7003
--- /dev/null
+++ b/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_dphy.c
@@ -0,0 +1,1080 @@
+/**
+ * @file mipi_dsih_dphy.c
+ * @brief D-PHY driver
+ *
+ * Synopsys Inc.
+ * SG DWC PT02
+ */
+#include "mipi_dsih_dphy.h"
+#define PRECISION_FACTOR (1000)
+/* Reference clock frequency divided by Input Frequency Division Ratio LIMITS */
+#define DPHY_DIV_UPPER_LIMIT (40000)
+#ifdef GEN_2
+#define DPHY_DIV_LOWER_LIMIT (5000)
+#else
+#define DPHY_DIV_LOWER_LIMIT (1000)
+#endif
+
+#if ((defined DWC_MIPI_DPHY_BIDIR_TSMC40LP) || (defined GEN_2))
+#define MIN_OUTPUT_FREQ (80)
+#elif defined DPHY2Btql
+#define MIN_OUTPUT_FREQ (200)
+#undef GEN_2
+#endif
+
+/**
+ * Initialise D-PHY module and power up
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @return error code
+ */
+dsih_error_t mipi_dsih_dphy_open(dphy_t * phy)
+{
+ if (phy == 0)
+ {
+ return ERR_DSI_PHY_INVALID;
+ }
+ else if ((phy->core_read_function == 0) || (phy->core_write_function == 0))
+ {
+ return ERR_DSI_INVALID_IO;
+ }
+ else if (phy->status == INITIALIZED)
+ {
+ return ERR_DSI_PHY_INVALID;
+ }
+ phy->status = NOT_INITIALIZED;
+#if 0
+ mipi_dsih_dphy_reset(phy, 0);
+ mipi_dsih_dphy_stop_wait_time(phy, 0x1C);
+ mipi_dsih_dphy_no_of_lanes(phy, 1);
+ mipi_dsih_dphy_clock_en(phy, 1);
+ mipi_dsih_dphy_shutdown(phy, 1);
+ mipi_dsih_dphy_reset(phy, 1);
+#endif
+ phy->status = INITIALIZED;
+ return OK;
+}
+/**
+ * Configure D-PHY and PLL module to desired operation mode
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @param no_of_lanes active
+ * @param output_freq desired high speed frequency
+ * @return error code
+ */
+ #ifdef GEN_2
+dsih_error_t mipi_dsih_dphy_configure(dphy_t * phy, uint8_t no_of_lanes, uint32_t output_freq)
+{
+ uint32_t loop_divider = 0; /* (M) */
+ uint32_t input_divider = 1; /* (N) */
+ uint8_t data[4]; /* maximum data for now are 4 bytes per test mode*/
+ uint8_t no_of_bytes = 0;
+ uint8_t i = 0;
+ uint8_t n=0;/* iterator */
+ uint8_t range = 0; /* ranges iterator */
+ int flag = 0;
+ struct
+ {
+ uint32_t loop_div; /* upper limit of loop divider range */
+ uint8_t cp_current; /* icpctrl */
+ uint8_t lpf_resistor; /* lpfctrl */
+ }
+ loop_bandwidth[] =
+
+ { /* gen 2 associates the charge pump current and LPF resistor with the
+ output frequency ranges (and thus we simplify here to use the
+ counter/pointer of the following structure) */
+ { 90, 0x02, 0x02}, { 100, 0x02, 0x02}, { 110, 0x02, 0x02},
+ { 130, 0x02, 0x01}, { 140, 0x02, 0x01}, { 150, 0x02, 0x01},
+ { 170, 0x09, 0x00}, { 180, 0x09, 0x01}, { 200, 0x09, 0x01},
+ { 220, 0x09, 0x04}, { 240, 0x09, 0x04}, { 250, 0x09, 0x04},
+ { 270, 0x06, 0x04}, { 300, 0x06, 0x04}, { 330, 0x09, 0x04},
+ { 360, 0x09, 0x04}, { 400, 0x09, 0x04}, { 450, 0x06, 0x04},
+ { 500, 0x06, 0x04}, { 550, 0x06, 0x04}, { 600, 0x06, 0x04},
+ { 650, 0x0A, 0x04}, { 700, 0x0A, 0x04}, { 750, 0x0A, 0x04},
+ { 800, 0x0A, 0x04}, { 850, 0x0A, 0x04}, { 900, 0x0A, 0x04},
+ { 950, 0x0B, 0x08}, {1000, 0x0B, 0x08}, {1050, 0x0B, 0x08},
+ {1100, 0x0B, 0x08}, {1150, 0x0B, 0x08}, {1200, 0x0B, 0x08},
+ {1250, 0x0B, 0x08}, {1300, 0x0B, 0x08}, {1350, 0x0B, 0x08},
+ {1400, 0x0B, 0x08}, {1450, 0x0B, 0x08}, {1500, 0x0B, 0x08}
+ };
+ uint32_t delta = 0;
+ uint32_t tmp_loop_divider = 0;
+ unsigned step = 0;
+
+ struct
+ {
+ uint32_t freq; /* upper margin of frequency range */
+ uint8_t hs_freq; /* hsfreqrange */
+ uint8_t vco_range; /* vcorange */
+ }
+ ranges[] =
+ {
+ { 90, 0x00, 0x00}, { 100, 0x10, 0x00}, { 110, 0x20, 0x00},
+ { 130, 0x01, 0x00}, { 140, 0x11, 0x00}, { 150, 0x21, 0x00},
+ { 170, 0x02, 0x00}, { 180, 0x12, 0x00}, { 200, 0x22, 0x00},
+ { 220, 0x03, 0x01}, { 240, 0x13, 0x01}, { 250, 0x23, 0x01},
+ { 270, 0x04, 0x01}, { 300, 0x14, 0x01}, { 330, 0x05, 0x02},
+ { 360, 0x15, 0x02}, { 400, 0x25, 0x02}, { 450, 0x06, 0x02},
+ { 500, 0x16, 0x02}, { 550, 0x07, 0x03}, { 600, 0x17, 0x03},
+ { 650, 0x08, 0x03}, { 700, 0x18, 0x03}, { 750, 0x09, 0x04},
+ { 800, 0x19, 0x04}, { 850, 0x29, 0x04}, { 900, 0x39, 0x04},
+ { 950, 0x0A, 0x05}, {1000, 0x1A, 0x05}, {1050, 0x2A, 0x05},
+ {1100, 0x3A, 0x05}, {1150, 0x0B, 0x06}, {1200, 0x1B, 0x06},
+ {1250, 0x2B, 0x06}, {1300, 0x3B, 0x06}, {1350, 0x0C, 0x07},
+ {1400, 0x1C, 0x07}, {1450, 0x2C, 0x07}, {1500, 0x3C, 0x07}
+ };
+
+ if (phy == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (phy->status < INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (output_freq < MIN_OUTPUT_FREQ)
+ {
+ return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;
+ }
+
+ loop_divider = ((output_freq * (phy->reference_freq / DPHY_DIV_LOWER_LIMIT)) / phy->reference_freq);
+ /* here delta will account for the rounding */
+ delta = ((loop_divider * phy->reference_freq) / (phy->reference_freq / DPHY_DIV_LOWER_LIMIT)) - output_freq;
+ for (input_divider = 1 + (phy->reference_freq / DPHY_DIV_UPPER_LIMIT); ((phy->reference_freq / input_divider) >= DPHY_DIV_LOWER_LIMIT) && (!flag); input_divider++)
+ {
+ tmp_loop_divider = ((output_freq * input_divider) / (phy->reference_freq));
+ if ((tmp_loop_divider % 2) == 0)
+ { /* if even */
+ if (output_freq == (tmp_loop_divider * (phy->reference_freq / input_divider)))
+ { /* exact values found */
+ flag = 1;
+ loop_divider = tmp_loop_divider;
+ delta = output_freq - (tmp_loop_divider * (phy->reference_freq / input_divider));
+ break;
+ }
+ else if ((output_freq - (tmp_loop_divider * (phy->reference_freq / input_divider))) < delta)
+ { /* values found with smaller delta */
+ loop_divider = tmp_loop_divider;
+ delta = output_freq - (tmp_loop_divider * (phy->reference_freq / input_divider));
+ step = 1;
+ }
+ }
+ else
+ {
+ tmp_loop_divider += 1;
+ if (output_freq == (tmp_loop_divider * (phy->reference_freq / input_divider)))
+ { /* exact values found */
+ flag = 1;
+ loop_divider = tmp_loop_divider;
+ delta = (tmp_loop_divider * (phy->reference_freq / input_divider)) - output_freq;
+ break;
+ }
+ else if (((tmp_loop_divider * (phy->reference_freq / input_divider)) - output_freq) < delta)
+ { /* values found with smaller delta */
+ loop_divider = tmp_loop_divider;
+ delta = (tmp_loop_divider * (phy->reference_freq / input_divider)) - output_freq;
+ step = 0;
+ }
+ }
+ }
+ if (!flag)
+ {
+ input_divider = step + (loop_divider * phy->reference_freq) / output_freq;
+// phy->log_info("D-PHY: Approximated Frequency: %d KHz", (loop_divider * (phy->reference_freq / input_divider)));
+ }
+#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING
+ if (phy->phy_keep_work != true)
+#endif
+ {
+ /* get the PHY in power down mode (shutdownz=0) and reset it (rstz=0) to
+ avoid transient periods in PHY operation during re-configuration procedures. */
+ mipi_dsih_dphy_reset(phy, 0);
+ mipi_dsih_dphy_clock_en(phy, 0);
+ mipi_dsih_dphy_shutdown(phy, 0);
+ /* provide an initial active-high test clear pulse in TESTCLR */
+ mipi_dsih_dphy_test_clear(phy, 1);
+ mipi_dsih_dphy_test_clear(phy, 0);
+ for(n=0;n<100;n++){
+ ;
+ }
+ }
+ /* find ranges */
+ for (range = 0; (range < (sizeof(ranges)/sizeof(ranges[0]))) && ((output_freq / 1000) > ranges[range].freq); range++)
+ {
+ ;
+ }
+ if (range >= (sizeof(ranges)/sizeof(ranges[0])))
+ {
+ return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;
+ }
+ /* set up board depending on environment if any */
+ if (phy->bsp_pre_config != 0)
+ {
+ phy->bsp_pre_config(phy, 0);
+ }
+
+ /* Jessica add - begin*/
+ data[0] = 0x83;//0x44;//0x44;//0x40; //0x40: ok for 200 clock lane lpx /*about 52ns*/
+ mipi_dsih_dphy_write(phy, 0x60, data, 1);
+// data[0] = 0x0; //0xA6;//0xC6;//0xC6;//0x86; //0x48: ok for 200 prepare time
+// mipi_dsih_dphy_write(phy, 0x61, data, 1);
+
+// data[0] = 0x0;//0x6a;//0x6a;//0x4a; //0x4a: ok for 200 zero time
+// mipi_dsih_dphy_write(phy, 0x62, data, 1);
+
+ data[0] = 0x83;//0x44;//0x40;//0x40; // 0x40: ok for 200 data lane lpx /*about 52ns*/
+ mipi_dsih_dphy_write(phy, 0x70, data, 1);
+
+// data[0] = 0x0;// 0x84;//0x96;//0x96;//0x86; //0x48: ok for 200 prepare time
+// mipi_dsih_dphy_write(phy, 0x71, data, 1);
+
+// data[0] = 0x0;//0x44;//0x44;//0x40; //0x4a: ok for 200 zero time
+// mipi_dsih_dphy_write(phy, 0x72, data, 1);
+
+ //data[0] = 0x44;
+ //mipi_dsih_dphy_write(phy, 0x73, data, 1);
+
+ //data[0] = 0x7F;
+ //mipi_dsih_dphy_write(phy, 0x74, data, 1);
+
+ /* Jessica add - end*/
+
+ data[0] = 0x70;
+ mipi_dsih_dphy_write(phy, 0x16, data, 1);
+
+ /* setup digital part */
+ /* hs frequency range [7]|[6:1]|[0]*/
+ data[0] = (0 << 7) | (ranges[range].hs_freq << 1) | 0;
+ //data[0] = (0 << 7) | (0x23 << 1) | 0;
+ /*From ASIC, we need unmask this code to make the frequency correct*/
+ mipi_dsih_dphy_write(phy, 0x44, data, 1); //Jessica remove for more accurate frequency
+ /* setup PLL */
+ /* vco range [7]|[6:3]|[2:1]|[0] */
+ data[0] = (1 << 7) | (ranges[range].vco_range << 3) | (0 << 1) | 0;
+ mipi_dsih_dphy_write(phy, 0x10, data, 1); //Jessica
+#ifdef TESTCHIP
+ /* for all Gen2 testchips, bypass LP TX enable idle low power */
+ data[0] = 0x80;
+ mipi_dsih_dphy_write(phy, 0x32, data, 1);
+ mipi_dsih_dphy_write(phy, 0x42, data, 1);
+ mipi_dsih_dphy_write(phy, 0x52, data, 1);
+ mipi_dsih_dphy_write(phy, 0x82, data, 1);
+ mipi_dsih_dphy_write(phy, 0x92, data, 1);
+#endif
+ if ((loop_divider % 2) != 0)
+ { /* only odd integers are allowed (1 will be subtracted upon writing,
+ see below) */
+ loop_divider -= 1;
+
+ }
+ /* gen 2 associates the charge pump current and LPF resistor with the
+ output frequency ranges (and thus we simplify here to use the
+ counter/pointer of the following structure) */
+ i = range;
+ data[0] = (0x00 << 6) | (0x01 << 5) | (0x01 << 4);
+
+ mipi_dsih_dphy_write(phy, 0x19, data, 1); //Jessica
+
+ /* PLL Lock bypass|charge pump current [7:4]|[3:0] */
+ data[0] = (0x00 << 4) | (loop_bandwidth[i].cp_current << 0);
+ mipi_dsih_dphy_write(phy, 0x11, data, 1); //Jessica
+ /* bypass CP default|bypass LPF default| LPF resistor [7]|[6]|[5:0] */
+ data[0] = (0x01 << 7) | (0x01 << 6) |(loop_bandwidth[i].lpf_resistor << 0);
+ mipi_dsih_dphy_write(phy, 0x12, data, 1);
+ /* PLL input divider ratio [7:0] */
+ data[0] = input_divider - 1;
+ mipi_dsih_dphy_write(phy, 0x17, data, 1); //Jessica
+
+ data[0] = 0x04; //short the delay time before BTA
+ mipi_dsih_dphy_write(phy, 0x07, data, 1);
+
+// data[0] = 1;
+// mipi_dsih_dphy_write(phy, 0xB0, data, 1);
+
+ data[0] = 0x8B;
+ mipi_dsih_dphy_write(phy, 0x22, data, 1);
+// data[1] = mipi_dsih_dphy_test_data_out(phy);
+// printk("sprdfb:mipi dphy config-->0x22 write:%x,read:%x \n",data[0],data[1]);
+
+ no_of_bytes = 2; /* pll loop divider (code 0x18) takes only 2 bytes (10 bits in data) */
+ for (i = 0; i < no_of_bytes; i++)
+ {
+ data[i] = ((uint8_t)((((loop_divider - 1) >> (5 * i)) & 0x1F) | (i << 7) ));
+ /* 7 is dependent on no_of_bytes
+ make sure 5 bits only of value are written at a time */
+ }
+ /* PLL loop divider ratio - SET no|reserved|feedback divider [7]|[6:5]|[4:0] */
+ mipi_dsih_dphy_write(phy, 0x18, data, no_of_bytes);
+ mipi_dsih_dphy_no_of_lanes(phy, no_of_lanes);
+#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING
+ if (phy->phy_keep_work != true)
+#endif
+ {
+ mipi_dsih_dphy_stop_wait_time(phy, 0x1C);
+ mipi_dsih_dphy_clock_en(phy, 1);
+ for(n=0;n<100;n++){
+ ;
+ }
+ mipi_dsih_dphy_shutdown(phy, 1);
+ for(n=0;n<100;n++){
+ ;
+ }
+ mipi_dsih_dphy_reset(phy, 1);
+ }
+ return OK;
+}
+#else
+dsih_error_t mipi_dsih_dphy_configure(dphy_t * phy, uint8_t no_of_lanes, uint32_t output_freq)
+{
+ uint32_t loop_divider = 0; /* (M) */
+ uint32_t input_divider = 1; /* (N) */
+ uint8_t data[4]; /* maximum data for now are 4 bytes per test mode*/
+ uint8_t no_of_bytes = 0;
+ uint8_t i = 0; /* iterator */
+ uint8_t n=0;/* iterator */
+ uint8_t range = 0; /* ranges iterator */
+ int flag = 0;
+#ifdef DWC_MIPI_DPHY_BIDIR_TSMC40LP
+ struct
+ {
+ uint32_t freq; /* upper margin of frequency range */
+ uint8_t hs_freq; /* hsfreqrange */
+ uint8_t vco_range; /* vcorange */
+ }
+ ranges[] =
+ {
+ {90, 0x00, 0x01}, {100, 0x10, 0x01}, {110, 0x20, 0x01},
+ {125, 0x01, 0x01}, {140, 0x11, 0x01}, {150, 0x21, 0x01},
+ {160, 0x02, 0x01}, {180, 0x12, 0x03}, {200, 0x22, 0x03},
+ {210, 0x03, 0x03}, {240, 0x13, 0x03}, {250, 0x23, 0x03},
+ {270, 0x04, 0x07}, {300, 0x14, 0x07}, {330, 0x24, 0x07},
+ {360, 0x15, 0x07}, {400, 0x25, 0x07}, {450, 0x06, 0x07},
+ {500, 0x16, 0x07}, {550, 0x07, 0x0f}, {600, 0x17, 0x0f},
+ {650, 0x08, 0x0f}, {700, 0x18, 0x0f}, {750, 0x09, 0x0f},
+ {800, 0x19, 0x0f}, {850, 0x0A, 0x0f}, {900, 0x1A, 0x0f},
+ {950, 0x2A, 0x0f}, {1000, 0x3A, 0x0f}
+ };
+ struct
+ {
+ uint32_t loop_div; /* upper limit of loop divider range */
+ uint8_t cp_current; /* icpctrl */
+ uint8_t lpf_resistor; /* lpfctrl */
+ }
+ loop_bandwidth[] =
+ {
+ {32, 0x06, 0x10}, {64, 0x06, 0x10}, {128, 0x0C, 0x08},
+ {256, 0x04, 0x04}, {512, 0x00, 0x01}, {768, 0x01, 0x01},
+ {1000, 0x02, 0x01}
+ };
+#elif defined DPHY2Btql
+ struct
+ {
+ uint32_t loop_div; /* upper limit of loop divider range */
+ uint8_t cp_current; /* icpctrl */
+ uint8_t lpf_resistor; /* lpfctrl */
+ }
+ loop_bandwidth[] =
+ {
+ {32, 0x0B, 0x00}, {64, 0x0A, 0x00}, {128, 0x09, 0x01},
+ {256, 0x08, 0x03}, {512, 0x08, 0x07}, {768, 0x08, 0x0F},
+ {1000, 0x08, 0x1F}
+ };
+#endif
+ if (phy == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (phy->status < INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ if (output_freq < MIN_OUTPUT_FREQ)
+ {
+ return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;
+ }
+ /* find M and N dividers */
+ for (input_divider = 1 + (phy->reference_freq / DPHY_DIV_UPPER_LIMIT); ((phy->reference_freq / input_divider) >= DPHY_DIV_LOWER_LIMIT) && (!flag); input_divider++)
+ { /* here the >= DPHY_DIV_LOWER_LIMIT is a phy constraint, formula should be above 1 MHz */
+ if (((output_freq * input_divider) % (phy->reference_freq )) == 0)
+ { /* values found */
+ loop_divider = ((output_freq * input_divider) / (phy->reference_freq ));
+ if (loop_divider >= 12)
+ {
+ flag = 1;
+ }
+ }
+ }
+ if ((!flag) || ((phy->reference_freq / input_divider) < DPHY_DIV_LOWER_LIMIT))
+ { /* no exact value found in previous for loop */
+ /* this solution is not favourable as jitter would be maximum */
+ loop_divider = output_freq / DPHY_DIV_LOWER_LIMIT;
+ input_divider = phy->reference_freq / DPHY_DIV_LOWER_LIMIT;
+ }
+ else
+ { /* variable was incremented before exiting the loop */
+ input_divider--;
+ }
+ for (i = 0; (i < (sizeof(loop_bandwidth)/sizeof(loop_bandwidth[0]))) && (loop_divider > loop_bandwidth[i].loop_div); i++)
+ {
+ ;
+ }
+ if (i >= (sizeof(loop_bandwidth)/sizeof(loop_bandwidth[0])))
+ {
+ return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;
+ }
+ printk("sprdfb: Gen1 D-PHY: Approximated Frequency: %d KHz\n", (loop_divider * (phy->reference_freq / input_divider)));
+#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING
+ if (phy->phy_keep_work != true)
+#endif
+ {
+ /* get the PHY in power down mode (shutdownz=0) and reset it (rstz=0) to
+ avoid transient periods in PHY operation during re-configuration procedures. */
+ mipi_dsih_dphy_reset(phy, 0);
+ mipi_dsih_dphy_clock_en(phy, 0);
+ mipi_dsih_dphy_shutdown(phy, 0);
+ /* provide an initial active-high test clear pulse in TESTCLR */
+ mipi_dsih_dphy_test_clear(phy, 1);
+ mipi_dsih_dphy_test_clear(phy, 0);
+ }
+#ifdef DWC_MIPI_DPHY_BIDIR_TSMC40LP
+ /* find ranges */
+ for (range = 0; (range < (sizeof(ranges)/sizeof(ranges[0]))) && ((output_freq / 1000) > ranges[range].freq); range++)
+ {
+ ;
+ }
+ if (range >= (sizeof(ranges)/sizeof(ranges[0])))
+ {
+ return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;
+ }
+ /* set up board depending on environment if any */
+ if (phy->bsp_pre_config != 0)
+ {
+ phy->bsp_pre_config(phy, 0);
+ }
+
+ /* Jessica add - begin*/
+ data[0] = 0x42;//0x44;//0x44;//0x40; //0x40: ok for 200 clock lane lpx /*about 52ns*/
+ mipi_dsih_dphy_write(phy, 0x60, data, 1);
+ data[0] = 0x0; //0xA6;//0xC6;//0xC6;//0x86; //0x48: ok for 200 prepare time
+ mipi_dsih_dphy_write(phy, 0x61, data, 1);
+
+ data[0] = 0x0;//0x6a;//0x6a;//0x4a; //0x4a: ok for 200 zero time
+ mipi_dsih_dphy_write(phy, 0x62, data, 1);
+
+ data[0] = 0x42;//0x44;//0x40;//0x40; // 0x40: ok for 200 data lane lpx /*about 52ns*/
+ mipi_dsih_dphy_write(phy, 0x70, data, 1);
+
+ data[0] = 0x0;// 0x84;//0x96;//0x96;//0x86; //0x48: ok for 200 prepare time
+ mipi_dsih_dphy_write(phy, 0x71, data, 1);
+
+ data[0] = 0x0;//0x44;//0x44;//0x40; //0x4a: ok for 200 zero time
+ mipi_dsih_dphy_write(phy, 0x72, data, 1);
+
+ //data[0] = 0x44;
+ //mipi_dsih_dphy_write(phy, 0x73, data, 1);
+
+ //data[0] = 0x7F;
+ //mipi_dsih_dphy_write(phy, 0x74, data, 1);
+
+ /* Jessica add - end*/
+
+ /* setup digital part */
+ /* hs frequency range [7]|[6:1]|[0]*/
+ data[0] = (0 << 7) | (ranges[range].hs_freq << 1) | 0;
+ //data[0] = (0 << 7) | (0x23 << 1) | 0;
+ /*From ASIC, we need unmask this code to make the frequency correct*/
+ mipi_dsih_dphy_write(phy, 0x44, data, 1); //Jessica remove for more accurate frequency
+ /* setup PLL */
+ /* vco range [7]|[6:3]|[2:1]|[0] */
+ data[0] = (1 << 7) | (ranges[range].vco_range << 3) | (0 << 1) | 0;
+ mipi_dsih_dphy_write(phy, 0x10, data, 1); //Jessica
+ /* PLL reserved|Input divider control|Loop Divider Control|Post Divider Ratio [7:6]|[5]|[4]|[3:0] */
+ data[0] = (0x00 << 6) | (0x01 << 5) | (0x01 << 4) | (0x03 << 0); /* post divider default = 0x03 - it is only used for clock out 2*/
+ mipi_dsih_dphy_write(phy, 0x19, data, 1); //Jessica
+#elif defined DPHY2Btql
+ /* vco range [7:5]|[4]|[3]|[2:1]|[0] */
+ data[0] = ((((output_freq / 1000) > 500 )? 1: 0) << 4) | (1 << 3) | (0 << 1) | 0;
+ mipi_dsih_dphy_write(phy, 0x10, data, 1);
+#endif
+ /* PLL Lock bypass|charge pump current [7:4]|[3:0] */
+ data[0] = (0x00 << 4) | (loop_bandwidth[i].cp_current << 0);
+ mipi_dsih_dphy_write(phy, 0x11, data, 1); //Jessica
+ /* bypass CP default|bypass LPF default| LPF resistor [7]|[6]|[5:0] */
+ data[0] = (0x01 << 7) | (0x01 << 6) |(loop_bandwidth[i].lpf_resistor << 0);
+ mipi_dsih_dphy_write(phy, 0x12, data, 1);
+ /* PLL input divider ratio [7:0] */
+ data[0] = input_divider - 1;
+ mipi_dsih_dphy_write(phy, 0x17, data, 1); //Jessica
+
+ data[0] = 0x04; //short the delay time before BTA
+ mipi_dsih_dphy_write(phy, 0x07, data, 1);
+
+// data[0] = 1;
+// mipi_dsih_dphy_write(phy, 0xB0, data, 1);
+
+ data[0] = 0x8B;
+ mipi_dsih_dphy_write(phy, 0x22, data, 1);
+ // data[1] = mipi_dsih_dphy_test_data_out(phy);
+// printk("sprdfb:mipi dphy config-->0x22 write:%x,read:%x \n",data[0],data[1]);
+
+ no_of_bytes = 2; /* pll loop divider (code 0x18) takes only 2 bytes (10 bits in data) */
+ for (i = 0; i < no_of_bytes; i++)
+ {
+ data[i] = ((uint8_t)((((loop_divider - 1) >> (5 * i)) & 0x1F) | (i << 7) ));
+ /* 7 is dependent on no_of_bytes
+ make sure 5 bits only of value are written at a time */
+ }
+ /* PLL loop divider ratio - SET no|reserved|feedback divider [7]|[6:5]|[4:0] */
+ mipi_dsih_dphy_write(phy, 0x18, data, no_of_bytes);
+ mipi_dsih_dphy_no_of_lanes(phy, no_of_lanes);
+#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING
+ if (phy->phy_keep_work != true)
+#endif
+ {
+ mipi_dsih_dphy_stop_wait_time(phy, 0x1C);
+ mipi_dsih_dphy_clock_en(phy, 1);
+ for(n=0;n<100;n++){
+ ;
+ }
+ mipi_dsih_dphy_shutdown(phy, 1);
+ for(n=0;n<100;n++){
+ ;
+ }
+ mipi_dsih_dphy_reset(phy, 1);
+ }
+ return OK;
+}
+#endif
+/**
+ * Close and power down D-PHY module
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @return error code
+ */
+dsih_error_t mipi_dsih_dphy_close(dphy_t * phy)
+{
+ if (phy == 0)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ else if ((phy->core_read_function == 0) || (phy->core_write_function == 0))
+ {
+ return ERR_DSI_INVALID_IO;
+ }
+ if (phy->status < NOT_INITIALIZED)
+ {
+ return ERR_DSI_INVALID_INSTANCE;
+ }
+ mipi_dsih_dphy_reset(phy, 0);
+ mipi_dsih_dphy_reset(phy, 1);
+ mipi_dsih_dphy_shutdown(phy, 0);
+ phy->status = NOT_INITIALIZED;
+ return OK;
+}
+/**
+ * Enable clock lane module
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param en
+ */
+void mipi_dsih_dphy_clock_en(dphy_t * instance, int en)
+{
+ mipi_dsih_dphy_write_part(instance, R_DPHY_RSTZ, en, 2, 1);
+}
+/**
+ * Reset D-PHY module
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param reset
+ */
+void mipi_dsih_dphy_reset(dphy_t * instance, int reset)
+{
+ mipi_dsih_dphy_write_part(instance, R_DPHY_RSTZ, reset, 1, 1);
+}
+/**
+ * Power up/down D-PHY module
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param powerup (1) shutdown (0)
+ */
+void mipi_dsih_dphy_shutdown(dphy_t * instance, int powerup)
+{
+ mipi_dsih_dphy_write_part(instance, R_DPHY_RSTZ, powerup, 0, 1);
+}
+/**
+ * Force D-PHY PLL to stay on while in ULPS
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param force (1) disable (0)
+ * @note To follow the programming model, use wakeup_pll function
+ */
+void mipi_dsih_dphy_force_pll(dphy_t * instance, int force)
+{
+ mipi_dsih_dphy_write_part(instance, R_DPHY_RSTZ, force, 3, 1);
+}
+/**
+ * Get force D-PHY PLL module
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @return force value
+ */
+int mipi_dsih_dphy_get_force_pll(dphy_t * instance)
+{
+ return mipi_dsih_dphy_read_part(instance, R_DPHY_RSTZ, 3, 1);
+}
+/**
+ * Wake up or make sure D-PHY PLL module is awake
+ * This function must be called after going into ULPS and before exiting it
+ * to force the DPHY PLLs to wake up. It will wait until the DPHY status is
+ * locked. It follows the procedure described in the user guide.
+ * This function should be used to make sure the PLL is awake, rather than
+ * the force_pll above.
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @return error code
+ * @note this function has an active wait
+ */
+int mipi_dsih_dphy_wakeup_pll(dphy_t * instance)
+{
+ unsigned i = 0;
+ if (mipi_dsih_dphy_status(instance, 0x1) == 0)
+ {
+ mipi_dsih_dphy_force_pll(instance, 1);
+ for (i = 0; i < DSIH_PHY_ACTIVE_WAIT; i++)
+ {
+ if(mipi_dsih_dphy_status(instance, 0x1))
+ {
+ break;
+ }
+ }
+ if (mipi_dsih_dphy_status(instance, 0x1) == 0)
+ {
+ return ERR_DSI_PHY_PLL_NOT_LOCKED;
+ }
+ }
+ return OK;
+}
+/**
+ * Configure minimum wait period for HS transmission request after a stop state
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param no_of_byte_cycles [in byte (lane) clock cycles]
+ */
+void mipi_dsih_dphy_stop_wait_time(dphy_t * instance, uint8_t no_of_byte_cycles)
+{
+ mipi_dsih_dphy_write_part(instance, R_DPHY_IF_CFG, no_of_byte_cycles, 8, 8);
+}
+/**
+ * Set number of active lanes
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param no_of_lanes
+ */
+void mipi_dsih_dphy_no_of_lanes(dphy_t * instance, uint8_t no_of_lanes)
+{
+ mipi_dsih_dphy_write_part(instance, R_DPHY_IF_CFG, no_of_lanes - 1, 0, 2);
+}
+/**
+ * Get number of currently active lanes
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @return number of active lanes
+ */
+uint8_t mipi_dsih_dphy_get_no_of_lanes(dphy_t * instance)
+{
+ return mipi_dsih_dphy_read_part(instance, R_DPHY_IF_CFG, 0, 2);
+}
+
+/**
+ * SPRD ADD
+ * Set non-continuous clock mode
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param enable
+ */
+void mipi_dsih_dphy_enable_nc_clk(dphy_t * instance, int enable)
+{
+ mipi_dsih_dphy_write_part(instance, R_DPHY_LPCLK_CTRL, enable, 1, 1);
+}
+
+/**
+ * Request the PHY module to start transmission of high speed clock.
+ * This causes the clock lane to start transmitting DDR clock on the
+ * lane interconnect.
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param enable
+ * @note this function should be called explicitly by user always except for
+ * transmitting
+ */
+void mipi_dsih_dphy_enable_hs_clk(dphy_t * instance, int enable)
+{
+ mipi_dsih_dphy_write_part(instance, R_DPHY_LPCLK_CTRL, enable, 0, 1);
+}
+/**
+ * One bit is asserted in the trigger_request (4bits) to cause the lane module
+ * to cause the associated trigger to be sent across the lane interconnect.
+ * The trigger request is synchronous with the rising edge of the clock.
+ * @note: Only one bit of the trigger_request is asserted at any given time, the
+ * remaining must be left set to 0, and only when not in LPDT or ULPS modes
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param trigger_request 4 bit request
+ */
+dsih_error_t mipi_dsih_dphy_escape_mode_trigger(dphy_t * instance, uint8_t trigger_request)
+{
+ uint8_t sum = 0;
+ int i = 0;
+ for (i = 0; i < 4; i++)
+ {
+ sum += ((trigger_request >> i) & 1);
+ }
+ if (sum == 1)
+ { /* clear old trigger */
+ mipi_dsih_dphy_write_part(instance, R_DPHY_TX_TRIGGERS, 0x00, 0, 4);
+ mipi_dsih_dphy_write_part(instance, R_DPHY_TX_TRIGGERS, trigger_request, 0, 4);
+ for (i = 0; i < DSIH_PHY_ACTIVE_WAIT; i++)
+ {
+ if(mipi_dsih_dphy_status(instance, 0x0010))
+ {
+ break;
+ }
+ }
+ mipi_dsih_dphy_write_part(instance, R_DPHY_TX_TRIGGERS, 0x00, 0, 4);
+ if (i >= DSIH_PHY_ACTIVE_WAIT)
+ {
+ return ERR_DSI_TIMEOUT;
+ }
+ return OK;
+ }
+ return ERR_DSI_INVALID_COMMAND;
+}
+/**
+ * ULPS mode request/exit on all active data lanes.
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param enable (request 1/ exit 0)
+ * @return error code
+ * @note this is a blocking function. wait upon exiting the ULPS will exceed 1ms
+ */
+#ifdef GEN_2
+dsih_error_t mipi_dsih_dphy_ulps_data_lanes(dphy_t * instance, int enable)
+{
+ int timeout;
+ /* mask 1 0101 0010 0000 */
+ uint16_t data_lanes_mask = 0;
+ if (enable)
+ {
+ mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 1, 2, 1);
+ return OK;
+ }
+ else
+ {
+ if (mipi_dsih_dphy_status(instance, 0x1) == 0)
+ {
+ return ERR_DSI_PHY_PLL_NOT_LOCKED;
+ }
+ mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 1, 3, 1);
+ switch (mipi_dsih_dphy_get_no_of_lanes(instance))
+ {
+ case 3:
+ data_lanes_mask |= (1 << 12);
+ case 2:
+ data_lanes_mask |= (1 << 10);
+ case 1:
+ data_lanes_mask |= (1 << 8);
+ case 0:
+ data_lanes_mask |= (1 << 5);
+ break;
+ default:
+ data_lanes_mask = 0;
+ break;
+ }
+ for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++)
+ { /* verify that the DPHY has left ULPM */
+
+ if (mipi_dsih_dphy_status(instance, data_lanes_mask) == data_lanes_mask)
+ {
+ break;
+ }
+ /* wait at least 1ms */
+ for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)
+ {
+ ;
+ }
+ }
+ if (mipi_dsih_dphy_status(instance, data_lanes_mask) != data_lanes_mask)
+ {
+ instance->log_info("sprdfb: stat %x, mask %x", mipi_dsih_dphy_status(instance, data_lanes_mask), data_lanes_mask);
+ return ERR_DSI_TIMEOUT;
+ }
+ mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 0, 2, 1);
+ mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 0, 3, 1);
+ }
+ return OK;
+}
+#else
+void mipi_dsih_dphy_ulps_data_lanes(dphy_t * instance, int enable)
+{
+ int timeout;
+ if (enable)
+ {
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 3, 1);
+ }
+ else
+ {
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 4, 1);
+ for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++)
+ { /* verify that the DPHY has left ULPM */
+ /* mask 1010100100000 */
+ if (mipi_dsih_dphy_status(instance, 0x1520) == 0)
+ { /* wait at least 1ms */
+ for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)
+ {
+ ;
+ }
+ break;
+ }
+ }
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 3, 1);
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 4, 1);
+ }
+}
+#endif
+/**
+ * ULPS mode request/exit on Clock Lane.
+ * @param instance pointer to structure which holds information about the
+ * d-phy module
+ * @param enable 1 or disable 0 of the Ultra Low Power State of the clock lane
+ * @return error code
+ * @note this is a blocking function. wait upon exiting the ULPS will exceed 1ms
+ */
+#ifdef GEN_2
+dsih_error_t mipi_dsih_dphy_ulps_clk_lane(dphy_t * instance, int enable)
+{
+ int timeout;
+ /* mask 1000 */
+ uint16_t clk_lane_mask = 0x0008;
+ if (enable)
+ {
+ /* mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 0, 0, 1); */
+ mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 1, 0, 1);
+ }
+ else
+ {
+ if (mipi_dsih_dphy_status(instance, 0x1) == 0)
+ {
+ return ERR_DSI_PHY_PLL_NOT_LOCKED;
+ }
+ mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 1, 1, 1);
+ for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++)
+ { /* verify that the DPHY has left ULPM */
+ /* mask 1010100100000 */
+ if (mipi_dsih_dphy_status(instance, clk_lane_mask) == clk_lane_mask)
+ { /* wait at least 1ms */
+ instance->log_info("sprdfb: stat %x, mask %x", mipi_dsih_dphy_status(instance, clk_lane_mask), clk_lane_mask);
+ break;
+ }
+ /* wait at least 1ms */
+ for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)
+ { /* dummy operation for the loop not to be optimised */
+ enable = mipi_dsih_dphy_status(instance, clk_lane_mask);
+ }
+ }
+ if (mipi_dsih_dphy_status(instance, clk_lane_mask) != clk_lane_mask)
+ {
+ return ERR_DSI_TIMEOUT;
+ }
+ mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 0, 0, 1);
+ mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 0, 1, 1);
+ }
+ return OK;
+}
+#else
+void mipi_dsih_dphy_ulps_clk_lane(dphy_t * instance, int enable)
+{
+ int timeout;
+ if (enable)
+ {
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 0, 1);
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 1, 1);
+ }
+ else
+ {
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 2, 1);
+ for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++)
+ { /* verify that the DPHY has left ULPM */
+ /* mask 1010100100000 */
+ if (mipi_dsih_dphy_status(instance, 0x0004) == 0)
+ { /* wait at least 1ms */
+ for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)
+ {
+ ;
+ }
+ break;
+ }
+ }
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 1, 1);
+ mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 2, 1);
+ }
+}
+#endif
+/**
+ * Get D-PHY PPI status
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param mask
+ * @return status
+ */
+uint32_t mipi_dsih_dphy_status(dphy_t * instance, uint16_t mask)
+{
+ return mipi_dsih_dphy_read_word(instance, R_DPHY_STATUS) & mask;
+}
+/**
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param value
+ */
+void mipi_dsih_dphy_test_clock(dphy_t * instance, int value)
+{
+ mipi_dsih_dphy_write_part(instance, R_DPHY_TST_CRTL0, value, 1, 1);
+}
+/**
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param value
+ */
+void mipi_dsih_dphy_test_clear(dphy_t * instance, int value)
+{
+ mipi_dsih_dphy_write_part(instance, R_DPHY_TST_CRTL0, value, 0, 1);
+}
+/**
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param on_falling_edge
+ */
+void mipi_dsih_dphy_test_en(dphy_t * instance, uint8_t on_falling_edge)
+{
+ mipi_dsih_dphy_write_part(instance, R_DPHY_TST_CRTL1, on_falling_edge, 16, 1);
+}
+/**
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ */
+uint8_t mipi_dsih_dphy_test_data_out(dphy_t * instance)
+{
+ return mipi_dsih_dphy_read_part(instance, R_DPHY_TST_CRTL1, 8, 8);
+}
+/**
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param test_data
+ */
+void mipi_dsih_dphy_test_data_in(dphy_t * instance, uint8_t test_data)
+{
+ mipi_dsih_dphy_write_word(instance, R_DPHY_TST_CRTL1, test_data);
+}
+/**
+ * Write to D-PHY module (encapsulating the digital interface)
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param address offset inside the D-PHY digital interface
+ * @param data array of bytes to be written to D-PHY
+ * @param data_length of the data array
+ */
+void mipi_dsih_dphy_write(dphy_t * instance, uint8_t address, uint8_t * data, uint8_t data_length)
+{
+ unsigned i = 0;
+ if (data != 0)
+ {
+#if ((defined DWC_MIPI_DPHY_BIDIR_TSMC40LP) || (defined DPHY2Btql) || (defined GEN_2))
+ /* set the TESTCLK input high in preparation to latch in the desired test mode */
+ mipi_dsih_dphy_test_clock(instance, 1);
+ /* set the desired test code in the input 8-bit bus TESTDIN[7:0] */
+ mipi_dsih_dphy_test_data_in(instance, address);
+ /* set TESTEN input high */
+ mipi_dsih_dphy_test_en(instance, 1);
+ /* drive the TESTCLK input low; the falling edge captures the chosen test code into the transceiver */
+ mipi_dsih_dphy_test_clock(instance, 0);
+ /* set TESTEN input low to disable further test mode code latching */
+ mipi_dsih_dphy_test_en(instance, 0);
+ /* start writing MSB first */
+ for (i = data_length; i > 0; i--)
+ { /* set TESTDIN[7:0] to the desired test data appropriate to the chosen test mode */
+ mipi_dsih_dphy_test_data_in(instance, data[i - 1]);
+ /* pulse TESTCLK high to capture this test data into the macrocell; repeat these two steps as necessary */
+ mipi_dsih_dphy_test_clock(instance, 1);
+ mipi_dsih_dphy_test_clock(instance, 0);
+ }
+#endif
+ }
+}
+
+
+
+/* abstracting BSP */
+/**
+ * Write to whole register to D-PHY module (encapsulating the bus interface)
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param reg_address offset
+ * @param data 32-bit word
+ */
+void mipi_dsih_dphy_write_word(dphy_t * instance, uint32_t reg_address, uint32_t data)
+{
+ if (instance->core_write_function != 0)
+ {
+ instance->core_write_function(instance->address, reg_address, data);
+ }
+}
+/**
+ * Write bit field to D-PHY module (encapsulating the bus interface)
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param reg_address offset
+ * @param data bits to be written to D-PHY
+ * @param shift from the right hand side of the register (big endian)
+ * @param width of the bit field
+ */
+void mipi_dsih_dphy_write_part(dphy_t * instance, uint32_t reg_address, uint32_t data, uint8_t shift, uint8_t width)
+{
+ uint32_t mask = 0;
+ uint32_t temp = 0;
+ if (instance->core_read_function != 0)
+ {
+ mask = (1 << width) - 1;
+ temp = mipi_dsih_dphy_read_word(instance, reg_address);
+ temp &= ~(mask << shift);
+ temp |= (data & mask) << shift;
+ mipi_dsih_dphy_write_word(instance, reg_address, temp);
+ }
+}
+/**
+ * Read whole register from D-PHY module (encapsulating the bus interface)
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param reg_address offset
+ * @return data 32-bit word
+ */
+uint32_t mipi_dsih_dphy_read_word(dphy_t * instance, uint32_t reg_address)
+{
+ if (instance->core_read_function == 0)
+ {
+ return ERR_DSI_INVALID_IO;
+ }
+ return instance->core_read_function(instance->address, reg_address);
+}
+/**
+ * Read bit field from D-PHY module (encapsulating the bus interface)
+ * @param instance pointer to structure which holds information about the d-phy
+ * module
+ * @param reg_address offset
+ * @param shift from the right hand side of the register (big endian)
+ * @param width of the bit field
+ * @return data bits to be written to D-PHY
+ */
+uint32_t mipi_dsih_dphy_read_part(dphy_t * instance, uint32_t reg_address, uint8_t shift, uint8_t width)
+{
+ return (mipi_dsih_dphy_read_word(instance, reg_address) >> shift) & ((1 << width) - 1);
+}
diff --git a/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_dphy.h b/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_dphy.h
new file mode 100644
index 00000000..111d3404
--- /dev/null
+++ b/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_dphy.h
@@ -0,0 +1,61 @@
+/*
+ * @file mipi_dsih_dphy.h
+ *
+ * Synopsys Inc.
+ * SG DWC PT02
+ */
+
+#ifndef MIPI_DSIH_DPHY_H_
+#define MIPI_DSIH_DPHY_H_
+
+#include "mipi_dsih_local.h"
+
+#define R_DPHY_LPCLK_CTRL (0x94)
+#define R_DPHY_RSTZ (0xA0)
+#define R_DPHY_IF_CFG (0xA4)
+#define R_DPHY_ULPS_CTRL (0xA8)
+#define R_DPHY_TX_TRIGGERS (0xAC)
+#define R_DPHY_STATUS (0xB0)
+#define R_DPHY_TST_CRTL0 (0xB4)
+#define R_DPHY_TST_CRTL1 (0xB8)
+
+/* obligatory functions - code can be changed for different phys*/
+dsih_error_t mipi_dsih_dphy_open(dphy_t * phy);
+dsih_error_t mipi_dsih_dphy_configure(dphy_t * phy, uint8_t no_of_lanes, uint32_t output_freq);
+dsih_error_t mipi_dsih_dphy_close(dphy_t * phy);
+
+void mipi_dsih_dphy_clock_en(dphy_t * instance, int en);
+void mipi_dsih_dphy_reset(dphy_t * instance, int reset);
+void mipi_dsih_dphy_shutdown(dphy_t * instance, int powerup);
+int mipi_dsih_dphy_get_force_pll(dphy_t * instance);
+void mipi_dsih_dphy_force_pll(dphy_t * instance, int force);
+int mipi_dsih_dphy_wakeup_pll(dphy_t * instance);
+
+void mipi_dsih_dphy_stop_wait_time(dphy_t * instance, uint8_t no_of_byte_cycles);
+void mipi_dsih_dphy_no_of_lanes(dphy_t * instance, uint8_t no_of_lanes);
+uint8_t mipi_dsih_dphy_get_no_of_lanes(dphy_t * instance);
+void mipi_dsih_dphy_enable_nc_clk(dphy_t * instance, int enable);
+void mipi_dsih_dphy_enable_hs_clk(dphy_t * instance, int enable);
+dsih_error_t mipi_dsih_dphy_escape_mode_trigger(dphy_t * instance, uint8_t trigger_request);
+#ifdef GEN_2
+dsih_error_t mipi_dsih_dphy_ulps_data_lanes(dphy_t * instance, int enable);
+dsih_error_t mipi_dsih_dphy_ulps_clk_lane(dphy_t * instance, int enable);
+#else
+void mipi_dsih_dphy_ulps_data_lanes(dphy_t * instance, int enable);
+void mipi_dsih_dphy_ulps_clk_lane(dphy_t * instance, int enable);
+#endif
+uint32_t mipi_dsih_dphy_status(dphy_t * instance, uint16_t mask);
+/* end of obligatory functions*/
+void mipi_dsih_dphy_test_clock(dphy_t * instance, int value);
+void mipi_dsih_dphy_test_clear(dphy_t * instance, int value);
+void mipi_dsih_dphy_test_en(dphy_t * instance, uint8_t on_falling_edge);
+uint8_t mipi_dsih_dphy_test_data_out(dphy_t * instance);
+void mipi_dsih_dphy_test_data_in(dphy_t * instance, uint8_t test_data);
+
+void mipi_dsih_dphy_write(dphy_t * instance, uint8_t address, uint8_t * data, uint8_t data_length);
+
+void mipi_dsih_dphy_write_word(dphy_t * instance, uint32_t reg_address, uint32_t data);
+void mipi_dsih_dphy_write_part(dphy_t * instance, uint32_t reg_address, uint32_t data, uint8_t shift, uint8_t width);
+uint32_t mipi_dsih_dphy_read_word(dphy_t * instance, uint32_t reg_address);
+uint32_t mipi_dsih_dphy_read_part(dphy_t * instance, uint32_t reg_address, uint8_t shift, uint8_t width);
+#endif /* MIPI_DSIH_DPHY_H_ */
diff --git a/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_dphy_megacores.c b/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_dphy_megacores.c
new file mode 100644
index 00000000..b70cdefb
--- /dev/null
+++ b/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_dphy_megacores.c
@@ -0,0 +1,1166 @@
+/*
+ * Copyright (C) 2014 Spreadtrum Communications Inc.
+ *
+ * modules/DISPC/dsi_1.21a/mipi_api_dsihost/mipi_dsih_dphy_megacores.c
+ *
+ * Author: Haibing.Yang <haibing.yang@spreadtrum.com>
+ * <yanghb41@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include "mipi_dsih_dphy.h"
+
+#define L 0
+#define H 1
+#define CLK 0
+#define DATA 1
+
+#ifndef INFINITY
+#define INFINITY 0xffffffff
+#endif
+
+#define MIN_OUTPUT_FREQ (100)
+#define MAX_LANES 2
+
+#ifndef ROUND_UP
+#define ROUND_UP(a, b) (((a) + (b) - 1) / (b))
+#endif
+
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) > (b) ? (b) : (a))
+#endif
+
+#ifndef abs
+/*
+ * abs() should not be used for 64-bit types
+ * (s64, u64, long long) - use abs64() for those.
+ */
+#define abs(x) ({ \
+ long ret; \
+ if (sizeof((x)) == sizeof(long)) { \
+ long __x = (x); \
+ ret = (__x < 0) ? - __x : __x; \
+ } else { \
+ int __x = (x); \
+ ret = (__x < 0) ? - __x : __x; \
+ } \
+ ret; \
+})
+#endif
+
+#define AVERAGE(a, b) (MIN(a, b) + abs((b) - (a)) / 2)
+
+typedef unsigned int u32;
+typedef unsigned short u16;
+typedef unsigned char u8;
+
+enum TIMING {
+ NONE,
+ REQUEST_TIME,
+ PREPARE_TIME,
+ SETTLE_TIME,
+ ZERO_TIME,
+ TRAIL_TIME,
+ EXIT_TIME,
+ CLKPOST_TIME,
+ TA_GET,
+ TA_GO,
+ TA_SURE,
+ TA_WAIT,
+};
+
+struct pll_regs {
+ union __reg_03__ {
+ struct __03 {
+ u8 prbs_bist: 1;
+ u8 en_lp_treot: 1;
+ u8 lpf_sel: 4;
+ u8 txfifo_bypass: 1;
+ u8 freq_hopping: 1;
+ } bits;
+ u8 val;
+ } _03;
+ union __reg_04__ {
+ struct __04 {
+ u8 div: 3;
+ u8 reserved: 2;
+ u8 cp_s: 2;
+ u8 fdk_s: 1;
+ } bits;
+ u8 val;
+ } _04;
+ union __reg_06__ {
+ struct __06 {
+ u8 nint: 7;
+ u8 mod_en: 1;
+ } bits;
+ u8 val;
+ } _06;
+ union __reg_07__ {
+ struct __07 {
+ u8 kdelta_h: 8;
+ } bits;
+ u8 val;
+ } _07;
+ union __reg_08__ {
+ struct __08 {
+ u8 vco_band: 1;
+ u8 sdm_en: 1;
+ u8 refin: 2;
+ u8 kdelta_l: 4;
+ } bits;
+ u8 val;
+ } _08;
+ union __reg_09__ {
+ struct __09 {
+ u8 kint_h: 8;
+ } bits;
+ u8 val;
+ } _09;
+ union __reg_0a__ {
+ struct __0a {
+ u8 kint_m: 8;
+ } bits;
+ u8 val;
+ } _0a;
+ union __reg_0b__ {
+ struct __0b {
+ u8 out_sel: 4;
+ u8 kint_l: 4;
+ } bits;
+ u8 val;
+ } _0b;
+ union __reg_0c__ {
+ struct __0c {
+ u8 kstep_h: 8;
+ } bits;
+ u8 val;
+ } _0c;
+ union __reg_0d__ {
+ struct __0d {
+ u8 kstep_m: 8;
+ } bits;
+ u8 val;
+ } _0d;
+ union __reg_0e__ {
+ struct __0e {
+ u8 pll_pu_byp: 1;
+ u8 pll_pu: 1;
+ u8 reserved1: 3;
+ u8 kstep_l: 3;
+ } bits;
+ u8 val;
+ } _0e;
+};
+
+struct dphy_pll {
+ u8 refin; /* Pre-divider control signal */
+ u8 cp_s; /* 00: SDM_EN=1, 10: SDM_EN=0 */
+ u8 fdk_s; /* PLL mode control: integer or fraction */
+ u8 hop_en;
+ u8 mod_en; /* ssc enable */
+ u8 sdm_en;
+ u8 div;
+ u8 int_n; /* integer N PLL */
+ u32 ref_clk; /* dphy reference clock, unit: MHz */
+ u32 freq; /* panel config, unit: KHz */
+ u32 fvco; /* MHz */
+ u32 potential_fvco; /* MHz */
+ u32 nint; /* sigma delta modulator NINT control */
+ u32 kint; /* sigma delta modulator KINT control */
+ u32 sign;
+ u32 kdelta;
+ u32 kstep;
+ u8 lpf_sel; /* low pass filter control */
+ u8 out_sel; /* post divider control */
+ u8 vco_band; /* vco range */
+};
+
+/**
+ * Initialise D-PHY module and power up
+ * @param phy: pointer to structure
+ * which holds information about the d-phy module
+ * @return error code
+ */
+dsih_error_t mipi_dsih_dphy_open(dphy_t *phy)
+{
+ if (!phy || !phy->core_read_function || !phy->core_write_function)
+ return ERR_DSI_PHY_INVALID;
+ else if (phy->status == INITIALIZED)
+ return ERR_DSI_PHY_INVALID;
+
+ phy->status = INITIALIZED;
+ return OK;
+}
+
+u8 mipi_dsih_dphy_test_data_read(dphy_t *phy, u8 address)
+{
+ mipi_dsih_dphy_test_clock(phy, 1);
+ /* set the desired test code in the input 8-bit bus TESTDIN[7:0] */
+ mipi_dsih_dphy_test_data_in(phy, address);
+ /* set TESTEN input high */
+ mipi_dsih_dphy_test_en(phy, 1);
+
+ /*
+ * drive the TESTCLK input low;
+ * the falling edge captures the
+ * chosen test code into the transceiver.
+ */
+ mipi_dsih_dphy_test_clock(phy, 0);
+
+ /* set TESTEN input low to disable further test mode code latching */
+ mipi_dsih_dphy_test_en(phy, 0);
+
+ udelay(1);
+
+ return mipi_dsih_dphy_test_data_out(phy);
+}
+
+static inline int mipi_dsih_if_dphy_keep_work(dphy_t *phy)
+{
+ int keep_work;
+
+#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING
+ keep_work = phy->phy_keep_work;
+#else
+ keep_work = false;
+#endif
+ return keep_work;
+}
+
+static int mipi_dsih_dphy_calc_pll_param(dphy_t *phy, struct dphy_pll *pll)
+{
+ int i;
+ const u32 hopping_period = 200;
+ const u32 khz = 1000;
+ const u32 mhz = 1000000;
+ int delta_freq;
+ static u32 origin_freq = 0;
+ const unsigned long long factor = 100;
+ unsigned long long tmp;
+
+ if (!pll || !pll->freq)
+ goto FAIL;
+
+ pll->potential_fvco = pll->freq / khz; /* MHz */
+ pll->ref_clk = phy->reference_freq / khz; /* MHz */
+
+ for (i = 0; i < 4; ++i) {
+ if (pll->potential_fvco >= 750 && pll->potential_fvco <= 1500) {
+ pll->fvco = pll->potential_fvco;
+ pll->out_sel = BIT(i);
+ break;
+ }
+ pll->potential_fvco <<= 1;
+ }
+ if (pll->fvco == 0)
+ goto FAIL;
+
+ if (pll->fvco >= 750 && pll->fvco <= 1100) {
+ /* vco band control */
+ pll->vco_band = 0x0;
+ /* low pass filter control */
+ pll->lpf_sel = 0x7;
+ } else if (pll->fvco > 1100 && pll->fvco <= 1500) {
+ pll->vco_band = 0x1;
+ pll->lpf_sel = 0x6;
+ } else
+ goto FAIL;
+
+ pll->nint = pll->fvco / pll->ref_clk;
+ tmp = pll->fvco * factor * mhz;
+ do_div(tmp, pll->ref_clk);
+ tmp = tmp - pll->nint * factor * mhz;
+ tmp *= BIT(20);
+ do_div(tmp, 100000000);
+ pll->kint = (u32)tmp;
+ pll->refin = 0x3; /* pre-divider bypass */
+ pll->sdm_en = true; /* use fraction N PLL */
+ pll->fdk_s = 0x1; /* fraction */
+ pll->cp_s = 0x0;
+ pll->mod_en = false;
+
+ if (0)
+ pll->hop_en = true;
+ else
+ pll->hop_en = false;
+
+ if (pll->hop_en) {
+ if (origin_freq == 0)
+ goto FAIL;
+
+ delta_freq = (int)pll->freq - (int)origin_freq;
+ if (delta_freq < 0) {
+ delta_freq = - delta_freq;
+ pll->sign = true;
+ }
+ pll->kstep = pll->ref_clk * hopping_period;
+ pll->kdelta = (1 << 20) * delta_freq * pll->out_sel
+ / pll->kstep / pll->ref_clk;
+ } else
+ origin_freq = pll->freq;
+
+ return 0;
+
+FAIL:
+ if (pll)
+ pll->fvco = 0;
+
+ phy->log_error("sprdfb: failed to calculate dphy pll parameters\n");
+ return ERR_DSI_PHY_PLL_NOT_LOCKED;
+}
+
+static int mipi_dsih_dphy_set_pll_reg(dphy_t *phy, struct dphy_pll *pll)
+{
+ int i;
+ u8 *val;
+
+ struct pll_regs regs;
+ u8 regs_addr[] = {
+ 0x03, 0x04, 0x06, 0x07, 0x08, 0x09,
+ 0x0a, 0x0b, 0x0c, 0x0d, 0x0e
+ };
+
+ if (!pll || !pll->fvco)
+ goto FAIL;
+
+ memset((u8 *)&regs, '\0', sizeof(regs));
+ regs._03.bits.prbs_bist = 1;
+ regs._03.bits.en_lp_treot = true;
+ regs._03.bits.lpf_sel = pll->lpf_sel;
+ regs._03.bits.txfifo_bypass = 0;
+ regs._03.bits.freq_hopping = pll->hop_en;
+ regs._04.bits.div = pll->div;
+ regs._04.bits.cp_s = pll->cp_s;
+ regs._04.bits.fdk_s = pll->fdk_s;
+ regs._06.bits.nint = pll->nint;
+ regs._06.bits.mod_en = pll->mod_en;
+ regs._07.bits.kdelta_h = pll->kdelta >> 4;
+ regs._07.bits.kdelta_h |= pll->sign << 7;
+ regs._08.bits.vco_band = pll->vco_band;
+ regs._08.bits.sdm_en = pll->sdm_en;
+ regs._08.bits.refin = pll->refin;
+ regs._08.bits.kdelta_l = pll->kdelta & 0xf;
+ regs._09.bits.kint_h = pll->kint >> 12;
+ regs._0a.bits.kint_m = (pll->kint >> 4) & 0xff;
+ regs._0b.bits.out_sel = pll->out_sel;
+ regs._0b.bits.kint_l = pll->kint & 0xf;
+ regs._0c.bits.kstep_h = pll->kstep >> 11;
+ regs._0d.bits.kstep_m = (pll->kstep >> 3) & 0xff;
+ regs._0e.bits.pll_pu_byp = 0;
+ regs._0e.bits.pll_pu = 0;
+ regs._0e.bits.kstep_l = pll->kstep & 0x7;
+
+ val = (u8 *)&regs;
+
+ for (i = 0; i < sizeof(regs_addr); ++i)
+ mipi_dsih_dphy_write(phy, regs_addr[i], &val[i], 1);
+
+ return 0;
+
+FAIL:
+ phy->log_error("sprdfb: failed to set dphy pll registers\n");
+ return ERR_DSI_PHY_PLL_NOT_LOCKED;
+}
+
+static int mipi_dsih_dphy_config_pll(dphy_t *phy, u32 freq)
+{
+ int ret;
+ struct dphy_pll pll = {0};
+
+ pll.freq = freq;
+
+ /* FREQ = 26M * (NINT + KINT / 2^20) / out_sel */
+ ret = mipi_dsih_dphy_calc_pll_param(phy, &pll);
+ if (ret)
+ goto FAIL;
+ ret = mipi_dsih_dphy_set_pll_reg(phy, &pll);
+ if (ret)
+ goto FAIL;
+
+ return 0;
+
+FAIL:
+ phy->log_error("sprdfb: failed to config dphy pll\n");
+ return ERR_DSI_PHY_PLL_NOT_LOCKED;
+}
+
+static int mipi_dsih_dphy_set_timing_regs(dphy_t *phy, int type, u8 val[])
+{
+ switch (type) {
+ case REQUEST_TIME:
+ if (!mipi_dsih_if_dphy_keep_work(phy)) {
+ mipi_dsih_dphy_write(phy, 0x31, &val[CLK], 1);
+ mipi_dsih_dphy_write(phy, 0x41, &val[DATA], 1);
+ mipi_dsih_dphy_write(phy, 0x51, &val[DATA], 1);
+ } else {
+ mipi_dsih_dphy_write(phy, 0x90, &val[CLK], 1);
+ mipi_dsih_dphy_write(phy, 0xa0, &val[DATA], 1);
+ mipi_dsih_dphy_write(phy, 0xb0, &val[DATA], 1);
+ }
+ break;
+ case PREPARE_TIME:
+ if (!mipi_dsih_if_dphy_keep_work(phy)) {
+ mipi_dsih_dphy_write(phy, 0x32, &val[CLK], 1);
+ mipi_dsih_dphy_write(phy, 0x42, &val[DATA], 1);
+ mipi_dsih_dphy_write(phy, 0x52, &val[DATA], 1);
+ } else {
+ mipi_dsih_dphy_write(phy, 0x91, &val[CLK], 1);
+ mipi_dsih_dphy_write(phy, 0xa1, &val[DATA], 1);
+ mipi_dsih_dphy_write(phy, 0xb1, &val[DATA], 1);
+ }
+ break;
+ case ZERO_TIME:
+ if (!mipi_dsih_if_dphy_keep_work(phy)) {
+ mipi_dsih_dphy_write(phy, 0x33, &val[CLK], 1);
+ mipi_dsih_dphy_write(phy, 0x43, &val[DATA], 1);
+ mipi_dsih_dphy_write(phy, 0x53, &val[DATA], 1);
+ } else {
+ mipi_dsih_dphy_write(phy, 0x92, &val[CLK], 1);
+ mipi_dsih_dphy_write(phy, 0xa2, &val[DATA], 1);
+ mipi_dsih_dphy_write(phy, 0xb2, &val[DATA], 1);
+ }
+ break;
+ case TRAIL_TIME:
+ if (!mipi_dsih_if_dphy_keep_work(phy)) {
+ mipi_dsih_dphy_write(phy, 0x34, &val[CLK], 1);
+ mipi_dsih_dphy_write(phy, 0x44, &val[DATA], 1);
+ mipi_dsih_dphy_write(phy, 0x54, &val[DATA], 1);
+ } else {
+ mipi_dsih_dphy_write(phy, 0x93, &val[CLK], 1);
+ mipi_dsih_dphy_write(phy, 0xa3, &val[DATA], 1);
+ mipi_dsih_dphy_write(phy, 0xb3, &val[DATA], 1);
+ }
+ break;
+ case EXIT_TIME:
+ if (!mipi_dsih_if_dphy_keep_work(phy)) {
+ mipi_dsih_dphy_write(phy, 0x36, &val[CLK], 1);
+ mipi_dsih_dphy_write(phy, 0x46, &val[DATA], 1);
+ mipi_dsih_dphy_write(phy, 0x56, &val[DATA], 1);
+ } else {
+ mipi_dsih_dphy_write(phy, 0x95, &val[CLK], 1);
+ mipi_dsih_dphy_write(phy, 0xA5, &val[DATA], 1);
+ mipi_dsih_dphy_write(phy, 0xB5, &val[DATA], 1);
+ }
+ break;
+ case CLKPOST_TIME:
+ if (!mipi_dsih_if_dphy_keep_work(phy))
+ mipi_dsih_dphy_write(phy, 0x35, &val[CLK], 1);
+ else
+ mipi_dsih_dphy_write(phy, 0x94, &val[CLK], 1);
+ break;
+
+ /* the following just use default value */
+ case SETTLE_TIME:
+ case TA_GET:
+ case TA_GO:
+ case TA_SURE:
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int mipi_dsih_dphy_config_lane_timing(dphy_t *phy,
+ u32 bitclk, int type)
+{
+ u8 val[2];
+ u32 tmp = 0;
+ u32 range[2], constant;
+ u32 t_ui, t_byteck, t_half_byteck;
+ const u32 factor = 2;
+ const u32 scale = 100;
+
+ /* t_ui: 1 ui, byteck: 8 ui, half byteck: 4 ui */
+ t_ui = 1000 * scale / (bitclk / 1000);
+ t_byteck = t_ui << 3;
+ t_half_byteck = t_ui << 2;
+ constant = t_ui << 1;
+
+ switch (type) {
+ case NONE:
+ case REQUEST_TIME: /* HS T-LPX: LP-01 */
+ /*
+ * NOTE
+ * For T-LPX, mipi spec defined min value is 50ns,
+ * but maybe it shouldn't be too small, because BTA,
+ * LP-10, LP-00, LP-01, all of this is related to T-LPX.
+ */
+ range[L] = 50 * scale;
+ range[H] = INFINITY;
+ val[CLK] = ROUND_UP(range[L] * (factor << 1), t_byteck) - 2;
+ val[DATA] = val[CLK];
+ mipi_dsih_dphy_set_timing_regs(phy, REQUEST_TIME, val);
+
+ case PREPARE_TIME: /* HS sequence: LP-00 */
+ range[L] = 38 * scale; /* clock */
+ range[H] = 95 * scale;
+ tmp = AVERAGE(range[L], range[H]);
+ val[CLK] = ROUND_UP(AVERAGE(range[L], range[H]),
+ t_half_byteck) - 1;
+ range[L] = 40 * scale + 4 * t_ui; /* data */
+ range[H] = 85 * scale + 6 * t_ui;
+ tmp |= AVERAGE(range[L], range[H]) << 16;
+ val[DATA] = ROUND_UP(AVERAGE(range[L], range[H]),
+ t_half_byteck) - 1;
+ mipi_dsih_dphy_set_timing_regs(phy, PREPARE_TIME, val);
+
+ case ZERO_TIME: /* HS-ZERO */
+ range[L] = 300 * scale; /* clock */
+ range[H] = INFINITY;
+ val[CLK] = ROUND_UP(range[L] * factor + (tmp & 0xffff)
+ - 525 * t_byteck / 100, t_byteck) - 2;
+ range[L] = 145 * scale + 10 * t_ui; /* data */
+ val[DATA] = ROUND_UP(range[L] * factor
+ + ((tmp >> 16) & 0xffff) - 525 * t_byteck / 100,
+ t_byteck) - 2;
+ mipi_dsih_dphy_set_timing_regs(phy, ZERO_TIME, val);
+
+ case TRAIL_TIME: /* HS-TRAIL */
+ range[L] = 60 * scale;
+ range[H] = INFINITY;
+ val[CLK] = ROUND_UP(range[L] * factor - constant, t_half_byteck);
+ range[L] = MAX(8 * t_ui, 60 * scale + 4 * t_ui);
+ val[DATA] = ROUND_UP(range[L] * factor /2 - constant, t_half_byteck);
+ mipi_dsih_dphy_set_timing_regs(phy, TRAIL_TIME, val);
+
+ case EXIT_TIME:
+ range[L] = 100 * scale;
+ range[H] = INFINITY;
+ val[CLK] = ROUND_UP(range[L] * factor, t_byteck) - 2;
+ val[DATA] = val[CLK];
+ mipi_dsih_dphy_set_timing_regs(phy, EXIT_TIME, val);
+
+ case CLKPOST_TIME:
+ range[L] = 60 * scale + 52 * t_ui;
+ range[H] = INFINITY;
+ val[CLK] = ROUND_UP(range[L] * factor, t_byteck) - 2;
+ val[DATA] = val[CLK];
+ mipi_dsih_dphy_set_timing_regs(phy, CLKPOST_TIME, val);
+
+ case SETTLE_TIME:
+ /*
+ * This time is used for receiver. So for transmitter,
+ * it can be ignored.
+ */
+ case TA_GO:
+ /*
+ * transmitter drives bridge state(LP-00) before releasing control,
+ * reg 0x1f default value: 0x04, which is good.
+ */
+ case TA_SURE:
+ /*
+ * After LP-10 state and before bridge state(LP-00),
+ * reg 0x20 default value: 0x01, which is good.
+ */
+ case TA_GET:
+ /*
+ * receiver drives Bridge state(LP-00) before releasing control
+ * reg 0x21 default value: 0x03, which is good.
+ */
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int mipi_dsih_dphy_powerup(dphy_t *phy, int enable)
+{
+ /*
+ * Make sure that DSI IP is connected to TestChip IO
+ *
+ * get the PHY in power down mode (shutdownz = 0) and
+ * reset it (rstz = 0) to avoid transient periods in
+ * PHY operation during re-configuration procedures.
+ */
+ if (enable) {
+ mipi_dsih_dphy_clock_en(phy, true);
+ mipi_dsih_dphy_stop_wait_time(phy, 0x1C);
+ mipi_dsih_dphy_clock_en(phy, true);
+ mipi_dsih_dphy_shutdown(phy, false);
+ mipi_dsih_dphy_reset(phy, false);
+ } else {
+ mipi_dsih_dphy_reset(phy, true);
+ mipi_dsih_dphy_shutdown(phy, true);
+ mipi_dsih_dphy_clock_en(phy, false);
+ /* provide an initial active-high test clear pulse in TESTCLR */
+ /* DPHY registers will be reset after test clear is set to high */
+ mipi_dsih_dphy_test_clear(phy, 0);
+ mipi_dsih_dphy_test_clear(phy, 1);
+ mipi_dsih_dphy_test_clear(phy, 0);
+ }
+ return 0;
+}
+
+/**
+ * Configure D-PHY and PLL module to desired operation mode
+ * @param phy: pointer to structure
+ * which holds information about the d-phy module
+ * @param no_of_lanes active
+ * @param output_freq desired high speed frequency
+ * @return error code
+ */
+dsih_error_t mipi_dsih_dphy_configure(dphy_t *phy,
+ u8 lane_num,
+ u32 output_freq)
+{
+ if (!phy)
+ return ERR_DSI_INVALID_INSTANCE;
+ if (phy->status < INITIALIZED)
+ return ERR_DSI_INVALID_INSTANCE;
+ if (output_freq < MIN_OUTPUT_FREQ)
+ return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;
+
+ if (!mipi_dsih_if_dphy_keep_work(phy))
+ mipi_dsih_dphy_powerup(phy, false);
+
+ /* set up board depending on environment if any */
+ if (phy->bsp_pre_config)
+ phy->bsp_pre_config(phy, 0);
+
+ mipi_dsih_dphy_config_pll(phy, output_freq);
+ mipi_dsih_dphy_config_lane_timing(phy, output_freq, NONE);
+ mipi_dsih_dphy_no_of_lanes(phy, lane_num);
+
+ if (!mipi_dsih_if_dphy_keep_work(phy))
+ mipi_dsih_dphy_powerup(phy, true);
+
+ return 0;
+}
+
+/**
+ * Close and power down D-PHY module
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @return error code
+ */
+dsih_error_t mipi_dsih_dphy_close(dphy_t *phy)
+{
+ if (!phy)
+ return ERR_DSI_INVALID_INSTANCE;
+
+ if (!phy->core_read_function || !phy->core_write_function)
+ return ERR_DSI_INVALID_IO;
+
+ if (phy->status < INITIALIZED)
+ return ERR_DSI_INVALID_INSTANCE;
+
+ mipi_dsih_dphy_reset(phy, true);
+ mipi_dsih_dphy_shutdown(phy, true);
+ mipi_dsih_dphy_reset(phy, false);
+ phy->status = NOT_INITIALIZED;
+
+ return OK;
+}
+
+/**
+ * Enable clock lane module
+ * @param phy pointer to structure
+ * which holds information about the d-phy module
+ * @param en
+ */
+void mipi_dsih_dphy_clock_en(dphy_t *phy, int en)
+{
+ mipi_dsih_dphy_write_part(phy, R_DPHY_RSTZ, en, 2, 1);
+}
+
+/**
+ * SPRD ADD
+ * Set non-continuous clock mode
+ * @param phy pointer to structure
+ * which holds information about the d-phy module
+ * @param enable 1: enable non continuous clock
+ */
+void mipi_dsih_dphy_enable_nc_clk(dphy_t *phy, int enable)
+{
+ mipi_dsih_dphy_write_part(phy, R_DPHY_LPCLK_CTRL, enable, 1, 1);
+}
+
+/**
+ * Reset D-PHY module
+ * @param phy: pointer to structure
+ * which holds information about the d-phy module
+ * @param reset
+ */
+void mipi_dsih_dphy_reset(dphy_t *phy, int enable)
+{
+ mipi_dsih_dphy_write_part(phy, R_DPHY_RSTZ, !!!enable, 1, 1);
+}
+
+/**
+ * Power up/down D-PHY module
+ * @param phy: pointer to structure
+ * which holds information about the d-phy module
+ * @param enable (1: shutdown)
+ */
+void mipi_dsih_dphy_shutdown(dphy_t *phy, int enable)
+{
+ mipi_dsih_dphy_write_part(phy, R_DPHY_RSTZ, !!!enable, 0, 1);
+}
+
+/**
+ * Force D-PHY PLL to stay on while in ULPS
+ * @param phy: pointer to structure
+ * which holds information about the d-phy module
+ * @param force (1) disable (0)
+ * @note To follow the programming model, use wakeup_pll function
+ */
+void mipi_dsih_dphy_force_pll(dphy_t *phy, int force)
+{
+ u8 data;
+
+ if (force)
+ data = 0x03;
+ else
+ data = 0x0;
+
+ /* for megocores, to force pll, dphy register should be set */
+ mipi_dsih_dphy_write(phy, 0x0e, &data, 1);
+
+ mipi_dsih_dphy_write_part(phy, R_DPHY_RSTZ, force, 3, 1);
+}
+
+/**
+ * Get force D-PHY PLL module
+ * @param phy pointer to structure
+ * which holds information about the d-phy module
+ * @return force value
+ */
+int mipi_dsih_dphy_get_force_pll(dphy_t *phy)
+{
+ /* FIXME: TODO: for megacores, this status is not true */
+ return mipi_dsih_dphy_read_part(phy, R_DPHY_RSTZ, 3, 1);
+}
+
+/**
+ * Wake up or make sure D-PHY PLL module is awake
+ * This function must be called after going into ULPS and before exiting it
+ * to force the DPHY PLLs to wake up. It will wait until the DPHY status is
+ * locked. It follows the procedure described in the user guide.
+ * This function should be used to make sure the PLL is awake, rather than
+ * the force_pll above.
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @return error code
+ * @note this function has an active wait
+ */
+int mipi_dsih_dphy_wakeup_pll(dphy_t *phy)
+{
+ unsigned i = 0;
+
+ if (mipi_dsih_dphy_status(phy, 0x1))
+ return OK;
+
+ mipi_dsih_dphy_force_pll(phy, 1);
+
+ for (i = 0; i < DSIH_PHY_ACTIVE_WAIT; i++) {
+ if (mipi_dsih_dphy_status(phy, 0x1))
+ break;
+ }
+
+ if (mipi_dsih_dphy_status(phy, 0x1) == 0)
+ return ERR_DSI_PHY_PLL_NOT_LOCKED;
+
+ return OK;
+}
+
+/**
+ * Configure minimum wait period for HS transmission request after a stop state
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @param no_of_byte_cycles [in byte (lane) clock cycles]
+ */
+void mipi_dsih_dphy_stop_wait_time(dphy_t *phy,
+ u8 no_of_byte_cycles)
+{
+ mipi_dsih_dphy_write_part(phy,
+ R_DPHY_IF_CFG,
+ no_of_byte_cycles,
+ 8, 8);
+}
+
+/**
+ * Set number of active lanes
+ * @param phy: pointer to structure
+ * which holds information about the d-phy module
+ * @param no_of_lanes
+ */
+void mipi_dsih_dphy_no_of_lanes(dphy_t *phy, u8 no_of_lanes)
+{
+ /* currently, dphy only support 2 lanes */
+ if (no_of_lanes > MAX_LANES)
+ no_of_lanes = MAX_LANES;
+
+ mipi_dsih_dphy_write_part(phy, R_DPHY_IF_CFG,
+ no_of_lanes - 1, 0, 2);
+}
+
+/**
+ * Get number of currently active lanes
+ * @param phy: pointer to structure
+ * which holds information about the d-phy module
+ * @return number of active lanes
+ */
+u8 mipi_dsih_dphy_get_no_of_lanes(dphy_t *phy)
+{
+ return mipi_dsih_dphy_read_part(phy, R_DPHY_IF_CFG, 0, 2);
+}
+
+/**
+ * Request the PHY module to start transmission of high speed clock.
+ * This causes the clock lane to start transmitting DDR clock on the
+ * lane interconnect.
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @param enable
+ * @note this function should be called explicitly by user always except for
+ * transmitting
+ */
+void mipi_dsih_dphy_enable_hs_clk(dphy_t *phy, int enable)
+{
+ mipi_dsih_dphy_write_part(phy, R_DPHY_LPCLK_CTRL, enable, 0, 1);
+}
+
+/**
+ * One bit is asserted in the trigger_request (4bits) to cause the lane module
+ * to cause the associated trigger to be sent across the lane interconnect.
+ * The trigger request is synchronous with the rising edge of the clock.
+ * @note: Only one bit of the trigger_request is asserted at any given time, the
+ * remaining must be left set to 0, and only when not in LPDT or ULPS modes
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @param trigger_request 4 bit request
+ */
+dsih_error_t mipi_dsih_dphy_escape_mode_trigger(dphy_t *phy,
+ u8 trigger_request)
+{
+ u8 sum = 0;
+ int i = 0;
+ for (i = 0; i < 4; i++) {
+ sum += ((trigger_request >> i) & 1);
+ }
+
+ if (sum == 1) { /* clear old trigger */
+ mipi_dsih_dphy_write_part(phy, R_DPHY_TX_TRIGGERS,
+ 0x00, 0, 4);
+ mipi_dsih_dphy_write_part(phy, R_DPHY_TX_TRIGGERS,
+ trigger_request, 0, 4);
+
+ for (i = 0; i < DSIH_PHY_ACTIVE_WAIT; i++) {
+ if (mipi_dsih_dphy_status(phy, 0x0010)) {
+ break;
+ }
+ }
+ mipi_dsih_dphy_write_part(phy, R_DPHY_TX_TRIGGERS, 0x00, 0, 4);
+ if (i >= DSIH_PHY_ACTIVE_WAIT)
+ return ERR_DSI_TIMEOUT;
+
+ return OK;
+ }
+ return ERR_DSI_INVALID_COMMAND;
+}
+
+/**
+ * ULPS mode request/exit on all active data lanes.
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @param enable (request 1/ exit 0)
+ * @return error code
+ * @note this is a blocking function. wait upon exiting the ULPS will exceed 1ms
+ */
+dsih_error_t mipi_dsih_dphy_ulps_data_lanes(dphy_t *phy, int enable)
+{
+ int timeout;
+ /* mask 1 0101 0010 0000 */
+ u16 data_lanes_mask = 0;
+
+ if (enable) {
+ mipi_dsih_dphy_write_part(phy, R_DPHY_ULPS_CTRL, 1, 2, 1);
+ return OK;
+ } else {
+ if (!mipi_dsih_dphy_status(phy, 0x1))
+ return ERR_DSI_PHY_PLL_NOT_LOCKED;
+
+ mipi_dsih_dphy_write_part(phy, R_DPHY_ULPS_CTRL, 1, 3, 1);
+ switch (mipi_dsih_dphy_get_no_of_lanes(phy)) {
+ /* Fall through */
+ case 3:
+ data_lanes_mask |= (1 << 12);
+ /* Fall through */
+ case 2:
+ data_lanes_mask |= (1 << 10);
+ /* Fall through */
+ case 1:
+ data_lanes_mask |= (1 << 8);
+ /* Fall through */
+ case 0:
+ data_lanes_mask |= (1 << 5);
+ break;
+ default:
+ data_lanes_mask = 0;
+ break;
+ }
+ /* verify that the DPHY has left ULPM */
+ for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++) {
+ if (mipi_dsih_dphy_status(phy, data_lanes_mask)
+ == data_lanes_mask)
+ break;
+ /* wait at least 1ms */
+ for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)
+ ;
+ }
+
+ if (mipi_dsih_dphy_status(phy, data_lanes_mask)
+ != data_lanes_mask) {
+ phy->log_info("stat %x, mask %x",
+ mipi_dsih_dphy_status(phy, data_lanes_mask),
+ data_lanes_mask);
+ return ERR_DSI_TIMEOUT;
+ }
+ mipi_dsih_dphy_write_part(phy, R_DPHY_ULPS_CTRL, 0, 2, 1);
+ mipi_dsih_dphy_write_part(phy, R_DPHY_ULPS_CTRL, 0, 3, 1);
+ }
+ return OK;
+}
+
+/**
+ * ULPS mode request/exit on Clock Lane.
+ * @param phy pointer to structure which holds information about the
+ * d-phy module
+ * @param enable 1 or disable 0 of the Ultra Low Power State of the clock lane
+ * @return error code
+ * @note this is a blocking function. wait upon exiting the ULPS will exceed 1ms
+ */
+dsih_error_t mipi_dsih_dphy_ulps_clk_lane(dphy_t *phy, int enable)
+{
+ int timeout;
+ /* mask 1000 */
+ u16 clk_lane_mask = 0x0008;
+ if (enable)
+ mipi_dsih_dphy_write_part(phy, R_DPHY_ULPS_CTRL, 1, 0, 1);
+ else {
+ if (!mipi_dsih_dphy_status(phy, 0x1))
+ return ERR_DSI_PHY_PLL_NOT_LOCKED;
+
+ mipi_dsih_dphy_write_part(phy, R_DPHY_ULPS_CTRL, 1, 1, 1);
+ /* verify that the DPHY has left ULPM */
+ for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++) {
+ if (mipi_dsih_dphy_status(phy, clk_lane_mask)
+ == clk_lane_mask) {
+ phy->log_info("stat %x, mask %x",
+ mipi_dsih_dphy_status(phy, clk_lane_mask),
+ clk_lane_mask);
+ break;
+ }
+ /* wait at least 1ms */
+ /* dummy operation for the loop not to be optimised */
+ for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)
+ enable = mipi_dsih_dphy_status(phy, clk_lane_mask);
+ }
+ if (mipi_dsih_dphy_status(phy, clk_lane_mask) != clk_lane_mask)
+ return ERR_DSI_TIMEOUT;
+
+ mipi_dsih_dphy_write_part(phy, R_DPHY_ULPS_CTRL, 0, 0, 1);
+ mipi_dsih_dphy_write_part(phy, R_DPHY_ULPS_CTRL, 0, 1, 1);
+ }
+ return OK;
+}
+
+/**
+ * Get D-PHY PPI status
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @param mask
+ * @return status
+ */
+u32 mipi_dsih_dphy_status(dphy_t *phy, u16 mask)
+{
+ return mipi_dsih_dphy_read_word(phy, R_DPHY_STATUS) & mask;
+}
+
+/**
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @param value
+ */
+void mipi_dsih_dphy_test_clock(dphy_t *phy, int value)
+{
+ mipi_dsih_dphy_write_part(phy, R_DPHY_TST_CRTL0, value, 1, 1);
+}
+
+/**
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @param value
+ */
+void mipi_dsih_dphy_test_clear(dphy_t *phy, int value)
+{
+ mipi_dsih_dphy_write_part(phy, R_DPHY_TST_CRTL0, value, 0, 1);
+}
+
+/**
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @param on_falling_edge
+ */
+void mipi_dsih_dphy_test_en(dphy_t *phy, u8 on_falling_edge)
+{
+ mipi_dsih_dphy_write_part(phy, R_DPHY_TST_CRTL1,
+ on_falling_edge, 16, 1);
+}
+
+/**
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ */
+u8 mipi_dsih_dphy_test_data_out(dphy_t *phy)
+{
+ return mipi_dsih_dphy_read_part(phy, R_DPHY_TST_CRTL1, 8, 8);
+}
+
+/**
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @param test_data
+ */
+void mipi_dsih_dphy_test_data_in(dphy_t *phy, u8 test_data)
+{
+ mipi_dsih_dphy_write_word(phy, R_DPHY_TST_CRTL1, test_data);
+}
+
+/**
+ * Write to D-PHY module (encapsulating the digital interface)
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @param address offset inside the D-PHY digital interface
+ * @param data array of bytes to be written to D-PHY
+ * @param data_length of the data array
+ */
+void mipi_dsih_dphy_write(dphy_t *phy, u8 address,
+ u8 *data, u8 data_length)
+{
+ int i = 0;
+
+ if (data) {
+ /*
+ * set the TESTCLK input high in preparation
+ * to latch in the desired test mode
+ */
+ mipi_dsih_dphy_test_clock(phy, 1);
+ /* set the desired test code in the input 8-bit bus TESTDIN[7:0] */
+ mipi_dsih_dphy_test_data_in(phy, address);
+ /* set TESTEN input high */
+ mipi_dsih_dphy_test_en(phy, 1);
+ /*
+ * drive the TESTCLK input low;
+ * the falling edge captures the chosen test code
+ * into the transceiver
+ */
+ mipi_dsih_dphy_test_clock(phy, 0);
+ /*
+ * set TESTEN input low
+ * to disable further test mode code latching
+ */
+ mipi_dsih_dphy_test_en(phy, 0);
+
+ /*
+ * start writing MSB first
+ * set TESTDIN[7:0] to the desired test data appropriate
+ * to the chosen test mode
+ */
+ for (i = data_length; i > 0; i--) {
+ mipi_dsih_dphy_test_data_in(phy, data[i - 1]);
+ /*
+ * pulse TESTCLK high to capture this test data
+ * into the macrocell; repeat these two steps as necessary
+ */
+ mipi_dsih_dphy_test_clock(phy, 1);
+ mipi_dsih_dphy_test_clock(phy, 0);
+ }
+ }
+}
+
+/**
+ * Write to whole register to D-PHY module (encapsulating the bus interface)
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @param reg_address offset
+ * @param data 32-bit word
+ */
+void mipi_dsih_dphy_write_word(dphy_t *phy,
+ u32 reg_address, u32 data)
+{
+ if (phy->core_write_function)
+ phy->core_write_function(phy->address,
+ reg_address, data);
+}
+
+/**
+ * Write bit field to D-PHY module (encapsulating the bus interface)
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @param reg_address offset
+ * @param data bits to be written to D-PHY
+ * @param shift from the right hand side of the register (big endian)
+ * @param width of the bit field
+ */
+void mipi_dsih_dphy_write_part(dphy_t *phy,
+ u32 reg_address, u32 data,
+ u8 shift, u8 width)
+{
+ u32 mask = 0;
+ u32 temp = 0;
+
+ if (phy->core_read_function) {
+ mask = (1 << width) - 1;
+ temp = mipi_dsih_dphy_read_word(phy, reg_address);
+ temp &= ~(mask << shift);
+ temp |= (data & mask) << shift;
+ mipi_dsih_dphy_write_word(phy, reg_address, temp);
+ }
+}
+
+/**
+ * Read whole register from D-PHY module (encapsulating the bus interface)
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @param reg_address offset
+ * @return data 32-bit word
+ */
+u32 mipi_dsih_dphy_read_word(dphy_t *phy, u32 reg_address)
+{
+ if (!phy->core_read_function)
+ return ERR_DSI_INVALID_IO;
+
+ return phy->core_read_function(phy->address, reg_address);
+}
+
+/**
+ * Read bit field from D-PHY module (encapsulating the bus interface)
+ * @param phy pointer to structure which holds information about the d-phy
+ * module
+ * @param reg_address offset
+ * @param shift from the right hand side of the register (big endian)
+ * @param width of the bit field
+ * @return data bits to be written to D-PHY
+ */
+u32 mipi_dsih_dphy_read_part(dphy_t *phy,
+ u32 reg_address,
+ u8 shift,
+ u8 width)
+{
+ return (mipi_dsih_dphy_read_word(phy, reg_address) >> shift)
+ & ((1 << width) - 1);
+}
diff --git a/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_hal.c b/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_hal.c
new file mode 100644
index 00000000..d20693f5
--- /dev/null
+++ b/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_hal.c
@@ -0,0 +1,1114 @@
+/**
+ * @file mipi_dsih_hal.c
+ * @brief Hardware Abstraction Level of DWC MIPI DSI HOST controller
+ *
+ * Synopsys Inc.
+ * SG DWC PT02
+ */
+#include "mipi_dsih_hal.h"
+
+/**
+ * Write a 32-bit word to the DSI Host core
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param reg_address register offset in core
+ * @param data 32-bit word to be written to register
+ */
+void mipi_dsih_write_word(dsih_ctrl_t * instance, uint32_t reg_address, uint32_t data)
+{
+
+ instance->core_write_function(instance->address, reg_address, data);
+}
+/**
+ * Write a bit field o a 32-bit word to the DSI Host core
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param reg_address register offset in core
+ * @param data to be written to register
+ * @param shift bit shift from the left (system is BIG ENDIAN)
+ * @param width of bit field
+ */
+void mipi_dsih_write_part(dsih_ctrl_t * instance, uint32_t reg_address, uint32_t data, uint8_t shift, uint8_t width)
+{
+ uint32_t mask = (1 << width) - 1;
+ uint32_t temp = mipi_dsih_read_word(instance, reg_address);
+
+ temp &= ~(mask << shift);
+ temp |= (data & mask) << shift;
+ mipi_dsih_write_word(instance, reg_address, temp);
+}
+/**
+ * Write a 32-bit word to the DSI Host core
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param reg_address offset of register
+ * @return 32-bit word value stored in register
+ */
+uint32_t mipi_dsih_read_word(dsih_ctrl_t * instance, uint32_t reg_address)
+{
+ return instance->core_read_function(instance->address, reg_address);
+}
+/**
+ * Write a 32-bit word to the DSI Host core
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param reg_address offset of register in core
+ * @param shift bit shift from the left (system is BIG ENDIAN)
+ * @param width of bit field
+ * @return bit field read from register
+ */
+uint32_t mipi_dsih_read_part(dsih_ctrl_t * instance, uint32_t reg_address, uint8_t shift, uint8_t width)
+{
+ return (mipi_dsih_read_word(instance, reg_address) >> shift) & ((1 << width) - 1);
+}
+/**
+ * Get DSI Host core version
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return ascii number of the version
+ */
+uint32_t mipi_dsih_hal_get_version(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_word(instance, R_DSI_HOST_VERSION);
+}
+/**
+ * Modify power status of DSI Host core
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param on (1) or off (0)
+ */
+void mipi_dsih_hal_power(dsih_ctrl_t * instance, int on)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_PWR_UP, on, 0, 1);
+}
+/**
+ * Get the power status of the DSI Host core
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return power status
+ */
+int mipi_dsih_hal_get_power(dsih_ctrl_t * instance)
+{
+ return (int)(mipi_dsih_read_part(instance, R_DSI_HOST_PWR_UP, 0, 1));
+}
+/**
+ * Write transmission escape timeout
+ * a safe guard so that the state machine would reset if transmission
+ * takes too long
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param tx_escape_division
+ */
+void mipi_dsih_hal_tx_escape_division(dsih_ctrl_t * instance, uint8_t tx_escape_division)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_CLK_MGR, tx_escape_division, 0, 8);
+}
+/**
+ * Write the DPI video virtual channel destination
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param vc virtual channel
+ */
+void mipi_dsih_hal_dpi_video_vc(dsih_ctrl_t * instance, uint8_t vc)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_DPI_VCID, (uint32_t)(vc), 0, 2);
+}
+/**
+ * Get the DPI video virtual channel destination
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return virtual channel
+ */
+uint8_t mipi_dsih_hal_dpi_get_video_vc(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_DPI_VCID, 0, 2);
+}
+/**
+ * Set DPI video color coding
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param color_coding enum (configuration and color depth)
+ * @return error code
+ */
+dsih_error_t mipi_dsih_hal_dpi_color_coding(dsih_ctrl_t * instance, dsih_color_coding_t color_coding)
+{
+ dsih_error_t err = OK;
+ if (color_coding > COLOR_CODE_MAX)
+ {
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: invalid colour configuration");
+ }
+ err = ERR_DSI_COLOR_CODING;
+ }
+ else
+ {
+ mipi_dsih_write_part(instance, R_DSI_HOST_DPI_COLOR_CODE, color_coding, 0, 4);
+ }
+ return err;
+}
+/**
+ * Get DPI video color coding
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return color coding enum (configuration and color depth)
+ */
+dsih_color_coding_t mipi_dsih_hal_dpi_get_color_coding(dsih_ctrl_t * instance)
+{
+ return (dsih_color_coding_t)(mipi_dsih_read_part(instance, R_DSI_HOST_DPI_COLOR_CODE, 0, 4));
+}
+/**
+ * Get DPI video color depth
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return number of bits per pixel
+ */
+uint8_t mipi_dsih_hal_dpi_get_color_depth(dsih_ctrl_t * instance)
+{
+ uint8_t color_depth = 0;
+ switch (mipi_dsih_read_part(instance, R_DSI_HOST_DPI_COLOR_CODE, 0, 4))
+ {
+ case 0:
+ case 1:
+ case 2:
+ color_depth = 16;
+ break;
+ case 3:
+ case 4:
+ color_depth = 18;
+ break;
+ case 5:
+ color_depth = 24;
+ break;
+ case 6:
+ color_depth = 20;
+ break;
+ case 7:
+ color_depth = 24;
+ break;
+ case 8:
+ color_depth = 16;
+ break;
+ case 9:
+ color_depth = 30;
+ break;
+ case 10:
+ color_depth = 36;
+ break;
+ case 11:
+ color_depth = 12;
+ break;
+ default:
+ break;
+ }
+ return color_depth;
+}
+/**
+ * Get DPI video pixel configuration
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return pixel configuration
+ */
+uint8_t mipi_dsih_hal_dpi_get_color_config(dsih_ctrl_t * instance)
+{
+ uint8_t color_config = 0;
+ switch (mipi_dsih_read_part(instance, R_DSI_HOST_DPI_COLOR_CODE, 0, 4))
+ {
+ case 0:
+ color_config = 1;
+ break;
+ case 1:
+ color_config = 2;
+ break;
+ case 2:
+ color_config = 3;
+ break;
+ case 3:
+ color_config = 1;
+ break;
+ case 4:
+ color_config = 2;
+ break;
+ default:
+ color_config = 0;
+ break;
+ }
+ return color_config;
+}
+/**
+ * Set DPI loosely packetisation video (used only when color depth = 18
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable
+ */
+void mipi_dsih_hal_dpi_18_loosely_packet_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_DPI_COLOR_CODE, enable, 8, 1);
+}
+/**
+ * Set DPI color mode pin polarity
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param active_low (1) or active high (0)
+ */
+void mipi_dsih_hal_dpi_color_mode_pol(dsih_ctrl_t * instance, int active_low)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG_POL, active_low, 4, 1);
+}
+/**
+ * Set DPI shut down pin polarity
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param active_low (1) or active high (0)
+ */
+void mipi_dsih_hal_dpi_shut_down_pol(dsih_ctrl_t * instance, int active_low)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG_POL, active_low, 3, 1);
+}
+/**
+ * Set DPI horizontal sync pin polarity
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param active_low (1) or active high (0)
+ */
+void mipi_dsih_hal_dpi_hsync_pol(dsih_ctrl_t * instance, int active_low)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG_POL, active_low, 2, 1);
+}
+/**
+ * Set DPI vertical sync pin polarity
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param active_low (1) or active high (0)
+ */
+void mipi_dsih_hal_dpi_vsync_pol(dsih_ctrl_t * instance, int active_low)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG_POL, active_low, 1, 1);
+}
+/**
+ * Set DPI data enable pin polarity
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param active_low (1) or active high (0)
+ */
+void mipi_dsih_hal_dpi_dataen_pol(dsih_ctrl_t * instance, int active_low)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG_POL, active_low, 0, 1);
+}
+/**
+ * Enable FRAME BTA ACK
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable (1) - disable (0)
+ */
+void mipi_dsih_hal_dpi_frame_ack_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 14, 1);
+}
+/**
+ * Enable null packets (value in null packet size will be taken in calculations)
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable (1) - disable (0)
+ * @note function retained for backward compatibility (not used from 1.20a on)
+ */
+void mipi_dsih_hal_dpi_null_packet_en(dsih_ctrl_t * instance, int enable)
+{
+}
+/**
+ * Enable multi packets (value in no of chunks will be taken in calculations)
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable (1) - disable (0)
+ */
+void mipi_dsih_hal_dpi_multi_packet_en(dsih_ctrl_t * instance, int enable)
+{
+}
+/**
+ * Enable return to low power mode inside horizontal front porch periods when
+ * timing allows
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable (1) - disable (0)
+ */
+void mipi_dsih_hal_dpi_lp_during_hfp(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 13, 1);
+}
+/**
+ * Enable return to low power mode inside horizontal back porch periods when
+ * timing allows
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable (1) - disable (0)
+ */
+void mipi_dsih_hal_dpi_lp_during_hbp(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 12, 1);
+}
+/**
+ * Enable return to low power mode inside vertical active lines periods when
+ * timing allows
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable (1) - disable (0)
+ */
+void mipi_dsih_hal_dpi_lp_during_vactive(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 11, 1);
+}
+/**
+ * Enable return to low power mode inside vertical front porch periods when
+ * timing allows
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable (1) - disable (0)
+ */
+void mipi_dsih_hal_dpi_lp_during_vfp(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 10, 1);
+}
+/**
+ * Enable return to low power mode inside vertical back porch periods when
+ * timing allows
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable (1) - disable (0)
+ */
+void mipi_dsih_hal_dpi_lp_during_vbp(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 9, 1);
+}
+/**
+ * Enable return to low power mode inside vertical sync periods when
+ * timing allows
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable (1) - disable (0)
+ */
+void mipi_dsih_hal_dpi_lp_during_vsync(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 8, 1);
+}
+/**
+ * Set DPI video mode type (burst/non-burst - with sync pulses or events)
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param type
+ * @return error code
+ */
+dsih_error_t mipi_dsih_hal_dpi_video_mode_type(dsih_ctrl_t * instance, dsih_video_mode_t type)
+{
+ if (type < 3)
+ {
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, type, 0, 2);
+ return OK;
+ }
+ else
+ {
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: undefined type");
+ }
+ return ERR_DSI_OUT_OF_BOUND;
+ }
+}
+/**
+ * Enable/disable DPI video mode
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable (1) - disable (0)
+ */
+void mipi_dsih_hal_dpi_video_mode_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_MODE_CFG, enable? 0: 1, 0, 1);
+}
+/**
+ * Get the status of video mode, whether enabled or not in core
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return status
+ */
+int mipi_dsih_hal_dpi_is_video_mode(dsih_ctrl_t * instance)
+{
+ return (mipi_dsih_read_part(instance, R_DSI_HOST_MODE_CFG, 0, 1) == 0);
+}
+/**
+ * Write the null packet size - will only be taken into account when null
+ * packets are enabled.
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param size of null packet
+ * @return error code
+ */
+dsih_error_t mipi_dsih_hal_dpi_null_packet_size(dsih_ctrl_t * instance, uint16_t size)
+{
+ if (size < (1 << 13)) /* 13-bit field */
+ {
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_NULL_SIZE, size, 0, 13);
+ return OK;
+ }
+ else
+ {
+ return ERR_DSI_OUT_OF_BOUND;
+ }
+}
+/**
+ * Write no of chunks to core - taken into consideration only when multi packet
+ * is enabled
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no of chunks
+ */
+dsih_error_t mipi_dsih_hal_dpi_chunks_no(dsih_ctrl_t * instance, uint16_t no)
+{
+ if (no < (1 << 13))
+ {
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_NUM_CHUNKS, no, 0, 13);
+ return OK;
+ }
+ else
+ {
+ return ERR_DSI_OUT_OF_BOUND;
+ }
+}
+/**
+ * Write video packet size. obligatory for sending video
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param size of video packet - containing information
+ * @return error code
+ */
+dsih_error_t mipi_dsih_hal_dpi_video_packet_size(dsih_ctrl_t * instance, uint16_t size)
+{
+ if (size < (1 << 14)) /* 14-bit field */
+ {
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_PKT_SIZE, size, 0, 14);
+ return OK;
+ }
+ else
+ {
+ return ERR_DSI_OUT_OF_BOUND;
+ }
+}
+/**
+ * function retained for backward compatibility (not used from 1.20a on)
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable (1) - disable (0)
+ */
+void mipi_dsih_hal_edpi_enable(dsih_ctrl_t * instance, int enable)
+{
+}
+/**
+ * Specifiy the size of the packet memory write start/continue
+ * @param instance pointer to structure holding the DSI Host core information
+ * @ size of the packet
+ * @note when different than zero (0) eDPI is enabled
+ */
+void mipi_dsih_hal_edpi_max_allowed_size(dsih_ctrl_t * instance, uint16_t size)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_EDPI_CMD_SIZE, size, 0, 16);
+}
+/**
+ * Enable tear effect acknowledge
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable (1) - disable (0)
+ */
+void mipi_dsih_hal_tear_effect_ack_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, enable, 0, 1);
+}
+/**
+ * Enable packets acknowledge request after each packet transmission
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable (1) - disable (0)
+ */
+void mipi_dsih_hal_cmd_ack_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, enable, 1, 1);
+}
+/**
+ * Set DCS command packet transmission to transmission type
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_param of command
+ * @param lp transmit in low power
+ * @return error code
+ */
+dsih_error_t mipi_dsih_hal_dcs_wr_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp)
+{
+ switch (no_of_param)
+ {
+ case 0:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 16, 1);
+ break;
+ case 1:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 17, 1);
+ break;
+ default:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 19, 1);
+ break;
+ }
+ return OK;
+}
+/**
+ * Set DCS read command packet transmission to transmission type
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_param of command
+ * @param lp transmit in low power
+ * @return error code
+ */
+dsih_error_t mipi_dsih_hal_dcs_rd_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp)
+{
+ dsih_error_t err = OK;
+ switch (no_of_param)
+ {
+ case 0:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 18, 1);
+ break;
+ default:
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: undefined DCS Read packet type");
+ }
+ err = ERR_DSI_OUT_OF_BOUND;
+ break;
+ }
+ return err;
+}
+
+/*Jessica add begin: to support max read packet size command */
+dsih_error_t mipi_dsih_hal_max_rd_packet_size_type(dsih_ctrl_t * instance, int lp)
+{
+ dsih_error_t err = OK;
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 10, 1);
+ return err;
+}
+/*Jessica add end*/
+
+/**
+ * Set generic write command packet transmission to transmission type
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_param of command
+ * @param lp transmit in low power
+ * @return error code
+ */
+dsih_error_t mipi_dsih_hal_gen_wr_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp)
+{
+ switch (no_of_param)
+ {
+ case 0:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 8, 1);
+ break;
+ case 1:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 9, 1);
+ break;
+ case 2:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 10, 1);
+ break;
+ default:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 14, 1);
+ break;
+ }
+ return OK;
+}
+/**
+ * Set generic command packet transmission to transmission type
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_param of command
+ * @param lp transmit in low power
+ * @return error code
+ */
+dsih_error_t mipi_dsih_hal_gen_rd_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp)
+{
+ dsih_error_t err = OK;
+ switch (no_of_param)
+ {
+ case 0:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 11, 1);
+ break;
+ case 1:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 12, 1);
+ break;
+ case 2:
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 13, 1);
+ break;
+ default:
+ if (instance->log_error != 0)
+ {
+ instance->log_error("sprdfb: undefined Generic Read packet type");
+ }
+ err = ERR_DSI_OUT_OF_BOUND;
+ break;
+ }
+ return err;
+}
+/**
+ * Configure maximum read packet size command transmission type
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param lp set to low power
+ */
+void mipi_dsih_hal_max_rd_size_tx_type(dsih_ctrl_t * instance, int lp)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 24, 1);
+}
+/**
+ * Enable command mode (Generic interface)
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable
+ */
+void mipi_dsih_hal_gen_cmd_mode_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_MODE_CFG, enable? 1: 0, 0, 1);
+}
+/**
+ * Retrieve the controller's status of whether command mode is ON or not
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return whether command mode is ON
+ */
+int mipi_dsih_hal_gen_is_cmd_mode(dsih_ctrl_t * instance)
+{
+ return (mipi_dsih_read_part(instance, R_DSI_HOST_MODE_CFG, 0, 1) == 1);
+}
+/**
+ * Configure the Horizontal Line time
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param time taken to transmit the total of the horizontal line
+ */
+void mipi_dsih_hal_dpi_hline(dsih_ctrl_t * instance, uint16_t time)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_HLINE_TIME, time, 0, 15);
+}
+/**
+ * Configure the Horizontal back porch time
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param time taken to transmit the horizontal back porch
+ */
+void mipi_dsih_hal_dpi_hbp(dsih_ctrl_t * instance, uint16_t time)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_HBP_TIME, time, 0, 12);
+}
+/**
+ * Configure the Horizontal sync time
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param time taken to transmit the horizontal sync
+ */
+void mipi_dsih_hal_dpi_hsa(dsih_ctrl_t * instance, uint16_t time)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_HSA_TIME, time, 0, 12);
+}
+/**
+ * Configure the vertical active lines of the video stream
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param lines
+ */
+void mipi_dsih_hal_dpi_vactive(dsih_ctrl_t * instance, uint16_t lines)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_VACTIVE_LINES, lines, 0, 14);
+}
+/**
+ * Configure the vertical front porch lines of the video stream
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param lines
+ */
+void mipi_dsih_hal_dpi_vfp(dsih_ctrl_t * instance, uint16_t lines)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_VFP_LINES, lines, 0, 10);
+}
+/**
+ * Configure the vertical back porch lines of the video stream
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param lines
+ */
+void mipi_dsih_hal_dpi_vbp(dsih_ctrl_t * instance, uint16_t lines)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_VBP_LINES, lines, 0, 10);
+}
+/**
+ * Configure the vertical sync lines of the video stream
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param lines
+ */
+void mipi_dsih_hal_dpi_vsync(dsih_ctrl_t * instance, uint16_t lines)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_VID_VSA_LINES, lines, 0, 10);
+}
+/**
+ * configure timeout divisions (so they would have more clock ticks)
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param byte_clk_division_factor no of hs cycles before transiting back to LP in
+ * (lane_clk / byte_clk_division_factor)
+ */
+void mipi_dsih_hal_timeout_clock_division(dsih_ctrl_t * instance, uint8_t byte_clk_division_factor)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_CLK_MGR, byte_clk_division_factor, 8, 8);
+}
+/**
+ * Configure the Low power receive time out
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param count (of byte cycles)
+ */
+void mipi_dsih_hal_lp_rx_timeout(dsih_ctrl_t * instance, uint16_t count)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_TO_CNT_CFG, count, 0, 16);
+}
+/**
+ * Configure a high speed transmission time out7
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param count (byte cycles)
+ */
+void mipi_dsih_hal_hs_tx_timeout(dsih_ctrl_t * instance, uint16_t count)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_TO_CNT_CFG, count, 16, 16);
+}
+/**
+ * Get the error 0 interrupt register status
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param mask the mask to be read from the register
+ * @return error status 0 value
+ */
+uint32_t mipi_dsih_hal_int_status_0(dsih_ctrl_t * instance, uint32_t mask)
+{
+ return (mipi_dsih_read_word(instance, R_DSI_HOST_INT_ST0) & mask);
+}
+/**
+ * Get the error 1 interrupt register status
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param mask the mask to be read from the register
+ * @return error status 1 value
+ */
+uint32_t mipi_dsih_hal_int_status_1(dsih_ctrl_t * instance, uint32_t mask)
+{
+ return (mipi_dsih_read_word(instance, R_DSI_HOST_INT_ST1) & mask);
+}
+/**
+ * Configure MASK (hiding) of interrupts coming from error 0 source
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param mask to be written to the register
+ */
+void mipi_dsih_hal_int_mask_0(dsih_ctrl_t * instance, uint32_t mask)
+{
+ mipi_dsih_write_word(instance, R_DSI_HOST_INT_MSK0, mask);
+}
+/**
+ * Get the ERROR MASK 0 register status
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param mask the bits to read from the mask register
+ */
+uint32_t mipi_dsih_hal_int_get_mask_0(dsih_ctrl_t * instance, uint32_t mask)
+{
+ return (mipi_dsih_read_word(instance, R_DSI_HOST_INT_MSK0) & mask);
+}
+/**
+ * Configure MASK (hiding) of interrupts coming from error 0 source
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param mask the mask to be written to the register
+ */
+void mipi_dsih_hal_int_mask_1(dsih_ctrl_t * instance, uint32_t mask)
+{
+ mipi_dsih_write_word(instance, R_DSI_HOST_INT_MSK1, mask);
+}
+/**
+ * Get the ERROR MASK 1 register status
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param mask the bits to read from the mask register
+ */
+uint32_t mipi_dsih_hal_int_get_mask_1(dsih_ctrl_t * instance, uint32_t mask)
+{
+ return (mipi_dsih_read_word(instance, R_DSI_HOST_INT_MSK1) & mask);
+}
+/* DBI NOT IMPLEMENTED */
+void mipi_dsih_hal_dbi_out_color_coding(dsih_ctrl_t * instance, uint8_t color_depth, uint8_t option);
+void mipi_dsih_hal_dbi_in_color_coding(dsih_ctrl_t * instance, uint8_t color_depth, uint8_t option);
+void mipi_dsih_hal_dbi_lut_size(dsih_ctrl_t * instance, uint8_t size);
+void mipi_dsih_hal_dbi_partitioning_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dbi_dcs_vc(dsih_ctrl_t * instance, uint8_t vc);
+void mipi_dsih_hal_dbi_max_cmd_size(dsih_ctrl_t * instance, uint16_t size);
+void mipi_dsih_hal_dbi_cmd_size(dsih_ctrl_t * instance, uint16_t size);
+void mipi_dsih_hal_dbi_max_cmd_size(dsih_ctrl_t * instance, uint16_t size);
+int mipi_dsih_hal_dbi_rd_cmd_busy(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_read_fifo_full(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_read_fifo_empty(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_write_fifo_full(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_write_fifo_empty(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_cmd_fifo_full(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_cmd_fifo_empty(dsih_ctrl_t * instance);
+
+/**
+ * Write command header in the generic interface
+ * (which also sends DCS commands) as a subset
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param vc of destination
+ * @param packet_type (or type of DCS command)
+ * @param ls_byte (if DCS, it is the DCS command)
+ * @param ms_byte (only parameter of short DCS packet)
+ * @return error code
+ */
+dsih_error_t mipi_dsih_hal_gen_packet_header(dsih_ctrl_t * instance, uint8_t vc, uint8_t packet_type, uint8_t ms_byte, uint8_t ls_byte)
+{
+ if (vc < 4)
+ {
+ mipi_dsih_write_part(instance, R_DSI_HOST_GEN_HDR, (ms_byte << 16) | (ls_byte << 8 ) | ((vc << 6) | packet_type), 0, 24);
+ return OK;
+ }
+ return ERR_DSI_OVERFLOW;
+}
+/**
+ * Write the payload of the long packet commands
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param payload array of bytes of payload
+ * @return error code
+ */
+dsih_error_t mipi_dsih_hal_gen_packet_payload(dsih_ctrl_t * instance, uint32_t payload)
+{
+ if (mipi_dsih_hal_gen_write_fifo_full(instance))
+ {
+ return ERR_DSI_OVERFLOW;
+ }
+ mipi_dsih_write_word(instance, R_DSI_HOST_GEN_PLD_DATA, payload);
+ return OK;
+
+}
+/**
+ * Write the payload of the long packet commands
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param payload pointer to 32-bit array to hold read information
+ * @return error code
+ */
+dsih_error_t mipi_dsih_hal_gen_read_payload(dsih_ctrl_t * instance, uint32_t* payload)
+{
+ *payload = mipi_dsih_read_word(instance, R_DSI_HOST_GEN_PLD_DATA);
+ return OK;
+}
+
+/**
+ * Configure the read back virtual channel for the generic interface
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param vc to listen to on the line
+ */
+void mipi_dsih_hal_gen_rd_vc(dsih_ctrl_t * instance, uint8_t vc)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_GEN_VCID, vc, 0, 2);
+}
+/**
+ * Enable EOTp reception
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable
+ */
+void mipi_dsih_hal_gen_eotp_rx_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_PCKHDL_CFG, enable, 1, 1);
+}
+/**
+ * Enable EOTp transmission
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable
+ */
+void mipi_dsih_hal_gen_eotp_tx_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_PCKHDL_CFG, enable, 0, 1);
+}
+/**
+ * Enable Bus Turn-around request
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable
+ */
+void mipi_dsih_hal_bta_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_PCKHDL_CFG, enable, 2, 1);
+}
+/**
+ * Enable ECC reception, error correction and reporting
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable
+ */
+void mipi_dsih_hal_gen_ecc_rx_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_PCKHDL_CFG, enable, 3, 1);
+}
+/**
+ * Enable CRC reception, error reporting
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable
+ */
+void mipi_dsih_hal_gen_crc_rx_en(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_PCKHDL_CFG, enable, 4, 1);
+}
+/**
+ * Get status of read command
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return 1 if busy
+ */
+int mipi_dsih_hal_gen_rd_cmd_busy(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 6, 1);
+}
+/**
+ * Get the FULL status of generic read payload fifo
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return 1 if fifo full
+ */
+int mipi_dsih_hal_gen_read_fifo_full(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 5, 1);
+}
+/**
+ * Get the EMPTY status of generic read payload fifo
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return 1 if fifo empty
+ */
+int mipi_dsih_hal_gen_read_fifo_empty(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 4, 1);
+}
+/**
+ * Get the FULL status of generic write payload fifo
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return 1 if fifo full
+ */
+int mipi_dsih_hal_gen_write_fifo_full(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 3, 1);
+}
+/**
+ * Get the EMPTY status of generic write payload fifo
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return 1 if fifo empty
+ */
+int mipi_dsih_hal_gen_write_fifo_empty(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 2, 1);
+}
+/**
+ * Get the FULL status of generic command fifo
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return 1 if fifo full
+ */
+int mipi_dsih_hal_gen_cmd_fifo_full(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 1, 1);
+}
+/**
+ * Get the EMPTY status of generic command fifo
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return 1 if fifo empty
+ */
+int mipi_dsih_hal_gen_cmd_fifo_empty(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 0, 1);
+}
+/* only if DPI */
+/**
+ * Configure how many cycles of byte clock would the PHY module take
+ * to switch data lane from high speed to low power
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_byte_cycles
+ * @return error code
+ */
+dsih_error_t mipi_dsih_phy_hs2lp_config(dsih_ctrl_t * instance, uint8_t no_of_byte_cycles)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 24, 8);
+ return OK;
+}
+/**
+ * Configure how many cycles of byte clock would the PHY module take
+ * to switch the data lane from to low power high speed
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_byte_cycles
+ * @return error code
+ */
+dsih_error_t mipi_dsih_phy_lp2hs_config(dsih_ctrl_t * instance, uint8_t no_of_byte_cycles)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 16, 8);
+ return OK;
+}
+/**
+ * Configure how many cycles of byte clock would the PHY module take
+ * to switch clock lane from high speed to low power
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_byte_cycles
+ * @return error code
+ */
+dsih_error_t mipi_dsih_phy_clk_hs2lp_config(dsih_ctrl_t * instance, uint8_t no_of_byte_cycles)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_PHY_TMR_LPCLK_CFG, no_of_byte_cycles, 16, 10);
+ return OK;
+}
+/**
+ * Configure how many cycles of byte clock would the PHY module take
+ * to switch clock lane from to low power high speed
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_byte_cycles
+ * @return error code
+ */
+dsih_error_t mipi_dsih_phy_clk_lp2hs_config(dsih_ctrl_t * instance, uint8_t no_of_byte_cycles)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_PHY_TMR_LPCLK_CFG, no_of_byte_cycles, 0, 10);
+ return OK;
+}
+/**
+ * Configure how many cycles of byte clock would the PHY module take
+ * to turn the bus around to start receiving
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_byte_cycles
+ * @return error code
+ */
+dsih_error_t mipi_dsih_phy_bta_time(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles)
+{
+ /*Jessica modified: From ASIC, the second table in spec is correct, this 15 bits are max rd time*/
+ if (no_of_byte_cycles < 0x8000) /* 15-bit field */
+ {
+ //mipi_dsih_write_part(instance, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 0, 12);
+ mipi_dsih_write_part(instance, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 0, 15);
+ }
+ else
+ {
+ return ERR_DSI_OVERFLOW;
+ }
+ return OK;
+}
+/**
+ * Enable the automatic mechanism to stop providing clock in the clock
+ * lane when time allows
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param enable
+ * @return error code
+ */
+void mipi_dsih_non_continuous_clock(dsih_ctrl_t * instance, int enable)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_LPCLK_CTRL, enable, 1, 1);
+}
+/**
+ * Get the status of the automatic mechanism to stop providing clock in the
+ * clock lane when time allows
+ * @param instance pointer to structure holding the DSI Host core information
+ * @return status 1 (enabled) 0 (disabled)
+ */
+int mipi_dsih_non_continuous_clock_status(dsih_ctrl_t * instance)
+{
+ return mipi_dsih_read_part(instance, R_DSI_HOST_LPCLK_CTRL, 1, 1);
+}
+/* PRESP Time outs */
+/**
+ * Timeout for peripheral (for controller to stay still) after LP data
+ * transmission write requests
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_byte_cycles period for which the DWC_mipi_dsi_host keeps the
+ * link still, after sending a low power write operation. This period is
+ * measured in cycles of lanebyteclk
+ */
+void mipi_dsih_hal_presp_timeout_low_power_write(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_LP_WR_TO_CNT, no_of_byte_cycles, 0, 16);
+}
+/**
+ * Timeout for peripheral (for controller to stay still) after LP data
+ * transmission read requests
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_byte_cycles period for which the DWC_mipi_dsi_host keeps the
+ * link still, after sending a low power read operation. This period is
+ * measured in cycles of lanebyteclk
+ */
+void mipi_dsih_hal_presp_timeout_low_power_read(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_LP_RD_TO_CNT, no_of_byte_cycles, 0, 16);
+}
+/**
+ * Timeout for peripheral (for controller to stay still) after HS data
+ * transmission write requests
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_byte_cycles period for which the DWC_mipi_dsi_host keeps the
+ * link still, after sending a high-speed write operation. This period is
+ * measured in cycles of lanebyteclk
+ */
+void mipi_dsih_hal_presp_timeout_high_speed_write(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_HS_WR_TO_CNT, no_of_byte_cycles, 0, 16);
+}
+/**
+ * Timeout for peripheral between HS data transmission read requests
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_byte_cycles period for which the DWC_mipi_dsi_host keeps the
+ * link still, after sending a high-speed read operation. This period is
+ * measured in cycles of lanebyteclk
+ */
+void mipi_dsih_hal_presp_timeout_high_speed_read(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_HS_RD_TO_CNT, no_of_byte_cycles, 0, 16);
+}
+/**
+ * Timeout for peripheral (for controller to stay still) after bus turn around
+ * @param instance pointer to structure holding the DSI Host core information
+ * @param no_of_byte_cycles period for which the DWC_mipi_dsi_host keeps the
+ * link still, after sending a BTA operation. This period is
+ * measured in cycles of lanebyteclk
+ */
+void mipi_dsih_hal_presp_timeout_bta(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles)
+{
+ mipi_dsih_write_part(instance, R_DSI_HOST_BTA_TO_CNT, no_of_byte_cycles, 0, 16);
+}
diff --git a/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_hal.h b/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_hal.h
new file mode 100644
index 00000000..a09450ea
--- /dev/null
+++ b/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_hal.h
@@ -0,0 +1,1807 @@
+/*
+ * @file mipi_dsih_hal.h
+ *
+ * Synopsys Inc.
+ * SG DWC PT02
+ */
+/*
+ The Synopsys Software Driver and documentation (hereinafter "Software")
+ is an unsupported work of Synopsys, Inc. unless otherwise
+ expressly agreed to in writing between Synopsys and you.
+
+ The Software IS NOT an item of Licensed Software or Licensed Product under
+ any End User Software License Agreement or Agreement for Licensed Product
+ with Synopsys or any supplement thereto. Permission is hereby granted,
+ free of charge, to any person obtaining a copy of this software annotated
+ with this license and the Software, to deal in the Software without
+ restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so, subject
+ to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
+ */
+
+#ifndef MIPI_DSIH_HAL_H_
+#define MIPI_DSIH_HAL_H_
+
+#include "mipi_dsih_local.h"
+
+#define R_DSI_HOST_VERSION (0x00)
+#define R_DSI_HOST_PWR_UP (0x04)
+#define R_DSI_HOST_CLK_MGR (0x08)
+#define R_DSI_HOST_DPI_VCID (0x0C)
+#define R_DSI_HOST_DPI_COLOR_CODE (0x10)
+#define R_DSI_HOST_DPI_CFG_POL (0x14)
+#define R_DSI_HOST_DPI_LP_CMD_TIM (0x18)
+#define R_DSI_HOST_DBI_VCID (0x1C)
+#define R_DSI_HOST_DBI_CFG (0x20)
+#define R_DSI_HOST_DBI_PARTITION_EN (0x24)
+#define R_DSI_HOST_DBI_CMDSIZE (0x28)
+#define R_DSI_HOST_PCKHDL_CFG (0x2C)
+#define R_DSI_HOST_GEN_VCID (0x30)
+#define R_DSI_HOST_MODE_CFG (0x34)
+#define R_DSI_HOST_VID_MODE_CFG (0x38)
+#define R_DSI_HOST_VID_PKT_SIZE (0x3C)
+#define R_DSI_HOST_VID_NUM_CHUNKS (0x40)
+#define R_DSI_HOST_VID_NULL_SIZE (0x44)
+#define R_DSI_HOST_VID_HSA_TIME (0x48)
+#define R_DSI_HOST_VID_HBP_TIME (0x4C)
+#define R_DSI_HOST_VID_HLINE_TIME (0x50)
+#define R_DSI_HOST_VID_VSA_LINES (0x54)
+#define R_DSI_HOST_VID_VBP_LINES (0x58)
+#define R_DSI_HOST_VID_VFP_LINES (0x5C)
+#define R_DSI_HOST_VID_VACTIVE_LINES (0x60)
+#define R_DSI_HOST_EDPI_CMD_SIZE (0x64)
+#define R_DSI_HOST_CMD_MODE_CFG (0x68)
+#define R_DSI_HOST_GEN_HDR (0x6C)
+#define R_DSI_HOST_GEN_PLD_DATA (0x70)
+#define R_DSI_HOST_CMD_PKT_STATUS (0x74)
+#define R_DSI_HOST_TO_CNT_CFG (0x78)
+#define R_DSI_HOST_HS_RD_TO_CNT (0x7C)
+#define R_DSI_HOST_LP_RD_TO_CNT (0x80)
+#define R_DSI_HOST_HS_WR_TO_CNT (0x84)
+#define R_DSI_HOST_LP_WR_TO_CNT (0x88)
+#define R_DSI_HOST_BTA_TO_CNT (0x8C)
+
+#define R_DSI_HOST_SDF_3D (0x90)
+
+#define R_DSI_HOST_LPCLK_CTRL (0x94)
+#define R_DSI_HOST_PHY_TMR_LPCLK_CFG (0x98)
+#define R_DSI_HOST_PHY_TMR_CFG (0x9C)
+#define R_DSI_HOST_INT_ST0 (0xBC)
+#define R_DSI_HOST_INT_ST1 (0xC0)
+#define R_DSI_HOST_INT_MSK0 (0xC4)
+#define R_DSI_HOST_INT_MSK1 (0xC8)
+#define R_DSI_HOST_PHY_STATUS (0xB0)
+
+#define R_DSI_HOST_MIPI_PLL_INT_STS (0x200)
+#define R_DSI_HOST_MIPI_PLL_INT_EN (0x200)
+#define R_DSI_HOST_MIPI_PLL_INT_MSK (0x204)
+#define R_DSI_HOST_MIPI_PLL_INT_CLR (0x208)
+
+typedef enum _Dsi_Int0_Type_ {
+ ack_with_err_0,
+ ack_with_err_1,
+ ack_with_err_2,
+ ack_with_err_3,
+ ack_with_err_4,
+ ack_with_err_5,
+ ack_with_err_6,
+ ack_with_err_7,
+ ack_with_err_8,
+ ack_with_err_9,
+ ack_with_err_10,
+ ack_with_err_11,
+ ack_with_err_12,
+ ack_with_err_13,
+ ack_with_err_14,
+ ack_with_err_15,
+ dphy_errors_0,
+ dphy_errors_1,
+ dphy_errors_2,
+ dphy_errors_3,
+ dphy_errors_4,
+ DSI_INT0_MAX,
+}Dsi_Int0_Type;
+
+typedef enum _Dsi_Int1_Type_ {
+ to_hs_tx,
+ to_lp_rx,
+ ecc_single_err,
+ ecc_multi_err,
+ crc_err,
+ pkt_size_err,
+ eopt_err,
+ dpi_pld_wr_err,
+ gen_cmd_wr_err,
+ gen_pld_wr_err,
+ gen_pld_send_err,
+ gen_pld_rd_err,
+ gen_pld_recv_err,
+ dbi_cmd_wr_err,
+ dbi_pld_wr_err,
+ dbi_pld_rd_err,
+ dbi_pld_recv_err,
+ dbi_illegal_comm_err,
+ DSI_INT1_MAX,
+}Dsi_Int1_Type;
+#define DSI_INT_MASK0_SET(bit,val)\
+{\
+ uint32_t reg_val = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_MSK0);\
+ reg_val = (val == 1)?(reg_val | (1UL<<bit)):(reg_val & (~(1UL<<bit)));\
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_MSK0, reg_val);\
+}
+
+#define DSI_INT_MASK1_SET(bit,val)\
+{\
+ uint32_t reg_val = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_MSK1);\
+ reg_val = (val == 1)?(reg_val | (1UL<<bit)):(reg_val & (~(1UL<<bit)));\
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_MSK1, reg_val);\
+}
+
+
+//base :0x2180 0000
+typedef struct _DSIH1P21A_REG_T_
+{
+ union _DSIH1P21A_VERSION_tag_t {
+ struct _DSIH1P21A_VERSION_map_t
+ {
+volatile unsigned int version :
+ 32; //0x3132302A
+ }
+ mBits;
+ volatile unsigned int dwVersion;
+ }VERSION;// 0x0000
+
+ union _DSIH1P21A_PWR_UP_tag_t {
+ struct _DSIH1P21A_PWR_UP_map_t
+ {
+volatile unsigned int power_up :
+ 1; //[0] 1 power up , 0 reset core
+volatile unsigned int reserved_0 :
+ 31; //[31:1] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }PWR_UP;// 0x0004
+
+
+ union _DSIH1P21A_CLKMGR_CFG_tag_t {
+ struct _DSIH1P21A_CLKMGR_CFG_map_t
+ {
+volatile unsigned int tx_esc_clk_division :
+ 8; //[7:0] This field indicates the division factor for the TX Escape clock source (lanebyteclk). The values 0 and 1 stop the TX_ESC clock generation
+volatile unsigned int to_clk_division :
+ 8; //[15:8] This field indicates the division factor for the Time Out clock used as the timing unit in the configuration of HS to LP and LP to HS transition error.
+volatile unsigned int reserved_0 :
+ 16; //[31:16] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }CLKMGR_CFG;// 0x0008
+
+ union _DSIH1P21A_DPI_VCID_tag_t {
+ struct _DSIH1P21A_DPI_VCID_map_t
+ {
+volatile unsigned int dpi_vcid :
+ 2; //[1:0] This field configures the DPI virtual channel id that is indexed to the Video mode packets.
+volatile unsigned int reserved_0 :
+ 30; //[31:2] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }DPI_VCID;// 0x000C
+ //======================
+
+ union _DSIH1P21A_DPI_COLOR_CODING_tag_t {
+ struct _DSIH1P21A_DPI_COLOR_CODING_map_t
+ {
+volatile unsigned int dpi_color_coding :
+ 4; //[3:0]
+ /*
+ This field configures the DPI color coding as follows:
+ 0000: 16-bit configuration 1
+ 0001: 16-bit configuration 2
+ 0010: 16-bit configuration 3
+ 0011: 18-bit configuration 1
+ 0100: 18-bit configuration 2
+ 0101: 24-bit
+ 0110: 20-bit YCbCr 4:2:2 loosely packed
+ 0111: 24-bit YCbCr 4:2:2
+ 1000: 16-bit YCbCr 4:2:2
+ 1001: 30-bit
+ 1010: 36-bit
+ 1011-1111: 12-bit YCbCr 4:2:0
+ Note: If the eDPI interface is chosen and currently works in the
+ Command mode (cmd_video_mode = 1), then
+ 0110-1111: 24-bit
+ */
+volatile unsigned int reserved_0 :
+ 4; //[7:4] Reserved
+volatile unsigned int loosely18_en :
+ 1; //[8] When set to 1, this bit activates loosely packed variant to 18-bit configurations.
+volatile unsigned int reserved_1 :
+ 23; //[31:9] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }DPI_COLOR_CODING;// 0x0010
+
+
+ union _DSIH1P21A_DPI_CFG_POL_tag_t {
+ struct _DSIH1P21A_DPI_CFG_POL_map_t
+ {
+volatile unsigned int dataen_active_low :
+ 1; //[0] When set to 1, this bit configures the data enable pin (dpidataen) asactive low.
+volatile unsigned int vsync_active_low :
+ 1; //[1] When set to 1, this bit configures the vertical synchronism pin (dpivsync) as active low.
+volatile unsigned int hsync_active_low :
+ 1; //[2] When set to 1, this bit configures the horizontal synchronism pin (dpihsync) as active low.
+volatile unsigned int shutd_active_low :
+ 1; //[3] When set to 1, this bit configures the shutdown pin (dpishutdn) as active low
+volatile unsigned int colorm_active_low :
+ 1; //[4] When set to 1, this bit configures the color mode pin (dpicolorm) as active low.
+volatile unsigned int reserved_0 :
+ 27; //[31:5]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }DPI_CFG_POL;// 0x0014
+
+
+ union _DSIH1P21A_DPI_LP_CMD_TIM_tag_t {
+ struct _DSIH1P21A_DPI_LP_CMD_TIM_map_t
+ {
+volatile unsigned int invact_lpcmd_time :
+ 8; //[7:0] This field is used for the transmission of commands in low-power mode. It defines the size, in bytes, of the largest packet that can fit in a line during the VACT region.
+volatile unsigned int reserved_0 :
+ 8; //[15:8] Reserved
+volatile unsigned int outvact_lpcmd_time :
+ 8; //[23:16] This field is used for the transmission of commands in low-power mode. It defines the size, in bytes, of the largest packet that can fit in a line during the VSA, VBP, and VFP regions.
+volatile unsigned int reserved_1 :
+ 8; //[31:24] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }DPI_LP_CMD_TIM;// 0x0018
+
+ union _DSIH1P21A_DBI_VCID_tag_t {
+ struct _DSIH1P21A_DBI_VCID_map_t
+ {
+volatile unsigned int dbi_vcid :
+ 2; //[1:0] This field configures the virtual channel id that is indexed to the DCS packets from DBI.
+volatile unsigned int reserved_0 :
+ 30; //[31:2] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }DBI_VCID;// 0x001C
+
+ union _DSIH1P21A_DBI_CFG_tag_t {
+ struct _DSIH1P21A_DBI_CFG_map_t
+ {
+volatile unsigned int in_dbi_conf :
+ 4; //[3:0]
+ /*
+ This field configures the DBI input pixel data as follows:
+ 0000: 8-bit 8 bpp
+ 0001: 8-bit 12 bpp
+ 0010: 8-bit 16 bpp
+ 0011: 8-bit 18 bpp
+ 0100: 8-bit 24 bpp
+ 0101: 9-bit 18 bpp
+ 0110: 16-bit 8 bpp
+ 0111: 16-bit 12 bpp
+ 1000: 16-bit 16 bpp
+ 1001: 16-bit 18 bpp, option 1
+ 1010: 16-bit 18 bpp, option 2
+ 1011: 16-bit 24 bpp, option 1
+ 1100: 16-bit 24 bpp, option 2
+ */
+volatile unsigned int reserved_0 :
+ 4; //[7:4] Reserved
+volatile unsigned int out_dbi_conf :
+ 4; //[11:8]
+ /*
+ This field configures the DBI output pixel data as follows:
+ 0000: 8-bit 8 bpp
+ 0001: 8-bit 12 bpp
+ 0010: 8-bit 16 bpp
+ 0011: 8-bit 18 bpp
+ 0100: 8-bit 24 bpp
+ 0101: 9-bit 18 bpp
+ 0110: 16-bit 8 bpp
+ 0111: 16-bit 12 bpp
+ 1000: 16-bit 16 bpp
+ 1001: 16-bit 18 bpp, option 1
+ 1010: 16-bit 18 bpp, option 2
+ 1011: 16-bit 24 bpp, option 1
+ 1100: 16-bit 24 bpp, option 2
+ */
+volatile unsigned int reserved_1 :
+ 4; //[15:12] Reserved
+
+volatile unsigned int lut_size_conf :
+ 2; //[17:16]
+ /*
+ This field configures the size used to transport the write Lut
+ commands as follows:
+ 00: 16-bit color display
+ 01: 18-bit color display
+ 10: 24-bit color display
+ 11: 16-bit color display
+ */
+
+volatile unsigned int reserved_2 :
+ 14; //[31:18] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }DBI_CFG;// 0x0020
+
+ union _DSIH1P21A_DBI_PARTITIONING_EN_tag_t {
+ struct _DSIH1P21A_DBI_PARTITIONING_EN_map_t
+ {
+volatile unsigned int partitioning_en :
+ 1; //[0]
+ /*
+ When set to 1, this bit enables the use of write_memory_continue
+ input commands (system needs to ensure correct partitioning of Long
+ Write commands). When not set, partitioning is automatically
+ performed in the DWC_mipi_dsi_host.
+ */
+volatile unsigned int reserved_0 :
+ 31; //[31:1] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }DBI_PARTITIONING_EN;// 0x0024
+
+ union _DSIH1P21A_DBI_CMDSIZE_tag_t {
+ struct _DSIH1P21A_DBI_CMDSIZE_map_t
+ {
+volatile unsigned int wr_cmd_size :
+ 16; //[15:0]
+ /*
+ This field configures the size of the DCS write memory commands.
+ The size of DSI packet payload is the actual payload size minus 1,
+ because the DCS command is in the DSI packet payload
+ */
+volatile unsigned int allowed_cmd_size :
+ 16; //[31:16]
+ /*
+ This field configures the maximum allowed size for a DCS write
+ memory command. This field is used to partition a write memory
+ command into one write_memory_start and a variable number of
+ write_memory_continue commands. It is only used if the
+ partitioning_en bit of the DBI_CFG register is disabled.
+ The size of the DSI packet payload is the actual payload size minus 1,
+ because the DCS command is in the DSI packet payload.
+ */
+
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }DBI_CMDSIZE;// 0x0028
+
+ union _DSIH1P21A_PCKHDL_CFG_tag_t {
+ struct _DSIH1P21A_PCKHDL_CFG_map_t
+ {
+volatile unsigned int eotp_tx_en :
+ 1; //[0] When set to 1, this bit enables the EoTp transmission
+volatile unsigned int eotp_rx_en :
+ 1; //[1] When set to 1, this bit enables the EoTp reception.
+volatile unsigned int bta_en :
+ 1; //[2] When set to 1, this bit enables the Bus Turn-Around (BTA) request.
+volatile unsigned int ecc_rx_en :
+ 1; //[3] When set to 1, this bit enables the ECC reception, error correction, and reporting.
+volatile unsigned int crc_rx_en :
+ 1; //[4] When set to 1, this bit enables the CRC reception and error reporting. Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3 or DSI_GENERIC = 1. Otherwise, this bit is reserved.
+volatile unsigned int reserved_0 :
+ 27; //[31:5]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }PCKHDL_CFG;// 0x002C
+
+ union _DSIH1P21A_GEN_VCID_tag_t {
+ struct _DSIH1P21A_GEN_VCID_map_t
+ {
+volatile unsigned int gen_vcid_rx :
+ 2; //[1:0] This field indicates the Generic interface read-back virtual channel identification.
+volatile unsigned int reserved_0 :
+ 30; //[31:2] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }GEN_VCID;// 0x0030
+
+ union _DSIH1P21A_MODE_CFG_tag_t {
+ struct _DSIH1P21A_MODE_CFG_map_t
+ {
+volatile unsigned int cmd_video_mode :
+ 1; //[0] This bit configures the operation mode:0: Video mode ; 1: Command mode
+volatile unsigned int reserved_0 :
+ 31; //[31:1] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }MODE_CFG;// 0x0034
+
+ union _DSIH1P21A_VID_MODE_CFG_tag_t {
+ struct _DSIH1P21A_VID_MODE_CFG_map_t
+ {
+volatile unsigned int vid_mode_type :
+ 2; //[1:0]
+ /*
+ This field indicates the video mode transmission type as follows:
+ 00: Non-burst with sync pulses
+ 01: Non-burst with sync events
+ 10 and 11: Burst mode
+ */
+volatile unsigned int reserved_0 :
+ 6; //[7:2]
+volatile unsigned int lp_vsa_en :
+ 1; //[8] When set to 1, this bit enables the return to low-power inside the VSA period when timing allows.
+volatile unsigned int lp_vbp_en :
+ 1; //[9] When set to 1, this bit enables the return to low-power inside the VBP period when timing allows.
+volatile unsigned int lp_vfp_en :
+ 1; //[10] When set to 1, this bit enables the return to low-power inside the VFP period when timing allows.
+volatile unsigned int lp_vact_en :
+ 1; //[11] When set to 1, this bit enables the return to low-power inside the VACT period when timing allows.
+volatile unsigned int lp_hbp_en :
+ 1; //[12] When set to 1, this bit enables the return to low-power inside the HBP period when timing allows.
+volatile unsigned int lp_hfp_en :
+ 1; //[13] When set to 1, this bit enables the return to low-power inside the HFP period when timing allows.
+volatile unsigned int frame_bta_ack_en :
+ 1; //[14] When set to 1, this bit enables the request for an acknowledgeresponse at the end of a frame
+volatile unsigned int lp_cmd_en :
+ 1; //[15] When set to 1, this bit enables the command transmission only in lowpower mode.
+volatile unsigned int reserved_1 :
+ 16; //[31:16]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }VID_MODE_CFG;// 0x0038
+
+ union _DSIH1P21A_VID_PKT_SIZE_tag_t {
+ struct _DSIH1P21A_VID_PKT_SIZE_map_t
+ {
+volatile unsigned int vid_pkt_size :
+ 14; //[13:0] This field configures the number of pixels in a single video packet. For 18-bit not loosely packed data types, this number must be a multiple of 4. For YCbCr data types, it must be a multiple of 2, as described in the DSI specification.
+volatile unsigned int reserved_0 :
+ 18; //[31:14] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }VID_PKT_SIZE;// 0x003C
+
+ union _DSIH1P21A_VID_NUM_CHUNKS_tag_t {
+ struct _DSIH1P21A_VID_NUM_CHUNKS_map_t
+ {
+volatile unsigned int vid_num_chunks :
+ 13; //[12:0]
+ /*
+ This register configures the number of chunks to be transmitted during
+ a Line period (a chunk consists of a video packet and a null packet).
+ If set to 0 or 1, the video line is transmitted in a single packet.
+ If set to 1, the packet is part of a chunk, so a null packet follows it if
+ vid_null_size > 0. Otherwise, multiple chunks are used to transmit each video line.
+ */
+volatile unsigned int reserved_0 :
+ 19; //[31:13] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }VID_NUM_CHUNKS;// 0x0040
+
+ union _DSIH1P21A_VID_NULL_SIZE_tag_t {
+ struct _DSIH1P21A_VID_NULL_SIZE_map_t
+ {
+volatile unsigned int vid_null_size :
+ 13; //[12:0]
+ /*
+ This register configures the number of bytes inside a null packet.
+ Setting it to 0 disables the null packets.
+ */
+volatile unsigned int reserved_0 :
+ 19; //[31:13] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }VID_NULL_SIZE;// 0x0044
+
+ union _DSIH1P21A_VID_HSA_TIME_tag_t {
+ struct _DSIH1P21A_VID_HSA_TIME_map_t
+ {
+volatile unsigned int vid_hsa_time :
+ 12; //[11:0] This field configures the Horizontal Synchronism Active period in lane byte clock cycles
+volatile unsigned int reserved_0 :
+ 20; //[31:12] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }VID_HSA_TIME;// 0x0048
+
+ union _DSIH1P21A_VID_HBP_TIME_tag_t {
+ struct _DSIH1P21A_VID_HBP_TIME_map_t
+ {
+volatile unsigned int vid_hbp_time :
+ 12; //[11:0] This field configures the Horizontal Back Porch period in lane byte clock cycles.
+volatile unsigned int reserved_0 :
+ 20; //[31:12] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }VID_HBP_TIME;// 0x004C
+
+ union _DSIH1P21A_VID_HLINE_TIME_tag_t {
+ struct _DSIH1P21A_VID_HLINE_TIME_map_t
+ {
+volatile unsigned int vid_hline_time :
+ 15; //[14:0] This field configures the size of the total line time (HSA+HBP+HACT+HFP) counted in lane byte clock cycles.
+volatile unsigned int reserved_0 :
+ 17; //[31:15] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }VID_HLINE_TIME;// 0x0050
+
+ union _DSIH1P21A_VID_VSA_LINES_tag_t {
+ struct _DSIH1P21A_VID_VSA_LINES_map_t
+ {
+volatile unsigned int vsa_lines :
+ 10; //[9:0] This field configures the Vertical Synchronism Active period measured in number of horizontal lines
+volatile unsigned int reserved_0 :
+ 22; //[31:10] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }VID_VSA_LINES;// 0x0054
+
+ union _DSIH1P21A_VID_VBP_LINES_tag_t {
+ struct _DSIH1P21A_VID_VBP_LINES_map_t
+ {
+volatile unsigned int vbp_lines :
+ 10; //[9:0] This field configures the Vertical Back Porch period measured in number of horizontal lines.
+volatile unsigned int reserved_0 :
+ 22; //[31:10] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }VID_VBP_LINES;// 0x0058
+
+ union _DSIH1P21A_VID_VFP_LINES_tag_t {
+ struct _DSIH1P21A_VID_VFP_LINES_map_t
+ {
+volatile unsigned int vfp_lines :
+ 10; //[9:0] This field configures the Vertical Front Porch period measured in number of horizontal lines.
+volatile unsigned int reserved_0 :
+ 22; //[31:10] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }VID_VFP_LINES;// 0x005C
+
+ union _DSIH1P21A_VID_VACTIVE_LINES_tag_t {
+ struct _DSIH1P21A_VID_VACTIVE_LINES_map_t
+ {
+volatile unsigned int v_active_lines :
+ 14; //[13:0] This field configures the Vertical Active period measured in number of horizontal lines.
+volatile unsigned int reserved_0 :
+ 18; //[31:14] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }VID_VACTIVE_LINES;// 0x0060
+
+ union _DSIH1P21A_EDPI_CMD_SIZE_tag_t {
+ struct _DSIH1P21A_EDPI_CMD_SIZE_map_t
+ {
+volatile unsigned int edpi_allowed_cmd_size :
+ 16; //[15:0] This field configures the maximum allowed size for an eDPI write memory command, measured in pixels. Automatic partitioning of data obtained from eDPI is permanently enabled.
+volatile unsigned int reserved_0 :
+ 16; //[31:16] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }EDPI_CMD_SIZE;// 0x0064
+
+ union _DSIH1P21A_CMD_MODE_CFG_tag_t {
+ struct _DSIH1P21A_CMD_MODE_CFG_map_t
+ {
+volatile unsigned int tear_fx_en :
+ 1; //[0] When set to 1, this bit enables the tearing effect acknowledge request.
+volatile unsigned int ack_rqst_en :
+ 1; //[1] When set to 1, this bit enables the acknowledge request after each packet transmission.
+volatile unsigned int reserved_0 :
+ 6; //[7:2]
+volatile unsigned int gen_sw_0p_tx :
+ 1; //[8] This bit configures the Generic short write packet with zero parameter command transmission type:0: High-speed 1: Low-power
+volatile unsigned int gen_sw_1p_tx :
+ 1; //[9] This bit configures the Generic short write packet with one parameter command transmission type: 0: High-speed 1: Low-power
+volatile unsigned int gen_sw_2p_tx :
+ 1; //[10] This bit configures the Generic short write packet with two parameters command transmission type:0: High-speed 1: Low-power
+volatile unsigned int gen_sr_0p_tx :
+ 1; //[11] This bit configures the Generic short read packet with zero parameter command transmission type:0: High-speed 1: Low-power
+volatile unsigned int gen_sr_1p_tx :
+ 1; //[12] This bit configures the Generic short read packet with one parameter command transmission type:0: High-speed 1: Low-power
+volatile unsigned int gen_sr_2p_tx :
+ 1; //[13] This bit configures the Generic short read packet with two parameters command transmission type:0: High-speed 1: Low-power
+volatile unsigned int gen_lw_tx :
+ 1; //[14] This bit configures the Generic long write packet command transmission type:0: High-speed 1: Low-power
+volatile unsigned int reserved_1 :
+ 1; //[15]
+volatile unsigned int dcs_sw_0p_tx :
+ 1; //[16] This bit configures the DCS short write packet with zero parameter command transmission type:0: High-speed 1: Low-power
+volatile unsigned int dcs_sw_1p_tx :
+ 1; //[17] This bit configures the DCS short write packet with one parameter command transmission type:0: High-speed 1: Low-power
+volatile unsigned int dcs_sr_0p_tx :
+ 1; //[18] This bit configures the DCS short read packet with zero parameter command transmission type:0: High-speed 1: Low-power
+volatile unsigned int dcs_lw_tx :
+ 1; //[19] This bit configures the DCS long write packet command transmission type:0: High-speed 1: Low-power
+volatile unsigned int reserved_2 :
+ 4; //[23:20]
+volatile unsigned int max_rd_pkt_size :
+ 1; //[24] This bit configures the maximum read packet size command transmission type:0: High-speed 1: Low-power
+volatile unsigned int reserved_3 :
+ 7; //[31:25]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }CMD_MODE_CFG;// 0x0068
+
+ union _DSIH1P21A_GEN_HDR_tag_t {
+ struct _DSIH1P21A_GEN_HDR_map_t
+ {
+volatile unsigned int gen_dt :
+ 6; //[5:0] This field configures the packet data type of the header packet.
+volatile unsigned int gen_vc :
+ 2; //[7:6] Reserved
+volatile unsigned int gen_wc_lsbyte :
+ 8; //[15:8] This field configures the least significant byte of the header packet's Word count for long packets or data 0 for short packets.
+volatile unsigned int gen_wc_msbyte :
+ 8; //[23:16] This field configures the most significant byte of the header packet's word count for long packets or data 1 for short packets.
+volatile unsigned int reserved_0 :
+ 8; //[31:24] Reserved
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }GEN_HDR;// 0x006C
+
+ union _DSIH1P21A_GEN_PLD_DATA_tag_t {
+ struct _DSIH1P21A_GEN_PLD_DATA_map_t
+ {
+volatile unsigned int gen_pld_b1 :
+ 8; //[7:0] This field indicates byte 1 of the packet payload.
+volatile unsigned int gen_pld_b2 :
+ 8; //[15:8] This field indicates byte 2 of the packet payload.
+volatile unsigned int gen_pld_b3 :
+ 8; //[23:16] This field indicates byte 3 of the packet payload.
+volatile unsigned int gen_pld_b4 :
+ 8; //[31:24] This field indicates byte 4 of the packet payload.
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }GEN_PLD_DATA;// 0x0070
+
+ union _DSIH1P21A_CMD_PKT_STATUS_tag_t {
+ struct _DSIH1P21A_CMD_PKT_STATUS_map_t
+ {
+volatile unsigned int gen_cmd_empty :
+ 1; //[0]
+ /*
+ This bit indicates the empty status of the generic command FIFO.
+ Dependency: DSI_GENERIC = 1. Otherwise, this bit is reserved.
+ Value after reset: 0x1
+ */
+volatile unsigned int gen_cmd_full :
+ 1; //[1]
+ /*
+ This bit indicates the full status of the generic command FIFO.
+ Dependency: DSI_GENERIC = 1. Otherwise, this bit is reserved.
+ Value after reset: 0x0
+ */
+volatile unsigned int gen_pld_w_empty :
+ 1; //[2]
+ /*
+ This bit indicates the empty status of the generic write payload FIFO.
+ Dependency: DSI_GENERIC = 1. Otherwise, this bit is reserved.
+ Value after reset: 0x1
+ */
+volatile unsigned int gen_pld_w_full :
+ 1; //[3]
+ /*
+ This bit indicates the full status of the generic write payload FIFO.
+ Dependency: DSI_GENERIC = 1. Otherwise, this bit is reserved.
+ Value after reset: 0x0
+ */
+volatile unsigned int gen_pld_r_empty :
+ 1; //[4]
+ /*
+ This bit indicates the empty status of the generic read payload FIFO.
+ Dependency: DSI_GENERIC = 1. Otherwise, this bit is reserved.
+ Value after reset: 0x1
+ */
+volatile unsigned int gen_pld_r_full :
+ 1; //[5]
+ /*
+ This bit indicates the full status of the generic read payload FIFO.
+ Dependency: DSI_GENERIC = 1. Otherwise, this bit is reserved.
+ Value after reset: 0x0
+ */
+volatile unsigned int gen_rd_cmd_busy :
+ 1; //[6]
+ /*
+ This bit is set when a read command is issued and cleared when the
+ entire response is stored in the FIFO.
+ Dependency: DSI_GENERIC = 1. Otherwise, this bit is reserved.
+ Value after reset: 0x0
+ */
+volatile unsigned int reserved_0 :
+ 1; //[7]
+ /*
+ */
+volatile unsigned int dbi_cmd_empy :
+ 1; //[8]
+ /*
+ This bit indicates the empty status of the DBI command FIFO.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3.
+ Otherwise, this bit is reserved.
+ Value after reset: 0x1
+ */
+volatile unsigned int dbi_cmd_full :
+ 1; //[9]
+ /*
+ This bit indicates the full status of the DBI command FIFO.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3.
+ Otherwise, this bit is reserved.
+ Value after reset: 0x0
+ */
+volatile unsigned int dbi_pld_w_empty :
+ 1; //[10]
+ /*
+ This bit indicates the empty status of the DBI write payload FIFO.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3.
+ Otherwise, this bit is reserved.
+ Value after reset: 0x1
+ */
+volatile unsigned int dbi_pld_w_full :
+ 1; //[11]
+ /*
+ This bit indicates the full status of the DBI write payload FIFO.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3.
+ Otherwise, this bit is reserved.
+ Value after reset: 0x0
+ */
+volatile unsigned int dbi_pld_r_empty :
+ 1; //[12]
+ /*
+ This bit indicates the empty status of the DBI read payload FIFO.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3.
+ Otherwise, this bit is reserved.
+ Value after reset: 0x1
+ */
+volatile unsigned int dbi_pld_r_full :
+ 1; //[13]
+ /*
+ This bit indicates the full status of the DBI read payload FIFO.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3.
+ Otherwise, this bit is reserved.
+ Value after reset: 0x0
+ */
+volatile unsigned int dbi_rd_cmd_busy :
+ 1; //[14]
+ /*
+ This bit is set when a read command is issued and cleared when the
+ entire response is stored in the FIFO.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3.
+ Otherwise, this bit is reserved.
+ Value after reset: 0x0
+ */
+volatile unsigned int reserved_1 :
+ 17; //[31:15]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }
+ CMD_PKT_STATUS;// 0x0074
+
+ union _DSIH1P21A_TO_CNT_CFG_tag_t {
+ struct _DSIH1P21A_TO_CNT_CFG_map_t
+ {
+volatile unsigned int lprx_to_cnt :
+ 16; //[15:0]
+ /*
+ This field configures the timeout counter that triggers a low-power
+ reception timeout contention detection (measured in
+ TO_CLK_DIVISION cycles).
+ */
+volatile unsigned int hstx_to_cnt :
+ 16; //[31:16]
+ /*
+ This field configures the timeout counter that triggers a high-speed
+ transmission timeout contention detection (measured in
+ TO_CLK_DIVISION cycles).
+ If using the non-burst mode and there is no sufficient time to switch
+ from HS to LP and back in the period which is from one line data
+ finishing to the next line sync start, the DSI link returns the LP state
+ once per frame, then you should configure the TO_CLK_DIVISION
+ and hstx_to_cnt to be in accordance with:
+ hstx_to_cnt * lanebyteclkperiod * TO_CLK_DIVISION >= the time of
+ one FRAME data transmission * (1 + 10%)
+ In burst mode, RGB pixel packets are time-compressed, leaving more
+ time during a scan line. Therefore, if in burst mode and there is
+ sufficient time to switch from HS to LP and back in the period of time
+ from one line data finishing to the next line sync start, the DSI link can
+ return LP mode and back in this time interval to save power. For this,
+ configure the TO_CLK_DIVISION and hstx_to_cnt to be in accordance
+ with:
+ hstx_to_cnt * lanebyteclkperiod * TO_CLK_DIVISION >= the time of
+ one LINE data transmission * (1 + 10%)
+ */
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }
+ TO_CNT_CFG;// 0x0078
+
+ union _DSIH1P21A_HS_RD_TO_CNT_tag_t {
+ struct _DSIH1P21A_HS_RD_TO_CNT_map_t
+ {
+volatile unsigned int hs_rd_to_cnt :
+ 16; //[15:0]
+ /*
+ This field sets a period for which the DWC_mipi_dsi_host keeps the
+ link still, after sending a high-speed read operation. This period is
+ measured in cycles of lanebyteclk. The counting starts when the
+ D-PHY enters the Stop state and causes no interrupts.
+ */
+volatile unsigned int reserved_0 :
+ 16; //[31:16]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }
+ HS_RD_TO_CNT;// 0x007C
+
+ union _DSIH1P21A_LP_RD_TO_CNT_tag_t {
+ struct _DSIH1P21A_LP_RD_TO_CNT_map_t
+ {
+volatile unsigned int lp_rd_to_cnt :
+ 16; //[15:0]
+ /*
+ This field sets a period for which the DWC_mipi_dsi_host keeps the
+ link still, after sending a low-power read operation. This period is
+ measured in cycles of lanebyteclk. The counting starts when the
+ D-PHY enters the Stop state and causes no interrupts.
+ */
+volatile unsigned int reserved_0 :
+ 16; //[31:16]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }
+ LP_RD_TO_CNT;// 0x0080
+
+ union _DSIH1P21A_HS_WR_TO_CNT_tag_t {
+ struct _DSIH1P21A_HS_WR_TO_CNT_map_t
+ {
+volatile unsigned int hs_wr_to_cnt :
+ 16; //[15:0]
+ /*
+ This field sets a period for which the DWC_mipi_dsi_host keeps the
+ link inactive after sending a high-speed write operation. This period is
+ measured in cycles of lanebyteclk. The counting starts when the
+ D-PHY enters the Stop state and causes no interrupts.
+ */
+volatile unsigned int reserved_0 :
+ 8; //[23:16]
+volatile unsigned int presp_to_mode :
+ 1; //[24]
+ /*
+ When set to 1, this bit ensures that the peripheral response timeout
+ caused by hs_wr_to_cnt is used only once per eDPI frame, when both
+ the following conditions are met:
+ dpivsync_edpiwms has risen and fallen.
+ Packets originated from eDPI have been transmitted and its FIFO
+ is empty again.
+ In this scenario no non-eDPI requests are sent to the D-PHY, even if
+ there is traffic from generic or DBI ready to be sent, making it return to
+ stop state. When it does so, PRESP_TO counter is activated and only
+ when it finishes does the controller send any other traffic that is ready.
+ Dependency: DSI_DATAINTERFACE = 4. Otherwise, this bit is
+ reserved.
+ */
+volatile unsigned int reserved_1 :
+ 7; //[31:25]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }
+ HS_WR_TO_CNT;// 0x0084
+
+ union _DSIH1P21A_LP_WR_TO_CNT_tag_t {
+ struct _DSIH1P21A_LP_WR_TO_CNT_map_t
+ {
+volatile unsigned int lp_wr_to_cnt :
+ 16; //[15:0]
+ /*
+ This field sets a period for which the DWC_mipi_dsi_host keeps the
+ link still, after sending a low-power write operation. This period is
+ measured in cycles of lanebyteclk. The counting starts when the
+ D-PHY enters the Stop state and causes no interrupts
+ */
+volatile unsigned int reserved_0 :
+ 16; //[31:16]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }
+ LP_WR_TO_CNT;// 0x0088
+
+ union _DSIH1P21A_BTA_TO_CNT_tag_t {
+ struct _DSIH1P21A_BTA_TO_CNT_map_t
+ {
+volatile unsigned int bta_to_cnt :
+ 16; //[15:0]
+ /*
+ This field sets a period for which the DWC_mipi_dsi_host keeps the
+ link still, after completing a Bus Turn-Around. This period is measured
+ in cycles of lanebyteclk. The counting starts when the D-PHY enters
+ the Stop state and causes no interrupts.
+ */
+volatile unsigned int reserved_0 :
+ 16; //[31:16]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }
+ BTA_TO_CNT;// 0x008C
+
+ union _DSIH1P21A_SDF_3D_tag_t {
+ struct _DSIH1P21A_SDF_3D_map_t
+ {
+volatile unsigned int mode_3d :
+ 2; //[1:0]
+ /*
+ This field defines the 3D mode on/off and display orientation:
+ 00: 3D mode off (2D mode on)
+ 01: 3D mode on, portrait orientation
+ 10: 3D mode on, landscape orientation
+ 11: Reserved
+
+ */
+volatile unsigned int ormat_3d :
+ 2; //[3:2]
+ /*
+ This field defines the 3D image format:
+ 00: Line (alternating lines of left and right data)
+ 01: Frame (alternating frames of left and right data)
+ 10: Pixel (alternating pixels of left and right data)
+ 11: Reserved
+
+ */
+volatile unsigned int second_vsync :
+ 1; //[4]
+ /*
+ This field defines whether there is a second VSYNC pulse between
+ Left and Right Images, when 3D Image Format is Frame-based:
+ 0: No sync pulses between left and right data
+ 1: Sync pulse (HSYNC, VSYNC, blanking) between left and right
+ data
+ */
+volatile unsigned int right_first :
+ 1; //[5]
+ /*
+ This bit defines the left or right order:
+ 0: Left eye data is sent first, and then the right eye data is sent.
+ 1: Right eye data is sent first, and then the left eye data is sent.
+ */
+volatile unsigned int reserved_0 :
+ 10; //[15:6]
+volatile unsigned int send_3d_cfg :
+ 1; //[16]
+ /*
+ When set, causes the next VSS packet to include 3D control payload
+ in every VSS packet.
+ */
+volatile unsigned int reserved_1 :
+ 15; //[31:17]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }
+ SDF_3D;// 0x0090
+
+ union _DSIH1P21A_LPCLK_CTRL_tag_t {
+ struct _DSIH1P21A_LPCLK_CTRL_map_t
+ {
+volatile unsigned int phy_txrequestclkhs :
+ 1; //[0] This bit controls the D-PHY PPI txrequestclkhs signal
+volatile unsigned int auto_clklane_ctrl :
+ 1; //[0] This bit enables the automatic mechanism to stop providing clock in the clock lane when time allows
+volatile unsigned int reserved_0 :
+ 30; //[31:2]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }
+ LPCLK_CTRL;// 0x0094
+
+ union _DSIH1P21A_PHY_TMR_LPCLK_CFG_tag_t {
+ struct _DSIH1P21A_PHY_TMR_LPCLK_CFG_map_t
+ {
+volatile unsigned int phy_clklp2hs_time :
+ 10; //[9:0]
+ /*
+ This field configures the maximum time that the D-PHY clock lane
+ takes to go from low-power to high-speed transmission measured in
+ lane byte clock cycles.
+ */
+volatile unsigned int reserved_0 :
+ 6; //[15:10]
+volatile unsigned int phy_clkhs2lp_time :
+ 10; //[25:16]
+ /*
+ This field configures the maximum time that the D-PHY clock lane
+ takes to go from high-speed to low-power transmission measured in
+ lane byte clock cycles.
+ */
+volatile unsigned int reserved_1 :
+ 6; //[31:26]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }
+ PHY_TMR_LPCLK_CFG;// 0x0098
+
+ union _DSIH1P21A_PHY_TMR_CFG_tag_t {
+ struct _DSIH1P21A_PHY_TMR_CFG_map_t
+ {
+volatile unsigned int max_rd_time :
+ 15; //[14:0]
+ /*
+ This field configures the maximum time required to perform a read
+ command in lane byte clock cycles. This register can only be modified
+ when no read command is in progress.
+ */
+volatile unsigned int reserved_0 :
+ 1; //[15]
+volatile unsigned int phy_lp2hs_time :
+ 8; //[23:16]
+ /*
+ This field configures the maximum time that the D-PHY data lanes
+ take to go from low-power to high-speed transmission measured in
+ lane byte clock cycles.
+ */
+volatile unsigned int phy_hs2lp_time :
+ 8; //[31:24]
+ /*
+ This field configures the maximum time that the D-PHY data lanes
+ take to go from high-speed to low-power transmission measured in
+ lane byte clock cycles.
+ */
+ }
+ mBits;
+ volatile unsigned int dValue;
+ } PHY_TMR_CFG;// 0x009C
+
+ union _DSIH1P21A_PHY_RSTZ_tag_t {
+ struct _DSIH1P21A_PHY_RSTZ_map_t
+ {
+volatile unsigned int phy_shutdownz :
+ 1; //[0] When set to 0, this bit places the D-PHY macro in power-down state
+volatile unsigned int phy_rstz :
+ 1; //[1] When set to 0, this bit places the digital section of the D-PHY in the reset state.
+volatile unsigned int phy_enableclk :
+ 1; //[2] When set to1, this bit enables the D-PHY Clock Lane module.
+volatile unsigned int phy_forcepll :
+ 1; //[3]
+ /*
+ When the D-PHY is in ULPS, this bit enables the D-PHY PLL.
+ Dependency: DSI_HOST_FPGA = 0. Otherwise, this bit is reserved
+ */
+volatile unsigned int reserved_0 :
+ 28; //[31:4]
+ }
+ mBits;
+ volatile unsigned int dValue;
+
+ } PHY_RSTZ;// 0x00A0
+
+ union _DSIH1P21A_PHY_IF_CFG_tag_t {
+ struct _DSIH1P21A_PHY_IF_CFG_map_t
+ {
+volatile unsigned int n_lanes :
+ 2; //[1:0]
+ /*
+ This field configures the number of active data lanes:
+ 00: One data lane (lane 0)
+ 01: Two data lanes (lanes 0 and 1)
+ 10: Three data lanes (lanes 0, 1, and 2)
+ 11: Four data lanes (lanes 0, 1, 2, and 3)
+ */
+volatile unsigned int reserved_0 :
+ 6; //[7:2]
+volatile unsigned int phy_stop_wait_time :
+ 8; //[15:8] This field configures the minimum wait period to request a high-speed transmission after the Stop state.
+volatile unsigned int reserved_1 :
+ 16; //[31:16]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }PHY_IF_CFG;// 0x00A4
+
+ union _DSIH1P21A_PHY_ULPS_CTRL_tag_t {
+ struct _DSIH1P21A_PHY_ULPS_CTRL_map_t
+ {
+volatile unsigned int phy_txrequlpsclk :
+ 1; //[0] ULPS mode Request on clock lane.
+volatile unsigned int phy_txexitulpsclk :
+ 1; //[1] ULPS mode Exit on clock lane.
+volatile unsigned int phy_txrequlpslan :
+ 1; //[2] ULPS mode Request on all active data lanes.
+volatile unsigned int phy_txexitulpslan :
+ 1; //[3] ULPS mode Exit on all active data lanes.
+volatile unsigned int reserved_0 :
+ 28; //[31:4]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }
+ PHY_ULPS_CTRL;// 0x00A8
+
+ union _DSIH1P21A_PHY_TX_TRIGGERS_tag_t {
+ struct _DSIH1P21A_PHY_TX_TRIGGERS_map_t
+ {
+volatile unsigned int phy_tx_triggers :
+ 4; //[3:0] This field controls the trigger transmissions
+volatile unsigned int reserved_0 :
+ 28; //[31:4]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }
+ PHY_TX_TRIGGERS;// 0x00AC
+
+ union _DSIH1P21A_PHY_STATUS_tag_t {
+ struct _DSIH1P21A_PHY_STATUS_map_t
+ {
+volatile unsigned int phy_lock :
+ 1; //[0] This bit indicates the status of phylock D-PHY signal.
+volatile unsigned int phy_direction :
+ 1; //[1] This bit indicates the status of phydirection D-PHY signal.
+volatile unsigned int phy_stopstateclklane :
+ 1; //[2] This bit indicates the status of phystopstateclklane D-PHY signal.
+volatile unsigned int phy_ulpsactivenotclk :
+ 1; //[3] This bit indicates the status of phyulpsactivenotclk D-PHY signal.
+volatile unsigned int phy_stopstate0lane :
+ 1; //[4] This bit indicates the status of phystopstate0lane D-PHY signal.
+volatile unsigned int phy_ulpsactivenot0lane :
+ 1; //[5] This bit indicates the status of ulpsactivenot0lane D-PHY signal.
+volatile unsigned int phy_rxulpsesc0lane :
+ 1; //[6] This bit indicates the status of rxulpsesc0lane D-PHY signal.
+volatile unsigned int phy_stopstate1lane :
+ 1; //[7]
+ /*
+ This bit indicates the status of phystopstate1lane D-PHY signal.
+ Dependency: DSI_HOST_NUMBER_OF_LANES > 1
+ If DSI_HOST_NUMBER_OF_LANES <= 1, this bit is reserved.
+ */
+volatile unsigned int phy_ulpsactivenot1lane :
+ 1; //[8]
+ /*
+ This bit indicates the status of ulpsactivenot1lane D-PHY signal.
+ Dependency: DSI_HOST_NUMBER_OF_LANES > 1
+ If DSI_HOST_NUMBER_OF_LANES <= 1, this bit is reserved.
+ */
+volatile unsigned int phy_stopstate2lane :
+ 1; //[9]
+ /*
+ This bit indicates the status of phystopstate2lane D-PHY signal.
+ Dependency: DSI_HOST_NUMBER_OF_LANES > 2
+ If DSI_HOST_NUMBER_OF_LANES <= 2, this bit is reserved.
+ */
+volatile unsigned int phy_ulpsactivenot2lane :
+ 1; //[10]
+ /*
+ This bit indicates the status of ulpsactivenot2lane D-PHY signal.
+ Dependency: DSI_HOST_NUMBER_OF_LANES > 2
+ If DSI_HOST_NUMBER_OF_LANES <= 2, this bit is reserved.
+ */
+volatile unsigned int phy_stopstate3lane :
+ 1; //[11]
+ /*
+ This bit indicates the status of phystopstate3lane D-PHY signal.
+ Dependency: DSI_HOST_NUMBER_OF_LANES > 3
+ If DSI_HOST_NUMBER_OF_LANES <= 3, this bit is reserved
+ */
+volatile unsigned int phy_ulpsactivenot3lane :
+ 1; //[12]
+ /*
+ This bit indicates the status of ulpsactivenot3lane D-PHY signal.
+ Dependency: DSI_HOST_NUMBER_OF_LANES > 3
+ If DSI_HOST_NUMBER_OF_LANES <= 3, this bit is reserved
+ */
+volatile unsigned int reserved_0 :
+ 19; //[31:13]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ } PHY_STATUS;// 0x00B0
+
+ union _DSIH1P21A_PHY_TST_CTRL0_tag_t {
+ struct _DSIH1P21A_PHY_TST_CTRL0_map_t
+ {
+volatile unsigned int phy_testclr :
+ 1; //[0] PHY test interface clear (active high).
+volatile unsigned int phy_testclk :
+ 1; //[1] This bit is used to clock the TESTDIN bus into the D-PHY.
+volatile unsigned int reserved_0 :
+ 30; //[31:2]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }
+ PHY_TST_CTRL0;// 0x00B4
+
+ union _DSIH1P21A_PHY_TST_CTRL1_tag_t {
+ struct _DSIH1P21A_PHY_TST_CTRL1_map_t
+ {
+volatile unsigned int phy_testdin :
+ 8; //[7:0] PHY test interface input 8-bit data bus for internal register programming and test functionalities access.
+volatile unsigned int pht_testdout :
+ 8; //[15:8] PHY output 8-bit data bus for read-back and internal probing functionalities.
+volatile unsigned int phy_testen :
+ 1; //[16]
+ /*
+ PHY test interface operation selector:
+ 1: The address write operation is set on the falling edge of the testclk signal.
+ 0: The data write operation is set on the rising edge of the testclk signal.
+ */
+volatile unsigned int reserved_0 :
+ 15; //[31:17]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }
+ PHY_TST_CTRL1;// 0x00B8
+
+ union _DSIH1P21A_INT_ST0_tag_t {
+ struct _DSIH1P21A_INT_ST0_map_t
+ {
+volatile unsigned int ack_with_err_0 :
+ 1; //[0] This bit retrieves the SoT error from the Acknowledge error report.
+volatile unsigned int ack_with_err_1 :
+ 1; //[1] This bit retrieves the SoT Sync error from the Acknowledge error report.
+volatile unsigned int ack_with_err_2 :
+ 1; //[2] This bit retrieves the EoT Sync error from the Acknowledge error report.
+volatile unsigned int ack_with_err_3 :
+ 1; //[3] This bit retrieves the Escape Mode Entry Command error from the Acknowledge error report.
+volatile unsigned int ack_with_err_4 :
+ 1; //[4] This bit retrieves the LP Transmit Sync error from the Acknowledge error report.
+volatile unsigned int ack_with_err_5 :
+ 1; //[5] This bit retrieves the Peripheral Timeout error from the Acknowledge Error report.
+volatile unsigned int ack_with_err_6 :
+ 1; //[6] This bit retrieves the False Control error from the Acknowledge error report.
+volatile unsigned int ack_with_err_7 :
+ 1; //[7] This bit retrieves the reserved (specific to device) from the Acknowledge error report.
+volatile unsigned int ack_with_err_8 :
+ 1; //[8] This bit retrieves the ECC error, single-bit (detected and corrected) from the Acknowledge error report.
+volatile unsigned int ack_with_err_9 :
+ 1; //[9] This bit retrieves the ECC error, multi-bit (detected, not corrected) from the Acknowledge error report.
+volatile unsigned int ack_with_err_10 :
+ 1; //[10]This bit retrieves the checksum error (long packet only) from the Acknowledge error report.
+volatile unsigned int ack_with_err_11 :
+ 1; //[11] This bit retrieves the not recognized DSI data type from the Acknowledge error report.
+volatile unsigned int ack_with_err_12 :
+ 1; //[12] This bit retrieves the DSI VC ID Invalid from the Acknowledge error report.
+volatile unsigned int ack_with_err_13 :
+ 1; //[13] This bit retrieves the invalid transmission length from the Acknowledge error report.
+volatile unsigned int ack_with_err_14 :
+ 1; //[14] This bit retrieves the reserved (specific to device) from the Acknowledge error report
+volatile unsigned int ack_with_err_15 :
+ 1; //[15] This bit retrieves the DSI protocol violation from the Acknowledge error report.
+volatile unsigned int dphy_errors_0 :
+ 1; //[16] This bit indicates ErrEsc escape entry error from Lane 0.
+volatile unsigned int dphy_errors_1 :
+ 1; //[17] This bit indicates ErrSyncEsc low-power data transmission synchronization error from Lane 0.
+volatile unsigned int dphy_errors_2 :
+ 1; //[18] This bit indicates the ErrControl error from Lane 0.
+volatile unsigned int dphy_errors_3 :
+ 1; //[19] This bit indicates the LP0 contention error ErrContentionLP0 from Lane 0.
+volatile unsigned int dphy_errors_4 :
+ 1; //[20] This bit indicates the LP1 contention error ErrContentionLP1 from Lane 0.
+volatile unsigned int reserved_0 :
+ 11; //[31:21]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }
+ INT_ST0;// 0x00BC
+
+ union _DSIH1P21A_INT_ST1_tag_t {
+ struct _DSIH1P21A_INT_ST1_map_t
+ {
+volatile unsigned int to_hs_tx :
+ 1; //[0]
+ /*
+ This bit indicates that the high-speed transmission timeout counter
+ reached the end and contention is detected.
+ */
+volatile unsigned int to_lp_rx :
+ 1; //[1]
+ /*
+ This bit indicates that the low-power reception timeout counter reached
+ the end and contention is detected.
+ */
+volatile unsigned int ecc_single_err :
+ 1; //[2]
+ /*
+ This bit indicates that the ECC single error is detected and corrected in a
+ received packet.
+ */
+volatile unsigned int ecc_multi_err :
+ 1; //[3]
+ /*
+ This bit indicates that the ECC multiple error is detected in a received
+ packet.
+ */
+volatile unsigned int crc_err :
+ 1; //[4]
+ /*
+ This bit indicates that the CRC error is detected in the received packet
+ payload.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3 or
+ DSI_GENERIC = 1. Otherwise, this bit is reserved.
+ */
+volatile unsigned int pkt_size_err :
+ 1; //[5]
+ /*
+ This bit indicates that the packet size error is detected during the packet
+ reception.
+ */
+volatile unsigned int eopt_err :
+ 1; //[6]
+ /*
+ This bit indicates that the EoTp packet is not received at the end of the
+ incoming peripheral transmission
+ */
+volatile unsigned int dpi_pld_wr_err :
+ 1; //[7]
+ /*
+ This bit indicates that during a DPI pixel line storage, the payload FIFO
+ becomes full and the data stored is corrupted.
+ Dependency: DSI_DATAINTERFACE = 2 or DSI_DATAINTERFACE = 3 or
+ DSI_DATAINTERFACE = 4. Otherwise, this bit is reserved.
+ */
+volatile unsigned int gen_cmd_wr_err :
+ 1; //[8]
+ /*
+ This bit indicates that the system tried to write a command through the
+ Generic interface and the FIFO is full. Therefore, the command is not
+ written.
+ Dependency: DSI_GENERIC = 1. Otherwise, this bit is reserved
+ */
+volatile unsigned int gen_pld_wr_err :
+ 1; //[9]
+ /*
+ This bit indicates that the system tried to write a payload data through the
+ Generic interface and the FIFO is full. Therefore, the payload is not
+ written.
+ Dependency: DSI_GENERIC = 1. Otherwise, this bit is reserved
+ */
+volatile unsigned int gen_pld_send_err :
+ 1; //[10]
+ /*
+ This bit indicates that during a Generic interface packet build, the payload
+ FIFO becomes empty and corrupt data is sent.
+ Dependency: DSI_GENERIC = 1. Otherwise, this bit is reserved
+ */
+volatile unsigned int gen_pld_rd_err :
+ 1; //[11]
+ /*
+ This bit indicates that during a DCS read data, the payload FIFO becomes
+ empty and the data sent to the interface is corrupted.
+ Dependency: DSI_GENERIC = 1. Otherwise, this bit is reserved.
+ */
+volatile unsigned int gen_pld_recev_err :
+ 1; //[12]
+ /*
+ This bit indicates that during a generic interface packet read back, the
+ payload FIFO becomes full and the received data is corrupted.
+ Dependency: DSI_GENERIC = 1
+ If DSI_GENERIC = 0, this bit is reserved.
+ */
+volatile unsigned int dbi_cmd_wr_err :
+ 1; //[13]
+ /*
+ This bit indicates that the system tried to write a command through the
+ DBI but the command FIFO is full. Therefore, the command is not written.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3.
+ Otherwise, this bit is reserved.
+ */
+volatile unsigned int dbi_pld_wr_err :
+ 1; //[14]
+ /*
+ This bit indicates that the system tried to write the payload data through
+ the DBI interface and the FIFO is full. Therefore, the command is not
+ written.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3.
+ Otherwise, this bit is reserved.
+ */
+volatile unsigned int dbi_pld_rd_err :
+ 1; //[15]
+ /*
+ This bit indicates that during a DCS read data, the payload FIFO goes
+ empty and the data sent to the interface is corrupted.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3.
+ Otherwise, this bit is reserved.
+ */
+volatile unsigned int dbi_pld_recv_err :
+ 1; //[16]
+ /*
+ This bit indicates that during a DBI read back packet, the payload FIFO
+ becomes full and the received data is corrupted.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3.
+ Otherwise, this bit is reserved.
+ */
+
+volatile unsigned int dbi_ilegal_comm_err :
+ 1; //[17]
+ /*
+ This bit indicates that an attempt to write an illegal command on the DBI
+ interface is made and the core is blocked by transmission.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3.
+ Otherwise, this bit is reserved.
+ */
+volatile unsigned int reserved_0 :
+ 14; //[31:18]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }
+ INT_ST1;// 0x00C0
+
+
+ union _DSIH1P21A_INT_MSK0_tag_t {
+ struct _DSIH1P21A_INT_MSK0_map_t
+ {
+volatile unsigned int ack_with_err_0 :
+ 1; //[0] This bit retrieves the SoT error from the Acknowledge error report.
+volatile unsigned int ack_with_err_1 :
+ 1; //[1] This bit retrieves the SoT Sync error from the Acknowledge error report.
+volatile unsigned int ack_with_err_2 :
+ 1; //[2] This bit retrieves the EoT Sync error from the Acknowledge error report.
+volatile unsigned int ack_with_err_3 :
+ 1; //[3] This bit retrieves the Escape Mode Entry Command error from the Acknowledge error report.
+volatile unsigned int ack_with_err_4 :
+ 1; //[4] This bit retrieves the LP Transmit Sync error from the Acknowledge error report.
+volatile unsigned int ack_with_err_5 :
+ 1; //[5] This bit retrieves the Peripheral Timeout error from the Acknowledge Error report.
+volatile unsigned int ack_with_err_6 :
+ 1; //[6] This bit retrieves the False Control error from the Acknowledge error report.
+volatile unsigned int ack_with_err_7 :
+ 1; //[7] This bit retrieves the reserved (specific to device) from the Acknowledge error report.
+volatile unsigned int ack_with_err_8 :
+ 1; //[8] This bit retrieves the ECC error, single-bit (detected and corrected) from the Acknowledge error report.
+volatile unsigned int ack_with_err_9 :
+ 1; //[9] This bit retrieves the ECC error, multi-bit (detected, not corrected) from the Acknowledge error report.
+volatile unsigned int ack_with_err_10 :
+ 1; //[10]This bit retrieves the checksum error (long packet only) from the Acknowledge error report.
+volatile unsigned int ack_with_err_11 :
+ 1; //[11] This bit retrieves the not recognized DSI data type from the Acknowledge error report.
+volatile unsigned int ack_with_err_12 :
+ 1; //[12] This bit retrieves the DSI VC ID Invalid from the Acknowledge error report.
+volatile unsigned int ack_with_err_13 :
+ 1; //[13] This bit retrieves the invalid transmission length from the Acknowledge error report.
+volatile unsigned int ack_with_err_14 :
+ 1; //[14] This bit retrieves the reserved (specific to device) from the Acknowledge error report
+volatile unsigned int ack_with_err_15 :
+ 1; //[15] This bit retrieves the DSI protocol violation from the Acknowledge error report.
+volatile unsigned int dphy_errors_0 :
+ 1; //[16] This bit indicates ErrEsc escape entry error from Lane 0.
+volatile unsigned int dphy_errors_1 :
+ 1; //[17] This bit indicates ErrSyncEsc low-power data transmission synchronization error from Lane 0.
+volatile unsigned int dphy_errors_2 :
+ 1; //[18] This bit indicates the ErrControl error from Lane 0.
+volatile unsigned int dphy_errors_3 :
+ 1; //[19] This bit indicates the LP0 contention error ErrContentionLP0 from Lane 0.
+volatile unsigned int dphy_errors_4 :
+ 1; //[20] This bit indicates the LP1 contention error ErrContentionLP1 from Lane 0.
+volatile unsigned int reserved_0 :
+ 11; //[31:21]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }
+ INT_MSK0;// 0x00C4
+
+
+ union _DSIH1P21A_INT_MSK1_tag_t {
+ struct _DSIH1P21A_INT_MSK1_map_t
+ {
+volatile unsigned int to_hs_tx :
+ 1; //[0]
+ /*
+ This bit indicates that the high-speed transmission timeout counter
+ reached the end and contention is detected.
+ */
+volatile unsigned int to_lp_rx :
+ 1; //[1]
+ /*
+ This bit indicates that the low-power reception timeout counter reached
+ the end and contention is detected.
+ */
+volatile unsigned int ecc_single_err :
+ 1; //[2]
+ /*
+ This bit indicates that the ECC single error is detected and corrected in a
+ received packet.
+ */
+volatile unsigned int ecc_multi_err :
+ 1; //[3]
+ /*
+ This bit indicates that the ECC multiple error is detected in a received
+ packet.
+ */
+volatile unsigned int crc_err :
+ 1; //[4]
+ /*
+ This bit indicates that the CRC error is detected in the received packet
+ payload.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3 or
+ DSI_GENERIC = 1. Otherwise, this bit is reserved.
+ */
+volatile unsigned int pkt_size_err :
+ 1; //[5]
+ /*
+ This bit indicates that the packet size error is detected during the packet
+ reception.
+ */
+volatile unsigned int eopt_err :
+ 1; //[6]
+ /*
+ This bit indicates that the EoTp packet is not received at the end of the
+ incoming peripheral transmission
+ */
+volatile unsigned int dpi_pld_wr_err :
+ 1; //[7]
+ /*
+ This bit indicates that during a DPI pixel line storage, the payload FIFO
+ becomes full and the data stored is corrupted.
+ Dependency: DSI_DATAINTERFACE = 2 or DSI_DATAINTERFACE = 3 or
+ DSI_DATAINTERFACE = 4. Otherwise, this bit is reserved.
+ */
+volatile unsigned int gen_cmd_wr_err :
+ 1; //[8]
+ /*
+ This bit indicates that the system tried to write a command through the
+ Generic interface and the FIFO is full. Therefore, the command is not
+ written.
+ Dependency: DSI_GENERIC = 1. Otherwise, this bit is reserved
+ */
+volatile unsigned int gen_pld_wr_err :
+ 1; //[9]
+ /*
+ This bit indicates that the system tried to write a payload data through the
+ Generic interface and the FIFO is full. Therefore, the payload is not
+ written.
+ Dependency: DSI_GENERIC = 1. Otherwise, this bit is reserved
+ */
+volatile unsigned int gen_pld_send_err :
+ 1; //[10]
+ /*
+ This bit indicates that during a Generic interface packet build, the payload
+ FIFO becomes empty and corrupt data is sent.
+ Dependency: DSI_GENERIC = 1. Otherwise, this bit is reserved
+ */
+volatile unsigned int gen_pld_rd_err :
+ 1; //[11]
+ /*
+ This bit indicates that during a DCS read data, the payload FIFO becomes
+ empty and the data sent to the interface is corrupted.
+ Dependency: DSI_GENERIC = 1. Otherwise, this bit is reserved.
+ */
+volatile unsigned int gen_pld_recev_err :
+ 1; //[12]
+ /*
+ This bit indicates that during a generic interface packet read back, the
+ payload FIFO becomes full and the received data is corrupted.
+ Dependency: DSI_GENERIC = 1
+ If DSI_GENERIC = 0, this bit is reserved.
+ */
+volatile unsigned int dbi_cmd_wr_err :
+ 1; //[13]
+ /*
+ This bit indicates that the system tried to write a command through the
+ DBI but the command FIFO is full. Therefore, the command is not written.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3.
+ Otherwise, this bit is reserved.
+ */
+volatile unsigned int dbi_pld_wr_err :
+ 1; //[14]
+ /*
+ This bit indicates that the system tried to write the payload data through
+ the DBI interface and the FIFO is full. Therefore, the command is not
+ written.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3.
+ Otherwise, this bit is reserved.
+ */
+volatile unsigned int dbi_pld_rd_err :
+ 1; //[15]
+ /*
+ This bit indicates that during a DCS read data, the payload FIFO goes
+ empty and the data sent to the interface is corrupted.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3.
+ Otherwise, this bit is reserved.
+ */
+volatile unsigned int dbi_pld_recv_err :
+ 1; //[16]
+ /*
+ This bit indicates that during a DBI read back packet, the payload FIFO
+ becomes full and the received data is corrupted.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3.
+ Otherwise, this bit is reserved.
+ */
+
+volatile unsigned int dbi_ilegal_comm_err :
+ 1; //[17]
+ /*
+ This bit indicates that an attempt to write an illegal command on the DBI
+ interface is made and the core is blocked by transmission.
+ Dependency: DSI_DATAINTERFACE = 1 or DSI_DATAINTERFACE = 3.
+ Otherwise, this bit is reserved.
+ */
+volatile unsigned int reserved_0 :
+ 14; //[31:18]
+ }
+ mBits;
+ volatile unsigned int dValue;
+ }
+ INT_MSK1;// 0x00C8
+}DSIH1P21A_REG_T;
+
+uint32_t mipi_dsih_hal_get_version(dsih_ctrl_t * instance);
+
+void mipi_dsih_hal_power(dsih_ctrl_t * instance, int on);
+
+int mipi_dsih_hal_get_power(dsih_ctrl_t * instance);
+
+void mipi_dsih_hal_tx_escape_division(dsih_ctrl_t * instance, uint8_t tx_escape_division);
+
+void mipi_dsih_hal_dpi_video_vc(dsih_ctrl_t * instance, uint8_t vc);
+
+uint8_t mipi_dsih_hal_dpi_get_video_vc(dsih_ctrl_t * instance);
+
+dsih_error_t mipi_dsih_hal_dpi_color_coding(dsih_ctrl_t * instance, dsih_color_coding_t color_coding);
+dsih_color_coding_t mipi_dsih_hal_dpi_get_color_coding(dsih_ctrl_t * instance);
+uint8_t mipi_dsih_hal_dpi_get_color_depth(dsih_ctrl_t * instance);
+uint8_t mipi_dsih_hal_dpi_get_color_config(dsih_ctrl_t * instance);
+void mipi_dsih_hal_dpi_18_loosely_packet_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dpi_color_mode_pol(dsih_ctrl_t * instance, int active_low);
+void mipi_dsih_hal_dpi_shut_down_pol(dsih_ctrl_t * instance, int active_low);
+void mipi_dsih_hal_dpi_hsync_pol(dsih_ctrl_t * instance, int active_low);
+void mipi_dsih_hal_dpi_vsync_pol(dsih_ctrl_t * instance, int active_low);
+void mipi_dsih_hal_dpi_dataen_pol(dsih_ctrl_t * instance, int active_low);
+void mipi_dsih_hal_dpi_frame_ack_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dpi_null_packet_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dpi_multi_packet_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dpi_lp_during_hfp(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dpi_lp_during_hbp(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dpi_lp_during_vactive(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dpi_lp_during_vfp(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dpi_lp_during_vbp(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dpi_lp_during_vsync(dsih_ctrl_t * instance, int enable);
+
+dsih_error_t mipi_dsih_hal_dpi_video_mode_type(dsih_ctrl_t * instance, dsih_video_mode_t type);
+void mipi_dsih_hal_dpi_video_mode_en(dsih_ctrl_t * instance, int enable);
+int mipi_dsih_hal_dpi_is_video_mode(dsih_ctrl_t * instance);
+dsih_error_t mipi_dsih_hal_dpi_null_packet_size(dsih_ctrl_t * instance, uint16_t size);
+dsih_error_t mipi_dsih_hal_dpi_chunks_no(dsih_ctrl_t * instance, uint16_t no);
+dsih_error_t mipi_dsih_hal_dpi_video_packet_size(dsih_ctrl_t * instance, uint16_t size);
+
+void mipi_dsih_hal_tear_effect_ack_en(dsih_ctrl_t * instance, int enable);
+
+void mipi_dsih_hal_cmd_ack_en(dsih_ctrl_t * instance, int enable);
+dsih_error_t mipi_dsih_hal_dcs_wr_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp);
+dsih_error_t mipi_dsih_hal_dcs_rd_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp);
+/*Jessica add to support max rd packet size command*/
+dsih_error_t mipi_dsih_hal_max_rd_packet_size_type(dsih_ctrl_t * instance, int lp);
+dsih_error_t mipi_dsih_hal_gen_wr_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp);
+dsih_error_t mipi_dsih_hal_gen_rd_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp);
+void mipi_dsih_hal_max_rd_size_type(dsih_ctrl_t * instance, int lp);
+void mipi_dsih_hal_gen_cmd_mode_en(dsih_ctrl_t * instance, int enable);
+int mipi_dsih_hal_gen_is_cmd_mode(dsih_ctrl_t * instance);
+
+void mipi_dsih_hal_dpi_hline(dsih_ctrl_t * instance, uint16_t time);
+void mipi_dsih_hal_dpi_hbp(dsih_ctrl_t * instance, uint16_t time);
+void mipi_dsih_hal_dpi_hsa(dsih_ctrl_t * instance, uint16_t time);
+void mipi_dsih_hal_dpi_vactive(dsih_ctrl_t * instance, uint16_t lines);
+void mipi_dsih_hal_dpi_vfp(dsih_ctrl_t * instance, uint16_t lines);
+void mipi_dsih_hal_dpi_vbp(dsih_ctrl_t * instance, uint16_t lines);
+void mipi_dsih_hal_dpi_vsync(dsih_ctrl_t * instance, uint16_t lines);
+
+void mipi_dsih_hal_edpi_max_allowed_size(dsih_ctrl_t * instance, uint16_t size);
+
+dsih_error_t mipi_dsih_hal_gen_packet_header(dsih_ctrl_t * instance, uint8_t vc, uint8_t packet_type, uint8_t ms_byte, uint8_t ls_byte);
+dsih_error_t mipi_dsih_hal_gen_packet_payload(dsih_ctrl_t * instance, uint32_t payload);
+dsih_error_t mipi_dsih_hal_gen_read_payload(dsih_ctrl_t * instance, uint32_t* payload);
+
+void mipi_dsih_hal_timeout_clock_division(dsih_ctrl_t * instance, uint8_t byte_clk_division_factor);
+void mipi_dsih_hal_lp_rx_timeout(dsih_ctrl_t * instance, uint16_t count);
+void mipi_dsih_hal_hs_tx_timeout(dsih_ctrl_t * instance, uint16_t count);
+
+uint32_t mipi_dsih_hal_int_status_0(dsih_ctrl_t * instance, uint32_t mask);
+uint32_t mipi_dsih_hal_int_status_1(dsih_ctrl_t * instance, uint32_t mask);
+void mipi_dsih_hal_int_mask_0(dsih_ctrl_t * instance, uint32_t mask);
+void mipi_dsih_hal_int_mask_1(dsih_ctrl_t * instance, uint32_t mask);
+uint32_t mipi_dsih_hal_int_get_mask_0(dsih_ctrl_t * instance, uint32_t mask);
+uint32_t mipi_dsih_hal_int_get_mask_1(dsih_ctrl_t * instance, uint32_t mask);
+/* DBI command interface */
+void mipi_dsih_hal_dbi_out_color_coding(dsih_ctrl_t * instance, uint8_t color_depth, uint8_t option);
+void mipi_dsih_hal_dbi_in_color_coding(dsih_ctrl_t * instance, uint8_t color_depth, uint8_t option);
+void mipi_dsih_hal_dbi_lut_size(dsih_ctrl_t * instance, uint8_t size);
+void mipi_dsih_hal_dbi_partitioning_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_dbi_dcs_vc(dsih_ctrl_t * instance, uint8_t vc);
+
+void mipi_dsih_hal_dbi_cmd_size(dsih_ctrl_t * instance, uint16_t size);
+void mipi_dsih_hal_dbi_max_cmd_size(dsih_ctrl_t * instance, uint16_t size);
+int mipi_dsih_hal_dbi_rd_cmd_busy(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_read_fifo_full(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_read_fifo_empty(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_write_fifo_full(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_write_fifo_empty(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_cmd_fifo_full(dsih_ctrl_t * instance);
+int mipi_dsih_hal_dbi_cmd_fifo_empty(dsih_ctrl_t * instance);
+/* Generic command interface */
+void mipi_dsih_hal_gen_rd_vc(dsih_ctrl_t * instance, uint8_t vc);
+void mipi_dsih_hal_gen_eotp_rx_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_gen_eotp_tx_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_bta_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_gen_ecc_rx_en(dsih_ctrl_t * instance, int enable);
+void mipi_dsih_hal_gen_crc_rx_en(dsih_ctrl_t * instance, int enable);
+int mipi_dsih_hal_gen_rd_cmd_busy(dsih_ctrl_t * instance);
+int mipi_dsih_hal_gen_read_fifo_full(dsih_ctrl_t * instance);
+int mipi_dsih_hal_gen_read_fifo_empty(dsih_ctrl_t * instance);
+int mipi_dsih_hal_gen_write_fifo_full(dsih_ctrl_t * instance);
+int mipi_dsih_hal_gen_write_fifo_empty(dsih_ctrl_t * instance);
+int mipi_dsih_hal_gen_cmd_fifo_full(dsih_ctrl_t * instance);
+int mipi_dsih_hal_gen_cmd_fifo_empty(dsih_ctrl_t * instance);
+
+/* only if DPI */
+dsih_error_t mipi_dsih_phy_hs2lp_config(dsih_ctrl_t * instance, uint8_t no_of_byte_cycles);
+dsih_error_t mipi_dsih_phy_lp2hs_config(dsih_ctrl_t * instance, uint8_t no_of_byte_cycles);
+dsih_error_t mipi_dsih_phy_clk_lp2hs_config(dsih_ctrl_t * instance, uint8_t no_of_byte_cycles);
+dsih_error_t mipi_dsih_phy_clk_hs2lp_config(dsih_ctrl_t * instance, uint8_t no_of_byte_cycles);
+dsih_error_t mipi_dsih_phy_bta_time(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles);
+void mipi_dsih_non_continuous_clock(dsih_ctrl_t * instance, int enable);
+int mipi_dsih_non_continuous_clock_status(dsih_ctrl_t * instance);
+/* PRESP Time outs */
+void mipi_dsih_hal_presp_timeout_low_power_write(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles);
+void mipi_dsih_hal_presp_timeout_low_power_read(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles);
+void mipi_dsih_hal_presp_timeout_high_speed_write(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles);
+void mipi_dsih_hal_presp_timeout_high_speed_read(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles);
+void mipi_dsih_hal_presp_timeout_bta(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles);
+/* bsp abstraction */
+void mipi_dsih_write_word(dsih_ctrl_t * instance, uint32_t reg_address, uint32_t data);
+void mipi_dsih_write_part(dsih_ctrl_t * instance, uint32_t reg_address, uint32_t data, uint8_t shift, uint8_t width);
+uint32_t mipi_dsih_read_word(dsih_ctrl_t * instance, uint32_t reg_address);
+uint32_t mipi_dsih_read_part(dsih_ctrl_t * instance, uint32_t reg_address, uint8_t shift, uint8_t width);
+
+#endif /* MIPI_DSI_API_H_ */
diff --git a/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_local.h b/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_local.h
new file mode 100644
index 00000000..98c3aecd
--- /dev/null
+++ b/drivers/video/sprdfb/dsi_1_21a/mipi_dsih_local.h
@@ -0,0 +1,361 @@
+/**
+ * @file mipi_dsih_local.h
+ * @brief instance context structure and enumerator definitions:
+ * errors, events, color coding, video modes and driver state
+ *
+ * Synopsys Inc.
+ * SG DWC PT02
+ */
+/*
+ The Synopsys Software Driver and documentation (hereinafter "Software")
+ is an unsupported work of Synopsys, Inc. unless otherwise
+ expressly agreed to in writing between Synopsys and you.
+
+ The Software IS NOT an item of Licensed Software or Licensed Product under
+ any End User Software License Agreement or Agreement for Licensed Product
+ with Synopsys or any supplement thereto. Permission is hereby granted,
+ free of charge, to any person obtaining a copy of this software annotated
+ with this license and the Software, to deal in the Software without
+ restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so, subject
+ to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
+ */
+
+#ifndef MIPI_DSIH_LOCAL_H_
+#define MIPI_DSIH_LOCAL_H_
+
+//#include <stdint.h>
+#include <linux/kernel.h>
+#include "../sprdfb_chip_common.h"
+
+
+//typedef unsigned char uint8_t;
+//typedef unsigned short uint16_t;
+//typedef unsigned int uint32_t;
+
+#define DSIH_PIXEL_TOLERANCE (2)
+#define DSIH_FIFO_ACTIVE_WAIT (5000) /* no of tries to access the fifo */
+#define DSIH_PHY_ACTIVE_WAIT (50000)
+#define ONE_MS_ACTIVE_WAIT (50000) /* 50MHz processor */
+#define DEFAULT_BYTE_CLOCK (432000) /* a value to start PHY PLL - random */
+#define MAX_NULL_SIZE (1023)
+#define FIFO_DEPTH (1096)
+#define WORD_LENGTH (4) /* bytes (32bit registers) */
+
+/** Define D-PHY type */
+
+#ifdef SPRD_MIPI_DPHY_GEN1
+/** DWC_MIPI_DPHY_BIDIR_TSMC40LP 4 Lanes Gen 1 1GHz */
+#define DWC_MIPI_DPHY_BIDIR_TSMC40LP
+#endif
+#ifdef SPRD_MIPI_DPHY_GEN2
+/** DWC_MIPI_DPHY_BIDIR_TSMC40LP / GF28LP 4 Lanes Gen 2 1.5GHz */
+#define GEN_2
+#endif
+/** 4 Lanes Gen 2 1.5GHz testchips */
+//#define TESTCHIP
+/** TQL 2 Lane test chip */
+/* #define DPHY2Btql */
+
+/**
+ * Errors generated by the DSI Host controller driver
+ */
+typedef enum
+{
+ OK = 0,
+ ERR_DSI_COLOR_CODING,
+ ERR_DSI_OUT_OF_BOUND,
+ ERR_DSI_OVERFLOW,
+ ERR_DSI_INVALID_INSTANCE,
+ ERR_DSI_INVALID_IO,
+ ERR_DSI_CORE_INCOMPATIBLE,
+ ERR_DSI_VIDEO_MODE,
+ ERR_DSI_INVALID_COMMAND,
+ ERR_DSI_INVALID_EVENT,
+ ERR_DSI_INVALID_HANDLE,
+ ERR_DSI_PHY_POWERUP,
+ ERR_DSI_PHY_INVALID,
+ ERR_DSI_PHY_FREQ_OUT_OF_BOUND,
+//#ifdef GEN_2
+ ERR_DSI_PHY_PLL_NOT_LOCKED,
+//#endif
+ ERR_DSI_TIMEOUT
+}
+dsih_error_t;
+/**
+ * Video stream type
+ */
+typedef enum
+{
+ VIDEO_NON_BURST_WITH_SYNC_PULSES = 0,
+ VIDEO_NON_BURST_WITH_SYNC_EVENTS,
+ VIDEO_BURST_WITH_SYNC_PULSES
+}
+dsih_video_mode_t;
+/**
+ * Color coding type (depth and pixel configuration)
+ */
+typedef enum
+{
+ COLOR_CODE_16BIT_CONFIG1 = 0,
+ COLOR_CODE_16BIT_CONFIG2 = 1,
+ COLOR_CODE_16BIT_CONFIG3 = 2,
+ COLOR_CODE_18BIT_CONFIG1 = 3,
+ COLOR_CODE_18BIT_CONFIG2 = 4,
+ COLOR_CODE_24BIT = 5,
+ COLOR_CODE_20BIT_YCC422_LOOSELY = 6,
+ COLOR_CODE_24BIT_YCC422 = 7,
+ COLOR_CODE_16BIT_YCC422 = 8,
+ COLOR_CODE_30BIT = 9,
+ COLOR_CODE_36BIT = 10,
+ COLOR_CODE_12BIT_YCC420 = 11,
+ COLOR_CODE_MAX
+}
+dsih_color_coding_t;
+/**
+ * Events generated by the DSI Host controller
+ */
+typedef enum
+{
+ ACK_SOT_ERR = 0,
+ ACK_SOT_SYNC,
+ ACK_EOT_SYNC,
+ ACK_ESCAPE_CMD_ERR,
+ ACK_LP_TX_SYNC_ERR,
+ ACK_HS_RX_TIMEOUT_ERR,
+ ACK_FALSE_CONTROL_ERR,
+ ACK_RSVD_DEVICE_ERR_7,
+ ACK_ECC_SINGLE_BIT_ERR,
+ ACK_ECC_MULTI_BIT_ERR,
+ ACK_CHECKSUM_ERR,
+ ACK_DSI_TYPE_NOT_RECOGNIZED_ERR,
+ ACK_VC_ID_INVALID_ERR,
+ ACK_INVALID_TX_LENGTH_ERR,
+ ACK_RSVD_DEVICE_ERR_14,
+ ACK_DSI_PROTOCOL_ERR,
+
+ DPHY_ESC_ENTRY_ERR,
+ DPHY_SYNC_ESC_LP_ERR,
+ DPHY_CONTROL_LANE0_ERR,
+ DPHY_CONTENTION_LP0_ERR,
+ DPHY_CONTENTION_LP1_ERR,
+ /* start of st1 */
+ HS_CONTENTION,
+ LP_CONTENTION,
+ RX_ECC_SINGLE_ERR,
+ RX_ECC_MULTI_ERR,
+ RX_CRC_ERR,
+ RX_PKT_SIZE_ERR,
+ RX_EOTP_ERR,
+ DPI_PLD_FIFO_FULL_ERR,
+ GEN_TX_CMD_FIFO_FULL_ERR,
+ GEN_TX_PLD_FIFO_FULL_ERR,
+ GEN_TX_PLD_FIFO_EMPTY_ERR,
+ GEN_RX_PLD_FIFO_EMPTY_ERR,
+ GEN_RX_PLD_FIFO_FULL_ERR,
+
+ DBI_TX_CMD_FIFO_FULL_ERR,
+ DBI_TX_PLD_FIFO_FULL_ERR,
+ DBI_RX_PLD_FIFO_EMPTY_ERR,
+ DBI_RX_PLD_FIFO_FULL_ERR,
+ DBI_ILLEGAL_CMD_ERR,
+ DSI_MAX_EVENT
+}
+dsih_event_t;
+/**
+ * DSI Host state machine states
+ * Holds the mapping of D-PHY to the OS, logging I/O, and hardware access layer.
+ */
+typedef enum
+{
+ NOT_INITIALIZED = 0,
+ INITIALIZED,
+ ON,
+ OFF
+}
+dsih_state_t;
+
+/**
+ * MIPI D-PHY
+ * Holds the mapping of API to the OS, logging I/O, and hardware access layer
+ * and HW module information.
+ */
+typedef struct dphy_t
+{
+ /** Physical base address of PHY module - REQUIRED */
+ unsigned long address;
+ /** Reference frequency provided to PHY module [KHz] - REQUIRED */
+ uint32_t reference_freq;
+#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING
+ /** mark if D-PHY should keep work or not */
+ uint32_t phy_keep_work;
+#endif
+ /** D-PHY driver state - used internally by driver */
+ dsih_state_t status;
+ /** Function handle of any board function that needs to be called
+ * in order to set up the environment for the D-PHY before it is
+ * configured. */
+ void (*bsp_pre_config)(struct dphy_t *instance, void* param);
+ /** Register read access function handle - REQUIRED */
+ uint32_t (*core_read_function)(unsigned long addr, uint32_t offset);
+ /** Register write access function handle - REQUIRED */
+ void (*core_write_function)(unsigned long addr, uint32_t offset, uint32_t data);
+ /** Log errors function handle */
+ void (*log_error)(const char * string);
+ /** Log information function handle */
+ void (*log_info)(const char *fmt, ...);
+}
+dphy_t;
+
+/**
+ * MIPI DSI Host Controller
+ * Holds important information for the functioning of the DSI Host Controller API
+ * Holds the mapping of API to the OS, logging I/O, and hardware access layer.
+ * It also holds important information set by the user about the HW considerations
+ * and internal state variables.
+ */
+typedef struct dsih_ctrl_t
+{
+ /** Physical base address of controller - REQUIRED */
+ unsigned long address;
+ /** D-PHY instance associated with the DSI host controller - REQUIRED */
+ dphy_t phy_instance;
+ /**D-PHY frequency*/
+ uint32_t phy_feq;
+ /** Number of lanes physically connected to controller - REQUIRED */
+ uint8_t max_lanes;
+ /** Maximum number of byte clock cycles needed by the PHY to perform
+ * the Bus Turn Around operation - REQUIRED */
+ uint16_t max_bta_cycles;
+ /** Describe the color mode pin (dpicolorm) whether it is active high or low - REQUIRED */
+ int color_mode_polarity;
+ /** Describe the shut down pin (dpishutdn) whether it is active high or low - REQUIRED */
+ int shut_down_polarity;
+ /** initialised or not */
+ dsih_state_t status;
+ /** Register read access function handle - REQUIRED */
+ uint32_t (*core_read_function)(unsigned long addr, uint32_t offset);
+ /** Register write access function handle - REQUIRED */
+ void (*core_write_function)(unsigned long addr, uint32_t offset, uint32_t data);
+ /** Log errors function handle */
+ void (*log_error)(const char * string);
+ /** Log information function handle */
+ void (*log_info)(const char *fmt, ...);
+ /** Event registry holds handlers of the callbacks of registered events */
+ void (*event_registry[DSI_MAX_EVENT])(struct dsih_ctrl_t *instance, void *handler);
+}
+dsih_ctrl_t;
+/**
+ * Video configurations
+ * Holds information about the video stream to be sent through the DPI interface.
+ */
+typedef struct
+{
+ /** Number of lanes used to send current video */
+ uint8_t no_of_lanes;
+ /** Virtual channel number to send this video stream */
+ uint8_t virtual_channel;
+ /** Video mode, whether burst with sync pulses, or packets with either sync pulses or events */
+ dsih_video_mode_t video_mode;
+ /** Maximum number of byte clock cycles needed by the PHY to transition
+ * the data lanes from high speed to low power - REQUIRED */
+ uint8_t max_hs_to_lp_cycles;
+ /** Maximum number of byte clock cycles needed by the PHY to transition
+ * the data lanes from low power to high speed - REQUIRED */
+ uint8_t max_lp_to_hs_cycles;
+ /** Maximum number of byte clock cycles needed by the PHY to transition
+ * the clock lane from high speed to low power - REQUIRED */
+ uint8_t max_clk_hs_to_lp_cycles;
+ /** Maximum number of byte clock cycles needed by the PHY to transition
+ * the clock lane from low power to high speed - REQUIRED */
+ uint8_t max_clk_lp_to_hs_cycles;
+ /** Enable non coninuous clock for energy saving
+ * - Clock lane will go to LS while not transmitting video */
+ int non_continuous_clock;
+ /** Enable receiving of ack packets */
+ int receive_ack_packets;
+ /** Byte (lane) clock [KHz] */
+ uint32_t byte_clock;
+ /** Pixel (DPI) Clock [KHz]*/
+ uint32_t pixel_clock;
+ /** Colour coding - BPP and Pixel configuration */
+ dsih_color_coding_t color_coding;
+ /** Is 18-bit loosely packets (valid only when BPP == 18) */
+ int is_18_loosely;
+ /** Data enable signal (dpidaten) whether it is active high or low */
+ int data_en_polarity;
+ /** Horizontal synchronisation signal (dpihsync) whether it is active high or low */
+ int h_polarity;
+ /** Horizontal resolution or Active Pixels */
+ uint16_t h_active_pixels; /* hadr */
+ /** Horizontal Sync Pixels - min 4 for best performance */
+ uint16_t h_sync_pixels;
+ /** Horizontal back porch pixels */
+ uint16_t h_back_porch_pixels; /* hbp */
+ /** Total Horizontal pixels */
+ uint16_t h_total_pixels; /* h_total */
+ /** Vertical synchronisation signal (dpivsync) whether it is active high or low */
+ int v_polarity;
+ /** Vertical active lines (resolution) */
+ uint16_t v_active_lines; /* vadr */
+ /** Vertical sync lines */
+ uint16_t v_sync_lines;
+ /** Vertical back porch lines */
+ uint16_t v_back_porch_lines; /* vbp */
+ /** Total no of vertical lines */
+ uint16_t v_total_lines; /* v_total */
+}
+dsih_dpi_video_t;
+
+typedef struct
+{
+ /** virtual channel */
+ uint8_t virtual_channel;
+ /** Commands to be sent in high speed or low power */
+ int lp;
+ /** Colour coding - BPP and Pixel configuration */
+ dsih_color_coding_t color_coding;
+ /** Top horizontal pixel position in the display */
+ uint16_t h_start;
+ /** Horizontal resolution or Active Pixels */
+ uint16_t h_active_pixels; /* hadr */
+ /** Left most line position in the display */
+ uint16_t v_start;
+ /** Vertical active lines (resolution) */
+ uint16_t v_active_lines; /* vadr */
+ /** Whether Tearing effect should be requested */
+ int te;
+ /** packet size of write memory command -
+ * 0 is default (optimum usage of RAM) */
+ uint16_t packet_size;
+}
+dsih_cmd_mode_video_t;
+/**
+ * Register configurations
+ */
+typedef struct
+{
+ /** Register offset */
+ uint32_t addr;
+ /** Register data [in or out] */
+ uint32_t data;
+}
+register_config_t;
+
+#endif /* MIPI_DSIH_LOCAL_H_ */
diff --git a/drivers/video/sprdfb/lcd/Makefile b/drivers/video/sprdfb/lcd/Makefile
new file mode 100644
index 00000000..6d392745
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/Makefile
@@ -0,0 +1,50 @@
+obj-$(CONFIG_FB_LCD_HX8363_RGB_SPI) += lcd_hx8363_rgb_spi.o
+obj-$(CONFIG_FB_LCD_HX8363_MCU) += lcd_hx8363_mcu.o
+obj-$(CONFIG_FB_LCD_HX8369) += lcd_hx8369.o
+obj-$(CONFIG_FB_LCD_S6D0139) += lcd_s6d0139.o
+obj-$(CONFIG_FB_LCD_NT35516_MCU) += lcd_nt35516_mcu.o
+obj-$(CONFIG_FB_LCD_NT35516_MIPI) += lcd_nt35516_mipi.o
+obj-$(CONFIG_FB_LCD_NT35516_RGB_I2C) += lcd_nt35516_rgb_i2c.o
+obj-$(CONFIG_FB_LCD_NT35516_RGB_SPI) += lcd_nt35516_rgb_spi.o
+obj-$(CONFIG_FB_LCD_NT35510_MIPI) += lcd_nt35510_mipi.o
+obj-$(CONFIG_FB_LCD_NT35512_MIPI) += lcd_nt35512_mipi.o
+obj-$(CONFIG_FB_LCD_OTM8018B_MIPI) += lcd_otm_8018b_mipi.o
+obj-$(CONFIG_FB_LCD_SSD2075_MIPI) += lcd_ssd2075_mipi.o
+obj-$(CONFIG_FB_LCD_ILI9486) += lcd_ili9486.o
+obj-$(CONFIG_FB_LCD_ILI9486_RGB_SPI) += lcd_ili9486_rgb_spi.o
+obj-$(CONFIG_FB_LCD_NT51017_MIPI_LVDS) += lcd_nt51017_mipi_lvds.o
+obj-$(CONFIG_FB_LCD_HX8369B_MIPI) += lcd_hx8369b_mipi.o
+obj-$(CONFIG_FB_LCD_HX8369B_MIPI_KIRAN3G) += lcd_hx8369b_mipi_kiran3g.o
+obj-$(CONFIG_FB_LCD_HX8369B_MIPI_COREPRIMELITE) += lcd_hx8369b_mipi_coreprimelite.o
+obj-$(CONFIG_FB_LCD_SD7798D_MIPI_COREPRIMELITE) += lcd_sd7798d_mipi.o
+obj-$(CONFIG_FB_LCD_HX8369B_MIPI_SHARKLS_Z3LTE) += lcd_hx8369b_mipi_sharkls_z3lte.o
+obj-$(CONFIG_FB_LCD_SD7798D_MIPI_SHARKLS_Z3LTE) += lcd_sd7798d_mipi_sharkls_z3lte.o
+obj-$(CONFIG_FB_LCD_ILI9341) += lcd_ili9341.o
+obj-$(CONFIG_FB_LCD_ST7789V_MCU) += lcd_st7789v_mcu.o
+obj-$(CONFIG_FB_LCD_OTM1283A_MIPI) += lcd_otm1283a_mipi.o
+obj-$(CONFIG_FB_LCD_NT35502_MIPI) += lcd_nt35502_mipi.o
+obj-$(CONFIG_FB_LCD_VIVA_RGB_SPI) += lcd_hx8363_rgb_spi_viva.o
+obj-$(CONFIG_FB_LCD_SC7798_RGB_SPI) += lcd_sc7798_rgb_spi.o
+obj-$(CONFIG_FB_LCD_ILI9806E_MIPI) += lcd_ili9806e_mipi.o
+obj-$(CONFIG_FB_LCD_ILI9806E_2_MIPI) += lcd_ili9806e_2_mipi.o
+obj-$(CONFIG_FB_LCD_T8861_MIPI) += lcd_t8861_mipi.o
+obj-$(CONFIG_FB_LCD_HX8379A_MIPI) += lcd_hx8379a_mipi.o
+obj-$(CONFIG_FB_LCD_HX8389C_MIPI) += lcd_hx8389c_mipi.o
+obj-$(CONFIG_FB_LCD_ILI6150_LVDS) += lcd_ili6150_lvds.o
+obj-$(CONFIG_FB_LCD_RM68180_MIPI) += lcd_rm68180_mipi.o
+obj-$(CONFIG_FB_LCD_ILI9486S1_MIPI) += lcd_ili9486s1_mipi.o
+obj-$(CONFIG_FB_LCD_VX5B3D_MIPI) += lcd_vx5b3d_mipi.o
+obj-$(CONFIG_FB_LCD_HX8369B_MIPI_VIVALTO_VE) += lcd_hx8369b_mipi_vivaltoVE.o
+obj-$(CONFIG_FB_LCD_GRANDNEO_MIPI) += lcd_hx8369b_grandneo_mipi.o
+obj-$(CONFIG_FB_LCD_TSHARK2_J3_MIPI) += lcd_hx8369b_tshark2_j3_mipi.o
+obj-$(CONFIG_FB_LCD_SD7798D_MIPI) += lcd_sd7798d_mipi.o
+obj-$(CONFIG_FB_LCD_S6D77A1_MIPI_PIKEA_J1) += lcd_s6d77a1_pikeA_mipi.o
+obj-$(CONFIG_FB_LCD_NT51017_MIPI) += lcd_nt51017_goyal_mipi.o
+obj-$(CONFIG_FB_LCD_OTM8019A_MIPI) += lcd_otm8019a_mipi.o
+obj-$(CONFIG_FB_LCD_FL10802_MIPI) += lcd_fl10802_mipi.o
+obj-$(CONFIG_FB_LCD_JD9161_MIPI) += lcd_jd9161_mipi.o
+obj-$(CONFIG_FB_LCD_HX8394D_MIPI) += lcd_hx8394d_mipi.o
+obj-$(CONFIG_FB_LCD_HX8394A_MIPI) += lcd_hx8394a_mipi.o
+obj-$(CONFIG_FB_LCD_NT35596H_MIPI) += lcd_nt35596h_mipi.o
+obj-$(CONFIG_FB_LCD_S6D7AA0X62_MIPI) += lcd_s6d7aa0x62_t8_mipi.o
+obj-$(CONFIG_FB_LCD_DUMMY) += lcd_dummy.o
diff --git a/drivers/video/sprdfb/lcd/lcd_dummy.c b/drivers/video/sprdfb/lcd/lcd_dummy.c
new file mode 100644
index 00000000..6254daf5
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_dummy.c
@@ -0,0 +1,104 @@
+/* drivers/video/sc8825/lcd_dummy.c
+ *
+ * Support for dummy LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+static int32_t dummy_mipi_init(struct panel_spec *self)
+{
+ pr_debug(KERN_DEBUG "dummy_init\n");
+ return 0;
+}
+
+static uint32_t dummy_readid(struct panel_spec *self)
+{
+ printk("lcd_dummy read id!\n");
+ printk("lcd_dummy read id success!\n");
+ return 0xFFFFFFFF;
+}
+
+static int32_t dummy_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ printk(KERN_DEBUG "dummy_enter_sleep, is_sleep = %d\n", is_sleep);
+ return 0;
+}
+
+static int32_t dummy_check_esd(struct panel_spec *self)
+{
+ pr_debug("dummy_check_esd!\n");
+ pr_debug("dummy_check_esd OK!\n");
+ return 1;
+}
+
+static struct panel_operations lcd_dummy_operations = {
+ .panel_init = dummy_mipi_init,
+ .panel_readid = dummy_readid,
+ .panel_enter_sleep = dummy_enter_sleep,
+ .panel_esd_check = dummy_check_esd,
+};
+
+static struct timing_rgb lcd_dummy_timing = {
+ .hfp = 20, /* unit: pixel */
+ .hbp = 20,
+ .hsync = 20,//4,
+ .vfp = 10, /*unit: line*/
+ .vbp = 10,
+ .vsync = 6,
+};
+
+static struct info_mipi lcd_dummy_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 3,
+ .phy_feq = 500*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_dummy_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_dummy_spec = {
+ .width = 320,
+ .height = 480,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .is_clean_lcd = true,
+ .info = {
+ .mipi = &lcd_dummy_info
+ },
+ .ops = &lcd_dummy_operations,
+};
+
+struct panel_cfg lcd_dummy = {
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0xFFFFFFFF,
+ .lcd_name = "lcd_dummy",
+ .panel = &lcd_dummy_spec,
+};
+
+static int __init lcd_dummy_init(void)
+{
+ return sprdfb_panel_register(&lcd_dummy);
+}
+
+subsys_initcall(lcd_dummy_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_fl10802_mipi.c b/drivers/video/sprdfb/lcd/lcd_fl10802_mipi.c
new file mode 100644
index 00000000..48565bb5
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_fl10802_mipi.c
@@ -0,0 +1,364 @@
+/* drivers/video/sc8825/lcd_fl10802_mipi.c
+ *
+ * Support for fl10802 mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+//#define LCD_Delay(ms) uDelay(ms*1000)
+
+#define MAX_DATA 80//48
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Force_Cmd_Code rd_prep_code[]={
+ {0x39,LCM_SEND(6), {4,0,0xb9,0xf1,0x08,0x01}},
+ {0x39,LCM_SEND(20), {18,0,0xba,0x31,0x00,0x44,0x25,0xb1,0x0a,0x00,0x00,0xc1,0x00,0x00,0x00,0x0d,0x02,0x5d,0xb5,0xee}},
+
+ {0x37,{LCM_SEND(2),{0x3,0}}},
+};
+
+static LCM_Force_Cmd_Code rd_prep_code_1[]={
+ {0x39,LCM_SEND(6), {4,0,0xb9,0xf1,0x08,0x01}},
+ {0x39,LCM_SEND(20), {18,0,0xba,0x31,0x00,0x44,0x25,0xb1,0x0a,0x00,0x00,0xc1,0x00,0x00,0x00,0x0d,0x02,0x5d,0xb5,0xee}},
+
+ {0x37,{LCM_SEND(2),{0x1,0}}},
+};
+
+
+static LCM_Init_Code init_data[] = {
+
+
+{LCM_SEND(6), {4,0,0xB9,0xF1,0x08,0x01}},
+
+{LCM_SEND(10), {8,0,0xB1,0x21,0x1E,0x1E,0x87,0x30,0x01,0x8B}},
+
+{LCM_SEND(2), {0xB2,0x23}},
+
+{LCM_SEND(11), {9,0,0xB3,0x00,0x00,0x06,0x06,0x20,0x20,0x30,0x30}},
+
+{LCM_SEND(20), {18,0,0xBA,0x31,0x00,0x44,0x25,0x91,0x0A,0x00,0x00,0xC1,
+ 0x00,0x00,0x00,0x0D,0x02,0x1D,0xB9,0xEE}},
+
+{LCM_SEND(8), {6,0,0xE3,0x04,0x04,0x01,0x01,0x00}},
+
+{LCM_SEND(2), {0xB4,0x02}}, // 2-dot
+
+{LCM_SEND(5), {3,0,0xB5,0x05,0x05}},
+
+{LCM_SEND(5), {3,0,0xB6,0x8C,0x8C}}, //VCOM //0x8C
+
+{LCM_SEND(5), {3,0,0xB8,0x64,0x28}}, //2x, -2.5x
+
+{LCM_SEND(2), {0xCC,0x00}},
+
+{LCM_SEND(2), {0xBC,0x44}},
+
+{LCM_SEND(54), {52,0,0xE9,0x00,0x00,0x07,0x00,0x00,0x81,0x89,0x12,0x31,
+ 0x23,0x23,0x08,0x81,0x80,0x23,0x00,0x00,0x10,0x00,
+ 0x00,0x00,0x0F,0x89,0x13,0x18,0x88,0x88,0x88,0x88,
+ 0x88,0x88,0x89,0x02,0x08,0x88,0x88,0x88,0x88,0x88,
+ 0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00}},
+
+{LCM_SEND(25), {23,0,0xEA,0x90,0x00,0x00,0x00,0x88,0x20,0x09,0x88,0x88,
+ 0x88,0x88,0x88,0x88,0x88,0x31,0x19,0x88,0x88,0x88,
+ 0x88,0x88,0x88}},
+
+{LCM_SEND(37), {35,0,0xE0,0x00,0x00,0x00,0x16,0x17,0x27,0x2D,0x3C,0x0A,
+ 0x13,0x12,0x17,0x19,0x17,0x17,0x12,0x16,
+ 0x00,0x00,0x00,0x16,0x17,0x27,0x2D,0x3C,0x0A,
+ 0x13,0x12,0x17,0x19,0x17,0x17,0x12,0x16}},
+
+
+
+{LCM_SEND(2), {0x11,0x00}},
+{LCM_SLEEP(120),},
+
+{LCM_SEND(2), {0x29,0x00}},
+{LCM_SLEEP(10),},
+
+};
+
+
+//static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+{LCM_SEND(1), {0x28}},
+{LCM_SLEEP(20)},
+{LCM_SEND(1), {0x10}},
+{LCM_SLEEP(120)},
+};
+
+static LCM_Init_Code sleep_out[] = {
+{LCM_SEND(1), {0x11}},
+{LCM_SLEEP(120)},
+{LCM_SEND(1), {0x29}},
+{LCM_SLEEP(20)},
+};
+
+static int32_t fl10802_mipi_init(struct panel_spec *self)
+{
+ int32_t i;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_debug(KERN_DEBUG "fl10802_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(1,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((init->tag & LCM_TAG_MASK));
+ }
+ init++;
+ }
+ mipi_eotp_set(1,1);
+ return 0;
+}
+
+static uint32_t fl10802_readid(struct panel_spec *self)
+{
+ /*Jessica TODO: need read id*/
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code;
+ uint8_t read_data[5] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel lcd_fl10802_mipi read id!\n");
+ #if 1
+ //self->info.mipi->ops->mipi_set_lp_mode();
+ mipi_set_cmd_mode();
+ mipi_eotp_set(1,0);
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ udelay((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK) * 1000);
+ }
+ rd_prepare++;
+ }
+ read_rtn = mipi_force_read(0x04, 3,(uint8_t *)read_data);
+ printk("kernel lcd_fl10802_mipi read id 0xa1 value is 0x%x, 0x%x, 0x%x!\n", read_data[0], read_data[1], read_data[2]);
+ mipi_eotp_set(1,1);
+ if((0x10 == read_data[0])&&(0x80== read_data[1])&&(0x1A == read_data[2])){
+ printk(" kernel lcd_fl10802_mipi read id success!\n");
+ return 0x1080;
+ }
+ }
+ #endif
+ printk("lcd_fl10802_mipi identify fail!\n");
+ //self->info.mipi->ops->mipi_set_hs_mode();
+ return 0x0;
+}
+
+static uint32_t fl10802_readpowermode(struct panel_spec *self)
+{
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code_1;
+ uint8_t read_data[1] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_debug("lcd_fl10802_mipi read power mode!\n");
+ mipi_eotp_set(0,1);
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code_1;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code_1); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }
+ rd_prepare++;
+ }
+ read_rtn = mipi_force_read(0x0A, 1,(uint8_t *)read_data);
+ printk("lcd_fl10802_mipi read power mode 0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+ if((0x9c == read_data[0]) && (0 == read_rtn)){
+ pr_debug("lcd_fl10802a_mipi read power mode success!\n");
+ mipi_eotp_set(1,1);
+ return 0x9c;
+ }
+ }
+
+ printk("lcd_fl10802_mipi read power mode fail!0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+ mipi_eotp_set(1,1);
+ return 0x0;
+}
+
+static int32_t fl10802_check_esd(struct panel_spec *self)
+{
+ uint32_t power_mode;
+
+ mipi_set_lp_mode_t mipi_set_data_lp_mode = self->info.mipi->ops->mipi_set_data_lp_mode;
+ mipi_set_hs_mode_t mipi_set_data_hs_mode = self->info.mipi->ops->mipi_set_data_hs_mode;
+ mipi_set_lp_mode_t mipi_set_lp_mode = self->info.mipi->ops->mipi_set_lp_mode;
+ mipi_set_hs_mode_t mipi_set_hs_mode = self->info.mipi->ops->mipi_set_hs_mode;
+ uint16_t work_mode = self->info.mipi->work_mode;
+
+ pr_debug("fl10802_check_esd!\n");
+ power_mode = fl10802_readpowermode(self);
+ //power_mode = 0x0;
+ if(power_mode == 0x9c){
+ pr_debug("fl10802_check_esd OK!\n");
+ return 1;
+ }else{
+ printk("fl10802_check_esd fail!(0x%x)\n", power_mode);
+ return 0;
+ }
+}
+
+
+static int32_t fl10802_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk(KERN_DEBUG "fl10802_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+ mipi_eotp_set(1,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((sleep_in_out->tag & LCM_TAG_MASK));
+ }
+ sleep_in_out++;
+ }
+ mipi_eotp_set(1,1);
+ return 0;
+}
+
+static struct panel_operations lcd_fl10802_mipi_operations = {
+ .panel_init = fl10802_mipi_init,
+ .panel_readid = fl10802_readid,
+ .panel_esd_check = fl10802_check_esd,
+ .panel_enter_sleep = fl10802_enter_sleep,
+};
+
+static struct timing_rgb lcd_fl10802_mipi_timing = {
+ .hfp = 80, /* unit: pixel */
+ .hbp = 80,
+ .hsync = 10,
+ .vfp = 17, /*unit: line*/
+ .vbp = 11,
+ .vsync = 3,
+};
+
+static struct info_mipi lcd_fl10802_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq = 400*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ //.te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_fl10802_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_fl10802_mipi_spec = {
+ .width = 480,
+ .height = 800,
+ .fps = 59,
+ .reset_timing = {5,10,120},
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_fl10802_mipi_info
+ },
+ .ops = &lcd_fl10802_mipi_operations,
+};
+
+struct panel_cfg lcd_fl10802_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x1080,
+ .lcd_name = "lcd_fl10802_mipi",
+ .panel = &lcd_fl10802_mipi_spec,
+};
+
+static int __init lcd_fl10802_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_fl10802_mipi);
+}
+
+subsys_initcall(lcd_fl10802_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_hx8363_mcu.c b/drivers/video/sprdfb/lcd/lcd_hx8363_mcu.c
new file mode 100644
index 00000000..1f7e4875
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_hx8363_mcu.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+
+static int32_t hx8363_init(struct panel_spec *self)
+{
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ printk("hx8363_init\n");
+
+ send_cmd(0xB9); // SET password
+ send_data(0xFF); //
+ send_data(0x83); //
+ send_data(0x63); //
+
+ send_cmd(0xB0);//Enable internal oscillator
+ send_data(0x01);
+ send_data(0x0B);
+
+ send_cmd(0xB1);
+ send_data(0x01);
+ send_data(0x00);
+ send_data(0x44);
+ send_data(0x08);
+ send_data(0x01);
+ send_data(0x11);
+ send_data(0x11);
+ send_data(0x36);
+ send_data(0x3E);
+ send_data(0x3F);
+ send_data(0x3F);
+ send_data(0x40);
+ send_data(0x32);
+ send_data(0x00);
+ send_data(0xE6);
+ send_data(0xE6);
+ send_data(0xE6);
+ send_data(0xE6);
+ send_data(0xE6);
+
+ send_cmd(0xB2); // SET DISP
+ send_data(0x08); //
+ send_data(0x00); //
+
+ send_cmd(0xB4);
+ send_data(0x00);//Column inversion
+ send_data(0x18);
+ send_data(0x9C);
+ send_data(0x08);
+ send_data(0x18);
+ send_data(0x04);
+ send_data(0x72);//72
+
+ send_cmd(0xB6);//Set_VCOM
+ send_data(0x1B);
+
+ send_cmd(0xCC);// SET Panel
+ send_data(0x01); //
+
+ LCD_DelayMS(5);
+
+ send_cmd(0xE0); // SET Gamma
+ send_data(0x00);
+ send_data(0x05);
+ send_data(0x07);
+ send_data(0x0C);
+ send_data(0x13);
+ send_data(0x2F);
+ send_data(0x0B);
+ send_data(0x1D);
+ send_data(0x86);
+ send_data(0x0D);
+ send_data(0x91);
+ send_data(0x16);
+ send_data(0x99);
+ send_data(0x16);
+ send_data(0x16);
+ send_data(0x09);
+ send_data(0x05);
+ send_data(0x00);
+ send_data(0x05);
+ send_data(0x07);
+ send_data(0x0C);
+ send_data(0x13);
+ send_data(0x2F);
+ send_data(0x0B);
+ send_data(0x1D);
+ send_data(0x86);
+ send_data(0x0D);
+ send_data(0x91);
+ send_data(0x16);
+ send_data(0x99);
+ send_data(0x16);
+ send_data(0x16);
+ send_data(0x09);
+ send_data(0x05);
+
+ send_cmd(0xC1); //COLMOD
+ send_data(0x01); //
+ //R
+ send_data(0x07 );
+ send_data(0x0A );
+ send_data(0x1A );
+ send_data(0x2F );
+ send_data(0x3E );
+ send_data(0x4A );
+ send_data(0x52 );
+ send_data(0x5A );
+ send_data(0x62 );
+ send_data(0x69 );
+ send_data(0x70 );
+ send_data(0x76 );
+ send_data(0x7D );
+ send_data(0x82 );
+ send_data(0x86 );
+ send_data(0x8C );
+ send_data(0x93 );
+ send_data(0x9A );
+ send_data(0x9F );
+ send_data(0xA4 );
+ send_data(0xA9 );
+ send_data(0xB0 );
+ send_data(0xB6 );
+ send_data(0xBB );
+ send_data(0xC2 );
+ send_data(0xC9 );
+ send_data(0xCF );
+ send_data(0xD7 );
+ send_data(0xE0 );
+ send_data(0xE7 );
+ send_data(0xEF );
+ send_data(0xF8 );
+ send_data(0xFF );
+ send_data(0x34 );
+ send_data(0x1E );
+ send_data(0x92 );
+ send_data(0x9E );
+ send_data(0x01 );
+ send_data(0xE6 );
+ send_data(0x08 );
+ send_data(0x6F );
+ send_data(0x02 );
+ //G
+ send_data(0x07 );
+ send_data(0x0A );
+ send_data(0x1A );
+ send_data(0x2F );
+ send_data(0x3E );
+ send_data(0x4A );
+ send_data(0x52 );
+ send_data(0x5A );
+ send_data(0x62 );
+ send_data(0x69 );
+ send_data(0x70 );
+ send_data(0x76 );
+ send_data(0x7D );
+ send_data(0x82 );
+ send_data(0x86 );
+ send_data(0x8C );
+ send_data(0x93 );
+ send_data(0x9A );
+ send_data(0x9F );
+ send_data(0xA4 );
+ send_data(0xA9 );
+ send_data(0xB0 );
+ send_data(0xB6 );
+ send_data(0xBB );
+ send_data(0xC2 );
+ send_data(0xC9 );
+ send_data(0xCF );
+ send_data(0xD7 );
+ send_data(0xE0 );
+ send_data(0xE7 );
+ send_data(0xEF );
+ send_data(0xF8 );
+ send_data(0xFF );
+ send_data(0x34 );
+ send_data(0x1E );
+ send_data(0x92 );
+ send_data(0x9E );
+ send_data(0x01 );
+ send_data(0xE6 );
+ send_data(0x08 );
+ send_data(0x6F );
+ send_data(0x02 );
+ //B
+ send_data(0x07 );
+ send_data(0x0A );
+ send_data(0x1A );
+ send_data(0x2F );
+ send_data(0x3E );
+ send_data(0x4A );
+ send_data(0x52 );
+ send_data(0x5A );
+ send_data(0x62 );
+ send_data(0x69 );
+ send_data(0x70 );
+ send_data(0x76 );
+ send_data(0x7D );
+ send_data(0x82 );
+ send_data(0x86 );
+ send_data(0x8C );
+ send_data(0x93 );
+ send_data(0x9A );
+ send_data(0x9F );
+ send_data(0xA4 );
+ send_data(0xA9 );
+ send_data(0xB0 );
+ send_data(0xB6 );
+ send_data(0xBB );
+ send_data(0xC2 );
+ send_data(0xC9 );
+ send_data(0xCF );
+ send_data(0xD7 );
+ send_data(0xE0 );
+ send_data(0xE7 );
+ send_data(0xEF );
+ send_data(0xF8 );
+ send_data(0xFF );
+ send_data(0x34 );
+ send_data(0x1E );
+ send_data(0x92 );
+ send_data(0x9E );
+ send_data(0x01 );
+ send_data(0xE6 );
+ send_data(0x08 );
+ send_data(0x6F );
+ send_data(0x02 );
+
+ send_cmd(0x3A); //COLMOD
+ send_data(0x07); //
+
+ send_cmd(0x11);//Sleep Out
+ LCD_DelayMS(120);
+
+ send_cmd(0xC2);// SET DISPIF
+ send_data(0x04); //24bit
+ send_cmd(0x35); //Tearing Effect
+ send_data(0x00); //
+ send_cmd(0x36);
+ send_data(0x02); //
+ send_cmd(0x29);
+ LCD_DelayMS(10);
+ send_cmd(0x2c);
+
+ return 0;
+}
+
+static int32_t hx8363_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ if(is_sleep==1){
+ //Sleep In
+ send_cmd(0x28);
+ LCD_DelayMS(120);
+ send_cmd(0x10);
+ LCD_DelayMS(120);
+ }else{
+ //Sleep Out
+ send_cmd(0x11);
+ LCD_DelayMS(120);
+ send_cmd(0x29);
+ LCD_DelayMS(120);
+ }
+
+ return 0;
+}
+
+
+
+
+static int32_t hx8363_set_window(struct panel_spec *self,
+ uint16_t left, uint16_t top, uint16_t right, uint16_t bottom)
+{
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ pr_debug("hx8363_set_window: %d, %d, %d, %d\n",left, top, right, bottom);
+
+ send_cmd(0x2A); // col
+ send_data((left >> 8));
+ send_data((left & 0xFF));
+ send_data((right >> 8));
+ send_data((right & 0xFF));
+
+ send_cmd(0x2B); // row
+ send_data((top >> 8));
+ send_data((top & 0xFF));
+ send_data((bottom >> 8));
+ send_data((bottom & 0xFF));
+
+ send_cmd(0x2C); //Write data
+
+ return 0;
+}
+static int32_t hx8363_invalidate(struct panel_spec *self)
+{
+ pr_debug("hx8363_invalidate\n");
+
+ return self->ops->panel_set_window(self, 0, 0,
+ self->width - 1, self->height - 1);
+}
+
+
+
+static int32_t hx8363_invalidate_rect(struct panel_spec *self,
+ uint16_t left, uint16_t top,
+ uint16_t right, uint16_t bottom)
+{
+ pr_debug("hx8363_invalidate_rect \n");
+
+ return self->ops->panel_set_window(self, left, top,
+ right, bottom);
+}
+
+static int32_t hx8363_read_id(struct panel_spec *self)
+{
+ int32_t id = 0;
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ read_data_t read_data = self->info.mcu->ops->read_data;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ //Get ID
+
+
+ return 0x18; // id;
+}
+
+static struct panel_operations lcd_hx8363_mcu_operations = {
+ .panel_init = hx8363_init,
+ .panel_set_window = hx8363_set_window,
+ .panel_invalidate_rect= hx8363_invalidate_rect,
+ .panel_invalidate = hx8363_invalidate,
+ .panel_enter_sleep = hx8363_enter_sleep,
+ .panel_readid = hx8363_read_id
+};
+
+static struct timing_mcu lcd_hx8363_mcu_timing[] = {
+[MCU_LCD_REGISTER_TIMING] = { // read/write register timing
+ .rcss = 15, // 15ns
+ .rlpw = 60,
+ .rhpw = 60,
+ .wcss = 10,
+ .wlpw = 35,
+ .whpw = 35,
+ },
+[MCU_LCD_GRAM_TIMING] = { // read/write gram timing
+ .rcss = 15, // 15ns
+ .rlpw = 60,
+ .rhpw = 60,
+ .wcss = 0,
+ .wlpw = 16,
+ .whpw = 16,
+ },
+};
+
+static struct info_mcu lcd_hx8363_mcu_info = {
+ .bus_mode = LCD_BUS_8080,
+ .bus_width = 24,
+ .bpp = 24,
+ .timing =lcd_hx8363_mcu_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_hx8363_mcu_spec = {
+ .width = 480,
+ .height = 854,
+ .type = LCD_MODE_MCU,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mcu = &lcd_hx8363_mcu_info
+ },
+ .ops = &lcd_hx8363_mcu_operations,
+};
+
+struct panel_cfg lcd_hx8363_mcu = {
+ /* this panel may on both CS0/1 */
+ .dev_id = SPRDFB_UNDEFINELCD_ID,
+ .lcd_id = 0x18,
+ .lcd_name = "lcd_hx8363_mcu",
+ .panel = &lcd_hx8363_mcu_spec,
+};
+
+static int __init lcd_hx8363_mcu_init(void)
+{
+ return sprdfb_panel_register(&lcd_hx8363_mcu);
+}
+
+subsys_initcall(lcd_hx8363_mcu_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_hx8363_rgb_spi.c b/drivers/video/sprdfb/lcd/lcd_hx8363_rgb_spi.c
new file mode 100644
index 00000000..18742b53
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_hx8363_rgb_spi.c
@@ -0,0 +1,445 @@
+/* drivers/video/sc8810/lcd_hx8363_rgb_spi.c
+ *
+ *
+ *
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+#define HX8363_SpiWriteCmd(cmd) \
+{ \
+ spi_send_cmd((cmd & 0xFF));\
+}
+
+#define HX8363_SpiWriteData(data)\
+{ \
+ spi_send_data((data & 0xFF));\
+}
+
+static int32_t hx8363_init(struct panel_spec *self)
+{
+ uint32_t test_data[8] = {0};
+ uint32_t left = 0;
+ uint32_t top = 0;
+ uint32_t right = 480;
+ uint32_t bottom = 854;
+ uint32_t data = 0;
+ spi_send_cmd_t spi_send_cmd = self->info.rgb->bus_info.spi->ops->spi_send_cmd;
+ spi_send_data_t spi_send_data = self->info.rgb->bus_info.spi->ops->spi_send_data;
+ spi_read_t spi_read = self->info.rgb->bus_info.spi->ops->spi_read;
+
+
+ printk("hx8363_init\n");
+
+ HX8363_SpiWriteCmd(0xB9); // SET password
+ HX8363_SpiWriteData(0xFF); //
+ HX8363_SpiWriteData(0x83); //
+ HX8363_SpiWriteData(0x63); //
+
+ HX8363_SpiWriteCmd(0xB1);
+ HX8363_SpiWriteData(0x01);
+ HX8363_SpiWriteData(0x00);
+ HX8363_SpiWriteData(0x44);
+ HX8363_SpiWriteData(0x08);
+ HX8363_SpiWriteData(0x01);
+// HX8363_SpiWriteData(0x0E); //
+// HX8363_SpiWriteData(0x0E); //
+// HX8363_SpiWriteData(0x1B); //the lower ,Saturation is better
+// HX8363_SpiWriteData(0x23); //the lower ,Saturation is better
+ HX8363_SpiWriteData(0x0F); //
+ HX8363_SpiWriteData(0x0F); //
+ HX8363_SpiWriteData(0x22); //the lower ,Saturation is better
+ HX8363_SpiWriteData(0x2A); //the lower ,Saturation is better
+ HX8363_SpiWriteData(0x3F);
+ HX8363_SpiWriteData(0x3F);
+ HX8363_SpiWriteData(0x40);
+ HX8363_SpiWriteData(0x32);
+ HX8363_SpiWriteData(0x00);
+ HX8363_SpiWriteData(0xE6);
+ HX8363_SpiWriteData(0xE6);
+ HX8363_SpiWriteData(0xE6);
+ HX8363_SpiWriteData(0xE6);
+ HX8363_SpiWriteData(0xE6);
+
+ HX8363_SpiWriteCmd(0xB2); // SET DISP
+ HX8363_SpiWriteData(0x08); //
+ HX8363_SpiWriteData(0x03); //
+
+ HX8363_SpiWriteCmd(0xB4);
+ HX8363_SpiWriteData(0x00);//Column inversion
+ HX8363_SpiWriteData(0x18);
+ HX8363_SpiWriteData(0x9C);
+ HX8363_SpiWriteData(0x08);
+ HX8363_SpiWriteData(0x18);
+ HX8363_SpiWriteData(0x04);
+ HX8363_SpiWriteData(0x82);
+
+ HX8363_SpiWriteCmd(0xB6); //Set_VCOM
+ HX8363_SpiWriteData(0x1B); //0x10
+
+ HX8363_SpiWriteCmd(0xCC); // SET Panel
+ HX8363_SpiWriteData(0x01); //
+ msleep(5);
+
+ HX8363_SpiWriteCmd(0xE0); // SET Gamma
+ HX8363_SpiWriteData(0x00);
+ HX8363_SpiWriteData(0x05);
+ HX8363_SpiWriteData(0x07);
+ HX8363_SpiWriteData(0x0C);
+ HX8363_SpiWriteData(0x13);
+ HX8363_SpiWriteData(0x2F);
+ HX8363_SpiWriteData(0x0B);
+ HX8363_SpiWriteData(0x1D);
+ HX8363_SpiWriteData(0x86);
+ HX8363_SpiWriteData(0x0D);
+ HX8363_SpiWriteData(0x91);
+ HX8363_SpiWriteData(0x16);
+ HX8363_SpiWriteData(0x99);
+ HX8363_SpiWriteData(0x16);
+ HX8363_SpiWriteData(0x16);
+ HX8363_SpiWriteData(0x09);
+ HX8363_SpiWriteData(0x05);
+ HX8363_SpiWriteData(0x00);
+ HX8363_SpiWriteData(0x05);
+ HX8363_SpiWriteData(0x07);
+ HX8363_SpiWriteData(0x0C);
+ HX8363_SpiWriteData(0x13);
+ HX8363_SpiWriteData(0x2F);
+ HX8363_SpiWriteData(0x0B);
+ HX8363_SpiWriteData(0x1D);
+ HX8363_SpiWriteData(0x86);
+ HX8363_SpiWriteData(0x0D);
+ HX8363_SpiWriteData(0x91);
+ HX8363_SpiWriteData(0x16);
+ HX8363_SpiWriteData(0x99);
+ HX8363_SpiWriteData(0x16);
+ HX8363_SpiWriteData(0x16);
+ HX8363_SpiWriteData(0x09);
+ HX8363_SpiWriteData(0x05);
+
+ HX8363_SpiWriteCmd(0xC1); //COLMOD
+ HX8363_SpiWriteData(0x01); //
+ //R
+ HX8363_SpiWriteData(0x07 );
+ HX8363_SpiWriteData(0x0A );
+ HX8363_SpiWriteData(0x1A );
+ HX8363_SpiWriteData(0x2F );
+ HX8363_SpiWriteData(0x3E );
+ HX8363_SpiWriteData(0x4A );
+ HX8363_SpiWriteData(0x52 );
+ HX8363_SpiWriteData(0x5A );
+ HX8363_SpiWriteData(0x62 );
+ HX8363_SpiWriteData(0x69 );
+ HX8363_SpiWriteData(0x70 );
+ HX8363_SpiWriteData(0x76 );
+ HX8363_SpiWriteData(0x7D );
+ HX8363_SpiWriteData(0x82 );
+ HX8363_SpiWriteData(0x86 );
+ HX8363_SpiWriteData(0x8C );
+ HX8363_SpiWriteData(0x93 );
+ HX8363_SpiWriteData(0x9A );
+ HX8363_SpiWriteData(0x9F );
+ HX8363_SpiWriteData(0xA4 );
+ HX8363_SpiWriteData(0xA9 );
+ HX8363_SpiWriteData(0xB0 );
+ HX8363_SpiWriteData(0xB6 );
+ HX8363_SpiWriteData(0xBB );
+ HX8363_SpiWriteData(0xC2 );
+ HX8363_SpiWriteData(0xC9 );
+ HX8363_SpiWriteData(0xCF );
+ HX8363_SpiWriteData(0xD7 );
+ HX8363_SpiWriteData(0xE0 );
+ HX8363_SpiWriteData(0xE7 );
+ HX8363_SpiWriteData(0xEF );
+ HX8363_SpiWriteData(0xF8 );
+ HX8363_SpiWriteData(0xFF );
+ HX8363_SpiWriteData(0x34 );
+ HX8363_SpiWriteData(0x1E );
+ HX8363_SpiWriteData(0x92 );
+ HX8363_SpiWriteData(0x9E );
+ HX8363_SpiWriteData(0x01 );
+ HX8363_SpiWriteData(0xE6 );
+ HX8363_SpiWriteData(0x08 );
+ HX8363_SpiWriteData(0x6F );
+ HX8363_SpiWriteData(0x02 );
+ //G
+ HX8363_SpiWriteData(0x07 );
+ HX8363_SpiWriteData(0x0A );
+ HX8363_SpiWriteData(0x1A );
+ HX8363_SpiWriteData(0x2F );
+ HX8363_SpiWriteData(0x3E );
+ HX8363_SpiWriteData(0x4A );
+ HX8363_SpiWriteData(0x52 );
+ HX8363_SpiWriteData(0x5A );
+ HX8363_SpiWriteData(0x62 );
+ HX8363_SpiWriteData(0x69 );
+ HX8363_SpiWriteData(0x70 );
+ HX8363_SpiWriteData(0x76 );
+ HX8363_SpiWriteData(0x7D );
+ HX8363_SpiWriteData(0x82 );
+ HX8363_SpiWriteData(0x86 );
+ HX8363_SpiWriteData(0x8C );
+ HX8363_SpiWriteData(0x93 );
+ HX8363_SpiWriteData(0x9A );
+ HX8363_SpiWriteData(0x9F );
+ HX8363_SpiWriteData(0xA4 );
+ HX8363_SpiWriteData(0xA9 );
+ HX8363_SpiWriteData(0xB0 );
+ HX8363_SpiWriteData(0xB6 );
+ HX8363_SpiWriteData(0xBB );
+ HX8363_SpiWriteData(0xC2 );
+ HX8363_SpiWriteData(0xC9 );
+ HX8363_SpiWriteData(0xCF );
+ HX8363_SpiWriteData(0xD7 );
+ HX8363_SpiWriteData(0xE0 );
+ HX8363_SpiWriteData(0xE7 );
+ HX8363_SpiWriteData(0xEF );
+ HX8363_SpiWriteData(0xF8 );
+ HX8363_SpiWriteData(0xFF );
+ HX8363_SpiWriteData(0x34 );
+ HX8363_SpiWriteData(0x1E );
+ HX8363_SpiWriteData(0x92 );
+ HX8363_SpiWriteData(0x9E );
+ HX8363_SpiWriteData(0x01 );
+ HX8363_SpiWriteData(0xE6 );
+ HX8363_SpiWriteData(0x08 );
+ HX8363_SpiWriteData(0x6F );
+ HX8363_SpiWriteData(0x02 );
+ //B
+ HX8363_SpiWriteData(0x07 );
+ HX8363_SpiWriteData(0x0A );
+ HX8363_SpiWriteData(0x1A );
+ HX8363_SpiWriteData(0x2F );
+ HX8363_SpiWriteData(0x3E );
+ HX8363_SpiWriteData(0x4A );
+ HX8363_SpiWriteData(0x52 );
+ HX8363_SpiWriteData(0x5A );
+ HX8363_SpiWriteData(0x62 );
+ HX8363_SpiWriteData(0x69 );
+ HX8363_SpiWriteData(0x70 );
+ HX8363_SpiWriteData(0x76 );
+ HX8363_SpiWriteData(0x7D );
+ HX8363_SpiWriteData(0x82 );
+ HX8363_SpiWriteData(0x86 );
+ HX8363_SpiWriteData(0x8C );
+ HX8363_SpiWriteData(0x93 );
+ HX8363_SpiWriteData(0x9A );
+ HX8363_SpiWriteData(0x9F );
+ HX8363_SpiWriteData(0xA4 );
+ HX8363_SpiWriteData(0xA9 );
+ HX8363_SpiWriteData(0xB0 );
+ HX8363_SpiWriteData(0xB6 );
+ HX8363_SpiWriteData(0xBB );
+ HX8363_SpiWriteData(0xC2 );
+ HX8363_SpiWriteData(0xC9 );
+ HX8363_SpiWriteData(0xCF );
+ HX8363_SpiWriteData(0xD7 );
+ HX8363_SpiWriteData(0xE0 );
+ HX8363_SpiWriteData(0xE7 );
+ HX8363_SpiWriteData(0xEF );
+ HX8363_SpiWriteData(0xF8 );
+ HX8363_SpiWriteData(0xFF );
+ HX8363_SpiWriteData(0x34 );
+ HX8363_SpiWriteData(0x1E );
+ HX8363_SpiWriteData(0x92 );
+ HX8363_SpiWriteData(0x9E );
+ HX8363_SpiWriteData(0x01 );
+ HX8363_SpiWriteData(0xE6 );
+ HX8363_SpiWriteData(0x08 );
+ HX8363_SpiWriteData(0x6F );
+ HX8363_SpiWriteData(0x02 );
+
+ HX8363_SpiWriteCmd(0x3A); //COLMOD
+ HX8363_SpiWriteData(0x77); //
+
+ HX8363_SpiWriteCmd(0x11);//Sleep Out
+ msleep(120);
+ HX8363_SpiWriteCmd(0x35); //Tearing Effect
+ HX8363_SpiWriteData(0x00); //
+ HX8363_SpiWriteCmd(0x36);
+ HX8363_SpiWriteData(0x02);
+ HX8363_SpiWriteCmd(0x29);
+ msleep(10);
+ HX8363_SpiWriteCmd(0x2C);
+
+}
+
+static int32_t hx8363_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ spi_send_cmd_t spi_send_cmd = self->info.rgb->bus_info.spi->ops->spi_send_cmd;
+ spi_send_data_t spi_send_data = self->info.rgb->bus_info.spi->ops->spi_send_data;
+
+ if(is_sleep==1){
+ //Sleep In
+ HX8363_SpiWriteCmd(0x28);
+ msleep(120);
+ HX8363_SpiWriteCmd(0x10);
+ msleep(10);
+ }else{
+ //Sleep Out
+ HX8363_SpiWriteCmd(0x11);
+ msleep(120);
+ HX8363_SpiWriteCmd(0x29);
+ msleep(10);
+ }
+
+ return 0;
+}
+
+
+
+
+static int32_t hx8363_set_window(struct panel_spec *self,
+ uint16_t left, uint16_t top, uint16_t right, uint16_t bottom)
+{
+ uint32_t *test_data[4] = {0};
+ spi_send_cmd_t spi_send_cmd = self->info.rgb->bus_info.spi->ops->spi_send_cmd;
+ spi_send_data_t spi_send_data = self->info.rgb->bus_info.spi->ops->spi_send_data;
+ spi_read_t spi_read = self->info.rgb->bus_info.spi->ops->spi_read;
+#if 0
+
+ printk("zxdbg add -hx8363_set_window: %d, %d, %d, %d\n",left, top, right, bottom);
+
+ HX8363_SpiWriteCmd(0x2A00);
+ HX8363_SpiWriteData((left>>8));// set left address
+ HX8363_SpiWriteData((left&0xff));
+ HX8363_SpiWriteData((right>>8));// set right address
+ HX8363_SpiWriteData((right&0xff));
+
+ HX8363_SpiWriteCmd(0x2B00);
+ HX8363_SpiWriteData((top>>8));// set left address
+ HX8363_SpiWriteData((top&0xff));
+ HX8363_SpiWriteData((bottom>>8));// set bottom address
+ HX8363_SpiWriteData((bottom&0xff));
+
+// HX8363_SpiWriteCmd(0x2C00);
+
+ HX8363_SpiWriteCmd(0x2A00);
+ spi_read(test_data);
+ spi_read(test_data+1);
+ HX8363_SpiWriteCmd(0x2B00);
+ spi_read(test_data+2);
+ spi_read(test_data+3);
+#endif
+// printk("zxdbg add -hx8363_read read: %x, %x, %x, %x\n",test_data[0], test_data[1], test_data[2], test_data[3]);
+
+ return 0;
+}
+static int32_t hx8363_invalidate(struct panel_spec *self)
+{
+// printk("hx8363_invalidate\n");
+
+ return self->ops->panel_set_window(self, 0, 0,
+ self->width - 1, self->height - 1);
+}
+
+
+
+static int32_t hx8363_invalidate_rect(struct panel_spec *self,
+ uint16_t left, uint16_t top,
+ uint16_t right, uint16_t bottom)
+{
+// printk("hx8363_invalidate_rect \n");
+
+ return self->ops->panel_set_window(self, left, top,
+ right, bottom);
+}
+
+static int32_t hx8363_read_id(struct panel_spec *self)
+{
+ int32_t id = 0x62;
+ spi_send_cmd_t spi_send_cmd = self->info.rgb->bus_info.spi->ops->spi_send_cmd;
+ spi_send_data_t spi_send_data = self->info.rgb->bus_info.spi->ops->spi_send_data;
+ spi_read_t spi_read = self->info.rgb->bus_info.spi->ops->spi_read;
+
+ printk("sprdfb hx8363_read_id \n");
+ HX8363_SpiWriteCmd(0xB9); // SET password
+ HX8363_SpiWriteData(0xFF); //
+ HX8363_SpiWriteData(0x83); //
+ HX8363_SpiWriteData(0x63); //
+
+ HX8363_SpiWriteCmd(0xFE); // SET SPI READ INDEX
+ HX8363_SpiWriteData(0xF4); // GETHXID
+ HX8363_SpiWriteCmd(0xFF); // GET SPI READ
+
+ spi_read(&id);
+ id &= 0xff;
+ printk(" hx8363_read_id kernel id = %x\n",id);
+// return id;
+ return 0x63;
+}
+
+static struct panel_operations lcd_hx8363_rgb_spi_operations = {
+ .panel_init = hx8363_init,
+ .panel_set_window = hx8363_set_window,
+ .panel_invalidate_rect= hx8363_invalidate_rect,
+ .panel_invalidate = hx8363_invalidate,
+ .panel_enter_sleep = hx8363_enter_sleep,
+ .panel_readid = hx8363_read_id
+};
+
+static struct timing_rgb lcd_hx8363_rgb_timing = {
+ .hfp = 15,//10, /* unit: pixel */
+ .hbp = 15,//6,
+ .hsync = 10, //8,
+ .vfp = 8, // 3, /*unit: line*/
+ .vbp = 8, // 3,
+ .vsync = 6, // 4,
+};
+
+static struct spi_info lcd_hx8363_rgb_spi_info = {
+ .ops = NULL,
+};
+
+static struct info_rgb lcd_hx8363_rgb_info = {
+ .cmd_bus_mode = SPRDFB_RGB_BUS_TYPE_SPI,
+ .video_bus_width = 24, /*18,16*/
+ .h_sync_pol = SPRDFB_POLARITY_NEG,
+ .v_sync_pol = SPRDFB_POLARITY_NEG,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .timing = &lcd_hx8363_rgb_timing,
+ .bus_info = {
+ .spi = &lcd_hx8363_rgb_spi_info,
+ }
+};
+
+struct panel_spec lcd_panel_hx8363_rgb_spi_spec = {
+ .width = 480,
+ .height = 854,
+ .reset_timing = {20, 10, 120},
+ .fps = 61,
+ .type = LCD_MODE_RGB,
+ .direction = LCD_DIRECT_NORMAL,
+ .is_clean_lcd = true,
+ .info = {
+ .rgb = &lcd_hx8363_rgb_info
+ },
+ .ops = &lcd_hx8363_rgb_spi_operations,
+};
+
+struct panel_cfg lcd_hx8363_rgb_spi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x63,
+ .lcd_name = "lcd_hx8363_rgb_spi",
+ .panel = &lcd_panel_hx8363_rgb_spi_spec,
+};
+static int __init lcd_hx8363_rgb_spi_init(void)
+{
+ return sprdfb_panel_register(&lcd_hx8363_rgb_spi);
+}
+
+subsys_initcall(lcd_hx8363_rgb_spi_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_hx8363_rgb_spi_viva.c b/drivers/video/sprdfb/lcd/lcd_hx8363_rgb_spi_viva.c
new file mode 100644
index 00000000..76b8b12a
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_hx8363_rgb_spi_viva.c
@@ -0,0 +1,442 @@
+/* drivers/video/sc8810/lcd_hx8363_rgb_spi.c
+ *
+ *
+ *
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+
+
+#define HX8363_SpiWriteCmd(cmd) \
+{ \
+ spi_send_cmd((cmd & 0xFF));\
+}
+
+#define HX8363_SpiWriteData(data)\
+{ \
+ spi_send_data((data & 0xFF));\
+}
+#define HX8369b_SpiWriteCmd(cmd) \
+{ \
+ spi_send_cmd((cmd & 0xFF));\
+}
+
+#define HX8369b_SpiWriteData(data)\
+{ \
+ spi_send_data((data & 0xFF));\
+}
+static int32_t hx8363_init(struct panel_spec *self)
+{
+ uint32_t test_data[8] = {0};
+ uint32_t left = 0;
+ uint32_t top = 0;
+ uint32_t right = 480;
+ uint32_t bottom = 800;
+ uint32_t data = 0;
+ spi_send_cmd_t spi_send_cmd = self->info.rgb->bus_info.spi->ops->spi_send_cmd;
+ spi_send_data_t spi_send_data = self->info.rgb->bus_info.spi->ops->spi_send_data;
+ spi_read_t spi_read = self->info.rgb->bus_info.spi->ops->spi_read;
+
+
+ printk("hx8363_init\n");
+
+ HX8369b_SpiWriteCmd(0xB9); // SET EXTC
+ HX8369b_SpiWriteData(0xFF); //
+ HX8369b_SpiWriteData(0x83); //
+ HX8369b_SpiWriteData(0x69); //
+
+ //Power Setting Sequence
+
+ HX8369b_SpiWriteCmd(0xB1); //Set Power
+ HX8369b_SpiWriteData(0x0B);
+ HX8369b_SpiWriteData(0x83);
+ HX8369b_SpiWriteData(0xA7);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x11);
+ HX8369b_SpiWriteData(0x11);
+ HX8369b_SpiWriteData(0x08);
+ HX8369b_SpiWriteData(0x08);
+ HX8369b_SpiWriteData(0x0C);
+ HX8369b_SpiWriteData(0x22);
+
+
+ HX8369b_SpiWriteCmd(0xC6); //Set Source EQ
+ HX8369b_SpiWriteData(0x41);
+ HX8369b_SpiWriteData(0xFF);
+ HX8369b_SpiWriteData(0x7A);
+ HX8369b_SpiWriteData(0xFF);
+
+ HX8369b_SpiWriteCmd(0xE3); //Set Source EQ
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+
+ HX8369b_SpiWriteCmd(0xC0); //Set Source Option
+ HX8369b_SpiWriteData(0x73);
+ HX8369b_SpiWriteData(0x50);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x34);
+ HX8369b_SpiWriteData(0xC4);
+ HX8369b_SpiWriteData(0x00);
+
+ // Initializing Sequence
+
+ HX8369b_SpiWriteCmd(0x3A); //Interface Pixel
+ HX8369b_SpiWriteData(0x70);
+
+ HX8369b_SpiWriteCmd(0xB3); //Set RGB Interface
+ HX8369b_SpiWriteData(0x83);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x31);
+ HX8369b_SpiWriteData(0x03);
+ HX8369b_SpiWriteData(0x01);
+ HX8369b_SpiWriteData(0x13);
+ HX8369b_SpiWriteData(0x06);
+
+ HX8369b_SpiWriteCmd(0xB4); //Set column inversion
+ HX8369b_SpiWriteData(0x00);
+
+ HX8369b_SpiWriteCmd(0xCC); //Set DGC
+ HX8369b_SpiWriteData(0x0C);
+
+ HX8369b_SpiWriteCmd(0xEA); //Set Color
+ HX8369b_SpiWriteData(0x72);
+
+ HX8369b_SpiWriteCmd(0xB2); //Set Display
+ HX8369b_SpiWriteData(0x03);
+
+ HX8369b_SpiWriteCmd(0xD5); //GIP Timing SET
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x0D);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x12);
+ HX8369b_SpiWriteData(0x40);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x01);
+ HX8369b_SpiWriteData(0x60);
+ HX8369b_SpiWriteData(0x37);
+ HX8369b_SpiWriteData(0x00);
+
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x0F);
+ HX8369b_SpiWriteData(0x01);
+ HX8369b_SpiWriteData(0x05);
+ HX8369b_SpiWriteData(0x47);
+ HX8369b_SpiWriteData(0x03);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x03);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x03);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x18);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x89);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x11);
+ HX8369b_SpiWriteData(0x33);
+ HX8369b_SpiWriteData(0x55);
+ HX8369b_SpiWriteData(0x77);
+ HX8369b_SpiWriteData(0x31);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x98);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x66);
+ HX8369b_SpiWriteData(0x44);
+ HX8369b_SpiWriteData(0x22);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x02);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x89);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x22);
+ HX8369b_SpiWriteData(0x44);
+ HX8369b_SpiWriteData(0x66);
+ HX8369b_SpiWriteData(0x20);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x98);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x77);
+ HX8369b_SpiWriteData(0x55);
+ HX8369b_SpiWriteData(0x33);
+ HX8369b_SpiWriteData(0x11);
+ HX8369b_SpiWriteData(0x13);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x01);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x03);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0xCF);
+ HX8369b_SpiWriteData(0xFF);
+ HX8369b_SpiWriteData(0xFF);
+ HX8369b_SpiWriteData(0x03);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0xCF);
+ HX8369b_SpiWriteData(0xFF);
+ HX8369b_SpiWriteData(0xFF);
+ HX8369b_SpiWriteData(0x20);
+ HX8369b_SpiWriteData(0x8C);
+ HX8369b_SpiWriteData(0x5A);
+
+ //Gamam Setting Sequence
+
+ HX8369b_SpiWriteCmd(0xE0); //Gamma
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x02);
+ HX8369b_SpiWriteData(0x0D);
+ HX8369b_SpiWriteData(0x0C);
+ HX8369b_SpiWriteData(0x3F);
+ HX8369b_SpiWriteData(0x19);
+ HX8369b_SpiWriteData(0x2D);
+ HX8369b_SpiWriteData(0x04);
+ HX8369b_SpiWriteData(0x0F);
+ HX8369b_SpiWriteData(0x0E);
+ HX8369b_SpiWriteData(0x14);
+ HX8369b_SpiWriteData(0x17);
+
+ HX8369b_SpiWriteData(0x15);
+ HX8369b_SpiWriteData(0x16);
+ HX8369b_SpiWriteData(0x10);
+ HX8369b_SpiWriteData(0x11);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x00);
+ HX8369b_SpiWriteData(0x02);
+ HX8369b_SpiWriteData(0x0C);
+ HX8369b_SpiWriteData(0x12);
+ HX8369b_SpiWriteData(0x3F);
+ HX8369b_SpiWriteData(0x19);
+ HX8369b_SpiWriteData(0x2C);
+ HX8369b_SpiWriteData(0x05);
+ HX8369b_SpiWriteData(0x08);
+ HX8369b_SpiWriteData(0x0E);
+ HX8369b_SpiWriteData(0x12);
+ HX8369b_SpiWriteData(0x16);
+ HX8369b_SpiWriteData(0x14);
+ HX8369b_SpiWriteData(0x15);
+ HX8369b_SpiWriteData(0x10);
+ HX8369b_SpiWriteData(0x12);
+ HX8369b_SpiWriteData(0x01);
+
+ //Dispaly on
+ HX8369b_SpiWriteCmd(0x11);
+ mdelay(120);
+ HX8369b_SpiWriteCmd(0x29);
+
+
+}
+
+static int32_t hx8363_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ spi_send_cmd_t spi_send_cmd = self->info.rgb->bus_info.spi->ops->spi_send_cmd;
+ spi_send_data_t spi_send_data = self->info.rgb->bus_info.spi->ops->spi_send_data;
+
+ if(is_sleep==1){
+ //Sleep In
+ HX8363_SpiWriteCmd(0x28);
+ mdelay(120);
+ HX8363_SpiWriteCmd(0x10);
+ mdelay(10);
+ }else{
+ //Sleep Out
+ HX8363_SpiWriteCmd(0x11);
+ mdelay(120);
+ HX8363_SpiWriteCmd(0x29);
+ mdelay(10);
+ }
+
+ return 0;
+}
+
+
+
+
+static int32_t hx8363_set_window(struct panel_spec *self,
+ uint16_t left, uint16_t top, uint16_t right, uint16_t bottom)
+{
+ uint32_t *test_data[4] = {0};
+ spi_send_cmd_t spi_send_cmd = self->info.rgb->bus_info.spi->ops->spi_send_cmd;
+ spi_send_data_t spi_send_data = self->info.rgb->bus_info.spi->ops->spi_send_data;
+ spi_read_t spi_read = self->info.rgb->bus_info.spi->ops->spi_read;
+#if 0
+
+ printk("zxdbg add -hx8363_set_window: %d, %d, %d, %d\n",left, top, right, bottom);
+
+ HX8363_SpiWriteCmd(0x2A00);
+ HX8363_SpiWriteData((left>>8));// set left address
+ HX8363_SpiWriteData((left&0xff));
+ HX8363_SpiWriteData((right>>8));// set right address
+ HX8363_SpiWriteData((right&0xff));
+
+ HX8363_SpiWriteCmd(0x2B00);
+ HX8363_SpiWriteData((top>>8));// set left address
+ HX8363_SpiWriteData((top&0xff));
+ HX8363_SpiWriteData((bottom>>8));// set bottom address
+ HX8363_SpiWriteData((bottom&0xff));
+
+// HX8363_SpiWriteCmd(0x2C00);
+
+ HX8363_SpiWriteCmd(0x2A00);
+ spi_read(test_data);
+ spi_read(test_data+1);
+ HX8363_SpiWriteCmd(0x2B00);
+ spi_read(test_data+2);
+ spi_read(test_data+3);
+#endif
+// printk("zxdbg add -hx8363_read read: %x, %x, %x, %x\n",test_data[0], test_data[1], test_data[2], test_data[3]);
+
+ return 0;
+}
+static int32_t hx8363_invalidate(struct panel_spec *self)
+{
+// printk("hx8363_invalidate\n");
+
+ return self->ops->panel_set_window(self, 0, 0,
+ self->width - 1, self->height - 1);
+}
+
+
+
+static int32_t hx8363_invalidate_rect(struct panel_spec *self,
+ uint16_t left, uint16_t top,
+ uint16_t right, uint16_t bottom)
+{
+// printk("hx8363_invalidate_rect \n");
+
+ return self->ops->panel_set_window(self, left, top,
+ right, bottom);
+}
+
+static int32_t hx8363_read_id(struct panel_spec *self)
+{
+ int32_t id = 0x62;
+ spi_send_cmd_t spi_send_cmd = self->info.rgb->bus_info.spi->ops->spi_send_cmd;
+ spi_send_data_t spi_send_data = self->info.rgb->bus_info.spi->ops->spi_send_data;
+ spi_read_t spi_read = self->info.rgb->bus_info.spi->ops->spi_read;
+/*
+ printk("sprdfb hx8363_read_id \n");
+ HX8363_SpiWriteCmd(0xB9); // SET password
+ HX8363_SpiWriteData(0xFF); //
+ HX8363_SpiWriteData(0x83); //
+ HX8363_SpiWriteData(0x63); //
+
+ HX8363_SpiWriteCmd(0xFE); // SET SPI READ INDEX
+ HX8363_SpiWriteData(0xF4); // GETHXID
+ HX8363_SpiWriteCmd(0xFF); // GET SPI READ
+
+ spi_read(&id);
+*/
+ id &= 0xff;
+ printk(" hx8363_read_id kernel id = %x\n",id);
+// return id;
+ return 0x63;
+}
+
+static struct panel_operations lcd_hx8363_rgb_spi_operations = {
+ .panel_init = hx8363_init,
+ .panel_set_window = hx8363_set_window,
+ .panel_invalidate_rect= hx8363_invalidate_rect,
+ .panel_invalidate = hx8363_invalidate,
+ .panel_enter_sleep = hx8363_enter_sleep,
+ .panel_readid = hx8363_read_id
+};
+
+static struct timing_rgb lcd_hx8363_rgb_timing = {
+#if 1
+ .hfp = 30,//10, /* unit: pixel */
+ .hbp = 55, //6,
+ .hsync = 10, //8,
+ .vfp = 6, // 3, /*unit: line*/
+ .vbp = 19, // 3,
+ .vsync = 6, // 4,
+#else
+ .hfp = 15,//10, /* unit: pixel */
+ .hbp = 15,//6,
+ .hsync = 10, //8,
+ .vfp = 8, // 3, /*unit: line*/
+ .vbp = 8, // 3,
+ .vsync = 6, // 4,
+#endif
+};
+
+static struct spi_info lcd_hx8363_rgb_spi_info = {
+ .ops = NULL,
+};
+
+static struct info_rgb lcd_hx8363_rgb_info = {
+ .cmd_bus_mode = SPRDFB_RGB_BUS_TYPE_SPI,
+ .video_bus_width = 24, /*18,16*/
+ .h_sync_pol = SPRDFB_POLARITY_NEG,
+ .v_sync_pol = SPRDFB_POLARITY_NEG,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .timing = &lcd_hx8363_rgb_timing,
+ .bus_info = {
+ .spi = &lcd_hx8363_rgb_spi_info,
+ }
+};
+
+struct panel_spec lcd_panel_hx8363_rgb_spi_spec = {
+ .width = 480,
+ .height = 800,
+ .fps = 61,
+ .type = LCD_MODE_RGB,
+ .direction = LCD_DIRECT_NORMAL,
+ .is_clean_lcd = true,
+ .info = {
+ .rgb = &lcd_hx8363_rgb_info
+ },
+ .ops = &lcd_hx8363_rgb_spi_operations,
+};
+
+struct panel_cfg lcd_hx8363_rgb_spi_spec_viva = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x63,
+ .lcd_name = "lcd_hx8363_rgb_spi",
+ .panel = &lcd_panel_hx8363_rgb_spi_spec,
+};
+
+static int __init lcd_hx8363_rgb_spi_init(void)
+{
+ return sprdfb_panel_register(&lcd_hx8363_rgb_spi_spec_viva);
+
+}
+
+subsys_initcall(lcd_hx8363_rgb_spi_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_hx8369.c b/drivers/video/sprdfb/lcd/lcd_hx8369.c
new file mode 100644
index 00000000..5c143a9a
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_hx8369.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "lcdpanel.h"
+
+static int32_t hx8369_init(struct panel_spec *self)
+{
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ /* SET password */
+ send_cmd(0xB9);
+ send_data(0xFF);
+ send_data(0x83);
+ send_data(0x69);
+
+ /* Set Power */
+ send_cmd(0xB1);
+ send_data(0x9D);
+ send_data(0x00);
+ send_data(0x34);
+ send_data(0x07);
+ send_data(0x00);
+ send_data(0x0B);
+ send_data(0x0B);
+ send_data(0x1A);
+ send_data(0x22);
+ send_data(0x3F);
+ send_data(0x3F);
+ send_data(0x01);
+ send_data(0x23);
+ send_data(0x01);
+ send_data(0xE6);
+ send_data(0xE6);
+ send_data(0xE6);
+ send_data(0xE6);
+ send_data(0xE6);
+
+ /* SET Display 480x800 */
+ send_cmd(0xB2);
+ send_data(0x00);
+ send_data(0x20);
+ send_data(0x03);
+ send_data(0x03);
+ send_data(0x70);
+ send_data(0x00);
+ send_data(0xFF);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x03);
+ send_data(0x03);
+ send_data(0x00);
+ send_data(0x01);
+
+ /* SET Display 480x800 */
+ send_cmd(0xB4);
+ send_data(0x00);
+ send_data(0x18);
+ send_data(0x80);
+ send_data(0x06);
+ send_data(0x02);
+
+ /* OSC */
+ send_cmd(0xB0);
+ send_data(0x00);
+ send_data(0x09); /*05 42HZ 07 50HZ 0B 100% 67HZ */
+
+ /* SET VCOM */
+ send_cmd(0xB6);
+ send_data(0x4A);
+ send_data(0x4A);
+
+ /* SET GIP */
+ send_cmd(0xD5);
+ send_data(0x00);
+ send_data(0x03);
+ send_data(0x03);
+ send_data(0x00);
+ send_data(0x01);
+ send_data(0x02);
+
+ send_data(0x28);
+ send_data(0x70);
+ send_data(0x11);
+ send_data(0x13);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x40);
+ send_data(0x06);
+ send_data(0x51);
+ send_data(0x07);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x41);
+ send_data(0x06);
+ send_data(0x50);
+ send_data(0x07);
+ send_data(0x07);
+ send_data(0x0F);
+ send_data(0x04);
+ send_data(0x00);
+
+ /* Set Gamma */
+ send_cmd(0xE0);
+ send_data(0x00);
+ send_data(0x01);
+ send_data(0x04);
+ send_data(0x23);
+ send_data(0x22);
+ send_data(0x3F);
+ send_data(0x13);
+ send_data(0x39);
+ send_data(0x06);
+ send_data(0x0B);
+ send_data(0x0E);
+ send_data(0x12);
+ send_data(0x15);
+ send_data(0x13);
+ send_data(0x15);
+ send_data(0x13);
+ send_data(0x1B);
+ send_data(0x00);
+ send_data(0x01);
+ send_data(0x04);
+ send_data(0x23);
+ send_data(0x22);
+ send_data(0x3F);
+ send_data(0x13);
+ send_data(0x39);
+ send_data(0x06);
+ send_data(0x0B);
+ send_data(0x0E);
+ send_data(0x12);
+ send_data(0x15);
+ send_data(0x13);
+ send_data(0x15);
+ send_data(0x13);
+ send_data(0x1B);
+ send_cmd(0x35); /* TE on*/
+ send_data(0x00);
+
+ /* set CSEL */
+ send_cmd(0x3A);
+ send_data(0x07); /* CSEL=0x06, 16bit-color CSEL=0x06, 18bit-color CSEL=0x07, 24bit-color */
+
+ /*24 bit don't need to set 2DH*/
+
+ /* Sleep Out */
+ send_cmd(0x11);
+
+ LCD_DelayMS(120);
+
+ #if 0
+ { /* for test the lcd */
+ int i;
+
+ send_cmd(0x2C); //Write data
+ for (i = 0; i < 480*800/3; i++)
+ send_data(0xff);
+ for (i = 0; i < 480*800/3; i++)
+ send_data(0xff00);
+ for (i = 0; i < 480*800/3; i++)
+ send_data(0xff0000);
+ }
+ #endif
+ /* Display On */
+ send_cmd(0x29);
+
+ LCD_DelayMS (120);
+
+ /* Write data */
+ send_cmd(0x2C);
+
+ return 0;
+}
+
+static int32_t hx8369_set_window(struct panel_spec *self,
+ uint16_t left, uint16_t top, uint16_t right, uint16_t bottom)
+{
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ pr_debug("hx8369_set_window:%d, %d, %d, %d\n", left, top, right, bottom);
+
+ /* col */
+ send_cmd(0x2A);
+ send_data((left >> 8));
+ send_data((left & 0xFF));
+ send_data((right >> 8));
+ send_data((right & 0xFF));
+
+ /* row */
+ send_cmd(0x2B);
+ send_data((top >> 8));
+ send_data((top & 0xFF));
+ send_data((bottom >> 8));
+ send_data((bottom & 0xFF));
+
+ /* Write data */
+ send_cmd(0x2C);
+
+ return 0;
+}
+
+
+static int32_t hx8369_invalidate(struct panel_spec *self)
+{
+
+ return self->ops->panel_set_window(self, 0, 0,
+ self->width-1, self->height-1);
+
+}
+
+static int32_t hx8369_invalidate_rect(struct panel_spec *self,
+ uint16_t left, uint16_t top,
+ uint16_t right, uint16_t bottom)
+{
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ pr_debug("hx8369_invalidate_rect\n");
+
+ /* TE scanline */
+ send_cmd(0x44);
+ send_data((top >> 8));
+ send_data((top & 0xFF));
+
+ return self->ops->panel_set_window(self, left, top,
+ right, bottom);
+}
+
+static int32_t hx8369_set_direction(struct panel_spec *self, uint16_t direction)
+{
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ pr_debug("hx8369_set_direction\n");
+ send_cmd(0x36);
+
+ switch (direction) {
+ case LCD_DIRECT_NORMAL:
+ send_data(0);
+ break;
+ case LCD_DIRECT_ROT_90:
+ send_data(0xA0);
+ break;
+ case LCD_DIRECT_ROT_180:
+ send_data(0x60);
+ break;
+ case LCD_DIRECT_ROT_270:
+ send_data(0xB0);
+ break;
+ case LCD_DIRECT_MIR_H:
+ send_data(0x40);
+ break;
+ case LCD_DIRECT_MIR_V:
+ send_data(0x10);
+ break;
+ case LCD_DIRECT_MIR_HV:
+ send_data(0xE0);
+ break;
+ default:
+ pr_debug("unknown lcd direction!\n");
+ send_data(0x0);
+ direction = LCD_DIRECT_NORMAL;
+ break;
+ }
+
+ self->direction = direction;
+
+ return 0;
+}
+
+static int32_t hx8369_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+
+ if(is_sleep) {
+ /* Sleep In */
+ send_cmd(0x28);
+ LCD_DelayMS(120);
+ send_cmd(0x10);
+ LCD_DelayMS(120);
+ }
+ else {
+#if 1
+ /* Sleep Out */
+ send_cmd(0x11);
+ LCD_DelayMS(120);
+ send_cmd(0x29);
+ LCD_DelayMS(120);
+#else
+ /* re init */
+ se1f->ops->reset(self);
+ se1f->ops->lcd_init(self);
+#endif
+ }
+ return 0;
+}
+
+static uint32_t hx8369_read_id(struct panel_spec *self)
+{
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+ read_data_t read_data = self->info.mcu->ops->read_data;
+
+ send_cmd(0xB9);
+ send_data(0xFF);
+ send_data(0x83);
+ send_data(0x69);
+
+ send_cmd(0xF4);
+ read_data();
+ return read_data();
+}
+
+static struct panel_operations lcd_hx8369_operations = {
+ .panel_init = hx8369_init,
+ .panel_set_window = hx8369_set_window,
+ .panel_invalidate = hx8369_invalidate,
+ .panel_invalidate_rect = hx8369_invalidate_rect,
+ .panel_set_direction = hx8369_set_direction,
+ .panel_enter_sleep = hx8369_enter_sleep,
+ .panel_readid = hx8369_read_id,
+};
+
+static struct timing_mcu lcd_hx8369_timing[] = {
+[LCD_REGISTER_TIMING] = { /* read/write register timing (ns) */
+ .rcss = 25, /* 25 ns */
+ .rlpw = 70,
+ .rhpw = 70,
+ .wcss = 10,
+ .wlpw = 50,
+ .whpw = 50,
+ },
+[LCD_GRAM_TIMING] = { /* read/write gram timing (ns) */
+ .rcss = 25,
+ .rlpw = 70,
+ .rhpw = 70,
+ .wcss = 0,
+ .wlpw = 15,
+ .whpw = 24,
+ }
+};
+
+static struct info_mcu lcd_hx8369_info = {
+ .bus_mode = LCD_BUS_8080,
+ .bus_width = 24,
+ .timing = lcd_hx8369_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_hx8369_spec = {
+ .width = 480,
+ .height = 800,
+ .mode = LCD_MODE_MCU,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mcu = &lcd_hx8369_info,
+ },
+ .ops = &lcd_hx8369_operations,
+};
+
+struct panel_cfg lcd_hx8369 = {
+ /* this panel may on both CS0/1 */
+ .lcd_cs = -1,
+ .lcd_id = 0x69,
+ .lcd_name = "lcd_hx8369",
+ .panel = &lcd_hx8369_spec,
+};
+
+static int __init lcd_hx8369_init(void)
+{
+ return sprd_register_panel(&lcd_hx8369);
+}
+
+subsys_initcall(lcd_hx8369_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_hx8369b_grandneo_mipi.c b/drivers/video/sprdfb/lcd/lcd_hx8369b_grandneo_mipi.c
new file mode 100755
index 00000000..35c2178b
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_hx8369b_grandneo_mipi.c
@@ -0,0 +1,338 @@
+/* drivers/video/sprdfb/lcd_hx8369b_mipi.c
+ *
+ * Support for hx8369b mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+#include <mach/gpio.h>
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 150
+//#define NEW_PANAL_BOE
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+#ifndef NEW_PANAL_BOE
+ {LCM_SEND(6),{4,0,0xB9,0xFF,0x83,0x69}},
+ {LCM_SLEEP(10)},
+ {LCM_SEND(18),{16,0,0xBA,0x31,0x00,0x16,0xCA,0xB1,0x0A,0x00,0x10,0x28,0x02,0x21,0x21,0x9A,0x1A,0x8F}},
+ //set GIP timing control
+ {LCM_SEND(95),{93,0,0xD5,0x00,0x00,0x08,0x03,0x30,0x00,0x00,0x10,0x01,0x00,0x00,0x00,0x01,0x39,0x45,0x00,0x00,\
+ 0x0D,0x44,0x39,0x37,0x00,0x00,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x37,0x59,\
+ 0x18,0x10,0x00,0x00,0x05,0x00,0x00,0x40,0x28,0x69,0x40,0x00,0x00,0x00,0x00,0x00,0x26,0x49,0x08,0x00,0x00,0x00,\
+ 0x04,0x00,0x00,0x51,0x39,0x78,0x50,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x07,\
+ 0xF8,0x0F,0xFF,0xFF,0x07,0xF8,0x0F,0xFF,0xFF,0x00,0x20,0x5A,\
+}},
+ {LCM_SEND(2),{0x3A,0x70}},
+ {LCM_SEND(15),{13,0,0xB1,0x12,0x83,0x77,0x00,0x10,0x10,0x1E,0x1E,0x0C,0x1A,0x20,0xD6}},
+ {LCM_SEND(7),{5,0,0xB3,0x83,0x00,0x3A,0x17}},
+ {LCM_SEND(2),{0xB4,0x01}},
+ {LCM_SEND(5),{3,0,0xB6,0x96,0x96}},
+ {LCM_SEND(2),{0xCC,0x0E}},
+ {LCM_SEND(9),{7,0,0xC0,0x73,0x50,0x00,0x20,0xC4,0x00}},
+ //gamma setting
+ {LCM_SEND(130),{128,0,0xC1,0x03,0x00,0x06,0x0D,0x15,0x1D,0x25,0x2D,0x35,0x3D,\
+ 0x45,0x4D,0x55,0x5D,0x65,0x6D,0x75,0x7C,0x84,0x8C,\
+ 0x94,0x9C,0xA4,0xAC,0xB4,0xBC,0xC4,0xCC,0xD4,0xDC,\
+ 0xE4,0xEC,0xF3,0xFD,0x0F,0xFA,0x95,0x40,0xFF,0xAA,\
+ 0x54,0x03,0xC0,0x00,0x07,0x0F,0x17,0x1F,0x27,0x2F,\
+ 0x37,0x3F,0x47,0x4F,0x57,0x5F,0x67,0x6F,0x77,0x7F,\
+ 0x87,0x8F,0x97,0x9F,0xA7,0xAF,0xB7,0xBF,0xC7,0xCF,\
+ 0xD7,0xDF,0xE7,0xEF,0xF7,0xFF,0x00,0x00,0x00,0x00,\
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x0F,0x17,0x1F,\
+ 0x27,0x2F,0x37,0x3F,0x47,0x4F,0x57,0x5F,0x67,0x6F,\
+ 0x77,0x7F,0x87,0x8F,0x97,0x9F,0xA7,0xAF,0xB7,0xBF,\
+ 0xC7,0xCF,0xD7,0xDF,0xE7,0xEF,0xF7,0xFF,0x00,0x00,\
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,}},
+ {LCM_SEND(7),{5,0,0xE3,0x0F,0x0F,0x11,0x11}},
+ {LCM_SEND(2),{0xEA,0x7A}},
+ {LCM_SEND(6),{4,0,0xC6,0x41,0xFF,0x7D}},
+ {LCM_SEND(38),{36,0,0xE0,0x01,0x0D,0x18,0x14,0x13,0x2F,0x31,0x3B,0x09,0x10,0x12,0x16,0x17,0x16,0x16,0x11,0x14,0x01,\
+ 0x0D,0x18,0x14,0x13,0x2F,0x30,0x3B,0x09,0x10,0x11,0x16,0x17,0x15,0x16,0x11,0x14,0x01}},
+ {LCM_SEND(2),{0x51,0x80}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(180)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(120)}, //40
+
+#else
+
+ {LCM_SEND(6),{4,0,0xB9,0xFF,0x83,0x69}},
+ //{LCM_SLEEP(10)},
+
+ {LCM_SEND(13),{11,0,0xB1,0x0B,0x83,0x77,0x00,0x0F,0x0F,0x0B,0x0B,0x0C,0x0A}},
+ {LCM_SEND(6),{4,0,0xC6,0x41,0xFF,0x7D}},
+ {LCM_SEND(7),{5,0,0xE3,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(9),{7,0,0xC0,0x73,0x50,0x00,0x34,0xC4,0x00}},
+ {LCM_SEND(6),{4,0,0xC3,0x55,0xB8,0x90}},
+ {LCM_SEND(18),{16,0,0xBA,0x31,0x00,0x16,0xCA,0xB1,0x0A,0x00,0x10,0x28,0x02,0x21,0x21,0x9A,0x1A,0x8F}},
+ {LCM_SEND(2),{0x3A,0x70}},
+ {LCM_SEND(7),{5,0,0xB3,0x83,0x00,0x31,0x03}},
+ {LCM_SEND(2),{0xB4,0x00}},
+ {LCM_SEND(2),{0xCC,0x0E}},
+ {LCM_SEND(2),{0xEA,0x72}},
+ {LCM_SEND(2),{0xB2,0x03}},
+
+
+ //set GIP timing control
+ {LCM_SEND(95),{93,0,0xD5,0x00,0x00,0x07,0x00,0x09,0x00,0x00,0x10,0x01,0x00,0x00,0x00,0x01,0x42,0x37,\
+ 0x00,0x00,0x08,0x2A,0x08,0x47,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+ 0x15,0x00,0x00,0x98,0x98,0x44,0x66,0x00,0x22,0x51,0x00,0x00,0x89,0x98,0x33,0x11,0x77,0x55,0x04,0x00,\
+ 0x00,0x98,0x98,0x55,0x77,0x11,0x33,0x40,0x00,0x00,0x89,0x98,0x22,0x00,0x66,0x44,0x15,0x00,0x00,0x00,\
+ 0x01,0x00,0x00,0x00,0x03,0x00,0x0F,0xFF,0xFF,0x03,0x00,0x0F,0xFF,0xFF,0x00,0x8C,0x5A}},
+
+ //gamma setting
+ {LCM_SEND(38),{36,0,0xE0,0x00,0x02,0x04,0x2C,0x33,0x3F,0x0D,0x32,0x05,0x0B,0x0E,0x11,0x14,0x12,0x13,0x13,0x1A,0x00,\
+0x02,0x04,0x2C,0x32,0x3F,0x0F,0x31,0x05,0x0B,0x0E,0x11,0x14,0x12,0x13,0x13,0x1A,0x01,
+}},
+
+
+ {LCM_SEND(5),{3,0,0xC9,0x0F,0x00}},
+ {LCM_SLEEP(5)},
+// {LCM_SEND(2),{0x51,0x80}},
+// {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(180)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(10)}, //40
+
+#endif
+
+};
+
+static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(150)}, //>150ms
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(150)}, //>150ms
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},//>120ms
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)}, //>20ms
+};
+static int32_t hx8369b_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel hx8369b_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t hx8369b_readid(struct panel_spec *self)
+{
+ int32_t j =0;
+ uint8_t read_data[3] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("kernel lcd_hx8369b_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x01;
+ param[1] = 0x00;
+ mipi_force_write(0x37, param, 2);
+ read_rtn = mipi_force_read(0xda,1,&read_data[0]);
+ read_rtn = mipi_force_read(0xdb,1,&read_data[1]);
+ read_rtn = mipi_force_read(0xdc,1,&read_data[2]);
+
+#ifndef NEW_PANAL_BOE
+ if((0x55 == read_data[0])&&(0xc0 == read_data[1])&&(0x90 == read_data[2]))
+#else
+ if((0x55 == read_data[0])&&(0xB8 == read_data[1])&&(0x90 == read_data[2]))
+#endif
+ {
+ printk("lcd_hx8369b_mipi read id success!\n");
+ return 0x8369;
+ }
+ }
+ mipi_eotp_set(0,0);
+ LCD_PRINT("lcd_hx8369b_mipi read id fail! 0xda,0xdb,0xdc is 0x%x,0x%x,0x%x!\n",read_data[0],read_data[1],read_data[2]);
+ return 0;
+}
+
+
+static int32_t hx8369b_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i = 0;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel hx8369b_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(sleep_in_out->tag & LCM_TAG_MASK);
+ }
+ sleep_in_out++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static struct panel_operations lcd_hx8369b_mipi_operations = {
+ .panel_init = hx8369b_mipi_init,
+ .panel_readid = hx8369b_readid,
+ .panel_enter_sleep = hx8369b_enter_sleep,
+};
+
+static struct timing_rgb lcd_hx8369b_mipi_timing = {
+ .hfp = 90, /* unit: pixel */
+ .hbp = 70,
+ .hsync = 60,
+ .vfp = 8, /*unit: line*/
+ .vbp = 12,
+ .vsync = 4,
+};
+
+
+static struct info_mipi lcd_hx8369b_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq =481*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_hx8369b_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_hx8369b_mipi_spec = {
+ .width = 480,
+ .height = 800,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_hx8369b_mipi_info
+ },
+ .ops = &lcd_hx8369b_mipi_operations,
+};
+struct panel_cfg lcd_hx8369b_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x8369,
+ .lcd_name = "lcd_hx8369b_mipi",
+ .panel = &lcd_hx8369b_mipi_spec,
+};
+
+//temp code
+static int __init lcd_hx8369b_mipi_init(void)
+{
+/*
+ printk("hx8369b_mipi_init: set lcd backlight.\n");
+
+ if (gpio_request(214, "LCD_BL")) {
+ printk("Failed ro request LCD_BL GPIO_%d \n",
+ 214);
+ return -ENODEV;
+ }
+ gpio_direction_output(214, 1);
+ gpio_set_value(214, 1);
+*/
+
+ return sprdfb_panel_register(&lcd_hx8369b_mipi);
+}
+
+subsys_initcall(lcd_hx8369b_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_hx8369b_mipi.c b/drivers/video/sprdfb/lcd/lcd_hx8369b_mipi.c
new file mode 100644
index 00000000..65e7014a
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_hx8369b_mipi.c
@@ -0,0 +1,348 @@
+/* drivers/video/sprdfb/lcd_hx8369b_mipi.c
+ *
+ * Support for hx8369b mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+#include <mach/gpio.h>
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 150
+#define NEW_PANAL_BOE
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+#ifndef NEW_PANAL_BOE
+ {LCM_SEND(6),{4,0,0xB9,0xFF,0x83,0x69}},
+ {LCM_SLEEP(10)},
+ {LCM_SEND(18),{16,0,0xBA,0x31,0x00,0x16,0xCA,0xB1,0x0A,0x00,0x10,0x28,0x02,0x21,0x21,0x9A,0x1A,0x8F}},
+
+ //set GIP timing control
+ {LCM_SEND(95),{93,0,0xD5,0x00,0x00,0x07,0x00,0x09,0x00,0x00,0x10,0x01,0x00,0x00,0x00,0x01,0x42,0x37,\
+ 0x00,0x00,0x08,0x2A,0x08,0x47,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+ 0x15,0x00,0x00,0x98,0x98,0x44,0x66,0x00,0x22,0x51,0x00,0x00,0x89,0x98,0x33,0x11,0x77,0x55,0x04,0x00,\
+ 0x00,0x98,0x98,0x55,0x77,0x11,0x33,0x40,0x00,0x00,0x89,0x98,0x22,0x00,0x66,0x44,0x15,0x00,0x00,0x00,\
+ 0x01,0x00,0x00,0x00,0x03,0x00,0x0F,0xFF,0xFF,0x03,0x00,0x0F,0xFF,0xFF,0x00,0x8C,0x5A}},
+ {LCM_SEND(2),{0x3A,0x70}},
+ {LCM_SEND(2),{0x36,0x00}},
+
+ {LCM_SEND(13),{11,0,0xB1,0x0B,0x83,0x77,0x00,0x0F,0x0F,0x16,0x16,0x0C,0x0A}},
+ {LCM_SEND(2),{0xB2,0x03}},
+// {LCM_SEND(5),{3,0,0xB2,0x00,0x70}},
+ {LCM_SEND(7),{5,0,0xB3,0x83,0x00,0x31,0x03}},
+ {LCM_SEND(2),{0xB4,0x00}},
+ {LCM_SEND(5),{3,0,0xB6,0xA3,0xA3}},
+ {LCM_SEND(2),{0xCC,0x0C}},
+ {LCM_SEND(9),{7,0,0xC0,0x73,0x50,0x00,0x34,0xc4,0x00}},
+ {LCM_SEND(7),{5,0,0xE3,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0xEA,0x72}},
+ {LCM_SEND(6),{4,0,0xC6,0x41,0xFF,0x7D}},
+
+
+ //gamma setting
+ {LCM_SEND(38),{36,0,0xE0,0x01,0x0D,0x18,0x14,0x13,0x2F,0x31,0x3B,0x09,0x10,0x12,0x16,0x17,0x16,0x16,0x11,0x14,0x01,\
+ 0x0D,0x18,0x14,0x13,0x2F,0x30,0x3B,0x09,0x10,0x11,0x16,0x17,0x15,0x16,0x11,0x14,0x01}},
+ {LCM_SEND(130),{128,0,0xC1,0x03,0x00,0x06,0x0D,0x15,0x1D,0x25,0x2D,0x35,0x3D,\
+ 0x45,0x4D,0x55,0x5D,0x65,0x6D,0x75,0x7C,0x84,0x8C,\
+ 0x94,0x9C,0xA4,0xAC,0xB4,0xBC,0xC4,0xCC,0xD4,0xDC,\
+ 0xE4,0xEC,0xF3,0xFD,0x0F,0xFA,0x95,0x40,0xFF,0xAA,\
+ 0x54,0x03,0xC0,0x00,0x07,0x0F,0x17,0x1F,0x27,0x2F,\
+ 0x37,0x3F,0x47,0x4F,0x57,0x5F,0x67,0x6F,0x77,0x7F,\
+ 0x87,0x8F,0x97,0x9F,0xA7,0xAF,0xB7,0xBF,0xC7,0xCF,\
+ 0xD7,0xDF,0xE7,0xEF,0xF7,0xFF,0x00,0x00,0x00,0x00,\
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x0F,0x17,0x1F,\
+ 0x27,0x2F,0x37,0x3F,0x47,0x4F,0x57,0x5F,0x67,0x6F,\
+ 0x77,0x7F,0x87,0x8F,0x97,0x9F,0xA7,0xAF,0xB7,0xBF,\
+ 0xC7,0xCF,0xD7,0xDF,0xE7,0xEF,0xF7,0xFF,0x00,0x00,\
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,}},
+
+ {LCM_SEND(5),{3,0,0xC9,0x0F,0x00}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(2),{0x51,0x00}},
+ {LCM_SLEEP(5)},
+// {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(180)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(10)}, //40
+
+#else
+
+ {LCM_SEND(6),{4,0,0xB9,0xFF,0x83,0x69}},
+ //{LCM_SLEEP(10)},
+
+ {LCM_SEND(13),{11,0,0xB1,0x0B,0x83,0x77,0x00,0x0F,0x0F,0x0B,0x0B,0x0C,0x0A}},
+ {LCM_SEND(6),{4,0,0xC6,0x41,0xFF,0x7D}},
+ {LCM_SEND(7),{5,0,0xE3,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(9),{7,0,0xC0,0x73,0x50,0x00,0x34,0xC4,0x00}},
+ {LCM_SEND(6),{4,0,0xC3,0x55,0xB8,0x90}},
+ {LCM_SEND(18),{16,0,0xBA,0x31,0x00,0x16,0xCA,0xB1,0x0A,0x00,0x10,0x28,0x02,0x21,0x21,0x9A,0x1A,0x8F}},
+ {LCM_SEND(2),{0x3A,0x70}},
+ {LCM_SEND(7),{5,0,0xB3,0x83,0x00,0x31,0x03}},
+ {LCM_SEND(2),{0xB4,0x00}},
+ {LCM_SEND(2),{0xCC,0x0E}},
+ {LCM_SEND(2),{0xEA,0x72}},
+ {LCM_SEND(2),{0xB2,0x03}},
+
+
+ //set GIP timing control
+ {LCM_SEND(95),{93,0,0xD5,0x00,0x00,0x07,0x00,0x09,0x00,0x00,0x10,0x01,0x00,0x00,0x00,0x01,0x42,0x37,\
+ 0x00,0x00,0x08,0x2A,0x08,0x47,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+ 0x15,0x00,0x00,0x98,0x98,0x44,0x66,0x00,0x22,0x51,0x00,0x00,0x89,0x98,0x33,0x11,0x77,0x55,0x04,0x00,\
+ 0x00,0x98,0x98,0x55,0x77,0x11,0x33,0x40,0x00,0x00,0x89,0x98,0x22,0x00,0x66,0x44,0x15,0x00,0x00,0x00,\
+ 0x01,0x00,0x00,0x00,0x03,0x00,0x0F,0xFF,0xFF,0x03,0x00,0x0F,0xFF,0xFF,0x00,0x8C,0x5A}},
+
+ //gamma setting
+ {LCM_SEND(38),{36,0,0xE0,0x00,0x02,0x04,0x2C,0x33,0x3F,0x0D,0x32,0x05,0x0B,0x0E,0x11,0x14,0x12,0x13,0x13,0x1A,0x00,\
+0x02,0x04,0x2C,0x32,0x3F,0x0F,0x31,0x05,0x0B,0x0E,0x11,0x14,0x12,0x13,0x13,0x1A,0x01,
+}},
+
+
+ {LCM_SEND(5),{3,0,0xC9,0x0F,0x00}},
+ {LCM_SLEEP(5)},
+// {LCM_SEND(2),{0x51,0x80}},
+// {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(180)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(10)}, //40
+
+#endif
+
+};
+
+static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(150)}, //>150ms
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(150)}, //>150ms
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},//>120ms
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)}, //>20ms
+};
+static int32_t hx8369b_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel hx8369b_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t hx8369b_readid(struct panel_spec *self)
+{
+ int32_t j =0;
+ uint8_t read_data[3] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("kernel lcd_hx8369b_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x01;
+ param[1] = 0x00;
+ mipi_force_write(0x37, param, 2);
+ read_rtn = mipi_force_read(0xda,1,&read_data[0]);
+ read_rtn = mipi_force_read(0xdb,1,&read_data[1]);
+ read_rtn = mipi_force_read(0xdc,1,&read_data[2]);
+
+#ifndef NEW_PANAL_BOE
+ if((0x55 == read_data[0])&&(0xc0 == read_data[1])&&(0x90 == read_data[2]))
+#else
+ if((0x55 == read_data[0])&&(0xB8 == read_data[1])&&(0x90 == read_data[2]))
+#endif
+ {
+ printk("lcd_hx8369b_mipi read id success!\n");
+ return 0x8369;
+ }
+ }
+ mipi_eotp_set(0,0);
+ LCD_PRINT("lcd_hx8369b_mipi read id fail! 0xda,0xdb,0xdc is 0x%x,0x%x,0x%x!\n",read_data[0],read_data[1],read_data[2]);
+ return 0;
+}
+
+
+static int32_t hx8369b_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i = 0;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel hx8369b_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(sleep_in_out->tag & LCM_TAG_MASK);
+ }
+ sleep_in_out++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static struct panel_operations lcd_hx8369b_mipi_operations = {
+ .panel_init = hx8369b_mipi_init,
+ .panel_readid = hx8369b_readid,
+ .panel_enter_sleep = hx8369b_enter_sleep,
+};
+
+static struct timing_rgb lcd_hx8369b_mipi_timing = {
+ .hfp = 110, /* unit: pixel */
+ .hbp = 110,
+ .hsync = 4,
+ .vfp = 10, /*unit: line*/
+ .vbp = 12,
+ .vsync = 4,
+};
+
+
+static struct info_mipi lcd_hx8369b_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq =481*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_hx8369b_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_hx8369b_mipi_spec = {
+ .width = 480,
+ .height = 800,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_hx8369b_mipi_info
+ },
+ .ops = &lcd_hx8369b_mipi_operations,
+};
+struct panel_cfg lcd_hx8369b_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x8369,
+ .lcd_name = "lcd_hx8369b_mipi",
+ .panel = &lcd_hx8369b_mipi_spec,
+};
+
+//temp code
+static int __init lcd_hx8369b_mipi_init(void)
+{
+/*
+ printk("hx8369b_mipi_init: set lcd backlight.\n");
+
+ if (gpio_request(214, "LCD_BL")) {
+ printk("Failed ro request LCD_BL GPIO_%d \n",
+ 214);
+ return -ENODEV;
+ }
+ gpio_direction_output(214, 1);
+ gpio_set_value(214, 1);
+*/
+
+ return sprdfb_panel_register(&lcd_hx8369b_mipi);
+}
+
+subsys_initcall(lcd_hx8369b_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_coreprimelite.c b/drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_coreprimelite.c
new file mode 100644
index 00000000..65e7014a
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_coreprimelite.c
@@ -0,0 +1,348 @@
+/* drivers/video/sprdfb/lcd_hx8369b_mipi.c
+ *
+ * Support for hx8369b mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+#include <mach/gpio.h>
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 150
+#define NEW_PANAL_BOE
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+#ifndef NEW_PANAL_BOE
+ {LCM_SEND(6),{4,0,0xB9,0xFF,0x83,0x69}},
+ {LCM_SLEEP(10)},
+ {LCM_SEND(18),{16,0,0xBA,0x31,0x00,0x16,0xCA,0xB1,0x0A,0x00,0x10,0x28,0x02,0x21,0x21,0x9A,0x1A,0x8F}},
+
+ //set GIP timing control
+ {LCM_SEND(95),{93,0,0xD5,0x00,0x00,0x07,0x00,0x09,0x00,0x00,0x10,0x01,0x00,0x00,0x00,0x01,0x42,0x37,\
+ 0x00,0x00,0x08,0x2A,0x08,0x47,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+ 0x15,0x00,0x00,0x98,0x98,0x44,0x66,0x00,0x22,0x51,0x00,0x00,0x89,0x98,0x33,0x11,0x77,0x55,0x04,0x00,\
+ 0x00,0x98,0x98,0x55,0x77,0x11,0x33,0x40,0x00,0x00,0x89,0x98,0x22,0x00,0x66,0x44,0x15,0x00,0x00,0x00,\
+ 0x01,0x00,0x00,0x00,0x03,0x00,0x0F,0xFF,0xFF,0x03,0x00,0x0F,0xFF,0xFF,0x00,0x8C,0x5A}},
+ {LCM_SEND(2),{0x3A,0x70}},
+ {LCM_SEND(2),{0x36,0x00}},
+
+ {LCM_SEND(13),{11,0,0xB1,0x0B,0x83,0x77,0x00,0x0F,0x0F,0x16,0x16,0x0C,0x0A}},
+ {LCM_SEND(2),{0xB2,0x03}},
+// {LCM_SEND(5),{3,0,0xB2,0x00,0x70}},
+ {LCM_SEND(7),{5,0,0xB3,0x83,0x00,0x31,0x03}},
+ {LCM_SEND(2),{0xB4,0x00}},
+ {LCM_SEND(5),{3,0,0xB6,0xA3,0xA3}},
+ {LCM_SEND(2),{0xCC,0x0C}},
+ {LCM_SEND(9),{7,0,0xC0,0x73,0x50,0x00,0x34,0xc4,0x00}},
+ {LCM_SEND(7),{5,0,0xE3,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0xEA,0x72}},
+ {LCM_SEND(6),{4,0,0xC6,0x41,0xFF,0x7D}},
+
+
+ //gamma setting
+ {LCM_SEND(38),{36,0,0xE0,0x01,0x0D,0x18,0x14,0x13,0x2F,0x31,0x3B,0x09,0x10,0x12,0x16,0x17,0x16,0x16,0x11,0x14,0x01,\
+ 0x0D,0x18,0x14,0x13,0x2F,0x30,0x3B,0x09,0x10,0x11,0x16,0x17,0x15,0x16,0x11,0x14,0x01}},
+ {LCM_SEND(130),{128,0,0xC1,0x03,0x00,0x06,0x0D,0x15,0x1D,0x25,0x2D,0x35,0x3D,\
+ 0x45,0x4D,0x55,0x5D,0x65,0x6D,0x75,0x7C,0x84,0x8C,\
+ 0x94,0x9C,0xA4,0xAC,0xB4,0xBC,0xC4,0xCC,0xD4,0xDC,\
+ 0xE4,0xEC,0xF3,0xFD,0x0F,0xFA,0x95,0x40,0xFF,0xAA,\
+ 0x54,0x03,0xC0,0x00,0x07,0x0F,0x17,0x1F,0x27,0x2F,\
+ 0x37,0x3F,0x47,0x4F,0x57,0x5F,0x67,0x6F,0x77,0x7F,\
+ 0x87,0x8F,0x97,0x9F,0xA7,0xAF,0xB7,0xBF,0xC7,0xCF,\
+ 0xD7,0xDF,0xE7,0xEF,0xF7,0xFF,0x00,0x00,0x00,0x00,\
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x0F,0x17,0x1F,\
+ 0x27,0x2F,0x37,0x3F,0x47,0x4F,0x57,0x5F,0x67,0x6F,\
+ 0x77,0x7F,0x87,0x8F,0x97,0x9F,0xA7,0xAF,0xB7,0xBF,\
+ 0xC7,0xCF,0xD7,0xDF,0xE7,0xEF,0xF7,0xFF,0x00,0x00,\
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,}},
+
+ {LCM_SEND(5),{3,0,0xC9,0x0F,0x00}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(2),{0x51,0x00}},
+ {LCM_SLEEP(5)},
+// {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(180)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(10)}, //40
+
+#else
+
+ {LCM_SEND(6),{4,0,0xB9,0xFF,0x83,0x69}},
+ //{LCM_SLEEP(10)},
+
+ {LCM_SEND(13),{11,0,0xB1,0x0B,0x83,0x77,0x00,0x0F,0x0F,0x0B,0x0B,0x0C,0x0A}},
+ {LCM_SEND(6),{4,0,0xC6,0x41,0xFF,0x7D}},
+ {LCM_SEND(7),{5,0,0xE3,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(9),{7,0,0xC0,0x73,0x50,0x00,0x34,0xC4,0x00}},
+ {LCM_SEND(6),{4,0,0xC3,0x55,0xB8,0x90}},
+ {LCM_SEND(18),{16,0,0xBA,0x31,0x00,0x16,0xCA,0xB1,0x0A,0x00,0x10,0x28,0x02,0x21,0x21,0x9A,0x1A,0x8F}},
+ {LCM_SEND(2),{0x3A,0x70}},
+ {LCM_SEND(7),{5,0,0xB3,0x83,0x00,0x31,0x03}},
+ {LCM_SEND(2),{0xB4,0x00}},
+ {LCM_SEND(2),{0xCC,0x0E}},
+ {LCM_SEND(2),{0xEA,0x72}},
+ {LCM_SEND(2),{0xB2,0x03}},
+
+
+ //set GIP timing control
+ {LCM_SEND(95),{93,0,0xD5,0x00,0x00,0x07,0x00,0x09,0x00,0x00,0x10,0x01,0x00,0x00,0x00,0x01,0x42,0x37,\
+ 0x00,0x00,0x08,0x2A,0x08,0x47,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+ 0x15,0x00,0x00,0x98,0x98,0x44,0x66,0x00,0x22,0x51,0x00,0x00,0x89,0x98,0x33,0x11,0x77,0x55,0x04,0x00,\
+ 0x00,0x98,0x98,0x55,0x77,0x11,0x33,0x40,0x00,0x00,0x89,0x98,0x22,0x00,0x66,0x44,0x15,0x00,0x00,0x00,\
+ 0x01,0x00,0x00,0x00,0x03,0x00,0x0F,0xFF,0xFF,0x03,0x00,0x0F,0xFF,0xFF,0x00,0x8C,0x5A}},
+
+ //gamma setting
+ {LCM_SEND(38),{36,0,0xE0,0x00,0x02,0x04,0x2C,0x33,0x3F,0x0D,0x32,0x05,0x0B,0x0E,0x11,0x14,0x12,0x13,0x13,0x1A,0x00,\
+0x02,0x04,0x2C,0x32,0x3F,0x0F,0x31,0x05,0x0B,0x0E,0x11,0x14,0x12,0x13,0x13,0x1A,0x01,
+}},
+
+
+ {LCM_SEND(5),{3,0,0xC9,0x0F,0x00}},
+ {LCM_SLEEP(5)},
+// {LCM_SEND(2),{0x51,0x80}},
+// {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(180)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(10)}, //40
+
+#endif
+
+};
+
+static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(150)}, //>150ms
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(150)}, //>150ms
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},//>120ms
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)}, //>20ms
+};
+static int32_t hx8369b_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel hx8369b_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t hx8369b_readid(struct panel_spec *self)
+{
+ int32_t j =0;
+ uint8_t read_data[3] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("kernel lcd_hx8369b_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x01;
+ param[1] = 0x00;
+ mipi_force_write(0x37, param, 2);
+ read_rtn = mipi_force_read(0xda,1,&read_data[0]);
+ read_rtn = mipi_force_read(0xdb,1,&read_data[1]);
+ read_rtn = mipi_force_read(0xdc,1,&read_data[2]);
+
+#ifndef NEW_PANAL_BOE
+ if((0x55 == read_data[0])&&(0xc0 == read_data[1])&&(0x90 == read_data[2]))
+#else
+ if((0x55 == read_data[0])&&(0xB8 == read_data[1])&&(0x90 == read_data[2]))
+#endif
+ {
+ printk("lcd_hx8369b_mipi read id success!\n");
+ return 0x8369;
+ }
+ }
+ mipi_eotp_set(0,0);
+ LCD_PRINT("lcd_hx8369b_mipi read id fail! 0xda,0xdb,0xdc is 0x%x,0x%x,0x%x!\n",read_data[0],read_data[1],read_data[2]);
+ return 0;
+}
+
+
+static int32_t hx8369b_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i = 0;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel hx8369b_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(sleep_in_out->tag & LCM_TAG_MASK);
+ }
+ sleep_in_out++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static struct panel_operations lcd_hx8369b_mipi_operations = {
+ .panel_init = hx8369b_mipi_init,
+ .panel_readid = hx8369b_readid,
+ .panel_enter_sleep = hx8369b_enter_sleep,
+};
+
+static struct timing_rgb lcd_hx8369b_mipi_timing = {
+ .hfp = 110, /* unit: pixel */
+ .hbp = 110,
+ .hsync = 4,
+ .vfp = 10, /*unit: line*/
+ .vbp = 12,
+ .vsync = 4,
+};
+
+
+static struct info_mipi lcd_hx8369b_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq =481*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_hx8369b_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_hx8369b_mipi_spec = {
+ .width = 480,
+ .height = 800,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_hx8369b_mipi_info
+ },
+ .ops = &lcd_hx8369b_mipi_operations,
+};
+struct panel_cfg lcd_hx8369b_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x8369,
+ .lcd_name = "lcd_hx8369b_mipi",
+ .panel = &lcd_hx8369b_mipi_spec,
+};
+
+//temp code
+static int __init lcd_hx8369b_mipi_init(void)
+{
+/*
+ printk("hx8369b_mipi_init: set lcd backlight.\n");
+
+ if (gpio_request(214, "LCD_BL")) {
+ printk("Failed ro request LCD_BL GPIO_%d \n",
+ 214);
+ return -ENODEV;
+ }
+ gpio_direction_output(214, 1);
+ gpio_set_value(214, 1);
+*/
+
+ return sprdfb_panel_register(&lcd_hx8369b_mipi);
+}
+
+subsys_initcall(lcd_hx8369b_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_coreprimelite_marlin.c b/drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_coreprimelite_marlin.c
new file mode 100644
index 00000000..65e7014a
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_coreprimelite_marlin.c
@@ -0,0 +1,348 @@
+/* drivers/video/sprdfb/lcd_hx8369b_mipi.c
+ *
+ * Support for hx8369b mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+#include <mach/gpio.h>
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 150
+#define NEW_PANAL_BOE
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+#ifndef NEW_PANAL_BOE
+ {LCM_SEND(6),{4,0,0xB9,0xFF,0x83,0x69}},
+ {LCM_SLEEP(10)},
+ {LCM_SEND(18),{16,0,0xBA,0x31,0x00,0x16,0xCA,0xB1,0x0A,0x00,0x10,0x28,0x02,0x21,0x21,0x9A,0x1A,0x8F}},
+
+ //set GIP timing control
+ {LCM_SEND(95),{93,0,0xD5,0x00,0x00,0x07,0x00,0x09,0x00,0x00,0x10,0x01,0x00,0x00,0x00,0x01,0x42,0x37,\
+ 0x00,0x00,0x08,0x2A,0x08,0x47,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+ 0x15,0x00,0x00,0x98,0x98,0x44,0x66,0x00,0x22,0x51,0x00,0x00,0x89,0x98,0x33,0x11,0x77,0x55,0x04,0x00,\
+ 0x00,0x98,0x98,0x55,0x77,0x11,0x33,0x40,0x00,0x00,0x89,0x98,0x22,0x00,0x66,0x44,0x15,0x00,0x00,0x00,\
+ 0x01,0x00,0x00,0x00,0x03,0x00,0x0F,0xFF,0xFF,0x03,0x00,0x0F,0xFF,0xFF,0x00,0x8C,0x5A}},
+ {LCM_SEND(2),{0x3A,0x70}},
+ {LCM_SEND(2),{0x36,0x00}},
+
+ {LCM_SEND(13),{11,0,0xB1,0x0B,0x83,0x77,0x00,0x0F,0x0F,0x16,0x16,0x0C,0x0A}},
+ {LCM_SEND(2),{0xB2,0x03}},
+// {LCM_SEND(5),{3,0,0xB2,0x00,0x70}},
+ {LCM_SEND(7),{5,0,0xB3,0x83,0x00,0x31,0x03}},
+ {LCM_SEND(2),{0xB4,0x00}},
+ {LCM_SEND(5),{3,0,0xB6,0xA3,0xA3}},
+ {LCM_SEND(2),{0xCC,0x0C}},
+ {LCM_SEND(9),{7,0,0xC0,0x73,0x50,0x00,0x34,0xc4,0x00}},
+ {LCM_SEND(7),{5,0,0xE3,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0xEA,0x72}},
+ {LCM_SEND(6),{4,0,0xC6,0x41,0xFF,0x7D}},
+
+
+ //gamma setting
+ {LCM_SEND(38),{36,0,0xE0,0x01,0x0D,0x18,0x14,0x13,0x2F,0x31,0x3B,0x09,0x10,0x12,0x16,0x17,0x16,0x16,0x11,0x14,0x01,\
+ 0x0D,0x18,0x14,0x13,0x2F,0x30,0x3B,0x09,0x10,0x11,0x16,0x17,0x15,0x16,0x11,0x14,0x01}},
+ {LCM_SEND(130),{128,0,0xC1,0x03,0x00,0x06,0x0D,0x15,0x1D,0x25,0x2D,0x35,0x3D,\
+ 0x45,0x4D,0x55,0x5D,0x65,0x6D,0x75,0x7C,0x84,0x8C,\
+ 0x94,0x9C,0xA4,0xAC,0xB4,0xBC,0xC4,0xCC,0xD4,0xDC,\
+ 0xE4,0xEC,0xF3,0xFD,0x0F,0xFA,0x95,0x40,0xFF,0xAA,\
+ 0x54,0x03,0xC0,0x00,0x07,0x0F,0x17,0x1F,0x27,0x2F,\
+ 0x37,0x3F,0x47,0x4F,0x57,0x5F,0x67,0x6F,0x77,0x7F,\
+ 0x87,0x8F,0x97,0x9F,0xA7,0xAF,0xB7,0xBF,0xC7,0xCF,\
+ 0xD7,0xDF,0xE7,0xEF,0xF7,0xFF,0x00,0x00,0x00,0x00,\
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x0F,0x17,0x1F,\
+ 0x27,0x2F,0x37,0x3F,0x47,0x4F,0x57,0x5F,0x67,0x6F,\
+ 0x77,0x7F,0x87,0x8F,0x97,0x9F,0xA7,0xAF,0xB7,0xBF,\
+ 0xC7,0xCF,0xD7,0xDF,0xE7,0xEF,0xF7,0xFF,0x00,0x00,\
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,}},
+
+ {LCM_SEND(5),{3,0,0xC9,0x0F,0x00}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(2),{0x51,0x00}},
+ {LCM_SLEEP(5)},
+// {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(180)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(10)}, //40
+
+#else
+
+ {LCM_SEND(6),{4,0,0xB9,0xFF,0x83,0x69}},
+ //{LCM_SLEEP(10)},
+
+ {LCM_SEND(13),{11,0,0xB1,0x0B,0x83,0x77,0x00,0x0F,0x0F,0x0B,0x0B,0x0C,0x0A}},
+ {LCM_SEND(6),{4,0,0xC6,0x41,0xFF,0x7D}},
+ {LCM_SEND(7),{5,0,0xE3,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(9),{7,0,0xC0,0x73,0x50,0x00,0x34,0xC4,0x00}},
+ {LCM_SEND(6),{4,0,0xC3,0x55,0xB8,0x90}},
+ {LCM_SEND(18),{16,0,0xBA,0x31,0x00,0x16,0xCA,0xB1,0x0A,0x00,0x10,0x28,0x02,0x21,0x21,0x9A,0x1A,0x8F}},
+ {LCM_SEND(2),{0x3A,0x70}},
+ {LCM_SEND(7),{5,0,0xB3,0x83,0x00,0x31,0x03}},
+ {LCM_SEND(2),{0xB4,0x00}},
+ {LCM_SEND(2),{0xCC,0x0E}},
+ {LCM_SEND(2),{0xEA,0x72}},
+ {LCM_SEND(2),{0xB2,0x03}},
+
+
+ //set GIP timing control
+ {LCM_SEND(95),{93,0,0xD5,0x00,0x00,0x07,0x00,0x09,0x00,0x00,0x10,0x01,0x00,0x00,0x00,0x01,0x42,0x37,\
+ 0x00,0x00,0x08,0x2A,0x08,0x47,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+ 0x15,0x00,0x00,0x98,0x98,0x44,0x66,0x00,0x22,0x51,0x00,0x00,0x89,0x98,0x33,0x11,0x77,0x55,0x04,0x00,\
+ 0x00,0x98,0x98,0x55,0x77,0x11,0x33,0x40,0x00,0x00,0x89,0x98,0x22,0x00,0x66,0x44,0x15,0x00,0x00,0x00,\
+ 0x01,0x00,0x00,0x00,0x03,0x00,0x0F,0xFF,0xFF,0x03,0x00,0x0F,0xFF,0xFF,0x00,0x8C,0x5A}},
+
+ //gamma setting
+ {LCM_SEND(38),{36,0,0xE0,0x00,0x02,0x04,0x2C,0x33,0x3F,0x0D,0x32,0x05,0x0B,0x0E,0x11,0x14,0x12,0x13,0x13,0x1A,0x00,\
+0x02,0x04,0x2C,0x32,0x3F,0x0F,0x31,0x05,0x0B,0x0E,0x11,0x14,0x12,0x13,0x13,0x1A,0x01,
+}},
+
+
+ {LCM_SEND(5),{3,0,0xC9,0x0F,0x00}},
+ {LCM_SLEEP(5)},
+// {LCM_SEND(2),{0x51,0x80}},
+// {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(180)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(10)}, //40
+
+#endif
+
+};
+
+static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(150)}, //>150ms
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(150)}, //>150ms
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},//>120ms
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)}, //>20ms
+};
+static int32_t hx8369b_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel hx8369b_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t hx8369b_readid(struct panel_spec *self)
+{
+ int32_t j =0;
+ uint8_t read_data[3] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("kernel lcd_hx8369b_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x01;
+ param[1] = 0x00;
+ mipi_force_write(0x37, param, 2);
+ read_rtn = mipi_force_read(0xda,1,&read_data[0]);
+ read_rtn = mipi_force_read(0xdb,1,&read_data[1]);
+ read_rtn = mipi_force_read(0xdc,1,&read_data[2]);
+
+#ifndef NEW_PANAL_BOE
+ if((0x55 == read_data[0])&&(0xc0 == read_data[1])&&(0x90 == read_data[2]))
+#else
+ if((0x55 == read_data[0])&&(0xB8 == read_data[1])&&(0x90 == read_data[2]))
+#endif
+ {
+ printk("lcd_hx8369b_mipi read id success!\n");
+ return 0x8369;
+ }
+ }
+ mipi_eotp_set(0,0);
+ LCD_PRINT("lcd_hx8369b_mipi read id fail! 0xda,0xdb,0xdc is 0x%x,0x%x,0x%x!\n",read_data[0],read_data[1],read_data[2]);
+ return 0;
+}
+
+
+static int32_t hx8369b_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i = 0;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel hx8369b_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(sleep_in_out->tag & LCM_TAG_MASK);
+ }
+ sleep_in_out++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static struct panel_operations lcd_hx8369b_mipi_operations = {
+ .panel_init = hx8369b_mipi_init,
+ .panel_readid = hx8369b_readid,
+ .panel_enter_sleep = hx8369b_enter_sleep,
+};
+
+static struct timing_rgb lcd_hx8369b_mipi_timing = {
+ .hfp = 110, /* unit: pixel */
+ .hbp = 110,
+ .hsync = 4,
+ .vfp = 10, /*unit: line*/
+ .vbp = 12,
+ .vsync = 4,
+};
+
+
+static struct info_mipi lcd_hx8369b_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq =481*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_hx8369b_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_hx8369b_mipi_spec = {
+ .width = 480,
+ .height = 800,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_hx8369b_mipi_info
+ },
+ .ops = &lcd_hx8369b_mipi_operations,
+};
+struct panel_cfg lcd_hx8369b_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x8369,
+ .lcd_name = "lcd_hx8369b_mipi",
+ .panel = &lcd_hx8369b_mipi_spec,
+};
+
+//temp code
+static int __init lcd_hx8369b_mipi_init(void)
+{
+/*
+ printk("hx8369b_mipi_init: set lcd backlight.\n");
+
+ if (gpio_request(214, "LCD_BL")) {
+ printk("Failed ro request LCD_BL GPIO_%d \n",
+ 214);
+ return -ENODEV;
+ }
+ gpio_direction_output(214, 1);
+ gpio_set_value(214, 1);
+*/
+
+ return sprdfb_panel_register(&lcd_hx8369b_mipi);
+}
+
+subsys_initcall(lcd_hx8369b_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_kiran3g.c b/drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_kiran3g.c
new file mode 100644
index 00000000..9926fd76
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_kiran3g.c
@@ -0,0 +1,384 @@
+/* drivers/video/sprdfb/lcd_hx8369b_mipi.c
+ *
+ * Support for hx8369b mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+#include <mach/gpio.h>
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 150
+#define LCD_NEW_PANEL
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+
+#ifndef LCD_NEW_PANEL
+ {LCM_SEND(6),{4,0,0xB9,0xFF,0x83,0x69}},
+ {LCM_SEND(13),{11,0,0xB1,0x0B,0x83,0x77,0x00,0x11,0x11,0x08,0x08,0x0C,0x12}},
+ {LCM_SEND(7),{5,0,0xC6,0x41,0xFF,0x7A,0xFF}},
+ {LCM_SEND(7),{5,0,0xE3,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(9),{7,0,0xC0,0x73,0x50,0x00,0x34,0xC4,0x00}},
+ {LCM_SEND(18),{16,0,0xBA,0x31,0x00,0x16,0xCA,0xB0,0x0A,0x00,0x10,0x28,0x02,0x21,0x21,0x9A,0x1A,0x8F}},
+ {LCM_SEND(2),{0x3A,0x70}},
+ {LCM_SEND(10),{8,0,0xB3,0x83,0x00,0x31,0x03,0x01,0x13,0x06}},
+ {LCM_SEND(2),{0xB4,0x00}},
+ {LCM_SEND(2),{0xCC,0x0C}},
+ {LCM_SEND(2),{0xEA,0x72}},
+ {LCM_SEND(2),{0xB2,0x03}},
+
+ //set GIP timing control
+ {LCM_SEND(95),{93, 0, 0xD5,
+ 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x12, 0x40, 0x00,\
+ 0x00, 0x00, 0x01, 0x60, 0x37, 0x00, 0x00, 0x0F, 0x01, 0x02,\
+ 0x47, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+ 0x00, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, 0x89, 0x00,\
+ 0x11, 0x33, 0x55, 0x77, 0x31, 0x00, 0x00, 0x98, 0x00, 0x66,\
+ 0x44, 0x22, 0x00, 0x02, 0x00, 0x00, 0x89, 0x00, 0x00, 0x22,\
+ 0x44, 0x66, 0x20, 0x00, 0x00, 0x98, 0x00, 0x77, 0x55, 0x33,\
+ 0x11, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03,\
+ 0x00, 0xCF, 0xFF, 0xFF, 0x03, 0x00, 0xCF, 0xFF, 0xFF, 0x20,\
+ 0x8C, 0x5A}},
+
+ //gamma setting
+ {LCM_SEND(38),{36, 0, 0xE0,
+ 0x00, 0x00, 0x00, 0x0D, 0x0C, 0x3F, 0x18, 0x2C, 0x04, 0x0F,\
+ 0x0E, 0x14, 0x17, 0x15, 0x16, 0x10, 0x13, 0x00, 0x00, 0x00,\
+ 0x0C, 0x12, 0x3F, 0x17, 0x2C, 0x05, 0x08, 0x0E, 0x12, 0x16,\
+ 0x14, 0x15, 0x11, 0x13, 0x01}},
+ {LCM_SEND(130),{128, 0, 0xC1,
+ 0x01, 0x00, 0x08, 0x10, 0x18, 0x1F, 0x27, 0x2E, 0x34, 0x3E,\
+ 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78, 0x80, 0x88, 0x90,\
+ 0x98, 0xA0, 0xA8, 0xB0, 0xB8, 0xC0, 0xC8, 0xD0, 0xD8, 0xE0,\
+ 0xE8, 0xF0, 0xF7, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x18, 0x1F, 0x27, 0x2E,\
+ 0x34, 0x3E, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78, 0x80,\
+ 0x88, 0x90, 0x98, 0xA0, 0xA8, 0xB0, 0xB8, 0xC0, 0xC8, 0xD0,\
+ 0xD8, 0xE0, 0xE8, 0xF0, 0xF7, 0xFF, 0x00, 0x00, 0x00, 0x00,\
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x18, 0x1F,\
+ 0x27, 0x2E, 0x34, 0x3E, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70,\
+ 0x78, 0x80, 0x88, 0x90, 0x98, 0xA0, 0xA8, 0xB0, 0xB8, 0xC0,\
+ 0xC8, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF7, 0xFF, 0x00, 0x00,\
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1),{0x29}},
+#else
+ /* Password */
+ {LCM_SEND(5),{3,0,0xF0,0x5A,0x5A}},
+ {LCM_SEND(5),{3,0,0xF1,0x5A,0x5A}},
+ {LCM_SEND(5),{3,0,0xFC,0xA5,0xA5}},
+
+ /* Resolution Control */
+ {LCM_SEND(2),{0xB3, 0x01}},
+ {LCM_SEND(2),{0xB5, 0x10}},
+ {LCM_SEND(6),{4,0,0xBC,0x00,0x29,0x51}}, /* 141006 Battery detect function disabled */
+
+ /* MIPI SETTING */
+ {LCM_SEND(5),{3,0,0xE3,0x24,0x2C}},
+
+ /* Display Inversion Off */
+ {LCM_SEND(1),{0x21}},
+
+ /* Display Control */
+ {LCM_SEND(11), {9,0,0xF2,0x11,0x04,0x08,0x10,0x10,0x72,0x4A,0x0A}},
+
+ /* power control 1 */
+ {LCM_SEND(8),{6,0,0xF3,0x91,0x00,0x00,0x00,0x10}},
+
+ /* power control 2 */
+ {LCM_SEND(46),{44,0,0xF4,0x01,0x02,0x23,0x24,0x25,0x25,0x26,0x26,0x29,0x29,0x2C,0x2B,0x2C,0x07,0x08,0x05,0x04,0x04,0x01,0x01,0x22,0x0A,0x17,0x0F,0x11,0x23,0x0D,0x0A,0x0B,0x02,0x19,0x13,0x1E,0x1F,0x23,0x20,0x05,0x16,0x1A,0x16,0x1E,0x24,0x1E}},
+
+ /* power control 3 */
+ {LCM_SEND(31),{29,0,0xF5,0x14,0x14,0xB9,0x21,0x35,0x55,0x36,0x0A,0x00,0x39,0x00,0x00,0x0B,0x4B,0xC4,0xCB,0x4B,0x12,0x12,0x1A,0x00,0x10,0xE0,0xE2,0x0E,0x34,0x34,0x03}},
+
+ /* 9.4 */
+ {LCM_SEND(20),{18,0,0xFE,0x00,0x02,0x01,0x39,0x60,0x40,0x21,0x00,0x4B,0x00,0x80,0x00,0xF0,0x00,0x00,0x00,0x06}},
+
+ /* ASG EQ Control */
+ {LCM_SEND(13),{11,0,0xEE,0x40,0xA0,0x40,0xA0,0x00,0x00,0x00,0x00,0x00,0x00}},
+
+ {LCM_SEND(23),{21,0,0xEF,0x23,0x01,0x00,0x00,0x2A,0x49,0x08,0x27,0x21,0x40,0x10,0x24,0x02,0x21,0x21,0x03,0x03,0x40,0x00,0x08}},
+
+ /* Panel Gate Control */
+ {LCM_SEND(33),{31,0,0xF7,0x02,0x1B,0x1A,0x00,0x01,0x0E,0x0E,0x0A,0x0A,0x0F,0x0F,0x0B,0x0B,0x05,0x07,0x02,0x1B,0x1A,0x00,0x01,0x0C,0x0C,0x08,0x08,0x0D,0x0D,0x09,0x09,0x04,0x06}},
+
+ /* Source Control */
+ {LCM_SEND(9),{7,0,0xF6,0x63,0x25,0x15,0x00,0x00,0x20}},
+
+ /* Memory Data Access Control */
+ {LCM_SEND(2),{0x36,0x10}},
+
+ /* Positive Gamma Control */
+ {LCM_SEND(20),{18,0,0xFA,0x0C,0x36,0x0B,0x10,0x07,0x0C,0x10,0x10,0x14,0x1D,0x1F,0x1F,0x20,0x21,0x22,0x25,0x2F}},
+
+ /* Negative Gamma Control */
+ {LCM_SEND(20),{18,0,0xFB,0x0C,0x36,0x0B,0x10,0x07,0x0C,0x10,0x0E,0x0E,0x15,0x1B,0x1E,0x20,0x1F,0x20,0x25,0x2F}},
+
+ /* display on */
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(120)},
+
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(120)},
+#endif
+
+};
+
+static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(150)}, //>150ms
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(150)}, //>150ms
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},//>120ms
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)}, //>20ms
+};
+static int32_t hx8369b_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel hx8369b_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t hx8369b_readid(struct panel_spec *self)
+ {
+ int32_t j =0;
+ uint8_t read_data[4] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("kernel lcd_hx8369b_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+#ifndef LCD_NEW_PANEL
+ param[0] = 0x01;
+ param[1] = 0x00;
+ mipi_force_write(0x37, param, 2);
+ read_rtn = mipi_force_read(0xda,1,&read_data[0]);
+ LCD_PRINT("lcd_hx8369b_mipi read id 0xda value is 0x%x!\n",read_data[0]);
+
+ read_rtn = mipi_force_read(0xdb,1,&read_data[1]);
+ LCD_PRINT("lcd_hx8369b_mipi read id 0xdb value is 0x%x!\n",read_data[1]);
+
+ read_rtn = mipi_force_read(0xdc,1,&read_data[2]);
+ LCD_PRINT("lcd_hx8369b_mipi read id 0xdc value is 0x%x!\n",read_data[2]);
+
+ if((0x55 == read_data[0])&&(0xbf == read_data[1] || 0xc0 == read_data[1] || 0xbe == read_data[1])&&(0x90 == read_data[2])){
+ LCD_PRINT("lcd_hx8369b_mipi read id success!\n");
+ return 0x8369;
+ }
+#else
+ param[0] = 0x03;
+ param[1] = 0x00;
+ mipi_force_write(0x37, param, 2);
+ read_rtn = mipi_force_read(0x04, 3, read_data);
+ LCD_PRINT("lcd_s6d77a1_mipi read id 0xda, 0xdb,0xdc is 0x%x,0x%x,0x%x!\n",
+ read_data[0], read_data[1], read_data[2]);
+ if ((0x55 == read_data[0]) && (0xB8 == read_data[1])
+ && (0x10 == read_data[2])) {
+ LCD_PRINT("lcd_s6d77a1_mipi read id success!\n");
+ return 0x8369;
+ }
+#endif
+ }
+
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+
+static int32_t hx8369b_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i = 0;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel hx8369b_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(sleep_in_out->tag & LCM_TAG_MASK);
+ }
+ sleep_in_out++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static struct panel_operations lcd_hx8369b_mipi_operations = {
+ .panel_init = hx8369b_mipi_init,
+ .panel_readid = hx8369b_readid,
+ .panel_enter_sleep = hx8369b_enter_sleep,
+};
+
+static struct timing_rgb lcd_hx8369b_mipi_timing = {
+#ifndef LCD_NEW_PANEL
+ .hfp = 115, /* unit: pixel */
+ .hbp = 55,
+ .hsync = 4,
+ .vfp = 6, /*unit: line*/
+ .vbp = 19,
+ .vsync = 4,
+#else
+ .hfp = 74, /* unit: pixel */
+ .hbp = 88,
+ .hsync = 26,
+ .vfp = 16, /* unit: line */
+ .vbp = 12,
+ .vsync = 4,
+#endif
+};
+
+
+static struct info_mipi lcd_hx8369b_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq =481*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_hx8369b_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_hx8369b_mipi_spec = {
+ .width = 480,
+ .height = 800,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .is_clean_lcd = true,
+ .info = {
+ .mipi = &lcd_hx8369b_mipi_info
+ },
+ .ops = &lcd_hx8369b_mipi_operations,
+};
+struct panel_cfg lcd_hx8369b_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x8369,
+ .lcd_name = "lcd_hx8369b_mipi",
+ .panel = &lcd_hx8369b_mipi_spec,
+};
+
+//temp code
+static int __init lcd_hx8369b_mipi_init(void)
+{
+/*
+ printk("hx8369b_mipi_init: set lcd backlight.\n");
+
+ if (gpio_request(214, "LCD_BL")) {
+ printk("Failed ro request LCD_BL GPIO_%d \n",
+ 214);
+ return -ENODEV;
+ }
+ gpio_direction_output(214, 1);
+ gpio_set_value(214, 1);
+*/
+
+ return sprdfb_panel_register(&lcd_hx8369b_mipi);
+}
+
+subsys_initcall(lcd_hx8369b_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_sharkls_z3lte.c b/drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_sharkls_z3lte.c
new file mode 100644
index 00000000..65e7014a
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_sharkls_z3lte.c
@@ -0,0 +1,348 @@
+/* drivers/video/sprdfb/lcd_hx8369b_mipi.c
+ *
+ * Support for hx8369b mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+#include <mach/gpio.h>
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 150
+#define NEW_PANAL_BOE
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+#ifndef NEW_PANAL_BOE
+ {LCM_SEND(6),{4,0,0xB9,0xFF,0x83,0x69}},
+ {LCM_SLEEP(10)},
+ {LCM_SEND(18),{16,0,0xBA,0x31,0x00,0x16,0xCA,0xB1,0x0A,0x00,0x10,0x28,0x02,0x21,0x21,0x9A,0x1A,0x8F}},
+
+ //set GIP timing control
+ {LCM_SEND(95),{93,0,0xD5,0x00,0x00,0x07,0x00,0x09,0x00,0x00,0x10,0x01,0x00,0x00,0x00,0x01,0x42,0x37,\
+ 0x00,0x00,0x08,0x2A,0x08,0x47,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+ 0x15,0x00,0x00,0x98,0x98,0x44,0x66,0x00,0x22,0x51,0x00,0x00,0x89,0x98,0x33,0x11,0x77,0x55,0x04,0x00,\
+ 0x00,0x98,0x98,0x55,0x77,0x11,0x33,0x40,0x00,0x00,0x89,0x98,0x22,0x00,0x66,0x44,0x15,0x00,0x00,0x00,\
+ 0x01,0x00,0x00,0x00,0x03,0x00,0x0F,0xFF,0xFF,0x03,0x00,0x0F,0xFF,0xFF,0x00,0x8C,0x5A}},
+ {LCM_SEND(2),{0x3A,0x70}},
+ {LCM_SEND(2),{0x36,0x00}},
+
+ {LCM_SEND(13),{11,0,0xB1,0x0B,0x83,0x77,0x00,0x0F,0x0F,0x16,0x16,0x0C,0x0A}},
+ {LCM_SEND(2),{0xB2,0x03}},
+// {LCM_SEND(5),{3,0,0xB2,0x00,0x70}},
+ {LCM_SEND(7),{5,0,0xB3,0x83,0x00,0x31,0x03}},
+ {LCM_SEND(2),{0xB4,0x00}},
+ {LCM_SEND(5),{3,0,0xB6,0xA3,0xA3}},
+ {LCM_SEND(2),{0xCC,0x0C}},
+ {LCM_SEND(9),{7,0,0xC0,0x73,0x50,0x00,0x34,0xc4,0x00}},
+ {LCM_SEND(7),{5,0,0xE3,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0xEA,0x72}},
+ {LCM_SEND(6),{4,0,0xC6,0x41,0xFF,0x7D}},
+
+
+ //gamma setting
+ {LCM_SEND(38),{36,0,0xE0,0x01,0x0D,0x18,0x14,0x13,0x2F,0x31,0x3B,0x09,0x10,0x12,0x16,0x17,0x16,0x16,0x11,0x14,0x01,\
+ 0x0D,0x18,0x14,0x13,0x2F,0x30,0x3B,0x09,0x10,0x11,0x16,0x17,0x15,0x16,0x11,0x14,0x01}},
+ {LCM_SEND(130),{128,0,0xC1,0x03,0x00,0x06,0x0D,0x15,0x1D,0x25,0x2D,0x35,0x3D,\
+ 0x45,0x4D,0x55,0x5D,0x65,0x6D,0x75,0x7C,0x84,0x8C,\
+ 0x94,0x9C,0xA4,0xAC,0xB4,0xBC,0xC4,0xCC,0xD4,0xDC,\
+ 0xE4,0xEC,0xF3,0xFD,0x0F,0xFA,0x95,0x40,0xFF,0xAA,\
+ 0x54,0x03,0xC0,0x00,0x07,0x0F,0x17,0x1F,0x27,0x2F,\
+ 0x37,0x3F,0x47,0x4F,0x57,0x5F,0x67,0x6F,0x77,0x7F,\
+ 0x87,0x8F,0x97,0x9F,0xA7,0xAF,0xB7,0xBF,0xC7,0xCF,\
+ 0xD7,0xDF,0xE7,0xEF,0xF7,0xFF,0x00,0x00,0x00,0x00,\
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x0F,0x17,0x1F,\
+ 0x27,0x2F,0x37,0x3F,0x47,0x4F,0x57,0x5F,0x67,0x6F,\
+ 0x77,0x7F,0x87,0x8F,0x97,0x9F,0xA7,0xAF,0xB7,0xBF,\
+ 0xC7,0xCF,0xD7,0xDF,0xE7,0xEF,0xF7,0xFF,0x00,0x00,\
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,}},
+
+ {LCM_SEND(5),{3,0,0xC9,0x0F,0x00}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(2),{0x51,0x00}},
+ {LCM_SLEEP(5)},
+// {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(180)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(10)}, //40
+
+#else
+
+ {LCM_SEND(6),{4,0,0xB9,0xFF,0x83,0x69}},
+ //{LCM_SLEEP(10)},
+
+ {LCM_SEND(13),{11,0,0xB1,0x0B,0x83,0x77,0x00,0x0F,0x0F,0x0B,0x0B,0x0C,0x0A}},
+ {LCM_SEND(6),{4,0,0xC6,0x41,0xFF,0x7D}},
+ {LCM_SEND(7),{5,0,0xE3,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(9),{7,0,0xC0,0x73,0x50,0x00,0x34,0xC4,0x00}},
+ {LCM_SEND(6),{4,0,0xC3,0x55,0xB8,0x90}},
+ {LCM_SEND(18),{16,0,0xBA,0x31,0x00,0x16,0xCA,0xB1,0x0A,0x00,0x10,0x28,0x02,0x21,0x21,0x9A,0x1A,0x8F}},
+ {LCM_SEND(2),{0x3A,0x70}},
+ {LCM_SEND(7),{5,0,0xB3,0x83,0x00,0x31,0x03}},
+ {LCM_SEND(2),{0xB4,0x00}},
+ {LCM_SEND(2),{0xCC,0x0E}},
+ {LCM_SEND(2),{0xEA,0x72}},
+ {LCM_SEND(2),{0xB2,0x03}},
+
+
+ //set GIP timing control
+ {LCM_SEND(95),{93,0,0xD5,0x00,0x00,0x07,0x00,0x09,0x00,0x00,0x10,0x01,0x00,0x00,0x00,0x01,0x42,0x37,\
+ 0x00,0x00,0x08,0x2A,0x08,0x47,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+ 0x15,0x00,0x00,0x98,0x98,0x44,0x66,0x00,0x22,0x51,0x00,0x00,0x89,0x98,0x33,0x11,0x77,0x55,0x04,0x00,\
+ 0x00,0x98,0x98,0x55,0x77,0x11,0x33,0x40,0x00,0x00,0x89,0x98,0x22,0x00,0x66,0x44,0x15,0x00,0x00,0x00,\
+ 0x01,0x00,0x00,0x00,0x03,0x00,0x0F,0xFF,0xFF,0x03,0x00,0x0F,0xFF,0xFF,0x00,0x8C,0x5A}},
+
+ //gamma setting
+ {LCM_SEND(38),{36,0,0xE0,0x00,0x02,0x04,0x2C,0x33,0x3F,0x0D,0x32,0x05,0x0B,0x0E,0x11,0x14,0x12,0x13,0x13,0x1A,0x00,\
+0x02,0x04,0x2C,0x32,0x3F,0x0F,0x31,0x05,0x0B,0x0E,0x11,0x14,0x12,0x13,0x13,0x1A,0x01,
+}},
+
+
+ {LCM_SEND(5),{3,0,0xC9,0x0F,0x00}},
+ {LCM_SLEEP(5)},
+// {LCM_SEND(2),{0x51,0x80}},
+// {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(180)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(10)}, //40
+
+#endif
+
+};
+
+static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(150)}, //>150ms
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(150)}, //>150ms
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},//>120ms
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)}, //>20ms
+};
+static int32_t hx8369b_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel hx8369b_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t hx8369b_readid(struct panel_spec *self)
+{
+ int32_t j =0;
+ uint8_t read_data[3] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("kernel lcd_hx8369b_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x01;
+ param[1] = 0x00;
+ mipi_force_write(0x37, param, 2);
+ read_rtn = mipi_force_read(0xda,1,&read_data[0]);
+ read_rtn = mipi_force_read(0xdb,1,&read_data[1]);
+ read_rtn = mipi_force_read(0xdc,1,&read_data[2]);
+
+#ifndef NEW_PANAL_BOE
+ if((0x55 == read_data[0])&&(0xc0 == read_data[1])&&(0x90 == read_data[2]))
+#else
+ if((0x55 == read_data[0])&&(0xB8 == read_data[1])&&(0x90 == read_data[2]))
+#endif
+ {
+ printk("lcd_hx8369b_mipi read id success!\n");
+ return 0x8369;
+ }
+ }
+ mipi_eotp_set(0,0);
+ LCD_PRINT("lcd_hx8369b_mipi read id fail! 0xda,0xdb,0xdc is 0x%x,0x%x,0x%x!\n",read_data[0],read_data[1],read_data[2]);
+ return 0;
+}
+
+
+static int32_t hx8369b_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i = 0;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel hx8369b_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(sleep_in_out->tag & LCM_TAG_MASK);
+ }
+ sleep_in_out++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static struct panel_operations lcd_hx8369b_mipi_operations = {
+ .panel_init = hx8369b_mipi_init,
+ .panel_readid = hx8369b_readid,
+ .panel_enter_sleep = hx8369b_enter_sleep,
+};
+
+static struct timing_rgb lcd_hx8369b_mipi_timing = {
+ .hfp = 110, /* unit: pixel */
+ .hbp = 110,
+ .hsync = 4,
+ .vfp = 10, /*unit: line*/
+ .vbp = 12,
+ .vsync = 4,
+};
+
+
+static struct info_mipi lcd_hx8369b_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq =481*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_hx8369b_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_hx8369b_mipi_spec = {
+ .width = 480,
+ .height = 800,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_hx8369b_mipi_info
+ },
+ .ops = &lcd_hx8369b_mipi_operations,
+};
+struct panel_cfg lcd_hx8369b_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x8369,
+ .lcd_name = "lcd_hx8369b_mipi",
+ .panel = &lcd_hx8369b_mipi_spec,
+};
+
+//temp code
+static int __init lcd_hx8369b_mipi_init(void)
+{
+/*
+ printk("hx8369b_mipi_init: set lcd backlight.\n");
+
+ if (gpio_request(214, "LCD_BL")) {
+ printk("Failed ro request LCD_BL GPIO_%d \n",
+ 214);
+ return -ENODEV;
+ }
+ gpio_direction_output(214, 1);
+ gpio_set_value(214, 1);
+*/
+
+ return sprdfb_panel_register(&lcd_hx8369b_mipi);
+}
+
+subsys_initcall(lcd_hx8369b_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_vivaltoVE.c b/drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_vivaltoVE.c
new file mode 100644
index 00000000..6ffe813e
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_vivaltoVE.c
@@ -0,0 +1,283 @@
+/* drivers/video/sprdfb/lcd_hx8369b_mipi.c
+ *
+ * Support for hx8369b mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+#include <mach/gpio.h>
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 150
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+ {LCM_SEND(6),{4,0,0xB9,0xFF,0x83,0x69}},
+ //{LCM_SLEEP(10)},
+ {LCM_SEND(13),{11,0,0xB1,0x0B,0x83,0x77,0x00,0x11,0x11,0x08,0x08,0x0C,0x12}},
+ {LCM_SEND(7),{5,0,0xC6,0x41,0xFF,0x7A,0xFF}},
+ {LCM_SEND(7),{5,0,0xE3,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(9),{7,0,0xC0,0x73,0x50,0x00,0x34,0xC4,0x00}},
+ {LCM_SEND(18),{16,0,0xBA,0x31,0x00,0x16,0xCA,0xB0,0x0A,0x00,0x10,0x28,0x02,0x21,0x21,0x9A,0x1A,0x8F}},
+ {LCM_SEND(2),{0x3A,0x70}},
+ {LCM_SEND(10),{8,0,0xB3,0x83,0x00,0x31,0x03,0x01,0x13,0x06}},
+ {LCM_SEND(2),{0xB4,0x00}},
+ {LCM_SEND(2),{0xCC,0x0C}},
+ {LCM_SEND(2),{0xEA,0x72}},
+ {LCM_SEND(2),{0xB2,0x03}},
+ //set GIP timing control
+ {LCM_SEND(95),{93,0,0xD5,0x00,0x00,0x0D,0x00,0x00,0x00,0x00,0x12,0x40,0x00,0x00,0x00,0x01,0x60,0x37,0x00,0x00,0x0F,
+ 0x01,0x02,0x47,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x18,
+ 0x00,0x00,0x89,0x00,0x11,0x33,0x55,0x77,0x31,0x00,0x00,0x98,0x00,0x66,0x44,0x22,0x00,0x02,
+ 0x00,0x00,0x89,0x00,0x00,0x22,0x44,0x66,0x20,0x00,0x00,0x98,0x00,0x77,0x55,0x33,0x11,0x13,
+ 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0xCF,0xFF,0xFF,0x03,0x00,0xCF,0xFF,0xFF,0x20,0x8C,0x5A}},
+ //gamma setting
+ {LCM_SEND(38),{36,0,0xE0,0x00,0x00,0x00,0x0D,0x0C,0x3F,0x18,0x2C,0x04,0x0F,0x0E,0x14,0x17,0x15,0x16,0x10,
+ 0x13,0x00,0x00,0x00,0x0C,0x12,0x3F,0x17,0x2C,0x05,0x08,0x0E,0x12,0x16,0x14,0x15,
+ 0x11,0x13,0x01}},
+ {LCM_SEND(130),{128,0,0xC1,0x01,0x00,0x08,0x10,0x18,0x1F,0x27,0x2E,0x34,0x3E,0x48,0x50,0x58,0x60,0x68,0x70,0x78,
+ 0x80,0x88,0x90,0x98,0xA0,0xA8,0xB0,0xB8,0xC0,0xC8,0xD0,0xD8,0xE0,0xE8,0xF0,0xF7,0xFF,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x18,0x1F,0x27,0x2E,0x34,
+ 0x3E,0x48,0x50,0x58,0x60,0x68,0x70,0x78,0x80,0x88,0x90,0x98,0xA0,0xA8,0xB0,0xB8,0xC0,
+ 0xC8,0xD0,0xD8,0xE0,0xE8,0xF0,0xF7,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x08,0x10,0x18,0x1F,0x27,0x2E,0x34,0x3E,0x48,0x50,0x58,0x60,0x68,0x70,0x78,0x80,
+ 0x88,0x90,0x98,0xA0,0xA8,0xB0,0xB8,0xC0,0xC8,0xD0,0xD8,0xE0,0xE8,0xF0,0xF7,0xFF,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(10)}, //40
+
+};
+
+static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(150)}, //>150ms
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(150)}, //>150ms
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},//>120ms
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)}, //>20ms
+};
+static int32_t hx8369b_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel hx8369b_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t hx8369b_readid(struct panel_spec *self)
+ {
+ int32_t j =0;
+ uint8_t read_data[4] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("kernel lcd_hx8369b_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x01;
+ param[1] = 0x00;
+ mipi_force_write(0x37, param, 2);
+ read_rtn = mipi_force_read(0xda,1,&read_data[0]);
+ LCD_PRINT("lcd_hx8369b_mipi read id 0xda value is 0x%x!\n",read_data[0]);
+
+ read_rtn = mipi_force_read(0xdb,1,&read_data[1]);
+ LCD_PRINT("lcd_hx8369b_mipi read id 0xdb value is 0x%x!\n",read_data[1]);
+
+ read_rtn = mipi_force_read(0xdc,1,&read_data[2]);
+ LCD_PRINT("lcd_hx8369b_mipi read id 0xdc value is 0x%x!\n",read_data[2]);
+
+ if((0x55 == read_data[0])&&(0x0c == read_data[1])&&(0x90 == read_data[2])){
+ printk("lcd_hx8369b_mipi read id success!\n");
+ return 0x8369;
+ }
+ }
+
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+
+static int32_t hx8369b_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i = 0;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel hx8369b_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(sleep_in_out->tag & LCM_TAG_MASK);
+ }
+ sleep_in_out++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static struct panel_operations lcd_hx8369b_mipi_operations = {
+ .panel_init = hx8369b_mipi_init,
+ .panel_readid = hx8369b_readid,
+ .panel_enter_sleep = hx8369b_enter_sleep,
+};
+
+static struct timing_rgb lcd_hx8369b_mipi_timing = {
+ .hfp = 115, /* unit: pixel */
+ .hbp = 55,
+ .hsync = 50,
+ .vfp = 6, /*unit: line*/
+ .vbp = 19,
+ .vsync = 4,
+};
+
+
+static struct info_mipi lcd_hx8369b_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq =481*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_hx8369b_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_hx8369b_mipi_spec = {
+ .width = 480,
+ .height = 800,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_hx8369b_mipi_info
+ },
+ .ops = &lcd_hx8369b_mipi_operations,
+};
+struct panel_cfg lcd_hx8369b_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x8369,
+ .lcd_name = "lcd_hx8369b_mipi",
+ .panel = &lcd_hx8369b_mipi_spec,
+};
+
+//temp code
+static int __init lcd_hx8369b_mipi_init(void)
+{
+/*
+ printk("hx8369b_mipi_init: set lcd backlight.\n");
+
+ if (gpio_request(214, "LCD_BL")) {
+ printk("Failed ro request LCD_BL GPIO_%d \n",
+ 214);
+ return -ENODEV;
+ }
+ gpio_direction_output(214, 1);
+ gpio_set_value(214, 1);
+*/
+
+ return sprdfb_panel_register(&lcd_hx8369b_mipi);
+}
+
+subsys_initcall(lcd_hx8369b_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_hx8369b_tshark2_j3_mipi.c b/drivers/video/sprdfb/lcd/lcd_hx8369b_tshark2_j3_mipi.c
new file mode 100755
index 00000000..5afb97e7
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_hx8369b_tshark2_j3_mipi.c
@@ -0,0 +1,290 @@
+/* drivers/video/sprdfb/lcd_tshark2_j3_mipi.c
+ *
+ * Support for tshark2_j3 mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+#include <mach/gpio.h>
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 150
+
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+
+ {LCM_SEND(6),{4,0,0xB9,0xFF,0x83,0x89}},
+ {LCM_SEND(23),{21,0,0xB1,0x7F,0x10,0x10,0xD2,0x32,0x80,0x10,0xF0,0x56,0x80,0x20,0x20,0xF8,0xAA,0xAA,0xA1,0x00,0x80,0x30,0x00}},
+ {LCM_SEND(13),{11,0,0xB2,0x82,0x50,0x05,0x07,0xF0,0x38,0x11,0x64,0x5D,0x09}},
+ {LCM_SEND(14),{12,0,0xB4,0x66,0x66,0x66,0x70,0x00,0x00,0x18,0x76,0x28,0x76,0xA8}},
+ {LCM_SEND(2),{0xD2,0x33}},
+ {LCM_SEND(7),{5,0,0xC0,0x30,0x17,0x00,0x03}},
+ {LCM_SEND(7),{5,0,0xC7,0x00,0x80,0x00,0xC0}},
+ {LCM_SEND(7),{5,0,0xBF,0x05,0x50,0x00,0x3E}},
+ {LCM_SLEEP(10)},
+ //{LCM_SEND(6),{4,0,0xB9,0xFF,0x83,0x89}},
+ {LCM_SEND(2),{0xCC,0x0E}},
+ {LCM_SEND(38),{36,0,0xD3,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x32,0x10,0x00,0x00,0x00,0x03,0xC6,0x03,0xC6,0x00,0x00,0x00,0x00 \
+ ,0x35,0x33,0x04,0x04,0x37,0x00,0x00,0x00,0x05,0x08,0x00,0x00,0x0A,0x00,0x01}},
+ {LCM_SEND(41),{39,0,0xD5,0x18,0x18,0x18,0x18,0x19,0x19,0x18,0x18,0x20,0x21,0x24,0x25,0x18,0x18,0x18,0x18,0x00,0x01,0x04,0x05 \
+ ,0x02,0x03,0x06,0x07,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ {LCM_SEND(41),{0x39,0,0xD6,0x18,0x18,0x18,0x18,0x18,0x18,0x19,0x19,0x25,0x24,0x21,0x20,0x18,0x18 \
+ ,0x18,0x18,0x07,0x06,0x03,0x02,0x05,0x04,0x01,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18 \
+ ,0x18,0x18,0x18,0x18,0x18,0x18}},
+ {LCM_SEND(6),{4,0,0xB7,0x20,0x80,0x00}},
+
+//gamma
+ {LCM_SEND(45),{43,0,0xE0,0x00,0x02,0x06,0x38,0x3C,0x3F,0x1B,0x46,0x06,0x09,0x0C,0x17 \
+ ,0x10,0x13,0x16,0x13,0x14,0x08,0x13,0x15,0x19,0x00,0x02,0x06,0x37,0x3C,0x3F \
+ ,0x1A,0x45,0x05,0x09,0x0B,0x16,0x0F,0x13,0x15,0x13,0x14,0x07,0x12,0x14,0x18}},
+
+ {LCM_SEND(2),{0xBD,0x00}},
+ {LCM_SEND(46),{44,0,0xC1,0x00,0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50 \
+ ,0x58,0x60,0x68,0x70,0x78,0x80,0x88,0x90,0x98,0xA0,0xA8,0xB0,0xB8,0xC0,0xC8,0xD0,0xD8 \
+ ,0xE0,0xE8,0xF0,0xF8,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0xBD,0x01}},
+ {LCM_SEND(45),{43,0,0xC1,0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x78 \
+ ,0x80,0x88,0x90,0x98,0xA0,0xA8,0xB0,0xB8,0xC0,0xC8,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0xFF,0x00,0x00,0x00 \
+ ,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0xBD,0x02}},
+ {LCM_SEND(45),{43,0,0xC1,0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x78,0x80,0x88,0x90 \
+ ,0x98,0xA0,0xA8,0xB0,0xB8,0xC0,0xC8,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+}},
+
+//CABC
+ {LCM_SEND(2),{0x51,0x80}},
+ {LCM_SLEEP(5)},
+
+ {LCM_SEND(16),{14,0,0xC9,0x1F,0x2E,0x0A,0x1E,0x81,0x1E,0x00,0x00,0x01,0x19,0x00,0x00,0x20}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(2),{0x55,0x00}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SLEEP(5)},
+
+//display on
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(180)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(10)},
+
+};
+
+static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(150)}, //>150ms
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(150)}, //>150ms
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},//>120ms
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)}, //>20ms
+};
+
+
+static int32_t tshark2_j3_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel J3_tshark2_j3_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t tshark2_j3_readid(struct panel_spec *self)
+{
+ int32_t j =0;
+ uint8_t read_data[3] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("kernel lcd_tshark2_j3_mipi_J3 read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x01;
+ param[1] = 0x00;
+ mipi_force_write(0x37, param, 2);
+ read_rtn = mipi_force_read(0xda,1,&read_data[0]);
+ read_rtn = mipi_force_read(0xdb,1,&read_data[1]);
+ read_rtn = mipi_force_read(0xdc,1,&read_data[2]);
+
+
+ if((0x55 == read_data[0])&&(0xc0 == read_data[1])&&(0x90 == read_data[2]))
+ {
+ printk("lcd_tshark2_j3_mipi read id success!\n");
+ return 0x8369;
+ }
+ }
+ mipi_eotp_set(0,0);
+ LCD_PRINT("lcd_tshark2_j3_mipi read id fail! 0xda,0xdb,0xdc is 0x%x,0x%x,0x%x!\n",read_data[0],read_data[1],read_data[2]);
+ return 0;
+}
+
+
+static int32_t tshark2_j3_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i = 0;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel tshark2_j3_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(sleep_in_out->tag & LCM_TAG_MASK);
+ }
+ sleep_in_out++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static struct panel_operations lcd_tshark2_j3_mipi_operations = {
+ .panel_init = tshark2_j3_mipi_init,
+ .panel_readid = tshark2_j3_readid,
+ .panel_enter_sleep = tshark2_j3_enter_sleep,
+};
+
+static struct timing_rgb lcd_tshark2_j3_mipi_timing = {
+ .hfp = 80, /* unit: pixel */
+ .hbp = 80,
+ .hsync = 20,
+ .vfp = 18, /*unit: line*/
+ .vbp = 13,
+ .vsync = 2,
+};
+
+
+static struct info_mipi lcd_tshark2_j3_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq =500*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_tshark2_j3_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_tshark2_j3_mipi_spec = {
+ .width = 540,
+ .height = 960,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_tshark2_j3_mipi_info
+ },
+ .ops = &lcd_tshark2_j3_mipi_operations,
+};
+struct panel_cfg lcd_tshark2_j3_mipi = {
+
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x8369,
+ .lcd_name = "lcd_tshark2_j3_mipi",
+ .panel = &lcd_tshark2_j3_mipi_spec,
+};
+
+//temp code
+static int __init lcd_tshark2_j3_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_tshark2_j3_mipi);
+}
+
+subsys_initcall(lcd_tshark2_j3_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_hx8379a_mipi.c b/drivers/video/sprdfb/lcd/lcd_hx8379a_mipi.c
new file mode 100644
index 00000000..4b6c4a08
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_hx8379a_mipi.c
@@ -0,0 +1,312 @@
+/* drivers/video/sprdfb/lcd_hx8379a_mipi.c
+ *
+ * Support for hx8379a mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+#include <mach/gpio.h>
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 100
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+// Set EXTC
+{LCM_SEND(6), {4, 0, 0xb9,0xff,0x83,0x79}},
+
+// Set MIPI
+{LCM_SEND(5), {3, 0, 0xba,0x51,0x93}},
+//Set Power
+{LCM_SEND(34), {32, 0, 0xB1,0x00,0x50,0x24,0xF5,0x98,0x08,0x11,0x17,0x77,0x29,0x31,0x9A,
+ 0x1A,0x12,0x0B,0x76,0xF1,0x00,0xE6,0xE6,0xE6,0xE6,0xE6,0x00,0x04,0x05,
+ 0x0A,0x0B,0x04,0x05,0x6F}},
+// Set Display
+{LCM_SEND(16), {14, 0, 0xB2,0x00,0x00,0xFE,0x0E,0x0A,0x19,0xE2,0x00,0xFF,0x0E,0x0A,0x19,0x20}},
+// Set CYC
+{LCM_SEND(34), {32, 0, 0xB4,0x80,0x12,0x00,0x32,0x10,0x03,0x54,0x13,0x67,0x32,0x13,0x6B,
+ 0x39,0x00,0x42,0x05,0x37,0x00,0x41,0x08,0x3C,0x3C,0x08,0x00,0x40,0x08,
+ 0x28,0x08,0x30,0x30,0x04}},
+// Set GIP
+{LCM_SEND(50), {48, 0, 0xD5,0x00,0x00,0x0A,0x00,0x01,0x00,0x00,0x06,0x01,0x01,0x01,
+ 0x23,0x45,0x67,0xAA,0xBB,0x88,0x88,0x67,0x45,0x88,0x88,0x88,0x88,0x88,
+ 0x54,0x10,0x76,0x54,0x32,0xAA,0xBB,0x88,0x88,0x76,0x10,0x88,0x88,0x88,
+ 0x88,0x88,0x39,0x01,0x00,0x00,0x00,0x00}},
+// Set Gamma
+{LCM_SEND(38), {36, 0, 0xE0,0x79,0x00,0x01,0x0F,0x25,0x26,0x3F,0x33,0x47,0x0A,0x11,0x11,
+ 0x15,0x17,0x14,0x16,0x11,0x17,0x00,0x01,0x0F,0x25,0x26,0x3F,0x33,0x47,
+ 0x0A,0x11,0x11,0x15,0x17,0x14,0x16,0x11,0x17}},
+// Set Panel
+//{LCM_SEND(2), {0xcc,0x02}}, //no rotation
+{LCM_SEND(2), {0xcc,0x0E}},//rotation 180
+// Set VCOM
+{LCM_SEND(7), {5, 0, 0xB6,0x00,0xAC,0x00,0xAC}},
+//set TE
+{LCM_SEND(2), {0x35,0x00}},
+
+{LCM_SEND(1), {0x11}},//0x11
+{LCM_SLEEP(200)},
+{LCM_SEND(1), {0x29}},//0x29
+{LCM_SLEEP(100)},
+};
+
+static LCM_Force_Cmd_Code rd_prep_code_1[]={
+ {0x37, {LCM_SEND(2), {0x1, 0}}},
+};
+
+static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(150)}, //>150ms
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(150)}, //>150ms
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},//>120ms
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)}, //>20ms
+};
+
+static int32_t hx8379a_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel hx8369b_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t hx8379a_readid(struct panel_spec *self)
+{
+ uint32_t j =0;
+ uint8_t read_data[4] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("lcd_hx8379a_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x01;
+ param[1] = 0x00;
+ mipi_force_write(0x37, param, 2);
+ read_rtn = mipi_force_read(0xda,1,&read_data[0]);
+ LCD_PRINT("lcd_hx8379a_mipi read id 0xda value is 0x%x!\n",read_data[0]);
+
+ read_rtn = mipi_force_read(0xdb,1,&read_data[1]);
+ LCD_PRINT("lcd_hx8379a_mipi read id 0xdb value is 0x%x!\n",read_data[1]);
+
+ read_rtn = mipi_force_read(0xdc,1,&read_data[2]);
+ LCD_PRINT("lcd_hx8379a_mipi read id 0xdc value is 0x%x!\n",read_data[2]);
+
+ if((0x83 == read_data[0])&&(0x79 == read_data[1])&&(0x0a == read_data[2])){
+ LCD_PRINT("lcd_hx8379a_mipi read id success!\n");
+ return 0x8379;
+ }
+ }
+
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t hx8379a_readpowermode(struct panel_spec *self)
+{
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code_1;
+ uint8_t read_data[1] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_debug("lcd_nt35516_mipi read power mode!\n");
+ mipi_eotp_set(0,1);
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code_1;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code_1); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }
+ rd_prepare++;
+ }
+ read_rtn = mipi_force_read(0x0A, 1,(uint8_t *)read_data);
+ pr_debug("lcd_hx8379a mipi read power mode 0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+ if((0x1c == read_data[0]) && (0 == read_rtn)){
+ //printk("lcd_hx8379a_mipi read power mode success!\n");
+ mipi_eotp_set(1,1);
+ return 0x1c;
+ }
+ }
+
+ printk("lcd_hx8379a mipi read power mode fail!0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+ mipi_eotp_set(1,1);
+ return 0x0;
+}
+
+static int32_t hx8379a_check_esd(struct panel_spec *self)
+{
+ uint32_t power_mode;
+
+ mipi_set_lp_mode_t mipi_set_data_lp_mode = self->info.mipi->ops->mipi_set_data_lp_mode;
+ mipi_set_hs_mode_t mipi_set_data_hs_mode = self->info.mipi->ops->mipi_set_data_hs_mode;
+ mipi_set_lp_mode_t mipi_set_lp_mode = self->info.mipi->ops->mipi_set_lp_mode;
+ mipi_set_hs_mode_t mipi_set_hs_mode = self->info.mipi->ops->mipi_set_hs_mode;
+ uint16_t work_mode = self->info.mipi->work_mode;
+
+ pr_debug("hx8379a_check_esd!\n");
+#ifndef FB_CHECK_ESD_IN_VFP
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_lp_mode();
+ }else{
+ mipi_set_data_lp_mode();
+ }
+#endif
+ power_mode = hx8379a_readpowermode(self);
+ //power_mode = 0x0;
+#ifndef FB_CHECK_ESD_IN_VFP
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_hs_mode();
+ }else{
+ mipi_set_data_hs_mode();
+ }
+#endif
+ if(power_mode == 0x1c){
+ pr_debug("hx8379a_check_esd OK!\n");
+ return 1;
+ }else{
+ printk("hx8379a_check_esd fail!(0x%x)\n", power_mode);
+ return 0;
+ }
+}
+
+static struct panel_operations lcd_hx8379a_mipi_operations = {
+ .panel_init = hx8379a_mipi_init,
+ .panel_readid = hx8379a_readid,
+ .panel_esd_check = hx8379a_check_esd,
+};
+
+static struct timing_rgb lcd_hx8379a_mipi_timing = {
+ .hfp = 25, /* unit: pixel */
+ .hbp = 25,
+ .hsync = 11,
+ .vfp = 22, /*unit: line*/
+ .vbp = 12,
+ .vsync = 3,
+};
+
+
+static struct info_mipi lcd_hx8379a_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq =500*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_hx8379a_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_hx8379a_mipi_spec = {
+ .width = 480,
+ .height = 854,
+ .fps = 62,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_hx8379a_mipi_info
+ },
+ .ops = &lcd_hx8379a_mipi_operations,
+};
+struct panel_cfg lcd_hx8379a_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x8379,
+ .lcd_name = "lcd_hx8379a_mipi",
+ .panel = &lcd_hx8379a_mipi_spec,
+};
+
+static int __init lcd_hx8379a_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_hx8379a_mipi);
+}
+
+subsys_initcall(lcd_hx8379a_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_hx8389c_mipi.c b/drivers/video/sprdfb/lcd/lcd_hx8389c_mipi.c
new file mode 100755
index 00000000..9ef8ed43
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_hx8389c_mipi.c
@@ -0,0 +1,318 @@
+/* drivers/video/sprdfb/lcd_hx8389c_mipi.c
+ *
+ * Support for hx8389c mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+#include <mach/gpio.h>
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 150
+
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#if defined(CONFIG_MACH_GRANDPRIME3G_VE) || defined(CONFIG_MACH_GRANDPRIME_DTV)
+static int is_gpio_request2=0;
+#endif
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+
+ {LCM_SEND(6),{4,0,0xB9,0xFF,0x83,0x89}},
+ {LCM_SEND(23),{21,0,0xB1,0x7F,0x10,0x10,0xD2,0x32,0x80,0x10,0xF0,0x56,0x80,0x20,0x20,0xF8,0xAA,0xAA,0xA1,0x00,0x80,0x30,0x00}},
+ {LCM_SEND(13),{11,0,0xB2,0x82,0x50,0x05,0x07,0xF0,0x38,0x11,0x64,0x5D,0x09}},
+ {LCM_SEND(14),{12,0,0xB4,0x66,0x66,0x66,0x70,0x00,0x00,0x18,0x76,0x28,0x76,0xA8}},
+ {LCM_SEND(2),{0xD2,0x33}},
+ {LCM_SEND(7),{5,0,0xC0,0x30,0x17,0x00,0x03}},
+ {LCM_SEND(7),{5,0,0xC7,0x00,0x80,0x00,0xC0}},
+ {LCM_SEND(7),{5,0,0xBF,0x05,0x50,0x00,0x3E}},
+ {LCM_SLEEP(10)},
+ //{LCM_SEND(6),{4,0,0xB9,0xFF,0x83,0x89}},
+ {LCM_SEND(2),{0xCC,0x0E}},
+ {LCM_SEND(38),{36,0,0xD3,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x32,0x10,0x00,0x00,0x00,0x03,0xC6,0x03,0xC6,0x00,0x00,0x00,0x00 \
+ ,0x35,0x33,0x04,0x04,0x37,0x00,0x00,0x00,0x05,0x08,0x00,0x00,0x0A,0x00,0x01}},
+ {LCM_SEND(41),{39,0,0xD5,0x18,0x18,0x18,0x18,0x19,0x19,0x18,0x18,0x20,0x21,0x24,0x25,0x18,0x18,0x18,0x18,0x00,0x01,0x04,0x05 \
+ ,0x02,0x03,0x06,0x07,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ {LCM_SEND(41),{39,0,0xD6,0x18,0x18,0x18,0x18,0x18,0x18,0x19,0x19,0x25,0x24,0x21,0x20,0x18,0x18 \
+ ,0x18,0x18,0x07,0x06,0x03,0x02,0x05,0x04,0x01,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18 \
+ ,0x18,0x18,0x18,0x18,0x18,0x18}},
+ {LCM_SEND(6),{4,0,0xB7,0x20,0x80,0x00}},
+
+//gamma
+ {LCM_SEND(45),{43,0,0xE0,0x00,0x02,0x06,0x38,0x3C,0x3F,0x1B,0x46,0x06,0x09,0x0C,0x17 \
+ ,0x10,0x13,0x16,0x13,0x14,0x08,0x13,0x15,0x19,0x00,0x02,0x06,0x37,0x3C,0x3F \
+ ,0x1A,0x45,0x05,0x09,0x0B,0x16,0x0F,0x13,0x15,0x13,0x14,0x07,0x12,0x14,0x18}},
+
+ {LCM_SEND(2),{0xBD,0x00}},
+ {LCM_SEND(46),{44,0,0xC1,0x00,0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50 \
+ ,0x58,0x60,0x68,0x70,0x78,0x80,0x88,0x90,0x98,0xA0,0xA8,0xB0,0xB8,0xC0,0xC8,0xD0,0xD8 \
+ ,0xE0,0xE8,0xF0,0xF8,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0xBD,0x01}},
+ {LCM_SEND(45),{43,0,0xC1,0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x78 \
+ ,0x80,0x88,0x90,0x98,0xA0,0xA8,0xB0,0xB8,0xC0,0xC8,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0xFF,0x00,0x00,0x00 \
+ ,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0xBD,0x02}},
+ {LCM_SEND(45),{43,0,0xC1,0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x78,0x80,0x88,0x90 \
+ ,0x98,0xA0,0xA8,0xB0,0xB8,0xC0,0xC8,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+}},
+
+//CABC
+ {LCM_SEND(2),{0x51,0x80}},
+ {LCM_SLEEP(5)},
+
+ {LCM_SEND(16),{14,0,0xC9,0x1F,0x2E,0x0A,0x1E,0x81,0x1E,0x00,0x00,0x01,0x19,0x00,0x00,0x20}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(2),{0x55,0x00}},
+ {LCM_SLEEP(5)},
+ {LCM_SEND(2),{0x53,0x24}},
+ {LCM_SLEEP(5)},
+
+//display on
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(180)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(10)},
+
+};
+
+static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(150)}, //>150ms
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(150)}, //>150ms
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},//>120ms
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)}, //>20ms
+};
+
+
+static int32_t hx8389c_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+#if defined(CONFIG_MACH_GRANDPRIME3G_VE) || defined(CONFIG_MACH_GRANDPRIME_DTV)
+static uint32_t hx8389c_before_resume(struct panel_spec *self)
+{
+ if(is_gpio_request2==0){
+ if (gpio_request(167, "LCD LDO")) {
+ printk("Failed ro request GPIO_%d \n",167);
+ return 0;
+ }
+ gpio_direction_output(167, 0);
+ is_gpio_request2=1;
+ }
+ gpio_set_value(167, 1);
+ return 0;
+}
+
+static uint32_t hx8389c_after_suspend(struct panel_spec *self)
+{
+ if(is_gpio_request2==0){
+ if (gpio_request(167, "LCD LDO")) {
+ printk("Failed ro request GPIO_%d \n",167);
+ return 0;
+ }
+ gpio_direction_output(167, 0);
+ is_gpio_request2=1;
+ }
+ gpio_set_value(167, 0);
+ return 0;
+}
+#endif
+
+static uint32_t hx8389c_readid(struct panel_spec *self)
+{
+ int32_t j =0;
+ uint8_t read_data[3] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("kernel lcd_hx8389c_mipi_J3 read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x01;
+ param[1] = 0x00;
+ mipi_force_write(0x37, param, 2);
+ read_rtn = mipi_force_read(0xda,1,&read_data[0]);
+ read_rtn = mipi_force_read(0xdb,1,&read_data[1]);
+ read_rtn = mipi_force_read(0xdc,1,&read_data[2]);
+
+
+ if((0x55 == read_data[0])&&(0xc0 == read_data[1])&&(0x90 == read_data[2]))
+ {
+ printk("lcd_hx8389c_mipi read id success!\n");
+ return 0x8389;
+ }
+ }
+ mipi_eotp_set(0,0);
+ LCD_PRINT("lcd_hx8389c_mipi read id fail! 0xda,0xdb,0xdc is 0x%x,0x%x,0x%x!\n",read_data[0],read_data[1],read_data[2]);
+ return 0;
+}
+
+
+static int32_t hx8389c_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i = 0;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel hx8389c_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(sleep_in_out->tag & LCM_TAG_MASK);
+ }
+ sleep_in_out++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static struct panel_operations lcd_hx8389c_mipi_operations = {
+ .panel_init = hx8389c_mipi_init,
+ .panel_readid = hx8389c_readid,
+ .panel_enter_sleep = hx8389c_enter_sleep,
+#if defined(CONFIG_MACH_GRANDPRIME3G_VE) || defined(CONFIG_MACH_GRANDPRIME_DTV)
+ .panel_after_suspend=hx8389c_after_suspend,
+ .panel_before_resume=hx8389c_before_resume,
+#endif
+};
+
+static struct timing_rgb lcd_hx8389c_mipi_timing = {
+ .hfp = 80, /* unit: pixel */
+ .hbp = 80,
+ .hsync = 20,
+ .vfp = 18, /*unit: line*/
+ .vbp = 13,
+ .vsync = 2,
+};
+
+
+static struct info_mipi lcd_hx8389c_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq =500*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_hx8389c_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_hx8389c_mipi_spec = {
+ .width = 540,
+ .height = 960,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_hx8389c_mipi_info
+ },
+ .ops = &lcd_hx8389c_mipi_operations,
+};
+struct panel_cfg lcd_hx8389c_mipi = {
+
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x8389,
+ .lcd_name = "lcd_hx8389c_mipi",
+ .panel = &lcd_hx8389c_mipi_spec,
+};
+
+//temp code
+static int __init lcd_hx8389c_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_hx8389c_mipi);
+}
+
+subsys_initcall(lcd_hx8389c_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_hx8394a_mipi.c b/drivers/video/sprdfb/lcd/lcd_hx8394a_mipi.c
new file mode 100644
index 00000000..b52eb976
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_hx8394a_mipi.c
@@ -0,0 +1,295 @@
+/* drivers/video/sprdfb/lcd_hx8389b_mipi.c
+ *
+ * Support for hx8389b mipi LCD device
+ *
+ * Copyright (C) 2015 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 150
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+{LCM_SEND(6), {4, 0, 0xB9,0xFF,0x83,0x94}},
+{LCM_SEND(19), {17, 0, 0xBA,0x63,0x82,0x00,0x16,0xC5,0x00,0x10,0xFF,0x0F,0x24,0x03,0x21,0x24,0x25,0x20,0x08}},
+{LCM_SEND(20), {18, 0, 0xB1,0x01,0x00,0x04,0xC4,0x03,0x12,0xF1,0x24,0x2C,0x3F,0x3F,0x57,0x02,0x00,0xE6,0xE2,0xA6}},
+{LCM_SEND(9), {7, 0, 0xB2,0x00,0xC8,0x0E,0x30,0x00,0x33}},
+{LCM_SEND(34), {32, 0, 0xB4,0x80,0x04,0x32,0x10,0x08,0x54,0x15,0x0F,0x22,0x10,0x08,0x47,0x53,0x54,0x0A,0x4B,0x53,0x54,0x02,0x61,0x61,0x02,0x06,0x44,0x06,0x5F,0x0A,0x6B,0x70,0x05,0x08}},
+{LCM_SEND(2), {0xB6, 0x21}},
+{LCM_SEND(57), {55, 0, 0xD5,0x00,0x00,0x00,0x00,0x0A,0x00,0x01,0x22,0x00,0x33,0xCC,0x00,0xAA,0xBB,0x01,0x23,0x45,0x67,0x9A,0xBC,0x45,0x67,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x01,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x3C,0x01}},
+
+{LCM_SEND(2), {0xCC, 0x09}},
+
+{LCM_SEND(7), {5, 0, 0xBF,0x06,0x02,0x10,0x04}},
+
+{LCM_SEND(7), {5, 0, 0xC7,0x00,0x10,0x00,0x10}},
+
+{LCM_SEND(28), {26, 0, 0xE0,0x00,0x04,0x08,0x28,0x2F,0x3F,0x15,0x34,0x06,0x0C,0x0E,0x12,0x14,0x13,0x14,0x11,0x19,0x00,0x04,0x08,0x29,0x2E,0x3F,0x15,0x35}},
+{LCM_SEND(19), {17, 0, 0x07,0x0C,0x0F,0x11,0x13,0x11,0x12,0x10,0x16,0x0A,0x17,0x07,0x12,0x0A,0x17,0x06,0x11}},
+
+{LCM_SEND(5), {3, 0, 0xC0,0x0C,0x17}},
+
+{LCM_SEND(5), {3, 0, 0xC6,0x08,0x08}},
+
+{LCM_SEND(2), {0xD4, 0x32}},
+{LCM_SEND(1), {0x11}},
+{LCM_SLEEP(200)},
+{LCM_SEND(1), {0x29}},
+{LCM_SLEEP(100)},
+
+};
+
+static LCM_Force_Cmd_Code rd_prep_code_1[]={
+ {0x37, {LCM_SEND(2), {0x1, 0}}},
+};
+
+static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(150)}, //>150ms
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(150)}, //>150ms
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},//>120ms
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)}, //>20ms
+};
+
+static int32_t hx8394a_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel hx8394a_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(init->data, (init->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t hx8394a_readid(struct panel_spec *self)
+{
+ uint32_t j =0;
+ uint8_t read_data[4] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("lcd_hx8394a_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x03;
+ param[1] = 0x00;
+ mipi_force_write(0x37, param, 2);
+ read_rtn = mipi_force_read(0x04,3, &read_data[0]);
+ LCD_PRINT("lcd_hx8394a_mipi read id 0x04 value is 0x%x, 0x%x, 0x%x!\n", read_data[0], read_data[1], read_data[2]);
+
+ if(0x83 == read_data[0] && 0x94 == read_data[1] && 0x1A == read_data[2]){
+ LCD_PRINT("hx8394a success!\n");
+ return 0x8394;
+ }
+ }
+
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t hx8394a_readpowermode(struct panel_spec *self)
+{
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code_1;
+ uint8_t read_data[1] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_debug("lcd_hx8394a_mipi read power mode!\n");
+ mipi_eotp_set(0,0);
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code_1;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code_1); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }
+ rd_prepare++;
+ }
+ read_rtn = mipi_force_read(0x0A, 1,(uint8_t *)read_data);
+ pr_debug("lcd_hx8389b mipi read power mode 0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+ if((0x1c == read_data[0])){
+ //printk("lcd_hx8389b_mipi read power mode success!\n");
+ mipi_eotp_set(0,0);
+ return 0x1c;
+ }
+ }
+
+ printk("lcd_hx8394a mipi read power mode fail!0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+ mipi_eotp_set(0,0);
+ return 0x0;
+}
+
+static int32_t hx8394a_check_esd(struct panel_spec *self)
+{
+ uint32_t power_mode;
+
+ mipi_set_lp_mode_t mipi_set_data_lp_mode = self->info.mipi->ops->mipi_set_data_lp_mode;
+ mipi_set_hs_mode_t mipi_set_data_hs_mode = self->info.mipi->ops->mipi_set_data_hs_mode;
+ mipi_set_lp_mode_t mipi_set_lp_mode = self->info.mipi->ops->mipi_set_lp_mode;
+ mipi_set_hs_mode_t mipi_set_hs_mode = self->info.mipi->ops->mipi_set_hs_mode;
+ uint16_t work_mode = self->info.mipi->work_mode;
+
+ pr_debug("hx8394a_check_esd!\n");
+#ifndef FB_CHECK_ESD_IN_VFP
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_lp_mode();
+ }else{
+ mipi_set_data_lp_mode();
+ }
+#endif
+ power_mode = hx8394a_readpowermode(self);
+ //power_mode = 0x0;
+#ifndef FB_CHECK_ESD_IN_VFP
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_hs_mode();
+ }else{
+ mipi_set_data_hs_mode();
+ }
+#endif
+ if(power_mode == 0x1c){
+ pr_debug("hx8394a_check_esd OK!\n");
+ return 1;
+ }else{
+ printk("hx8394a_check_esd fail!(0x%x)\n", power_mode);
+ return 0;
+ }
+}
+
+static struct panel_operations lcd_hx8394a_mipi_operations = {
+ .panel_init = hx8394a_mipi_init,
+ .panel_readid = hx8394a_readid,
+ .panel_esd_check = hx8394a_check_esd,
+};
+
+static struct timing_rgb lcd_hx8394a_mipi_timing = {
+ .hfp = 80, /* unit: pixel */
+ .hbp = 60,
+ .hsync = 60,
+ .vfp = 38, /*unit: line*/
+ .vbp = 12,
+ .vsync = 4,
+};
+
+
+static struct info_mipi lcd_hx8394a_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 4,
+ .phy_feq = 450*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_hx8394a_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_hx8394a_mipi_spec = {
+ .width = 720,
+ .height = 1280,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_hx8394a_mipi_info
+ },
+ .ops = &lcd_hx8394a_mipi_operations,
+};
+
+struct panel_cfg lcd_hx8394a_mipi = {
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x8394,
+ .lcd_name = "lcd_hx8394a_mipi",
+ .panel = &lcd_hx8394a_mipi_spec,
+};
+
+static int __init lcd_hx8394a_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_hx8394a_mipi);
+}
+
+subsys_initcall(lcd_hx8394a_mipi_init);
+
+
diff --git a/drivers/video/sprdfb/lcd/lcd_hx8394d_mipi.c b/drivers/video/sprdfb/lcd/lcd_hx8394d_mipi.c
new file mode 100644
index 00000000..9643cf60
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_hx8394d_mipi.c
@@ -0,0 +1,430 @@
+/* drivers/video/sprdfb/lcd_hx8394d_mipi.c
+ *
+ * Support for hx8394d mipi LCD device
+ *
+ * Copyright (C) 2014 Spreadtrum
+ * Author: Haibing.Yang <haibing.yang@spreadtrum.com>
+ *
+ * The panel info is got from raolihua@trulyopto.cn
+ * Panel: 5.0HD(720*1280) LG LTPS
+ * Driver IC: HX8394D
+ * Interface: MIPI 4LANES
+ * Test condition: IOVCC=VCC=2.8V
+ * DATE: 20150105
+ * Version: 1.0
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#define pr_fmt(fmt) "sprdfb_hx8394b: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+
+#include "../sprdfb_panel.h"
+
+#define MAX_DATA 100
+#define DATA_TYPE_SET_RX_PKT_SIZE 0x37
+#define PANEL_READ_CNT 3
+
+#define PANEL_ID_LENGTH 3
+#define PANEL_RETURN_ID 0x8394
+#define PANEL_ACTUAL_ID 0x8394
+#define PANEL_ID_REG 0x04
+#define PANEL_ID_OFFSET 0
+
+#define PANEL_POWER_MODE_REG 0x0A
+#define PANEL_POWER_MODE_LEN 2
+#define PANEL_NOT_DEAD_STS 0x1C
+#define PANEL_POWER_MODE_OFFSET 1
+
+#define LCM_TAG_SHIFT 24
+#define LCM_DATA_TYPE_SHIFT 16
+#define LCM_TAG_MASK ((1 << LCM_DATA_TYPE_SHIFT) - 1)
+
+#define LCM_TAG_SEND (1 << LCM_TAG_SHIFT)
+#define LCM_TAG_SLEEP (2 << LCM_TAG_SHIFT)
+
+#define LCM_SEND(len) (LCM_TAG_SEND | len)
+#define LCM_SEND_WITH_TYPE(len, type) \
+ (LCM_TAG_SEND | len | (type << LCM_DATA_TYPE_SHIFT))
+#define LCM_SLEEP(ms) (LCM_TAG_SLEEP | ms)
+
+struct panel_cmds {
+ u32 tag;
+ u8 data[MAX_DATA];
+};
+
+static struct panel_cmds hx8394d_init_cmds[] = {
+ {
+ LCM_SEND(06), {04, 0,
+ 0xB9, 0xFF, 0x83, 0x94}
+ },
+ {
+ LCM_SEND(05), {03, 0,
+ 0xBA,0x33,0x83}
+ },
+ { /* Set power */
+ LCM_SEND(20), {18, 0,
+ 0xB1, 0x6C, 0x12, 0x12, 0x26, 0x04, 0x11, 0xF1,
+ 0x81, 0x3A, 0x54, 0x23, 0x80, 0xC0, 0xD2, 0x58}
+ },
+ { /* Set display related register */
+ LCM_SEND(14), {12, 0,
+ 0xB2, 0x00, 0x64, 0x0E, 0x0D, 0x22, 0x1C, 0x08,
+ 0x08, 0x1C, 0x4D, 0x00}
+ },
+ { /* Set panel driving timing */
+ LCM_SEND(15), {13, 0,
+ 0xB4, 0x00, 0xFF, 0x51, 0x5A, 0x59, 0x5A, 0x03,
+ 0x5A, 0x01, 0x70, 0x01, 0x70}
+ },
+ {LCM_SEND(2), {0xBC, 0x07}},
+ {
+ LCM_SEND(06), {04, 0,
+ 0xBF, 0x41, 0x0E, 0x01}
+ },
+ { /* Set GIP */
+ LCM_SEND(40), {38, 0,
+ 0xD3, 0x00, 0x0F, 0x00, 0x40, 0x07, 0x10, 0x00,
+ 0x08, 0x10, 0x08, 0x00, 0x08, 0x54, 0x15, 0x0E,
+ 0x05, 0x0E, 0x02, 0x15, 0x06, 0x05, 0x06, 0x47,
+ 0x44, 0x0A, 0x0A, 0x4B, 0x10, 0x07, 0x07, 0x08,
+ 0x00, 0x00, 0x00, 0x0A, 0x00, 0x01}
+ },
+ { /* Set GIP */
+ LCM_SEND(47), {45, 0,
+ 0xD5, 0x1A, 0x1A, 0x1B, 0x1B, 0x00, 0x01, 0x02,
+ 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
+ 0x0B, 0x24, 0x25, 0x18, 0x18, 0x26, 0x27, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x20,
+ 0x21, 0x18, 0x18, 0x18, 0x18}
+ },
+ { /* Set GIP */
+ LCM_SEND(47), {45, 0,
+ 0xD6, 0x1A, 0x1A, 0x1B, 0x1B, 0x0B, 0x0A, 0x09,
+ 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
+ 0x00, 0x21, 0x20, 0x58, 0x58, 0x27, 0x26, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x25,
+ 0x24, 0x18, 0x18, 0x18, 0x18}
+ },
+ /* SETPANEL CCh: can set normally-white/black panel */
+ {LCM_SEND(2), {0xCC, 0x09}},
+ {
+ LCM_SEND(5), {3, 0,
+ 0xC0, 0x30, 0x14}
+ },
+ {
+ LCM_SEND(7), {5, 0,
+ 0xC7, 0x00, 0xC0, 0x40, 0xC0}
+ },
+ {
+ LCM_SEND(5), {3, 0,
+ 0xB6, 0x6B, 0x6B}
+ },
+ { /* Analog gamma setting */
+ LCM_SEND(45), {43, 0,
+ 0xE0, 0x00, 0x0A, 0x0F, 0x24, 0x3A, 0x3F, 0x20,
+ 0x3B, 0x08, 0x0D, 0x0E, 0x16, 0x0F, 0x12, 0x15,
+ 0x13, 0x15, 0x09, 0x12, 0x12, 0x18, 0x00, 0x0A,
+ 0x0F, 0x24, 0x3A, 0x3F, 0x20, 0x3B, 0x08, 0x0D,
+ 0x0E, 0x16, 0x0F, 0x12, 0x15, 0x13, 0x15, 0x09,
+ 0x12, 0x12, 0x18}
+ },
+
+ {LCM_SEND(2), {0xBD, 0x00}}, /* BANK: RED */
+ {
+ LCM_SEND(46), {44, 0,
+ 0xC1, 0x01, 0x00, 0x06, 0x0C, 0x14, 0x1D, 0x27,
+ 0x2F, 0x38, 0x41, 0x49, 0x51, 0x59, 0x61, 0x69,
+ 0x71, 0x79, 0x81, 0x89, 0x91, 0x99, 0xA1, 0xA9,
+ 0xB2, 0xB9, 0xC1, 0xCA, 0xD1, 0xD8, 0xE2, 0xEA,
+ 0xF0, 0xF7, 0xFF, 0x38, 0xFC, 0x3F, 0x0B, 0xC1,
+ 0x13, 0xF1, 0x0D, 0xC0}
+ },
+ {LCM_SEND(2), {0xBD, 0x01}}, /* BANK: GREEN */
+ {
+ LCM_SEND(45), {43, 0,
+ 0xC1, 0x00, 0x06, 0x0C, 0x14, 0x1D, 0x27, 0x2F,
+ 0x38, 0x41, 0x49, 0x51, 0x59, 0x61, 0x69, 0x71,
+ 0x79, 0x81, 0x89, 0x91, 0x99, 0xA1, 0xA9, 0xB2,
+ 0xB9, 0xC1, 0xCA, 0xD1, 0xD8, 0xE2, 0xEA, 0xF0,
+ 0xF7, 0xFF, 0x38, 0xFC, 0x3F, 0x0B, 0xC1, 0x13,
+ 0xF1, 0x0D, 0xC0}
+ },
+ {LCM_SEND(2), {0xBD, 0x02}}, /* BANK: BLUE */
+ {
+ LCM_SEND(45), {43, 0,
+ 0xC1, 0x00, 0x06, 0x0C, 0x14, 0x1D, 0x27, 0x2F,
+ 0x38, 0x41, 0x49, 0x51, 0x59, 0x61, 0x69, 0x71,
+ 0x79, 0x81, 0x89, 0x91, 0x99, 0xA1, 0xA9, 0xB2,
+ 0xB9, 0xC1, 0xCA, 0xD1, 0xD8, 0xE2, 0xEA, 0xF0,
+ 0xF7, 0xFF, 0x38, 0xFC, 0x3F, 0x0B, 0xC1, 0x13,
+ 0xF1, 0x0D, 0xC0}
+ },
+
+ /* Set_address_mode (36h): RGB order and source/gate dir */
+ {LCM_SEND(2), {0x36, 0x03}},
+
+ /* sleep out */
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(10)},
+};
+
+static struct panel_cmds sleep_in[] = {
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(10)},
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(120)},
+};
+
+static struct panel_cmds sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(10)},
+};
+
+int sprdfb_dsi_tx_cmds(struct panel_spec *panel,
+ struct panel_cmds *cmds, u32 cmds_len, bool force_lp)
+{
+ int i, time;
+ struct ops_mipi *ops = panel->info.mipi->ops;
+ u16 work_mode = panel->info.mipi->work_mode;
+ u8 write_type = (cmds->tag >> 16) & 0xff;
+
+ pr_info("%s, len: %d\n", __func__, cmds_len);
+
+ if (!ops->mipi_set_cmd_mode ||
+ !ops->mipi_dcs_write ||
+ !ops->mipi_set_hs_mode ||
+ !ops->mipi_set_lp_mode ||
+ !ops->mipi_force_write) {
+ pr_err("%s: Expected functions are NULL.\n", __func__);
+ return -EFAULT;
+ }
+ if (force_lp) {
+ if (work_mode == SPRDFB_MIPI_MODE_CMD)
+ ops->mipi_set_lp_mode();
+ else
+ ops->mipi_set_data_lp_mode();
+ }
+
+ ops->mipi_set_cmd_mode();
+
+ for (i = 0; i < cmds_len; i++) {
+ if (cmds->tag & LCM_TAG_SEND) {
+ if (write_type)
+ ops->mipi_force_write(write_type, cmds->data,
+ cmds->tag & LCM_TAG_MASK);
+ else
+ ops->mipi_dcs_write(cmds->data, cmds->tag & LCM_TAG_MASK);
+ udelay(20);
+ } else if (cmds->tag & LCM_TAG_SLEEP) {
+ time = (cmds->tag & LCM_TAG_MASK) * 1000;
+ usleep_range(time, time);
+ }
+ cmds++;
+ }
+
+ if (force_lp) {
+ if (work_mode == SPRDFB_MIPI_MODE_CMD)
+ ops->mipi_set_hs_mode();
+ else
+ ops->mipi_set_data_hs_mode();
+ }
+ return 0;
+}
+
+int sprdfb_dsi_rx_cmds(struct panel_spec *panel,
+ u8 regs, u16 get_len, u8 *data, bool in_bllp)
+{
+ int ret;
+ struct ops_mipi *ops = panel->info.mipi->ops;
+ u8 pkt_size[2];
+ u16 work_mode = panel->info.mipi->work_mode;
+
+ pr_debug("%s, read data len: %d\n", __func__, get_len);
+ if (!data) {
+ pr_err("Expected registers or data is NULL.\n");
+ return -EIO;
+ }
+ if (!ops->mipi_set_cmd_mode ||
+ !ops->mipi_force_read ||
+ !ops->mipi_force_write) {
+ pr_err("%s: Expected functions are NULL.\n", __func__);
+ return -EFAULT;
+ }
+
+ if (!in_bllp) {
+ if (work_mode == SPRDFB_MIPI_MODE_CMD)
+ ops->mipi_set_lp_mode();
+ else
+ ops->mipi_set_data_lp_mode();
+ /*
+ * If cmds is transmitted in LP mode, not in BLLP,
+ * commands mode should be enabled
+ * */
+ ops->mipi_set_cmd_mode();
+ }
+
+ pkt_size[0] = get_len & 0xff;
+ pkt_size[1] = (get_len >> 8) & 0xff;
+
+ ops->mipi_force_write(DATA_TYPE_SET_RX_PKT_SIZE,
+ pkt_size, sizeof(pkt_size));
+
+ ret = ops->mipi_force_read(regs, get_len, data);
+ if (ret < 0) {
+ pr_err("%s: dsi read id fail\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!in_bllp) {
+ if (work_mode == SPRDFB_MIPI_MODE_CMD)
+ ops->mipi_set_hs_mode();
+ else
+ ops->mipi_set_data_hs_mode();
+ }
+
+ return 0;
+}
+
+int sprdfb_dsi_panel_sleep(struct panel_spec *panel, u8 is_sleep)
+{
+ int len;
+ struct panel_cmds *sleep_inout;
+
+ if (is_sleep) {
+ sleep_inout = sleep_in;
+ len = ARRAY_SIZE(sleep_in);
+ } else {
+ sleep_inout = sleep_out;
+ len = ARRAY_SIZE(sleep_out);
+ }
+
+ return sprdfb_dsi_tx_cmds(panel, sleep_inout, len, false);
+}
+
+u32 sprdfb_dsi_panel_readid(struct panel_spec *panel)
+{
+ int i, cnt = PANEL_READ_CNT;
+ u8 regs = PANEL_ID_REG;
+ u8 data[PANEL_ID_LENGTH] = { 0 };
+ u8 id[PANEL_ID_LENGTH] = { 0 };
+
+ i = PANEL_ID_OFFSET;
+ id[i++] = (PANEL_RETURN_ID >> 8) & 0xFF;
+ id[i] = PANEL_RETURN_ID & 0xFF;
+ do {
+ sprdfb_dsi_rx_cmds(panel, regs, PANEL_ID_LENGTH, data, true);
+ i = PANEL_ID_OFFSET;
+ pr_debug("%s: reading panel id(0x%2x) is 0x%x, 0x%x",
+ __func__, regs, data[i], data[i+1]);
+ if (data[i] == id[i] && data[i + 1] == id[i + 1])
+ return PANEL_ACTUAL_ID;
+ } while (cnt-- > 0);
+
+ pr_err("%s: failed to read panel id, 0x%x, 0x%x.\n",
+ __func__, data[i], data[i + 1]);
+ return 0;
+}
+
+static int hx8394d_dsi_panel_dead(struct panel_spec *panel)
+{
+ int i, cnt = PANEL_READ_CNT;
+ u8 regs = PANEL_POWER_MODE_REG;
+ u8 data[PANEL_POWER_MODE_LEN] = { 0 };
+ bool in_bllp = false;
+
+#ifdef FB_CHECK_ESD_IN_VFP
+ in_bllp = true;
+#endif
+ do {
+ sprdfb_dsi_rx_cmds(panel, regs, PANEL_POWER_MODE_LEN, data, in_bllp);
+ i = PANEL_POWER_MODE_OFFSET;
+ pr_debug("%s: reading panel power mode(0x%2x) is 0x%x",
+ __func__, regs, data[i]);
+ if ((data[i] & PANEL_NOT_DEAD_STS) == PANEL_NOT_DEAD_STS)
+ return true;
+ } while (cnt-- > 0);
+
+ pr_err("panel is dead, read power mode is 0x%x.\n", data[i]);
+ return false;
+}
+
+static int hx8394d_dsi_panel_init(struct panel_spec *panel)
+{
+ return sprdfb_dsi_tx_cmds(panel, hx8394d_init_cmds,
+ ARRAY_SIZE(hx8394d_init_cmds), false);
+}
+
+static struct panel_operations lcd_hx8394d_mipi_ops = {
+ .panel_init = hx8394d_dsi_panel_init,
+ .panel_readid = sprdfb_dsi_panel_readid,
+ .panel_enter_sleep = sprdfb_dsi_panel_sleep,
+ .panel_esd_check = hx8394d_dsi_panel_dead,
+};
+
+static struct timing_rgb lcd_hx8394d_mipi_timing = {
+ .hfp = 16, /* unit: pixel */
+ .hbp = 16,
+ .hsync = 10,
+ .vfp = 12, /*unit: line */
+ .vbp = 15,
+ .vsync = 4,
+};
+
+static struct info_mipi lcd_hx8394d_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24,
+ .lan_number = 4,
+ .phy_feq = 430000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_POS,
+ .shut_down_pol = SPRDFB_POLARITY_POS,
+ .timing = &lcd_hx8394d_mipi_timing,
+ .ops = NULL,
+};
+
+static struct panel_spec lcd_hx8394d_mipi_spec = {
+ .width = 720,
+ .height = 1280,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_hx8394d_mipi_info
+ },
+ .ops = &lcd_hx8394d_mipi_ops,
+};
+
+static struct panel_cfg lcd_hx8394d_mipi = {
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = PANEL_ACTUAL_ID,
+ .lcd_name = "lcd_hx8394d_mipi",
+ .panel = &lcd_hx8394d_mipi_spec,
+};
+
+static int __init lcd_hx8394d_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_hx8394d_mipi);
+}
+subsys_initcall(lcd_hx8394d_mipi_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_ili6150_lvds.c b/drivers/video/sprdfb/lcd/lcd_ili6150_lvds.c
new file mode 100644
index 00000000..b6d5b12c
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_ili6150_lvds.c
@@ -0,0 +1,81 @@
+/*
+ * drivers/video/sprdfb/lcd/lcd_ili6150_lvds.c
+ *
+ * Copyright (C) 2014 Spreadtrum Communications Inc.
+ *
+ * Author: Haibing.Yang <haibing.yang@spreadtrum.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#include "../sprdfb.h"
+#include "../sprdfb_panel.h"
+
+static uint32_t ili6150_lvds_readid(struct panel_spec *self)
+{
+ return 0x1806;
+}
+
+static struct panel_operations ili6150_lvds_ops = {
+ .panel_init = sprdchip_lvds_init,
+ .panel_readid = ili6150_lvds_readid,
+};
+
+static struct timing_rgb ili6150_lvds_timing = {
+ .hfp = 150, /* unit: pixel */
+ .hbp = 150,
+ .hsync = 1,//4
+ .vfp = 16, /*unit: line*/
+ .vbp = 16,
+ .vsync = 1,
+};
+
+static struct info_rgb ili6150_lvds_info = {
+ .cmd_bus_mode = SPRDFB_RGB_BUS_TYPE_LVDS,
+ .video_bus_width = 24, /*18,16*/
+#if 0
+ .h_sync_pol = SPRDFB_POLARITY_NEG,
+ .v_sync_pol = SPRDFB_POLARITY_NEG,
+ .de_pol = SPRDFB_POLARITY_POS,
+#endif
+ .timing = &ili6150_lvds_timing,
+ .bus_info = {
+ .spi = NULL,
+ }
+};
+
+static struct panel_spec ili6150_lvds_spec = {
+ //.cap = PANEL_CAP_NOT_TEAR_SYNC,
+ .width = 1024,
+ .height = 600,
+ .fps = 60,
+ .type = SPRDFB_PANEL_TYPE_LVDS,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .rgb = &ili6150_lvds_info
+ },
+ .ops = &ili6150_lvds_ops,
+};
+
+struct panel_cfg lcd_ili6150_lvds = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x1806,
+ .lcd_name = "lcd_ili6150_lvds",
+ .panel = &ili6150_lvds_spec,
+};
+
+static int __init lcd_ili6150_lvds_init(void)
+{
+ return sprdfb_panel_register(&lcd_ili6150_lvds);
+}
+
+subsys_initcall(lcd_ili6150_lvds_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_ili9341.c b/drivers/video/sprdfb/lcd/lcd_ili9341.c
new file mode 100644
index 00000000..c857c4bc
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_ili9341.c
@@ -0,0 +1,428 @@
+/* drivers/video/sc8810/lcd_ili9341.c
+ *
+ * Support for ili9341 LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+static int32_t ili9341_init(struct panel_spec *self)
+{
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ pr_debug("ili9341_init\n");
+
+ //Power Setting
+ send_cmd(0xCF);
+ send_data(0x00);
+ send_data(0xE1);
+ send_data(0x30);
+
+ send_cmd(0xED);
+ send_data(0x64);
+ send_data(0x03);
+ send_data(0x12);
+ send_data(0x81);
+
+ send_cmd(0xCB);
+ send_data(0x39);
+ send_data(0x2C);
+ send_data(0x00);
+ send_data(0x34);
+ send_data(0x02);
+
+ send_cmd(0xF7);
+ send_data(0x20);
+
+ send_cmd(0xEA);
+ send_data(0x00);
+ send_data(0x00);
+
+ send_cmd(0xC5);
+ send_data(0x4C);
+ send_data(0x2B);
+
+ send_cmd(0xC7);
+ send_data(0x00);
+
+ send_cmd(0xC0);
+ send_data(0x22);
+
+ send_cmd(0xC1);
+ send_data(0x11);
+
+ //Initializing Sequence
+ send_cmd(0x35);
+ send_data(0x00);
+
+ send_cmd(0x36);
+ send_data(0x08);
+
+ send_cmd(0x3A);
+ send_data(0x05);
+
+ send_cmd(0xF2);
+ send_data(0x02);
+
+ send_cmd(0xB6);
+ send_data(0x01);
+ send_data(0xC2);
+
+ send_cmd(0xF6);
+ send_data(0x01);
+ send_data(0x10);
+ send_data(0x00);
+
+ send_cmd(0xB1);
+ send_data(0x00);
+ send_data(0x1A);
+
+ send_cmd(0xB5);
+ send_data(0x02);
+ send_data(0x02);
+ send_data(0x0A);
+ send_data(0x14);
+
+ send_cmd(0xE8);
+ send_data(0x85);
+ send_data(0x01);
+ send_data(0x78);
+
+ //Gamma Setting
+ send_cmd(0xE0);
+ send_data(0x0F);
+ send_data(0x31);
+ send_data(0x2F);
+ send_data(0x0D);
+ send_data(0x10);
+ send_data(0x08);
+ send_data(0x5F);
+ send_data(0xB6);
+ send_data(0x50);
+ send_data(0x07);
+ send_data(0x14);
+ send_data(0x07);
+ send_data(0x2A);
+ send_data(0x1F);
+ send_data(0x08);
+
+ send_cmd(0xE1);
+ send_data(0x00);
+ send_data(0x0E);
+ send_data(0x10);
+ send_data(0x04);
+ send_data(0x10);
+ send_data(0x04);
+ send_data(0x23);
+ send_data(0x54);
+ send_data(0x35);
+ send_data(0x03);
+ send_data(0x0B);
+ send_data(0x09);
+ send_data(0x20);
+ send_data(0x2A);
+ send_data(0x08);
+
+ send_cmd(0xE2);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+
+ send_cmd(0xE3);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x22);
+ send_data(0x22);
+ send_data(0x22);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x33);
+ send_data(0x03);
+ send_data(0x03);
+ send_data(0x03);
+ send_data(0x03);
+ send_data(0x03);
+ send_data(0x03);
+ send_data(0x03);
+ send_data(0x03);
+ send_data(0x03);
+ send_data(0x03);
+ send_data(0x03);
+ send_data(0x02);
+ send_data(0x01);
+ send_data(0x00);
+#if 1
+ //Display on
+ send_cmd(0x11); // (SLPOUT)
+ mdelay(10); // 100ms
+ send_cmd(0x29); // (DISPON)
+ mdelay(10); // 100ms
+ pr_debug("ili9341_init: end\n");
+
+ return 0;
+#else
+ if (1) { // for test the lcd
+ int i;
+ send_cmd(0x2C); //Write data
+ for (i = 0; i < 240*320/3; i++)
+ send_data(0xff);
+ for (i = 0; i < 240*320/3; i++)
+ send_data(0xff00);
+ for (i = 0; i < 24*320/3; i++)
+ send_data(0xff0000);
+ }
+ send_cmd(0x11); //Display On
+ mdelay(10); //120ms
+ send_cmd(0x29); //Write data
+ mdelay(10); //120ms
+#endif
+ pr_debug("ili9341_init: end\n");
+
+ return 0;
+}
+
+static int32_t ili9341_set_window(struct panel_spec *self,
+ uint16_t left, uint16_t top, uint16_t right, uint16_t bottom)
+{
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ pr_debug("ili9341_set_window\n");
+
+ send_cmd(0x2A); // col
+ send_data((left >> 8));
+ send_data((left & 0xFF));
+ send_data((right >> 8));
+ send_data((right & 0xFF));
+
+ send_cmd(0x2B); // row
+ send_data((top >> 8));
+ send_data((top & 0xFF));
+ send_data((bottom >> 8));
+ send_data((bottom & 0xFF));
+
+ send_cmd(0x2C);
+
+ return 0;
+}
+
+
+static int32_t ili9341_invalidate(struct panel_spec *self)
+{
+ pr_debug("ili9341_invalidate\n");
+
+ return self->ops->panel_set_window(self, 0, 0,
+ self->width-1, self->height-1);
+}
+
+static int32_t ili9341_invalidate_rect(struct panel_spec *self,
+ uint16_t left, uint16_t top,
+ uint16_t right, uint16_t bottom)
+{
+
+ pr_debug("ili9341_invalidate_rect : (%d, %d, %d, %d)\n",left, top, right, bottom);
+
+ return self->ops->panel_set_window(self, left, top,
+ right, bottom);
+}
+
+static int32_t ili9341_set_direction(struct panel_spec *self, uint16_t direction)
+{
+
+ pr_debug("ili9341_set_direction\n");
+ return 0;
+}
+
+static int32_t ili9341_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ //send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+
+ if(is_sleep) {
+ //send_cmd(0x10);
+ mdelay(120);
+ }
+ else {
+ //send_cmd(0x11);
+ mdelay(120);
+ }
+ return 0;
+}
+
+static uint32_t ili9341_read_id(struct panel_spec *self)
+{
+ int32_t read_value = 0;
+#if 0
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ read_data_t read_data = self->info.mcu->ops->read_data;
+
+ send_cmd(0x04);
+
+ read_data();
+ read_value += read_data()<< 16;
+ read_value += read_data()<< 8;
+ read_value += read_data();
+#endif
+ pr_debug("ili9341_read_id=%x\n",read_value);
+
+ read_value = 0x9341;
+
+ return read_value;
+}
+
+static int32_t ili9341_change_epf(struct panel_spec *self, bool is_default)
+{
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ return 0;
+
+ if(is_default){
+ send_cmd(0xF6);
+ send_data(0x01);
+ send_data(0x30);
+ send_data(0x00);
+ }else{
+ send_cmd(0xF6);
+ send_data(0x01);
+ send_data(0x10);
+ send_data(0x00);
+ }
+
+ return 0;
+}
+
+static struct panel_operations lcd_ili9341_operations = {
+ .panel_init = ili9341_init,
+ .panel_set_window = ili9341_set_window,
+ .panel_invalidate = ili9341_invalidate,
+ //.lcd_invalidate_rect = ili9341_invalidate_rect,
+ .panel_set_direction = ili9341_set_direction,
+ .panel_enter_sleep = ili9341_enter_sleep,
+ .panel_readid = ili9341_read_id,
+ .panel_change_epf = ili9341_change_epf,
+};
+
+static struct timing_mcu lcd_ili9341_timing[] = {
+ [MCU_LCD_REGISTER_TIMING] = {
+ .rcss = 25,
+ .rlpw = 45,
+ .rhpw = 90,
+ .wcss = 30,
+ .wlpw = 20,
+ .whpw = 20,
+ },
+ [MCU_LCD_GRAM_TIMING] = {
+ .rcss = 25,
+ .rlpw = 45,
+ .rhpw = 90,
+ .wcss = 30,
+ .wlpw = 20,
+ .whpw = 20,
+ }
+};
+
+static struct info_mcu lcd_ili9341_info = {
+ .bus_mode = LCD_BUS_8080,
+ .bus_width = 16,
+ .bpp = 16, /*RGB88*/
+ .timing = &lcd_ili9341_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_panel_ili9341 = {
+ .width = 240,
+ .height = 320,
+ .fps = 60,
+ .type = LCD_MODE_MCU,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mcu = &lcd_ili9341_info
+ },
+ .ops = &lcd_ili9341_operations,
+};
+
+struct panel_cfg lcd_ili9341 = {
+ /* this panel may on both CS0/1 */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x9341,
+ .lcd_name = "lcd_ili9341",
+ .panel = &lcd_panel_ili9341,
+};
+
+static int __init lcd_ili9341_init(void)
+{
+ printk(KERN_INFO "sprdfb_111: [%s]: 0x%x!\n", __FUNCTION__,lcd_ili9341.lcd_id);
+
+ return sprdfb_panel_register(&lcd_ili9341);
+}
+
+subsys_initcall(lcd_ili9341_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_ili9486.c b/drivers/video/sprdfb/lcd/lcd_ili9486.c
new file mode 100644
index 00000000..885e8f76
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_ili9486.c
@@ -0,0 +1,434 @@
+/* drivers/video/sc8810/lcd_ili9486.c
+ *
+ * Support for ili9486 LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+static int32_t ili9486_init(struct panel_spec *self)
+{
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ pr_debug("ili9486_init\n");
+#if 0
+ // Hidden register setting
+ send_cmd(0xF9);
+ send_data(0x00);
+ send_data(0x08);
+
+ send_cmd(0xF2);
+ send_data(0x18);
+ send_data(0xA3);
+ send_data(0x02);
+ send_data(0x02);
+ send_data(0xB2);
+ send_data(0x12);
+ send_data(0xFF);
+ send_data(0x10);
+ send_data(0x00);
+
+ send_cmd(0xF1);
+ send_data(0x36);
+ send_data(0x04);
+ send_data(0x00);
+ send_data(0x3C);
+ send_data(0x0F);
+ send_data(0x8F);
+#endif
+ //Power setting sequence
+ send_cmd(0xC0);
+ send_data(0x0B);
+ send_data(0x0B);
+
+ send_cmd(0xC1);
+ send_data(0x45);
+
+ send_cmd(0xC2);
+ send_data(0x22);
+
+ mdelay(150); // 150ms
+
+ //Display parameter setting
+ send_cmd(0x2A);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x01);
+ send_data(0x3F);
+
+ send_cmd(0x2B);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x01);
+ send_data(0xDF);
+
+ send_cmd(0xB1);
+ send_data(0xB0);
+ send_data(0x12);//11: 67hz, 12:63.5hz
+
+ send_cmd(0xB4);
+ send_data(0x02);
+
+ send_cmd(0xB5);
+ send_data(0x08);
+ send_data(0x0C);
+ send_data(0x10);
+ send_data(0x0A);
+
+ send_cmd(0xB6);
+ send_data(0x02);
+ send_data(0x22);//0x42
+ send_data(0x3B);
+
+ send_cmd(0xB7);
+ send_data(0xC6);
+
+ send_cmd(0xF2);
+ send_data(0x18);
+ send_data(0xA3);
+ send_data(0x12);
+ send_data(0x02);
+ send_data(0xB2);
+ send_data(0x12);
+ send_data(0xFF);
+ send_data(0x10);
+ send_data(0x00);
+
+ send_cmd(0xF4);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x08);
+ send_data(0x91);
+ send_data(0x04);
+
+ send_cmd(0x3A);
+ send_data(0x06);
+
+ send_cmd(0x35);
+
+ send_cmd(0x36);
+ send_data(0xD8);//0xC8
+
+ send_cmd(0x44);
+ send_data(0x01);
+ send_data(0xD5);
+
+ //Gamma setting
+ send_cmd(0xF8);
+ send_data(0x21);
+ send_data(0x06);
+
+ send_cmd(0xE0);
+ send_data(0x0F);
+ send_data(0x18);
+ send_data(0x13);
+ send_data(0x08);
+ send_data(0x0B);
+ send_data(0x07);
+ send_data(0x4A);
+ send_data(0xA7);
+ send_data(0x3A);
+ send_data(0x0C);
+ send_data(0x16);
+ send_data(0x07);
+ send_data(0x09);
+ send_data(0x06);
+ send_data(0x00);
+
+ send_cmd(0xE1);
+ send_data(0x0F);
+ send_data(0x34);
+ send_data(0x31);
+ send_data(0x09);
+ send_data(0x0B);
+ send_data(0x02);
+ send_data(0x41);
+ send_data(0x53);
+ send_data(0x30);
+ send_data(0x04);
+ send_data(0x0F);
+ send_data(0x02);
+ send_data(0x17);
+ send_data(0x14);
+ send_data(0x00);
+
+ send_cmd(0xE2);
+ send_data(0x19);
+ send_data(0x19);
+ send_data(0x19);
+ send_data(0x19);
+ send_data(0x19);
+ send_data(0x19);
+ send_data(0x1A);
+ send_data(0x1A);
+ send_data(0x1A);
+ send_data(0x1A);
+ send_data(0x1A);
+ send_data(0x1A);
+ send_data(0x19);
+ send_data(0x19);
+ send_data(0x09);
+ send_data(0x09);
+
+ send_cmd(0xE3);
+ send_data(0x04);
+ send_data(0x04);
+ send_data(0x04);
+ send_data(0x04);
+ send_data(0x04);
+ send_data(0x04);
+ send_data(0x04);
+ send_data(0x04);
+ send_data(0x04);
+ send_data(0x04);
+ send_data(0x24);
+ send_data(0x24);
+ send_data(0x24);
+ send_data(0x24);
+ send_data(0x24);
+ send_data(0x24);
+ send_data(0x24);
+ send_data(0x24);
+ send_data(0x24);
+ send_data(0x24);
+ send_data(0x24);
+ send_data(0x24);
+ send_data(0x24);
+ send_data(0x25);
+ send_data(0x3D);
+ send_data(0x4D);
+ send_data(0x4D);
+ send_data(0x4D);
+ send_data(0x4C);
+ send_data(0x7C);
+ send_data(0x6D);
+ send_data(0x6D);
+ send_data(0x7D);
+ send_data(0x6D);
+ send_data(0x6E);
+ send_data(0x6D);
+ send_data(0x6D);
+ send_data(0x6D);
+ send_data(0x6D);
+ send_data(0x6D);
+ send_data(0x5C);
+ send_data(0x5C);
+ send_data(0x5C);
+ send_data(0x6B);
+ send_data(0x6B);
+ send_data(0x6A);
+ send_data(0x5B);
+ send_data(0x5B);
+ send_data(0x53);
+ send_data(0x53);
+ send_data(0x53);
+ send_data(0x53);
+ send_data(0x53);
+ send_data(0x53);
+ send_data(0x43);
+ send_data(0x33);
+ send_data(0xB4);
+ send_data(0x94);
+ send_data(0x74);
+ send_data(0x64);
+ send_data(0x64);
+ send_data(0x43);
+ send_data(0x13);
+ send_data(0x24);
+#if 1
+ //Display on
+ send_cmd(0x11); // (SLPOUT)
+
+ mdelay(120); // 100ms
+
+ send_cmd(0x29); // (DISPON)
+
+ mdelay(100); // 100ms
+#else
+ if (1) { // for test the lcd
+ int i;
+ send_cmd(0x2C); //Write data
+ for (i = 0; i < 480*320/3; i++)
+ send_data(0xff);
+ for (i = 0; i < 480*320/3; i++)
+ send_data(0xff00);
+ for (i = 0; i < 480*320/3; i++)
+ send_data(0xff0000);
+ }
+ send_cmd(0x29); //Display On
+ mdelay(120); //120ms
+ send_cmd(0x2C); //Write data
+ mdelay(1200); //120ms
+#endif
+ pr_debug("ili9486_init: end\n");
+
+ return 0;
+}
+
+static int32_t ili9486_set_window(struct panel_spec *self,
+ uint16_t left, uint16_t top, uint16_t right, uint16_t bottom)
+{
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ pr_debug("ili9486_set_window\n");
+
+ send_cmd(0x2A); // col
+ send_data((left >> 8));
+ send_data((left & 0xFF));
+ send_data((right >> 8));
+ send_data((right & 0xFF));
+
+ send_cmd(0x2B); // row
+ send_data((top >> 8));
+ send_data((top & 0xFF));
+ send_data((bottom >> 8));
+ send_data((bottom & 0xFF));
+
+ send_cmd(0x2C);
+
+ return 0;
+}
+
+
+static int32_t ili9486_invalidate(struct panel_spec *self)
+{
+ pr_debug("ili9486_invalidate\n");
+
+ return self->ops->panel_set_window(self, 0, 0,
+ self->width-1, self->height-1);
+}
+
+static int32_t ili9486_invalidate_rect(struct panel_spec *self,
+ uint16_t left, uint16_t top,
+ uint16_t right, uint16_t bottom)
+{
+
+ pr_debug("ili9486_invalidate_rect : (%d, %d, %d, %d)\n",left, top, right, bottom);
+
+ return self->ops->panel_set_window(self, left, top,
+ right, bottom);
+}
+
+static int32_t ili9486_set_direction(struct panel_spec *self, uint16_t direction)
+{
+
+ pr_debug("ili9486_set_direction\n");
+ return 0;
+}
+
+static int32_t ili9486_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ //send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+
+ if(is_sleep) {
+ //send_cmd(0x10);
+ mdelay(120);
+ }
+ else {
+ //send_cmd(0x11);
+ mdelay(120);
+ }
+ return 0;
+}
+
+static uint32_t ili9486_read_id(struct panel_spec *self)
+{
+ int32_t read_value = 0;
+#if 0
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ read_data_t read_data = self->info.mcu->ops->read_data;
+
+ send_cmd(0x04);
+
+ read_data();
+ read_value += read_data()<< 16;
+ read_value += read_data()<< 8;
+ read_value += read_data();
+#endif
+ pr_debug("ili9486_read_id=%x\n",read_value);
+
+ read_value = 0x9486;
+
+ return read_value;
+}
+
+static struct panel_operations lcd_ili9486_operations = {
+ .panel_init = ili9486_init,
+ .panel_set_window = ili9486_set_window,
+ .panel_invalidate = ili9486_invalidate,
+ //.lcd_invalidate_rect = ili9486_invalidate_rect,
+ .panel_set_direction = ili9486_set_direction,
+ .panel_enter_sleep = ili9486_enter_sleep,
+ .panel_readid = ili9486_read_id,
+};
+
+static struct timing_mcu lcd_ili9486_timing[] = {
+ [MCU_LCD_REGISTER_TIMING] = {
+ .rcss = 25,
+ .rlpw = 45,
+ .rhpw = 90,
+ .wcss = 30,
+ .wlpw = 20,
+ .whpw = 20,
+ },
+ [MCU_LCD_GRAM_TIMING] = {
+ .rcss = 25,
+ .rlpw = 45,
+ .rhpw = 90,
+ .wcss = 30,
+ .wlpw = 20,
+ .whpw = 20,
+ }
+};
+
+static struct info_mcu lcd_ili9486_info = {
+ .bus_mode = LCD_BUS_8080,
+ .bus_width = 18,
+ .bpp = 18, /*RGB88*/
+ .timing = &lcd_ili9486_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_panel_ili9486 = {
+ .width = 320,
+ .height = 480,
+ .fps = 60,
+ .type = LCD_MODE_MCU,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mcu = &lcd_ili9486_info
+ },
+ .ops = &lcd_ili9486_operations,
+};
+
+struct panel_cfg lcd_ili9486 = {
+ /* this panel may on both CS0/1 */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x9486,
+ .lcd_name = "lcd_ili9486",
+ .panel = &lcd_panel_ili9486,
+};
+
+static int __init lcd_ili9486_init(void)
+{
+ printk(KERN_INFO "sprdfb_111: [%s]: 0x%x!\n", __FUNCTION__,lcd_ili9486.lcd_id);
+
+ return sprdfb_panel_register(&lcd_ili9486);
+}
+
+subsys_initcall(lcd_ili9486_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_ili9486_rgb_spi.c b/drivers/video/sprdfb/lcd/lcd_ili9486_rgb_spi.c
new file mode 100644
index 00000000..1eac114c
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_ili9486_rgb_spi.c
@@ -0,0 +1,397 @@
+/* drivers/video/sc8810/lcd_ili9486_rgb_spi.c
+ *
+ *
+ *
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+#define ili9486_SpiWriteCmd(cmd) \
+{ \
+ spi_send_cmd((cmd & 0xFF));\
+}
+
+#define ili9486_SpiWriteData(data)\
+{ \
+ spi_send_data((data & 0xFF));\
+}
+
+
+static int32_t ili9486_init(struct panel_spec *self)
+{
+ uint32_t test_data[8] = {0};
+ uint32_t left = 0;
+ uint32_t top = 0;
+ uint32_t right = 480;
+ uint32_t bottom = 854;
+ uint32_t data = 0;
+ spi_send_cmd_t spi_send_cmd = self->info.rgb->bus_info.spi->ops->spi_send_cmd;
+ spi_send_data_t spi_send_data = self->info.rgb->bus_info.spi->ops->spi_send_data;
+ spi_read_t spi_read = self->info.rgb->bus_info.spi->ops->spi_read;
+
+
+ printk("ili9486_init\n");
+
+ ili9486_SpiWriteCmd(0xC0);
+
+ ili9486_SpiWriteData(0x15);
+ ili9486_SpiWriteData(0x15);
+
+ ili9486_SpiWriteCmd(0xC1);
+ ili9486_SpiWriteData(0x42);
+
+ ili9486_SpiWriteCmd(0xC2);
+ ili9486_SpiWriteData(0x22);
+
+ ili9486_SpiWriteCmd(0xC5);
+ ili9486_SpiWriteData(0x00);
+ ili9486_SpiWriteData(0x3A);
+
+ //Display parameter setting
+ ili9486_SpiWriteCmd(0x2A);
+ ili9486_SpiWriteData(0x00);
+ ili9486_SpiWriteData(0x00);
+ ili9486_SpiWriteData(0x01);
+ ili9486_SpiWriteData(0x3F);
+
+ ili9486_SpiWriteCmd(0x2B);
+ ili9486_SpiWriteData(0x00);
+ ili9486_SpiWriteData(0x00);
+ ili9486_SpiWriteData(0x01);
+ ili9486_SpiWriteData(0xDF);
+
+ ili9486_SpiWriteCmd(0x36);
+ ili9486_SpiWriteData(0x08);
+
+ ili9486_SpiWriteCmd(0x35);
+ ili9486_SpiWriteData(0x00);
+
+ ili9486_SpiWriteCmd(0x3A);
+ ili9486_SpiWriteData(0x66);
+
+ ili9486_SpiWriteCmd(0xB0);
+ ili9486_SpiWriteData(0x80);
+
+ ili9486_SpiWriteCmd(0xB4);
+ ili9486_SpiWriteData(0x02);
+
+ ili9486_SpiWriteCmd(0xB5);
+ ili9486_SpiWriteData(0x0C);
+ ili9486_SpiWriteData(0x08);
+ ili9486_SpiWriteData(0x2C);
+ ili9486_SpiWriteData(0x26);
+
+ ili9486_SpiWriteCmd(0xB6);
+ ili9486_SpiWriteData(0x20);
+ ili9486_SpiWriteData(0x42);//0x42
+ ili9486_SpiWriteData(0x3B);
+
+ ili9486_SpiWriteCmd(0xB7);
+ ili9486_SpiWriteData(0x07);
+
+ ili9486_SpiWriteCmd(0xF9);
+ ili9486_SpiWriteData(0x00);
+ ili9486_SpiWriteData(0x08);
+
+ //Gamma setting
+ ili9486_SpiWriteCmd(0xE0);
+ ili9486_SpiWriteData(0x1E);
+ ili9486_SpiWriteData(0x21);
+ ili9486_SpiWriteData(0x1F);
+ ili9486_SpiWriteData(0x0C);
+ ili9486_SpiWriteData(0x0B);
+ ili9486_SpiWriteData(0x0C);
+ ili9486_SpiWriteData(0x4E);
+ ili9486_SpiWriteData(0xB9);
+ ili9486_SpiWriteData(0x40);
+ ili9486_SpiWriteData(0x07);
+ ili9486_SpiWriteData(0x16);
+ ili9486_SpiWriteData(0x06);
+ ili9486_SpiWriteData(0x12);
+ ili9486_SpiWriteData(0x12);
+ ili9486_SpiWriteData(0x00);
+
+ ili9486_SpiWriteCmd(0xE1);
+ ili9486_SpiWriteData(0x1F);
+ ili9486_SpiWriteData(0x2A);
+ ili9486_SpiWriteData(0x25);
+ ili9486_SpiWriteData(0x0C);
+ ili9486_SpiWriteData(0x11);
+ ili9486_SpiWriteData(0x09);
+ ili9486_SpiWriteData(0x4C);
+ ili9486_SpiWriteData(0x42);
+ ili9486_SpiWriteData(0x35);
+ ili9486_SpiWriteData(0x08);
+ ili9486_SpiWriteData(0x09);
+ ili9486_SpiWriteData(0x02);
+ ili9486_SpiWriteData(0x26);
+ ili9486_SpiWriteData(0x23);
+ ili9486_SpiWriteData(0x00);
+
+ ili9486_SpiWriteCmd(0xF8);
+ ili9486_SpiWriteData(0x21);
+ ili9486_SpiWriteData(0x07);
+ ili9486_SpiWriteData(0x02);
+
+ ili9486_SpiWriteCmd(0xE2);
+ ili9486_SpiWriteData(0x00);
+ ili9486_SpiWriteData(0x09);
+ ili9486_SpiWriteData(0x09);
+ ili9486_SpiWriteData(0x09);
+ ili9486_SpiWriteData(0x09);
+ ili9486_SpiWriteData(0x09);
+ ili9486_SpiWriteData(0x09);
+ ili9486_SpiWriteData(0x09);
+ ili9486_SpiWriteData(0x09);
+ ili9486_SpiWriteData(0x09);
+ ili9486_SpiWriteData(0x09);
+ ili9486_SpiWriteData(0x09);
+ ili9486_SpiWriteData(0x09);
+ ili9486_SpiWriteData(0x09);
+ ili9486_SpiWriteData(0x09);
+ ili9486_SpiWriteData(0x00);
+
+ ili9486_SpiWriteCmd(0xE3);
+ ili9486_SpiWriteData(0x00);
+ ili9486_SpiWriteData(0x00);
+ ili9486_SpiWriteData(0x00);
+ ili9486_SpiWriteData(0x00);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x04);
+ ili9486_SpiWriteData(0x00);
+
+ ili9486_SpiWriteCmd(0xF4);
+ ili9486_SpiWriteData(0x00);
+ ili9486_SpiWriteData(0x00);
+ ili9486_SpiWriteData(0x08);
+ ili9486_SpiWriteData(0x91);
+ ili9486_SpiWriteData(0x04);
+
+ ili9486_SpiWriteCmd(0xF2);
+ ili9486_SpiWriteData(0x18);
+ ili9486_SpiWriteData(0xA3);
+ ili9486_SpiWriteData(0x12);
+ ili9486_SpiWriteData(0x02);
+ ili9486_SpiWriteData(0x82);
+ ili9486_SpiWriteData(0x32);
+ ili9486_SpiWriteData(0xFF);
+ ili9486_SpiWriteData(0x10);
+ ili9486_SpiWriteData(0x00);
+
+ ili9486_SpiWriteCmd(0xFC);
+ ili9486_SpiWriteData(0x00);
+ ili9486_SpiWriteData(0x00);
+ ili9486_SpiWriteData(0x83);
+
+ //Display on
+ ili9486_SpiWriteCmd(0x11); // (SLPOUT)
+ mdelay(120); // 100ms
+ ili9486_SpiWriteCmd(0x29); // (DISPON)
+ mdelay(10); // 100ms
+ printk("ili9486_init: end\n");
+
+ return 0;
+}
+
+static int32_t ili9486_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ spi_send_cmd_t spi_send_cmd = self->info.rgb->bus_info.spi->ops->spi_send_cmd;
+ spi_send_data_t spi_send_data = self->info.rgb->bus_info.spi->ops->spi_send_data;
+
+ if(is_sleep==1){
+ //Sleep In
+ ili9486_SpiWriteCmd(0x28);
+ mdelay(120);
+ ili9486_SpiWriteCmd(0x10);
+ mdelay(10);
+ }else{
+ //Sleep Out
+ ili9486_SpiWriteCmd(0x11);
+ mdelay(120);
+ ili9486_SpiWriteCmd(0x29);
+ mdelay(10);
+ }
+
+ return 0;
+}
+
+
+
+
+static int32_t ili9486_set_window(struct panel_spec *self,
+ uint16_t left, uint16_t top, uint16_t right, uint16_t bottom)
+{
+ uint32_t *test_data[4] = {0};
+ spi_send_cmd_t spi_send_cmd = self->info.rgb->bus_info.spi->ops->spi_send_cmd;
+ spi_send_data_t spi_send_data = self->info.rgb->bus_info.spi->ops->spi_send_data;
+ spi_read_t spi_read = self->info.rgb->bus_info.spi->ops->spi_read;
+ return 0;
+}
+static int32_t ili9486_invalidate(struct panel_spec *self)
+{
+ return self->ops->panel_set_window(self, 0, 0,
+ self->width - 1, self->height - 1);
+}
+
+static int32_t ili9486_invalidate_rect(struct panel_spec *self,
+ uint16_t left, uint16_t top,
+ uint16_t right, uint16_t bottom)
+{
+ return self->ops->panel_set_window(self, left, top,
+ right, bottom);
+}
+
+static int32_t ili9486_read_id(struct panel_spec *self)
+{
+ int32_t id = 0x62;
+ spi_send_cmd_t spi_send_cmd = self->info.rgb->bus_info.spi->ops->spi_send_cmd;
+ spi_send_data_t spi_send_data = self->info.rgb->bus_info.spi->ops->spi_send_data;
+ spi_read_t spi_read = self->info.rgb->bus_info.spi->ops->spi_read;
+
+ printk("sprdfb ili9486_read_id \n");
+ ili9486_SpiWriteCmd(0xB9); // SET password
+ ili9486_SpiWriteData(0xFF); //
+ ili9486_SpiWriteData(0x83); //
+ ili9486_SpiWriteData(0x63); //
+
+ ili9486_SpiWriteCmd(0xFE); // SET SPI READ INDEX
+ ili9486_SpiWriteData(0xF4); // GETHXID
+ ili9486_SpiWriteCmd(0xFF); // GET SPI READ
+
+ spi_read(&id);
+ id &= 0xff;
+ printk(" ili9486_read_id kernel id = %x\n",id);
+ return 0x9486;
+}
+
+static struct panel_operations lcd_ili9486_rgb_spi_operations = {
+ .panel_init = ili9486_init,
+ .panel_set_window = ili9486_set_window,
+ .panel_invalidate_rect= ili9486_invalidate_rect,
+ .panel_invalidate = ili9486_invalidate,
+ .panel_enter_sleep = ili9486_enter_sleep,
+ .panel_readid = ili9486_read_id
+};
+
+static struct timing_rgb lcd_ili9486_rgb_timing = {
+ .hfp = 30,
+ .hbp = 26,
+ .hsync = 4,
+ .vfp = 12,
+ .vbp = 8,
+ .vsync = 2,
+};
+
+static struct spi_info lcd_ili9486_rgb_spi_info = {
+ .ops = NULL,
+};
+
+static struct info_rgb lcd_ili9486_rgb_info = {
+ .cmd_bus_mode = SPRDFB_RGB_BUS_TYPE_SPI,
+ .video_bus_width = 18, /*18,16*/
+ .h_sync_pol = SPRDFB_POLARITY_NEG,
+ .v_sync_pol = SPRDFB_POLARITY_NEG,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .timing = &lcd_ili9486_rgb_timing,
+ .bus_info = {
+ .spi = &lcd_ili9486_rgb_spi_info,
+ }
+};
+
+struct panel_spec lcd_panel_ili9486_rgb_spi = {
+ .width = 320,
+ .height = 480,
+ .fps = 61,
+ .type = LCD_MODE_RGB,
+ .direction = LCD_DIRECT_NORMAL,
+ .is_clean_lcd = true,
+ .info = {
+ .rgb = &lcd_ili9486_rgb_info
+ },
+ .ops = &lcd_ili9486_rgb_spi_operations,
+};
+
+struct panel_cfg lcd_ili9486_rgb_spi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x9486,
+ .lcd_name = "lcd_ili9486_rgb_spi",
+ .panel = &lcd_panel_ili9486_rgb_spi,
+};
+static int __init lcd_ili9486_rgb_spi_init(void)
+{
+ return sprdfb_panel_register(&lcd_ili9486_rgb_spi);
+}
+
+subsys_initcall(lcd_ili9486_rgb_spi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_ili9486s1_mipi.c b/drivers/video/sprdfb/lcd/lcd_ili9486s1_mipi.c
new file mode 100644
index 00000000..b25e6390
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_ili9486s1_mipi.c
@@ -0,0 +1,268 @@
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+#include <mach/gpio.h>
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 100
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+ //Power setting Sequence
+ {LCM_SEND(5),{3,0,0xC0,0x0A,0x0A}},
+ {LCM_SEND(2),{0xc1,0x45}},
+ {LCM_SEND(2),{0xc2, 0x00}},
+
+ //Initializing Sequence
+ {LCM_SEND(7),{5,0,0x2A,0x00,0x00,0x01,0x3F}},
+ {LCM_SEND(7),{5,0,0x2B,0x00,0x00,0x01,0xDF}},
+ {LCM_SEND(2),{0x36,0xc8}},
+ {LCM_SEND(2),{0x3A,0x66}},
+ {LCM_SEND(2),{0xB0,0x8c}},
+ {LCM_SEND(2),{0xB4,0x02}},
+ {LCM_SEND(6),{4,0,0xB6,0x32,0x22,0x3B}},
+ {LCM_SEND(2),{0xB7,0xC6}},
+ {LCM_SEND(5),{3,0,0xF9,0x00,0x08}},
+ {LCM_SEND(7),{5,0,0xF7,0xA9,0x91,0x2D,0x8A}},
+ {LCM_SEND(6),{4,0,0xF8,0x21,0x07,0x02}},
+ {LCM_SEND(11),{9,0,0xF1,0x36,0x04,0x00,0x3C,0x0F,0x0F,0x04,0x02}},
+ {LCM_SEND(12),{10,0,0xF2,0x18,0xA3,0x12,0x02,0xB2,0x12,0xFF,0x10,0x00}},
+ {LCM_SEND(6),{4,0,0xFC,0x00,0x0C,0x80}},
+ //gamma setting
+ {LCM_SEND(18),{16,0,0xE0,0x01,0x15,0x17,0x0C,0x0F,0x07,0x44,0x65,0x35,0x07,0x12,0x04,0x09,0x06,0x06}},
+ {LCM_SEND(18),{16,0,0xE1,0x0F,0x38,0x34,0x0B,0x0B,0x03,0x43,0x22,0x30,0x03,0x0E,0x03,0x21,0x1B,0x00}},
+ // 3Gamma Setting Sequence
+ {LCM_SEND(19),{17,0,0xE2,0x00,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x00}},
+ {LCM_SEND(67),{65,0,0xE3,0x00,0x00,0x00,0x00,
+ 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+ 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+ 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+ 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+ 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+ 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00}},
+
+ //Display on
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(100)},
+
+};
+
+static LCM_Init_Code disp_on[] = {
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(100)},
+};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(50)}, //>150ms
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(120)}, //>150ms
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},//>120ms
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)}, //>20ms
+};
+
+static int32_t ili9486s1_mipi_init(struct panel_spec *self)
+{
+ int32_t i;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel ili9486s1_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t ili9486s1_readid(struct panel_spec *self)
+{
+#if 0
+ uint8_t j =0;
+ uint8_t read_data[4] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("ili9486s1_readid!\n");
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x01;
+ param[1] = 0x00;
+
+ mipi_force_write(0x04, param, 2);
+
+ read_rtn = mipi_force_read(0xda,1,&read_data[0]);
+ LCD_PRINT("lcdili9486s1_mipi read id 0xda value is 0x%x!\n",read_data[0]);
+
+ read_rtn = mipi_force_read(0xdb,1,&read_data[1]);
+ LCD_PRINT("lcd_ili9486s1_mipi read id 0xdb value is 0x%x!\n",read_data[1]);
+
+ read_rtn = mipi_force_read(0xdc,1,&read_data[2]);
+ LCD_PRINT("lcd_ili9486s1_mipi read id 0xdc value is 0x%x!\n",read_data[2]);
+
+ if((0x55 == read_data[0])&&(0x4c == read_data[1])&&(0xc0 == read_data[2])){
+ printk("lcd_nili9486s1_mipi read id success!\n");
+ return 0x8370;
+ }
+ }
+
+ mipi_eotp_set(0,0);
+#endif
+ return 0x8370;
+}
+
+
+
+static int32_t ili9486s1_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel nt35502_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(sleep_in_out->tag & LCM_TAG_MASK);
+ }
+ sleep_in_out++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static struct panel_operations lcd_ili9486s1_mipi_operations = {
+ .panel_init = ili9486s1_mipi_init,
+ .panel_readid = ili9486s1_readid,
+ .panel_enter_sleep = ili9486s1_enter_sleep,
+};
+
+static struct timing_rgb lcd_ili9486s1_mipi_timing = {
+ .hfp = 30, /* unit: pixel */
+ .hbp = 26,
+ .hsync = 0,
+ .vfp = 12, /*unit: line*/
+ .vbp = 8,
+ .vsync = 1,
+};
+
+
+
+static struct info_mipi lcd_ili9486s1_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 18, /*18,16*/
+ .lan_number = 1,
+ .phy_feq =340*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_ili9486s1_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_ili9486s1_mipi_spec = {
+ .width = 320,
+ .height = 480,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_ili9486s1_mipi_info
+ },
+ .ops = &lcd_ili9486s1_mipi_operations,
+};
+struct panel_cfg lcd_ili9486s1_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x8370,
+ .lcd_name = "lcd_ili9486s1_mipi",
+ .panel = &lcd_ili9486s1_mipi_spec,
+};
+
+//temp code
+static int __init lcd_ili9486s1_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_ili9486s1_mipi);
+}
+
+subsys_initcall(lcd_ili9486s1_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_ili9806e_2_mipi.c b/drivers/video/sprdfb/lcd/lcd_ili9806e_2_mipi.c
new file mode 100644
index 00000000..e391ef26
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_ili9806e_2_mipi.c
@@ -0,0 +1,487 @@
+/* drivers/video/sc8825/lcd_ili9806e_2_mipi.c
+ *
+ * Support for ili9806e_2 mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+//#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 48
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x01}},// Change to Page 1
+ {LCM_SLEEP(5)},
+
+ {LCM_SEND(2), {0x08,0x10}},// output SDA
+
+ {LCM_SEND(2), {0x21,0x01}},// DE = 1 Active
+
+ {LCM_SEND(2), {0x30,0x02}},// 480 X 800 Ó¦¸ÃÉèΪ2
+ {LCM_SEND(2), {0x31,0x02}}, // 2-dot Inversion
+
+ {LCM_SEND(2), {0x50,0x78}},// VGMP
+ {LCM_SEND(2), {0x51,0x78}},// VGMN
+ {LCM_SEND(2), {0x52,0x00}}, //Flicker
+ {LCM_SEND(2), {0x53,0x77}},//Flicker
+ {LCM_SEND(2), {0x54,0x00}},//Flicker
+ {LCM_SEND(2), {0x55,0x77}},//Flicker
+
+ {LCM_SEND(2), {0x60,0x07}},// SDTI
+ {LCM_SEND(2), {0x61,0x00}},// CRTI
+ {LCM_SEND(2), {0x62,0x08}},// EQTI
+ {LCM_SEND(2), {0x63,0x00}}, // PCTI
+
+ {LCM_SEND(2), {0x40,0x10}},// VGH/VGL
+ {LCM_SEND(2), {0x41,0x33}}, // VGH/VGL
+ {LCM_SEND(2), {0x42,0x02}},// VGH/VGL
+ {LCM_SEND(2), {0x43,0x09}},// VGH/VGL
+ {LCM_SEND(2), {0x44,0x07}},// VGH/VGL
+
+//++++++++++++++++++ Gamma Setting ++++++++++++++++++//
+
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x01}},// Change to Page 1
+
+ {LCM_SEND(2), {0xA0,0x00}},// Gamma 0
+ {LCM_SEND(2), {0xA1,0x04}},// Gamma 4
+ {LCM_SEND(2), {0xA2,0x0A}},// Gamma 8
+ {LCM_SEND(2), {0xA3,0x11}},// Gamma 16
+ {LCM_SEND(2), {0xA4,0x0C}},// Gamma 24
+ {LCM_SEND(2), {0xA5,0x1D}},// Gamma 52
+ {LCM_SEND(2), {0xA6,0x0D}},// Gamma 80
+ {LCM_SEND(2), {0xA7,0x07}},// Gamma 108
+ {LCM_SEND(2), {0xA8,0x05}},// Gamma 147
+ {LCM_SEND(2), {0xA9,0x0B}},// Gamma 175
+ {LCM_SEND(2), {0xAA,0x07}},// Gamma 203
+ {LCM_SEND(2), {0xAB,0x04}},// Gamma 231
+ {LCM_SEND(2), {0xAC,0x0F}},// Gamma 239
+ {LCM_SEND(2), {0xAD,0x2B}},// Gamma 247
+ {LCM_SEND(2), {0xAE,0x24}},// Gamma 251
+ {LCM_SEND(2), {0xAF,0x00}},// Gamma 255
+
+///==============Nagitive
+ {LCM_SEND(2), {0xC0,0x00}}, // Gamma 0
+ {LCM_SEND(2), {0xC1,0x04}}, // Gamma 4
+ {LCM_SEND(2), {0xC2,0x0D}}, // Gamma 8
+ {LCM_SEND(2), {0xC3,0x0E}}, // Gamma 16
+ {LCM_SEND(2), {0xC4,0x0B}}, // Gamma 24
+ {LCM_SEND(2), {0xC5,0x15}}, // Gamma 52
+ {LCM_SEND(2), {0xC6,0x07}}, // Gamma 80
+ {LCM_SEND(2), {0xC7,0x09}}, // Gamma 108
+ {LCM_SEND(2), {0xC8,0x02}}, // Gamma 147
+ {LCM_SEND(2), {0xC9,0x06}}, // Gamma 175
+ {LCM_SEND(2), {0xCA,0x05}}, // Gamma 203
+ {LCM_SEND(2), {0xCB,0x04}}, // Gamma 231
+ {LCM_SEND(2), {0xCC,0x09}}, // Gamma 239
+ {LCM_SEND(2), {0xCD,0x2C}}, // Gamma 247
+ {LCM_SEND(2), {0xCE,0x27}}, // Gamma 251
+ {LCM_SEND(2), {0xCF,0x00}}, // Gamma 255
+
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x06}}, // Change to Page 6
+
+ {LCM_SEND(2), {0x00,0x21}},
+ {LCM_SEND(2), {0x01,0x09}},
+ {LCM_SEND(2), {0x02,0x00}},
+ {LCM_SEND(2), {0x03,0x00}},
+ {LCM_SEND(2), {0x04,0x01}},
+ {LCM_SEND(2), {0x05,0x01}},
+ {LCM_SEND(2), {0x06,0x80}},
+ {LCM_SEND(2), {0x07,0x05}},
+ {LCM_SEND(2), {0x08,0x02}},
+ {LCM_SEND(2), {0x09,0x80}},
+ {LCM_SEND(2), {0x0A,0x00}},
+ {LCM_SEND(2), {0x0B,0x00}},
+ {LCM_SEND(2), {0x0C,0x0a}},
+ {LCM_SEND(2), {0x0D,0x0a}},
+ {LCM_SEND(2), {0x0E,0x00}},
+ {LCM_SEND(2), {0x0F,0x00}},
+
+ {LCM_SEND(2), {0x10,0xE0}},
+ {LCM_SEND(2), {0x11,0xE4}},
+ {LCM_SEND(2), {0x12,0x04}},
+ {LCM_SEND(2), {0x13,0x00}},
+ {LCM_SEND(2), {0x14,0x00}},
+ {LCM_SEND(2), {0x15,0xC0}},
+ {LCM_SEND(2), {0x16,0x08}},
+ {LCM_SEND(2), {0x17,0x00}},
+ {LCM_SEND(2), {0x18,0x00}},
+ {LCM_SEND(2), {0x19,0x00}},
+ {LCM_SEND(2), {0x1A,0x00}},
+ {LCM_SEND(2), {0x1B,0x00}},
+ {LCM_SEND(2), {0x1C,0x00}},
+ {LCM_SEND(2), {0x1D,0x00}},
+
+ {LCM_SEND(2), {0x20,0x01}},
+ {LCM_SEND(2), {0x21,0x23}},
+ {LCM_SEND(2), {0x22,0x45}},
+ {LCM_SEND(2), {0x23,0x67}},
+ {LCM_SEND(2), {0x24,0x01}},
+ {LCM_SEND(2), {0x25,0x23}},
+ {LCM_SEND(2), {0x26,0x45}},
+ {LCM_SEND(2), {0x27,0x67}},
+
+ {LCM_SEND(2), {0x30,0x01}},
+ {LCM_SEND(2), {0x31,0x11}},
+ {LCM_SEND(2), {0x32,0x00}},
+ {LCM_SEND(2), {0x33,0xee}},
+ {LCM_SEND(2), {0x34,0xff}},
+ {LCM_SEND(2), {0x35,0xCB}},
+ {LCM_SEND(2), {0x36,0xDA}},
+ {LCM_SEND(2), {0x37,0xAD}},
+ {LCM_SEND(2), {0x38,0xBC}},
+ {LCM_SEND(2), {0x39,0x76}},
+ {LCM_SEND(2), {0x3A,0x67}},
+ {LCM_SEND(2), {0x3B,0x22}},
+ {LCM_SEND(2), {0x3C,0x22}},
+ {LCM_SEND(2), {0x3D,0x22}},
+ {LCM_SEND(2), {0x3E,0x22}},
+ {LCM_SEND(2), {0x3F,0x22}},
+
+ {LCM_SEND(2), {0x40,0x22}},
+
+ {LCM_SEND(2), {0x52,0x10}},
+
+ {LCM_SEND(2), {0x53,0x10}},
+
+// {LCM_SEND(2), {0x58,0x97}},
+
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x07}}, // Change to Page 7
+ {LCM_SEND(2), {0x17,0x22}},
+
+ {LCM_SEND(2), {0x02,0x77}},
+
+ {LCM_SEND(2), {0xe1,0x79}},
+ {LCM_SEND(2), {0x26,0xB2}},
+ //{LCM_SEND(2), {0x06,0x13}},
+
+//****************************************************************************//
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x00}}, // Change to Page 0
+
+ {LCM_SEND(2), {0x35,0x00}},
+ {LCM_SEND(2), {0x55,0xB0}},
+
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},
+
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)},
+ };
+
+static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x00}},
+ {LCM_SLEEP(1)},
+
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(20)},
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(120)},
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)},
+};
+
+static LCM_Force_Cmd_Code rd_prep_code[]={
+ {0x39, {LCM_SEND(8), {0x6, 0, 0xFF, 0xFF, 0x98, 0x06,0x04,0x01}}},
+ {0x37, {LCM_SEND(2), {0x3, 0}}},
+};
+
+static LCM_Force_Cmd_Code rd_prep_code_1[]={
+ {0x37, {LCM_SEND(2), {0x1, 0}}},
+};
+static int32_t ili9806e_2_mipi_init(struct panel_spec *self)
+{
+ int32_t i;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_debug(KERN_DEBUG "ili9806e_2_mipi_init\n");
+
+ msleep(2);
+ mipi_set_cmd_mode();
+ mipi_eotp_set(1,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ //udelay((init->tag & LCM_TAG_MASK) * 1000);
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(1,1);
+
+ return 0;
+}
+
+static uint32_t ili9806e_2_readid(struct panel_spec *self)
+{
+ /*Jessica TODO: need read id*/
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code;
+ uint8_t read_data[3] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("lcd_ili9806e_2_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(1,0);
+
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }
+ rd_prepare++;
+ }
+ read_rtn = mipi_force_read(0x02, 3,(uint8_t *)read_data);
+ printk("lcd_ili9806e_2_mipi read id 0xc5 value is 0x%x, 0x%x, 0x%x!\n", read_data[0], read_data[1], read_data[2]);
+
+ if((0x04 == read_data[0])){
+ printk("lcd_ili9806e_2_mipi read id success!\n");
+ mipi_eotp_set(1,1);
+ return 0x980602;
+ }
+ }
+ mipi_eotp_set(1,1);
+ return 0x0;
+}
+
+static int32_t ili9806e_2_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk(KERN_DEBUG "ili9806e_2_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+ mipi_eotp_set(1,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ //udelay((sleep_in_out->tag & LCM_TAG_MASK) * 1000);
+ msleep((sleep_in_out->tag & LCM_TAG_MASK));
+ }
+ sleep_in_out++;
+ }
+ return 0;
+}
+
+static uint32_t ili9806e_2_readpowermode(struct panel_spec *self)
+{
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code_1;
+ uint8_t read_data[1] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+ uint32_t reg_val_1 = 0;
+ uint32_t reg_val_2 = 0;
+
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_debug("lcd_ili9806e_2_mipi read power mode!\n");
+ mipi_eotp_set(0,1);
+
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code_1;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code_1); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }
+ rd_prepare++;
+ }
+
+ read_rtn = mipi_force_read(0x0A, 1,(uint8_t *)read_data);
+ //printk("lcd_ili9806e_2 mipi read power mode 0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+
+ if((0x9c == read_data[0]) && (0 == read_rtn)){
+ pr_debug("lcd_ili9806e_2_mipi read power mode success!\n");
+ mipi_eotp_set(1,1);
+ return 0x9c;
+ }
+ }
+
+ mipi_eotp_set(1,1);
+ return 0x0;
+}
+
+
+static uint32_t ili9806e_2_check_esd(struct panel_spec *self)
+{
+ uint32_t power_mode;
+
+ pr_debug("ili9806e_2_check_esd!\n");
+ mipi_set_lp_mode_t mipi_set_data_lp_mode = self->info.mipi->ops->mipi_set_data_lp_mode;
+ mipi_set_hs_mode_t mipi_set_data_hs_mode = self->info.mipi->ops->mipi_set_data_hs_mode;
+
+ mipi_set_lp_mode_t mipi_set_lp_mode = self->info.mipi->ops->mipi_set_lp_mode;
+ mipi_set_hs_mode_t mipi_set_hs_mode = self->info.mipi->ops->mipi_set_hs_mode;
+ uint16_t work_mode = self->info.mipi->work_mode;
+
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_lp_mode();
+ }else{
+ mipi_set_data_lp_mode();
+ }
+ power_mode = ili9806e_2_readpowermode(self);
+ //power_mode = 0x0;
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_hs_mode();
+ }else{
+ mipi_set_data_hs_mode();
+ }
+ if(power_mode == 0x9c){
+ pr_debug("ili9806e_2_check_esd OK!\n");
+ return 1;
+ }else{
+ printk("ili9806e_2_check_esd fail!(0x%x)\n", power_mode);
+ return 0;
+ }
+}
+
+static uint32_t ili9806e_2_mipi_after_suspend(struct panel_spec *self)
+{
+ return 0;
+}
+
+static struct panel_operations lcd_ili9806e_2_mipi_operations = {
+ .panel_init = ili9806e_2_mipi_init,
+ .panel_readid = ili9806e_2_readid,
+ .panel_enter_sleep = ili9806e_2_enter_sleep,
+ .panel_esd_check = ili9806e_2_check_esd,
+ .panel_after_suspend = ili9806e_2_mipi_after_suspend,
+};
+
+static struct timing_rgb lcd_ili9806e_2_mipi_timing = {
+ .hfp = 80, //60 /* unit: pixel */// 100
+ .hbp = 80,//80
+ .hsync = 10,//60
+ .vfp = 20, /*unit: line*/
+ .vbp = 16, //14
+ .vsync =4, //6,
+};
+
+static struct info_mipi lcd_ili9806e_2_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq = 400*1000, //500->10MHz,400->8M in lp mode
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_ili9806e_2_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_ili9806e_2_mipi_spec = {
+ //.cap = PANEL_CAP_NOT_TEAR_SYNC,
+ .width = 480,
+ .height = 800,
+ .fps = 59,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .is_clean_lcd = true,
+ .reset_timing = {5, 15, 120},
+ .info = {
+ .mipi = &lcd_ili9806e_2_mipi_info
+ },
+ .ops = &lcd_ili9806e_2_mipi_operations,
+};
+
+struct panel_cfg lcd_ili9806e_2_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x980602,
+ .lcd_name = "lcd_ili9806e_2_mipi",
+ .panel = &lcd_ili9806e_2_mipi_spec,
+};
+
+static int __init lcd_ili9806e_2_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_ili9806e_2_mipi);
+}
+
+subsys_initcall(lcd_ili9806e_2_mipi_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_ili9806e_mipi.c b/drivers/video/sprdfb/lcd/lcd_ili9806e_mipi.c
new file mode 100644
index 00000000..075c7058
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_ili9806e_mipi.c
@@ -0,0 +1,632 @@
+/* drivers/video/sc8825/lcd_ili9806e_mipi.c
+ *
+ * Support for ili9806e mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+//#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 48
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+#if 0 /*For SS*/
+static LCM_Init_Code init_data[] = {
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x01}},
+ {LCM_SLEEP(5)},
+
+ {LCM_SEND(2), {0x08,0x10}},
+
+ {LCM_SEND(2), {0x21,0x01}},
+
+ {LCM_SEND(2), {0x30,0x02}},
+ {LCM_SEND(2), {0x31,0x00}}, //0x02
+
+ {LCM_SEND(2), {0x60,0x07}},
+ {LCM_SEND(2), {0x61,0x06}},
+ {LCM_SEND(2), {0x62,0x06}},
+ {LCM_SEND(2), {0x63,0x04}},
+
+ {LCM_SEND(2), {0x40,0x14}},
+ {LCM_SEND(2), {0x41,0x44}},//22
+ {LCM_SEND(2), {0x42,0x01}},
+ {LCM_SEND(2), {0x43,0x89}},
+ {LCM_SEND(2), {0x44,0x89}},
+ {LCM_SEND(2), {0x45,0x1b}},
+ {LCM_SEND(2), {0x46,0x44}},
+ {LCM_SEND(2), {0x47,0x44}},
+
+ {LCM_SEND(2), {0x50,0x85}},
+ {LCM_SEND(2), {0x51,0x85}},
+ {LCM_SEND(2), {0x52,0x00}},
+ {LCM_SEND(2), {0x53,0x64}},//90
+
+ //{LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x01}},
+
+ {LCM_SEND(2), {0xA0,0x00}},
+ {LCM_SEND(2), {0xA1,0x00}},//01
+ {LCM_SEND(2), {0xA2,0x03}},//08
+ {LCM_SEND(2), {0xA3,0x0e}},//0e
+ {LCM_SEND(2), {0xA4,0x08}},//08
+ {LCM_SEND(2), {0xA5,0x1f}},//19
+ {LCM_SEND(2), {0xA6,0x0f}},//0b
+ {LCM_SEND(2), {0xA7,0x0b}},//0a
+ {LCM_SEND(2), {0xA8,0x03}},//02
+ {LCM_SEND(2), {0xA9,0x06}},//08
+ {LCM_SEND(2), {0xAA,0x05}},//04
+ {LCM_SEND(2), {0xAB,0x02}},//03
+ {LCM_SEND(2), {0xAC,0x0e}},//0a
+ {LCM_SEND(2), {0xAD,0x25}},//2c
+ {LCM_SEND(2), {0xAE,0x1d}},//28
+ {LCM_SEND(2), {0xAF,0x00}},
+
+ {LCM_SEND(2), {0xC0,0x00}},//00
+ {LCM_SEND(2), {0xC1,0x04}},//02
+ {LCM_SEND(2), {0xC2,0x0f}},//09
+ {LCM_SEND(2), {0xC3,0x10}},//0e
+ {LCM_SEND(2), {0xC4,0x0b}},//09
+ {LCM_SEND(2), {0xC5,0x1e}},//19
+ {LCM_SEND(2), {0xC6,0x09}},//0a
+ {LCM_SEND(2), {0xC7,0x0a}},//0a
+ {LCM_SEND(2), {0xC8,0x00}},//02
+ {LCM_SEND(2), {0xC9,0x0a}},//07
+ {LCM_SEND(2), {0xCA,0x01}},//05
+ {LCM_SEND(2), {0xCB,0x06}},//04
+ {LCM_SEND(2), {0xCC,0x09}},//0a
+ {LCM_SEND(2), {0xCD,0x2a}},//2d
+ {LCM_SEND(2), {0xCE,0x28}},//28
+ {LCM_SEND(2), {0xCF,0x00}},//00
+
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x06}},
+ {LCM_SEND(2), {0x00,0xa0}},
+ {LCM_SEND(2), {0x01,0x05}},
+ {LCM_SEND(2), {0x02,0x00}},
+ {LCM_SEND(2), {0x03,0x00}},
+ {LCM_SEND(2), {0x04,0x01}},
+ {LCM_SEND(2), {0x05,0x01}},
+ {LCM_SEND(2), {0x06,0x88}},
+ {LCM_SEND(2), {0x07,0x04}},
+ {LCM_SEND(2), {0x08,0x01}},
+ {LCM_SEND(2), {0x09,0x90}},
+ {LCM_SEND(2), {0x0A,0x04}},
+ {LCM_SEND(2), {0x0B,0x01}},
+ {LCM_SEND(2), {0x0C,0x01}},
+ {LCM_SEND(2), {0x0D,0x01}},
+ {LCM_SEND(2), {0x0E,0x00}},
+ {LCM_SEND(2), {0x0F,0x00}},
+
+ {LCM_SEND(2), {0x10,0x55}},
+ {LCM_SEND(2), {0x11,0x50}},
+ {LCM_SEND(2), {0x12,0x01}},
+ {LCM_SEND(2), {0x13,0x85}},
+ {LCM_SEND(2), {0x14,0x85}},
+ {LCM_SEND(2), {0x15,0xc0}},
+ {LCM_SEND(2), {0x16,0x0B}},
+ {LCM_SEND(2), {0x17,0x00}},
+ {LCM_SEND(2), {0x18,0x00}},
+ {LCM_SEND(2), {0x19,0x00}},
+ {LCM_SEND(2), {0x1A,0x00}},
+ {LCM_SEND(2), {0x1B,0x00}},
+ {LCM_SEND(2), {0x1C,0x00}},
+ {LCM_SEND(2), {0x1D,0x00}},
+
+ {LCM_SEND(2), {0x20,0x01}},
+ {LCM_SEND(2), {0x21,0x23}},
+ {LCM_SEND(2), {0x22,0x45}},
+ {LCM_SEND(2), {0x23,0x67}},
+ {LCM_SEND(2), {0x24,0x01}},
+ {LCM_SEND(2), {0x25,0x23}},
+ {LCM_SEND(2), {0x26,0x45}},
+ {LCM_SEND(2), {0x27,0x67}},
+
+ {LCM_SEND(2), {0x30,0x02}},
+ {LCM_SEND(2), {0x31,0x22}},
+ {LCM_SEND(2), {0x32,0x11}},
+ {LCM_SEND(2), {0x33,0xaa}},
+ {LCM_SEND(2), {0x34,0xbb}},
+ {LCM_SEND(2), {0x35,0x66}},
+ {LCM_SEND(2), {0x36,0x00}},
+ {LCM_SEND(2), {0x37,0x22}},
+ {LCM_SEND(2), {0x38,0x22}},
+ {LCM_SEND(2), {0x39,0x22}},
+ {LCM_SEND(2), {0x3A,0x22}},
+ {LCM_SEND(2), {0x3B,0x22}},
+ {LCM_SEND(2), {0x3C,0x22}},
+ {LCM_SEND(2), {0x3D,0x22}},
+ {LCM_SEND(2), {0x3E,0x22}},
+ {LCM_SEND(2), {0x3F,0x22}},
+
+ {LCM_SEND(2), {0x40,0x22}},
+ {LCM_SEND(2), {0x53,0x1a}},
+
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x07}},
+ {LCM_SEND(2), {0x18,0x1d}},
+ {LCM_SEND(2), {0x17,0x12}},
+
+ {LCM_SEND(2), {0x02,0x77}},
+
+ {LCM_SEND(2), {0xe1,0x79}},
+
+ {LCM_SEND(2), {0x06,0x13}},
+
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x00}},
+
+// {LCM_SEND(2), {0x35,0x00}},
+
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},
+
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(1)},
+
+// {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x08}},
+};
+
+#else /*For SPRD*/
+static LCM_Init_Code init_data[] = {
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x01}},// Change to Page 1
+ {LCM_SLEEP(5)},
+
+ {LCM_SEND(2), {0x08,0x10}},// output SDA
+
+ {LCM_SEND(2), {0x21,0x01}},// DE = 1 Active
+
+ {LCM_SEND(2), {0x30,0x02}},// 480 X 800
+ {LCM_SEND(2), {0x31,0x02}}, // 2-dot Inversion
+
+ {LCM_SEND(2), {0x50,0x78}},// VGMP
+ {LCM_SEND(2), {0x51,0x78}},// VGMN
+ {LCM_SEND(2), {0x52,0x00}}, //Flicker
+ {LCM_SEND(2), {0x53,0x61}},//Flicker
+
+ {LCM_SEND(2), {0x60,0x07}},// SDTI
+ {LCM_SEND(2), {0x61,0x00}},// CRTI
+ {LCM_SEND(2), {0x62,0x08}},// EQTI
+ {LCM_SEND(2), {0x63,0x00}}, // PCTI
+
+ {LCM_SEND(2), {0x40,0x15}},// VGH/VGL
+ {LCM_SEND(2), {0x41,0x44}}, // VGH/VGL
+ {LCM_SEND(2), {0x42,0x03}},// VGH/VGL
+ {LCM_SEND(2), {0x43,0x89}},// VGH/VGL
+ {LCM_SEND(2), {0x44,0x82}},// VGH/VGL
+
+//++++++++++++++++++ Gamma Setting ++++++++++++++++++//
+
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x01}},// Change to Page 1
+
+ {LCM_SEND(2), {0xA0,0x00}},// Gamma 0
+ {LCM_SEND(2), {0xA1,0x06}},// Gamma 4
+ {LCM_SEND(2), {0xA2,0x0c}},// Gamma 8
+ {LCM_SEND(2), {0xA3,0x12}},// Gamma 16
+ {LCM_SEND(2), {0xA4,0x0d}},// Gamma 24
+ {LCM_SEND(2), {0xA5,0x1f}},// Gamma 52
+ {LCM_SEND(2), {0xA6,0x0b}},// Gamma 80
+ {LCM_SEND(2), {0xA7,0x08}},// Gamma 108
+ {LCM_SEND(2), {0xA8,0x04}},// Gamma 147
+ {LCM_SEND(2), {0xA9,0x0a}},// Gamma 175
+ {LCM_SEND(2), {0xAA,0x06}},// Gamma 203
+ {LCM_SEND(2), {0xAB,0x04}},// Gamma 231
+ {LCM_SEND(2), {0xAC,0x10}},// Gamma 239
+ {LCM_SEND(2), {0xAD,0x37}},// Gamma 247
+ {LCM_SEND(2), {0xAE,0x30}},// Gamma 251
+ {LCM_SEND(2), {0xAF,0x07}},// Gamma 255
+
+///==============Nagitive
+ {LCM_SEND(2), {0xC0,0x00}}, // Gamma 0
+ {LCM_SEND(2), {0xC1,0x06}}, // Gamma 4
+ {LCM_SEND(2), {0xC2,0x1f}}, // Gamma 8
+ {LCM_SEND(2), {0xC3,0x06}}, // Gamma 16
+ {LCM_SEND(2), {0xC4,0x04}}, // Gamma 24
+ {LCM_SEND(2), {0xC5,0x13}}, // Gamma 52
+ {LCM_SEND(2), {0xC6,0x05}}, // Gamma 80
+ {LCM_SEND(2), {0xC7,0x05}}, // Gamma 108
+ {LCM_SEND(2), {0xC8,0x03}}, // Gamma 147
+ {LCM_SEND(2), {0xC9,0x06}}, // Gamma 175
+ {LCM_SEND(2), {0xCA,0x06}}, // Gamma 203
+ {LCM_SEND(2), {0xCB,0x03}}, // Gamma 231
+ {LCM_SEND(2), {0xCC,0x01}}, // Gamma 239
+ {LCM_SEND(2), {0xCD,0x27}}, // Gamma 247
+ {LCM_SEND(2), {0xCE,0x24}}, // Gamma 251
+ {LCM_SEND(2), {0xCF,0x07}}, // Gamma 255
+
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x06}}, // Change to Page 6
+
+ {LCM_SEND(2), {0x00,0x3c}},
+ {LCM_SEND(2), {0x01,0x06}},
+ {LCM_SEND(2), {0x02,0x00}},
+ {LCM_SEND(2), {0x03,0x00}},
+ {LCM_SEND(2), {0x04,0x0d}},
+ {LCM_SEND(2), {0x05,0x0d}},
+ {LCM_SEND(2), {0x06,0x80}},
+ {LCM_SEND(2), {0x07,0x04}},
+ {LCM_SEND(2), {0x08,0x03}},
+ {LCM_SEND(2), {0x09,0x00}},
+ {LCM_SEND(2), {0x0A,0x00}},
+ {LCM_SEND(2), {0x0B,0x00}},
+ {LCM_SEND(2), {0x0C,0x0d}},
+ {LCM_SEND(2), {0x0D,0x0d}},
+ {LCM_SEND(2), {0x0E,0x00}},
+ {LCM_SEND(2), {0x0F,0x00}},
+
+ {LCM_SEND(2), {0x10,0x50}},
+ {LCM_SEND(2), {0x11,0xd0}},
+ {LCM_SEND(2), {0x12,0x00}},
+ {LCM_SEND(2), {0x13,0x00}},
+ {LCM_SEND(2), {0x14,0x00}},
+ {LCM_SEND(2), {0x15,0xc0}},
+ {LCM_SEND(2), {0x16,0x08}},
+ {LCM_SEND(2), {0x17,0x00}},
+ {LCM_SEND(2), {0x18,0x00}},
+ {LCM_SEND(2), {0x19,0x00}},
+ {LCM_SEND(2), {0x1A,0x00}},
+ {LCM_SEND(2), {0x1B,0x00}},
+ {LCM_SEND(2), {0x1C,0x48}},
+ {LCM_SEND(2), {0x1D,0x00}},
+
+ {LCM_SEND(2), {0x20,0x01}},
+ {LCM_SEND(2), {0x21,0x23}},
+ {LCM_SEND(2), {0x22,0x45}},
+ {LCM_SEND(2), {0x23,0x67}},
+ {LCM_SEND(2), {0x24,0x01}},
+ {LCM_SEND(2), {0x25,0x23}},
+ {LCM_SEND(2), {0x26,0x45}},
+ {LCM_SEND(2), {0x27,0x67}},
+
+ {LCM_SEND(2), {0x30,0x13}},
+ {LCM_SEND(2), {0x31,0x22}},
+ {LCM_SEND(2), {0x32,0xdd}},
+ {LCM_SEND(2), {0x33,0xcc}},
+ {LCM_SEND(2), {0x34,0xbb}},
+ {LCM_SEND(2), {0x35,0xaa}},
+ {LCM_SEND(2), {0x36,0x22}},
+ {LCM_SEND(2), {0x37,0x26}},
+ {LCM_SEND(2), {0x38,0x72}},
+ {LCM_SEND(2), {0x39,0xff}},
+ {LCM_SEND(2), {0x3A,0x22}},
+ {LCM_SEND(2), {0x3B,0xee}},
+ {LCM_SEND(2), {0x3C,0x22}},
+ {LCM_SEND(2), {0x3D,0x22}},
+ {LCM_SEND(2), {0x3E,0x22}},
+ {LCM_SEND(2), {0x3F,0x22}},
+ {LCM_SEND(2), {0x52,0x10}}, /*reduce current when battery charging*/
+
+ {LCM_SEND(2), {0x40,0x22}},
+
+ {LCM_SEND(2), {0x58,0xa7}},//refresh black after resume
+
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x07}}, // Change to Page 7
+ {LCM_SEND(2), {0x17,0x22}},
+
+ {LCM_SEND(2), {0x02,0x77}},
+
+//****************************************************************************//
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x00}}, // Change to Page 0
+
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},
+
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(10)},
+ };
+
+#endif
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x00}},
+ {LCM_SLEEP(1)},
+
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(10)},
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x01}},
+ {LCM_SLEEP(1)},
+
+ {LCM_SEND(2), {0x58,0x91}},
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)},
+};
+
+static LCM_Force_Cmd_Code rd_prep_code[]={
+ {0x39, {LCM_SEND(8), {0x6, 0, 0xFF, 0xFF, 0x98, 0x06,0x04,0x01}}},
+ {0x37, {LCM_SEND(2), {0x3, 0}}},
+};
+
+static LCM_Force_Cmd_Code rd_prep_code_1[]={
+ {0x37, {LCM_SEND(2), {0x1, 0}}},
+};
+static int32_t ili9806e_mipi_init(struct panel_spec *self)
+{
+ int32_t i;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_debug(KERN_DEBUG "ili9806e_mipi_init\n");
+
+ msleep(2);
+ mipi_set_cmd_mode();
+ mipi_eotp_set(1,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ //udelay((init->tag & LCM_TAG_MASK) * 1000);
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(1,1);
+
+ return 0;
+}
+
+static uint32_t ili9806e_readid(struct panel_spec *self)
+{
+ /*Jessica TODO: need read id*/
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code;
+ uint8_t read_data[3] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("lcd_ili9806e_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(1,0);
+
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }
+ rd_prepare++;
+ }
+ read_rtn = mipi_force_read(0x02, 3,(uint8_t *)read_data);
+ printk("lcd_ili9806e_mipi read id 0xc5 value is 0x%x, 0x%x, 0x%x!\n", read_data[0], read_data[1], read_data[2]);
+
+ if((0x04 == read_data[0])){
+ printk("lcd_ili9806e_mipi read id success!\n");
+ mipi_eotp_set(1,1);
+ return 0x04;
+ }
+ }
+ mipi_eotp_set(1,1);
+ return 0x0;
+}
+
+static int32_t ili9806e_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk(KERN_DEBUG "ili9806e_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+ mipi_eotp_set(1,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ //udelay((sleep_in_out->tag & LCM_TAG_MASK) * 1000);
+ msleep((sleep_in_out->tag & LCM_TAG_MASK));
+ }
+ sleep_in_out++;
+ }
+ return 0;
+}
+
+static uint32_t ili9806e_readpowermode(struct panel_spec *self)
+{
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code_1;
+ uint8_t read_data[1] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+ uint32_t reg_val_1 = 0;
+ uint32_t reg_val_2 = 0;
+
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_debug("lcd_ili9806e_mipi read power mode!\n");
+ mipi_eotp_set(0,1);
+
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code_1;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code_1); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }
+ rd_prepare++;
+ }
+
+ read_rtn = mipi_force_read(0x0A, 1,(uint8_t *)read_data);
+ //printk("lcd_ili9806e mipi read power mode 0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+
+ if((0x9c == read_data[0]) && (0 == read_rtn)){
+ pr_debug("lcd_ili9806e_mipi read power mode success!\n");
+ mipi_eotp_set(1,1);
+ return 0x9c;
+ }
+ }
+
+ mipi_eotp_set(1,1);
+ return 0x0;
+}
+
+
+static uint32_t ili9806e_check_esd(struct panel_spec *self)
+{
+ uint32_t power_mode;
+
+ pr_debug("ili9806e_check_esd!\n");
+ mipi_set_lp_mode_t mipi_set_data_lp_mode = self->info.mipi->ops->mipi_set_data_lp_mode;
+ mipi_set_hs_mode_t mipi_set_data_hs_mode = self->info.mipi->ops->mipi_set_data_hs_mode;
+
+ mipi_set_lp_mode_t mipi_set_lp_mode = self->info.mipi->ops->mipi_set_lp_mode;
+ mipi_set_hs_mode_t mipi_set_hs_mode = self->info.mipi->ops->mipi_set_hs_mode;
+ uint16_t work_mode = self->info.mipi->work_mode;
+
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_lp_mode();
+ }else{
+ mipi_set_data_lp_mode();
+ }
+ power_mode = ili9806e_readpowermode(self);
+ //power_mode = 0x0;
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_hs_mode();
+ }else{
+ mipi_set_data_hs_mode();
+ }
+ if(power_mode == 0x9c){
+ pr_debug("ili9806e_check_esd OK!\n");
+ return 1;
+ }else{
+ printk("ili9806e_check_esd fail!(0x%x)\n", power_mode);
+ return 0;
+ }
+}
+
+static uint32_t ili9806e_mipi_after_suspend(struct panel_spec *self)
+{
+ return 0;
+}
+
+static struct panel_operations lcd_ili9806e_mipi_operations = {
+ .panel_init = ili9806e_mipi_init,
+ .panel_readid = ili9806e_readid,
+ .panel_enter_sleep = ili9806e_enter_sleep,
+ .panel_esd_check = ili9806e_check_esd,
+ .panel_after_suspend = ili9806e_mipi_after_suspend,
+
+};
+
+static struct timing_rgb lcd_ili9806e_mipi_timing = {
+ .hfp = 60, /* unit: pixel */// 100
+ .hbp = 80,//80
+ .hsync = 60,//6
+ .vfp = 20, /*unit: line*/
+ .vbp = 14,
+ .vsync =6, //6,
+};
+
+static struct info_mipi lcd_ili9806e_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq = 500*1000, //500->10MHz,400->8M in lp mode
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_ili9806e_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_ili9806e_mipi_spec = {
+ //.cap = PANEL_CAP_NOT_TEAR_SYNC,
+ .width = 480,
+ .height = 800,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .is_clean_lcd = true,
+ .reset_timing = {5, 15, 120},
+ .info = {
+ .mipi = &lcd_ili9806e_mipi_info
+ },
+ .ops = &lcd_ili9806e_mipi_operations,
+};
+
+struct panel_cfg lcd_ili9806e_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x04,
+ .lcd_name = "lcd_ili9806e_mipi",
+ .panel = &lcd_ili9806e_mipi_spec,
+};
+
+static int __init lcd_ili9806e_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_ili9806e_mipi);
+}
+
+subsys_initcall(lcd_ili9806e_mipi_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_jd9161_mipi.c b/drivers/video/sprdfb/lcd/lcd_jd9161_mipi.c
new file mode 100644
index 00000000..ae6311cf
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_jd9161_mipi.c
@@ -0,0 +1,380 @@
+/* drivers/video/sc8825/lcd_jd9161_mipi.c
+ *
+ * Support for jd9161 mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 48
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+ {LCM_SEND(6), {4,0,0xBF,0x91,0x61,0xF2}},
+ {LCM_SLEEP(1)},
+ {LCM_SEND(5), {3,0,0xB3,0x00,0x7F}},//VCOM
+ {LCM_SLEEP(1)},
+ {LCM_SEND(5), {3,0,0xB4,0x00,0x7F}},//VCOM_R
+ {LCM_SLEEP(1)},
+ {LCM_SEND(9), {7,0,0xB8,0x00,0xB6,0x01,0x00,0xB6,0x01}},//VGMP, VGSP, VGMN
+ {LCM_SLEEP(1)},
+ {LCM_SEND(6), {4,0,0xBA,0x34,0x23,0x00}},//GIP output volta
+ {LCM_SLEEP(1)},
+ {LCM_SEND(2), {0xC3,0x02}},//column
+ {LCM_SLEEP(1)},
+ {LCM_SEND(5), {3,0,0xC4,0x00,0x64}},//TCON
+ {LCM_SLEEP(1)},
+ {LCM_SEND(12), {10,0,0xC7,0x00,0x01,0x32,0x05,0x65,0x2C,0x13,0xA5,0xA5}},//POWER CTRL
+ {LCM_SLEEP(1)},
+ //Gamma
+ {LCM_SEND(41), {39,0,0xC8,0x74,0x70,0x2C,0x3A,0x1C,0x11,0x17,0x06,0x24,0x29,
+ 0x2F,0x55,0x4B,0x5D,0x58,0x61,0x5D,0x57,0x50,
+ 0x74,0x70,0x2C,0x3A,0x1C,0x11,0x17,0x06,0x24,0x29,
+ 0x2F,0x55,0x4B,0x5D,0x58,0x61,0x5D,0x57,0x50}},
+ {LCM_SLEEP(1)},
+ {LCM_SEND(19), {17,0,0xD4,0x1F,0x1E,0x1F,0x00,0x10,0x1F,0x1F,0x04,0x08,0x06,
+ 0x0A,0x1F,0x1F,0x1F,0x1F,0x1F}}, //SET GIP_L
+ {LCM_SLEEP(1)},
+ {LCM_SEND(19), {17,0,0xD5,0x1F,0x1E,0x1F,0x01,0x11,0x1F,0x1F,0x05,0x09,0x07,
+ 0x0B,0x1F,0x1F,0x1F,0x1F,0x1F}}, //SET GIP_R
+ {LCM_SLEEP(1)},
+ {LCM_SEND(19), {17,0,0xD6,0x1F,0x1F,0x1E,0x11,0x01,0x1F,0x1F,0x0B,0x07,0x09,
+ 0x05,0x1F,0x1F,0x1F,0x1F,0x1F}}, //SET GIP_GS_L
+ {LCM_SLEEP(1)},
+ {LCM_SEND(19), {17,0,0xD7,0x1F,0x1F,0x1E,0x10,0x00,0x1F,0x1F,0x0A,0x06,0x08,
+ 0x04,0x1F,0x1F,0x1F,0x1F,0x1F}}, //SET GIP_GS_R
+ {LCM_SLEEP(1)},
+ {LCM_SEND(23), {21,0,0xD8,0x20,0x02,0x0A,0x10,0x05,0x30,0x01,0x02,0x30,0x01,0x02,0x06,0x70,
+ 0x53,0x2C,0x73,0x09,0x06,0x70,0x08}}, //SET GIP1
+ {LCM_SLEEP(1)},
+ {LCM_SEND(22), {20,0,0xD9,0x00,0x0A,0x0A,0x88,0x00,0x00,0x06,0x7B,0x00,0x00,
+ 0x00,0x3B,0x2F,0x1F,0x00,0x00,0x00,0x03,0x7B}}, //SET GIP2
+ {LCM_SLEEP(1)},
+ {LCM_SEND(1), {0x11}},//SLP OUT
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1), {0x29}},//DISP ON
+ {LCM_SLEEP(50)},
+
+ };
+
+static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x00}},
+ {LCM_SLEEP(1)},
+
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(10)},
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x01}},
+ {LCM_SLEEP(1)},
+
+ {LCM_SEND(2), {0x58,0x91}},
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)},
+};
+
+static LCM_Force_Cmd_Code rd_prep_code[]={
+ {0x39, {LCM_SEND(6), {4,0,0xBF,0x91,0x61,0xF2}}},
+ {0x37, {LCM_SEND(2), {0x3, 0}}},
+};
+
+static LCM_Force_Cmd_Code rd_prep_code_1[]={
+ {0x37, {LCM_SEND(2), {0x1, 0}}},
+};
+static int32_t jd9161_mipi_init(struct panel_spec *self)
+{
+ int32_t i;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk( "kernel jd9161_mipi_init\n");
+
+ msleep(2);
+ mipi_set_cmd_mode();
+ mipi_eotp_set(1,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ //udelay((init->tag & LCM_TAG_MASK) * 1000);
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(1,1);
+
+ return 0;
+}
+
+static uint32_t jd9161_readid(struct panel_spec *self)
+{
+ /*Jessica TODO: need read id*/
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code;
+ uint8_t read_data[3] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel lcd_jd9161_mipi read id!\n");
+#if 1
+ mipi_set_cmd_mode();
+ mipi_eotp_set(1,0);
+
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }
+ rd_prepare++;
+ }
+ read_rtn = mipi_force_read(0x04, 3,(uint8_t *)read_data);
+ printk("lcd_jd9161_mipi read id 0x04 value is 0x%x, 0x%x, 0x%x!\n", read_data[0], read_data[1], read_data[2]);
+
+ if((0x91 == read_data[0])){
+ printk("lcd_jd9161_mipi read id success!\n");
+ mipi_eotp_set(1,1);
+ return 0x916100;
+ }
+ }
+ mipi_eotp_set(1,1);
+ #endif
+ return 0x916100;
+}
+
+static int32_t jd9161_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("jd9161_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+ mipi_eotp_set(1,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ //udelay((sleep_in_out->tag & LCM_TAG_MASK) * 1000);
+ msleep((sleep_in_out->tag & LCM_TAG_MASK));
+ }
+ sleep_in_out++;
+ }
+ return 0;
+}
+
+static uint32_t jd9161_readpowermode(struct panel_spec *self)
+{
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code_1;
+ uint8_t read_data[1] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+ uint32_t reg_val_1 = 0;
+ uint32_t reg_val_2 = 0;
+
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_debug("lcd_jd9161_mipi read power mode!\n");
+ mipi_eotp_set(0,1);
+
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code_1;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code_1); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }
+ rd_prepare++;
+ }
+
+ read_rtn = mipi_force_read(0x0A, 1,(uint8_t *)read_data);
+ //printk("lcd_jd9161 mipi read power mode 0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+
+ if((0x9c == read_data[0]) && (0 == read_rtn)){
+ pr_debug("lcd_jd9161_mipi read power mode success!\n");
+ mipi_eotp_set(1,1);
+ return 0x9c;
+ }
+ }
+
+ mipi_eotp_set(1,1);
+ return 0x0;
+}
+
+
+static uint32_t jd9161_check_esd(struct panel_spec *self)
+{
+ uint32_t power_mode;
+
+ pr_debug("jd9161_check_esd!\n");
+ mipi_set_lp_mode_t mipi_set_data_lp_mode = self->info.mipi->ops->mipi_set_data_lp_mode;
+ mipi_set_hs_mode_t mipi_set_data_hs_mode = self->info.mipi->ops->mipi_set_data_hs_mode;
+
+ mipi_set_lp_mode_t mipi_set_lp_mode = self->info.mipi->ops->mipi_set_lp_mode;
+ mipi_set_hs_mode_t mipi_set_hs_mode = self->info.mipi->ops->mipi_set_hs_mode;
+ uint16_t work_mode = self->info.mipi->work_mode;
+
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_lp_mode();
+ }else{
+ mipi_set_data_lp_mode();
+ }
+ power_mode = jd9161_readpowermode(self);
+ //power_mode = 0x0;
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_hs_mode();
+ }else{
+ mipi_set_data_hs_mode();
+ }
+ if(power_mode == 0x9c){
+ pr_debug("jd9161_check_esd OK!\n");
+ return 1;
+ }else{
+ printk("jd9161_check_esd fail!(0x%x)\n", power_mode);
+ return 0;
+ }
+}
+
+
+static struct panel_operations lcd_jd9161_mipi_operations = {
+ .panel_init = jd9161_mipi_init,
+ .panel_readid = jd9161_readid,
+ .panel_enter_sleep = jd9161_enter_sleep,
+ .panel_esd_check = jd9161_check_esd,
+};
+
+static struct timing_rgb lcd_jd9161_mipi_timing = {
+ .hfp = 20, /* unit: pixel */// 100
+ .hbp = 20,//80
+ .hsync = 20,//6
+ .vfp = 6, /*unit: line*/
+ .vbp = 6,
+ .vsync =6, //6,
+};
+
+static struct info_mipi lcd_jd9161_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq = 450*1000, //500->10MHz,400->8M in lp mode
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_jd9161_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_jd9161_mipi_spec = {
+ //.cap = PANEL_CAP_NOT_TEAR_SYNC,
+ .width = 480,
+ .height = 800,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .is_clean_lcd = true,
+ .reset_timing = {5, 15, 120},
+ .info = {
+ .mipi = &lcd_jd9161_mipi_info
+ },
+ .ops = &lcd_jd9161_mipi_operations,
+};
+
+struct panel_cfg lcd_jd9161_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x916100,
+ .lcd_name = "lcd_jd9161_mipi",
+ .panel = &lcd_jd9161_mipi_spec,
+};
+
+static int __init lcd_jd9161_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_jd9161_mipi);
+}
+
+subsys_initcall(lcd_jd9161_mipi_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_nt35502_mipi.c b/drivers/video/sprdfb/lcd/lcd_nt35502_mipi.c
new file mode 100755
index 00000000..cccb146f
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_nt35502_mipi.c
@@ -0,0 +1,300 @@
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+#include <mach/gpio.h>
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 100
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+ //Power setting Sequence
+ {LCM_SEND(8),{6,0,0xF0,0x55,0xAA,0x52,0x08,0x01}},
+ {LCM_SEND(4),{2,0,0xB0,0x08}},
+ {LCM_SEND(4),{2,0,0xB2,0x40}},
+ {LCM_SEND(4),{2,0,0xB3,0x28}},
+ {LCM_SEND(4),{2,0,0xB4,0x19}},
+ {LCM_SEND(4),{2,0,0xB5,0x54}},
+ {LCM_SEND(4),{2,0,0xB9,0x36}},
+ {LCM_SEND(4),{2,0,0xBA,0x024}},
+ {LCM_SEND(5),{3,0,0xBC,0xA0,0x00}},
+ {LCM_SEND(5),{3,0,0xBD,0xA0,0x00}},
+
+
+ //gamma setting
+ {LCM_SEND(19),{17,0,0xD1,0x00,0x3D,0x00,0x67,0x00,0x97,0x00,0xBE,0x00,0xE4,0x01,0x1B,0x01,0x45,0x01,0x80}},
+ {LCM_SEND(19),{17,0,0xD2,0x01,0xA8,0x01,0xDF,0x02,0x06,0x02,0x3C,0x02,0x65,0x02,0x66,0x02,0x89,0x02,0xAC}},
+ {LCM_SEND(19),{17,0,0xD3,0x02,0xC0,0x02,0xD8,0x02,0xE6,0x02,0xF8,0x03,0x04,0x03,0x14,0x03,0x1E,0x03,0x2B}},
+ {LCM_SEND(7),{5,0,0xD4,0x03,0x5A,0x03,0x9A}},
+ {LCM_SEND(19),{17,0,0xD5,0x00,0x3D,0x00,0x67,0x00,0x97,0x00,0xBE,0x00,0xE4,0x01,0x1B,0x01,0x45,0x01,0x80}},
+ {LCM_SEND(19),{17,0,0xD6,0x01,0xA8,0x01,0xDF,0x02,0x06,0x02,0x3C,0x02,0x65,0x02,0x66,0x02,0x89,0x02,0xAC}},
+ {LCM_SEND(19),{17,0,0xD7,0x02,0xC0,0x02,0xD8,0x02,0xE6,0x02,0xF8,0x03,0x04,0x03,0x14,0x03,0x1E,0x03,0x2B}},
+ {LCM_SEND(7),{5,0,0xD8,0x03,0x5A,0x03,0x9A}},
+ {LCM_SEND(19),{17,0,0xD9,0x00,0x3D,0x00,0x67,0x00,0x97,0x00,0xBE,0x00,0xE4,0x01,0x1B,0x01,0x45,0x01,0x80}},
+ {LCM_SEND(19),{17,0,0xDD,0x01,0xA8,0x01,0xDF,0x02,0x06,0x02,0x3C,0x02,0x65,0x02,0x66,0x02,0x89,0x02,0xAC}},
+ {LCM_SEND(19),{17,0,0xDE,0x02,0xC0,0x02,0xD8,0x02,0xE6,0x02,0xF8,0x03,0x04,0x03,0x14,0x03,0x1E,0x03,0x2B}},
+ {LCM_SEND(7),{5,0,0xDF,0x03,0x5A,0x03,0x9A}},
+ {LCM_SEND(19),{17,0,0xE0,0x00,0x3D,0x00,0x67,0x00,0x97,0x00,0xBE,0x00,0xE4,0x01,0x1B,0x01,0x45,0x01,0x80}},
+ {LCM_SEND(19),{17,0,0xE1,0x01,0xA8,0x01,0xDF,0x02,0x06,0x02,0x3C,0x02,0x65,0x02,0x66,0x02,0x89,0x02,0xAC}},
+ {LCM_SEND(19),{17,0,0xE2,0x02,0xC0,0x02,0xD8,0x02,0xE6,0x02,0xF8,0x03,0x04,0x03,0x14,0x03,0x1E,0x03,0x2B}},
+ {LCM_SEND(7),{5,0,0xE3,0x03,0x5A,0x03,0x9A}},
+ {LCM_SEND(19),{17,0,0xE4,0x00,0x3D,0x00,0x67,0x00,0x97,0x00,0xBE,0x00,0xE4,0x01,0x1B,0x01,0x45,0x01,0x80}},
+ {LCM_SEND(19),{17,0,0xE5,0x01,0xA8,0x01,0xDF,0x02,0x06,0x02,0x3C,0x02,0x65,0x02,0x66,0x02,0x89,0x02,0xAC}},
+ {LCM_SEND(19),{17,0,0xE6,0x02,0xC0,0x02,0xD8,0x02,0xE6,0x02,0xF8,0x03,0x04,0x03,0x14,0x03,0x1E,0x03,0x2B}},
+ {LCM_SEND(7),{5,0,0xE7,0x03,0x5A,0x03,0x9A}},
+ {LCM_SEND(19),{17,0,0xE8,0x00,0x3D,0x00,0x67,0x00,0x97,0x00,0xBE,0x00,0xE4,0x01,0x1B,0x01,0x45,0x01,0x80}},
+ {LCM_SEND(19),{17,0,0xE9,0x01,0xA8,0x01,0xDF,0x02,0x06,0x02,0x3C,0x02,0x65,0x02,0x66,0x02,0x89,0x02,0xAC}},
+ {LCM_SEND(19),{17,0,0xEA,0x02,0xC0,0x02,0xD8,0x02,0xE6,0x02,0xF8,0x03,0x04,0x03,0x14,0x03,0x1E,0x03,0x2B}},
+ {LCM_SEND(7),{5,0,0xEB,0x03,0x5A,0x03,0x9A}},
+
+ //initializing sequence
+
+ {LCM_SEND(8),{6,0,0xF0,0x55,0xAA,0x52,0x08,0x00}},
+ {LCM_SEND(5),{3,0,0xB1,0x16,0x08}},
+ {LCM_SEND(5),{3,0,0xB4,0x08,0x50}},
+ {LCM_SEND(4),{2,0,0xB6,0x03}},
+ {LCM_SEND(5),{3,0,0xB7,0x70,0x70}},
+ {LCM_SEND(5),{3,0,0xB8,0x61,0x66}},
+ {LCM_SEND(4),{2,0,0xBC,0x02}},
+
+ {LCM_SEND(21),{19,0,0xC8,0x80,0x00,0x46,0x64,0x46,0x64,0x46,0x64,0x46,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64}},
+ {LCM_SEND(8),{6,0,0xF0,0x55,0xAA,0x52,0x00,0x00}},
+ {LCM_SEND(7),{5,0,0xFF,0xAA,0x55,0x25,0x01}},
+ {LCM_SEND(4),{2,0,0x6F,0x02}},
+ {LCM_SEND(4),{2,0,0xF4,0x57}},
+ {LCM_SEND(6),{4,0,0xAA,0x55,0x25,0x00}},
+ {LCM_SEND(4),{2,0,0x36,0x00}},
+ {LCM_SEND(4),{2,0,0x35,0x00}},
+ {LCM_SEND(4),{2,0,0x0B,0xD8}},
+
+ //Display on
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(100)},
+
+};
+
+static LCM_Init_Code disp_on[] = {
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(100)},
+
+};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(150)}, //>150ms
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(150)}, //>150ms
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},//>120ms
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)}, //>20ms
+};
+static int32_t nt35502_mipi_init(struct panel_spec *self)
+{
+ int32_t i;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel nt35502_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t nt35502_readid(struct panel_spec *self)
+{
+ int32_t j =0;
+ uint8_t read_data[4] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("kernel lcd_nt35502_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x01;
+ param[1] = 0x00;
+ mipi_force_write(0x04, param, 2);
+ read_rtn = mipi_force_read(0xda,1,&read_data[0]);
+ LCD_PRINT("lcd_nt35502_mipi read id 0xda value is 0x%x!\n",read_data[0]);
+ read_rtn = mipi_force_read(0xdb,1,&read_data[1]);
+ LCD_PRINT("lcd_nt35502_mipi read id 0xdb value is 0x%x!\n",read_data[1]);
+ read_rtn = mipi_force_read(0xdc,1,&read_data[2]);
+ LCD_PRINT("lcd_nt35502_mipi read id 0xdc value is 0x%x!\n",read_data[2]);
+
+ // if((0x55 == read_data[0])&&(0xbc == read_data[1])&&(0x90 == read_data[2])){
+ printk("lcd_nt35502_mipi read id success!\n");
+ return 0x8370;
+ // }
+ }
+
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+
+static int32_t nt35502_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel nt35502_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(sleep_in_out->tag & LCM_TAG_MASK);
+ }
+ sleep_in_out++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static struct panel_operations lcd_nt35502_mipi_operations = {
+ .panel_init = nt35502_mipi_init,
+ .panel_readid = nt35502_readid,
+ .panel_enter_sleep = nt35502_enter_sleep,
+};
+
+static struct timing_rgb lcd_nt35502_mipi_timing = {
+ .hfp = 160, /* unit: pixel */
+ .hbp = 20,
+ .hsync = 20,
+ .vfp = 1, /*unit: line*/
+ .vbp = 11,
+ .vsync = 4,
+};
+
+
+static struct info_mipi lcd_nt35502_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq =500*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_nt35502_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_nt35502_mipi_spec = {
+ .width = 480,
+ .height = 800,
+ .fps = 62,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_nt35502_mipi_info
+ },
+ .ops = &lcd_nt35502_mipi_operations,
+};
+struct panel_cfg lcd_nt35502_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x8370,
+ .lcd_name = "lcd_nt35502_mipi",
+ .panel = &lcd_nt35502_mipi_spec,
+};
+
+//temp code
+static int __init lcd_nt35502_mipi_init(void)
+{
+/*
+ printk("nt35502_mipi_init: set lcd backlight.\n");
+
+ if (gpio_request(214, "LCD_BL")) {
+ printk("Failed ro request LCD_BL GPIO_%d \n",
+ 214);
+ return -ENODEV;
+ }
+ gpio_direction_output(214, 1);
+ gpio_set_value(214, 1);
+*/
+
+ return sprdfb_panel_register(&lcd_nt35502_mipi);
+}
+
+subsys_initcall(lcd_nt35502_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_nt35510_mipi.c b/drivers/video/sprdfb/lcd/lcd_nt35510_mipi.c
new file mode 100644
index 00000000..3ef26edb
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_nt35510_mipi.c
@@ -0,0 +1,291 @@
+/* drivers/video/sc8825/lcd_nt35516_mipi.c
+ *
+ * Support for nt35516 mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+//#define LCD_Delay(ms) uDelay(ms*1000)
+
+#define MAX_DATA 56
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+
+{LCM_SEND(8), {6, 0, 0xF0,0x55,0xAA,0x52,0x08,0x01}},
+
+{LCM_SEND(6), {4, 0, 0xB0,0x09,0x09,0x09}},
+{LCM_SEND(6), {4, 0, 0xB6,0x34,0x34,0x34}},
+{LCM_SEND(6), {4, 0, 0xB1,0x09,0x09,0x09}},
+{LCM_SEND(6), {4, 0, 0xB7,0x24,0x24,0x24}},
+{LCM_SEND(6), {4, 0, 0xB3,0x05,0x05,0x05}},
+{LCM_SEND(6), {4, 0, 0xB9,0x24,0x24,0x24}},
+
+{LCM_SEND(2), {0xBF,0x01}},
+
+{LCM_SEND(6), {4, 0, 0xB5,0x0B,0x0B,0x0B}},
+{LCM_SEND(6), {4, 0, 0xBA,0x24,0x24,0x24}},
+{LCM_SEND(6), {4, 0, 0xBC,0x00,0xA3,0x00}},
+{LCM_SEND(6), {4, 0, 0xBD,0x00,0xA3,0x00}},
+
+{LCM_SEND(5), {3, 0, 0xBE,0x00,0x58}},
+
+{LCM_SEND(55), {53, 0, 0xD1,0x00,0x01,0x00,0x43,0x00,0x6B,0x00,0x87,0x00,0xA3,
+0x00,0xCE,0x00,0xF1,0x01,0x27,0x01,0x53,0x01,0x98,0x01,0xCE,0x02,0x22,0x02,
+0x83,0x02,0x78,0x02,0x9E,0x02,0xDD,0x03,0x00,0x03,0x2E,0x03,0x54,0x03,0x7F,
+0x03,0x95,0x03,0xB3,0x03,0xC2,0x03,0xE1,0x03,0xF1,0x03,0xFE}},
+{LCM_SEND(55), {53, 0, 0xD2,0x00,0x01,0x00,0x43,0x00,0x6B,0x00,0x87,0x00,0xA3,
+0x00,0xCE,0x00,0xF1,0x01,0x27,0x01,0x53,0x01,0x98,0x01,0xCE,0x02,0x22,0x02,
+0x83,0x02,0x78,0x02,0x9E,0x02,0xDD,0x03,0x00,0x03,0x2E,0x03,0x54,0x03,0x7F,
+0x03,0x95,0x03,0xB3,0x03,0xC2,0x03,0xE1,0x03,0xF1,0x03,0xFE}},
+{LCM_SEND(55), {53, 0, 0xD3,0x00,0x01,0x00,0x43,0x00,0x6B,0x00,0x87,0x00,0xA3,
+0x00,0xCE,0x00,0xF1,0x01,0x27,0x01,0x53,0x01,0x98,0x01,0xCE,0x02,0x22,0x02,
+0x83,0x02,0x78,0x02,0x9E,0x02,0xDD,0x03,0x00,0x03,0x2E,0x03,0x54,0x03,0x7F,
+0x03,0x95,0x03,0xB3,0x03,0xC2,0x03,0xE1,0x03,0xF1,0x03,0xFE}},
+{LCM_SEND(55), {53, 0, 0xD4,0x00,0x01,0x00,0x43,0x00,0x6B,0x00,0x87,0x00,0xA3,
+0x00,0xCE,0x00,0xF1,0x01,0x27,0x01,0x53,0x01,0x98,0x01,0xCE,0x02,0x22,0x02,
+0x83,0x02,0x78,0x02,0x9E,0x02,0xDD,0x03,0x00,0x03,0x2E,0x03,0x54,0x03,0x7F,
+0x03,0x95,0x03,0xB3,0x03,0xC2,0x03,0xE1,0x03,0xF1,0x03,0xFE}},
+{LCM_SEND(55), {53, 0, 0xD5,0x00,0x01,0x00,0x43,0x00,0x6B,0x00,0x87,0x00,0xA3,
+0x00,0xCE,0x00,0xF1,0x01,0x27,0x01,0x53,0x01,0x98,0x01,0xCE,0x02,0x22,0x02,
+0x83,0x02,0x78,0x02,0x9E,0x02,0xDD,0x03,0x00,0x03,0x2E,0x03,0x54,0x03,0x7F,
+0x03,0x95,0x03,0xB3,0x03,0xC2,0x03,0xE1,0x03,0xF1,0x03,0xFE}},
+{LCM_SEND(55), {53, 0, 0xD6,0x00,0x01,0x00,0x43,0x00,0x6B,0x00,0x87,0x00,0xA3,
+0x00,0xCE,0x00,0xF1,0x01,0x27,0x01,0x53,0x01,0x98,0x01,0xCE,0x02,0x22,0x02,
+0x83,0x02,0x78,0x02,0x9E,0x02,0xDD,0x03,0x00,0x03,0x2E,0x03,0x54,0x03,0x7F,
+0x03,0x95,0x03,0xB3,0x03,0xC2,0x03,0xE1,0x03,0xF1,0x03,0xFE}},
+
+{LCM_SEND(8), {6, 0, 0xF0,0x55,0xAA,0x52,0x08,0x00}},
+
+{LCM_SEND(5), {3, 0, 0xB1,0xFC,0x04}},
+{LCM_SEND(2), {0x36,0x02}},
+{LCM_SEND(2), {0xB6,0x0A}},
+{LCM_SEND(5), {3, 0, 0xB7,0x00,0x00}},
+{LCM_SEND(7), {5, 0, 0xB8,0x01,0x05,0x05,0x05}},
+{LCM_SEND(2), {0xBA,0x01}},
+{LCM_SEND(6), {4, 0, 0xBC,0x00,0x00,0x00}},
+{LCM_SEND(8), {6, 0, 0xBD,0x01,0x84,0x07,0x32,0x00}},
+{LCM_SEND(8), {6, 0, 0xBE,0x01,0x84,0x07,0x31,0x00}},
+{LCM_SEND(8), {6, 0, 0xBF,0x01,0x84,0x07,0x31,0x00}},
+{LCM_SEND(2), {0x35,0x00}},// Tearing Effect On
+{LCM_SEND(6), {4, 0, 0xCC,0x03,0x00,0x00}},
+{LCM_SEND(2), {0x3A, 0x77}},
+
+{LCM_SEND(1), {0x11}}, // sleep out
+{LCM_SLEEP(120),},
+{LCM_SEND(1), {0x29}}, // display on
+{LCM_SLEEP(100),},
+{LCM_SEND(1), {0x2c}}, // normal on
+
+
+};
+
+//static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+{LCM_SEND(1), {0x28}},
+{LCM_SLEEP(10)},
+{LCM_SEND(1), {0x10}},
+{LCM_SLEEP(120)},
+{LCM_SEND(2), {0x4f, 0x01}},
+};
+
+static LCM_Init_Code sleep_out[] = {
+{LCM_SEND(1), {0x11}},
+{LCM_SLEEP(120)},
+{LCM_SEND(1), {0x29}},
+{LCM_SLEEP(20)},
+};
+
+static LCM_Init_Code change_fps_40[] = {
+{LCM_SEND(8), {6, 0, 0xF0,0x55,0xAA,0x52,0x08,0x00}},
+{LCM_SEND(8), {6, 0, 0xBD,0x02,0x46,0x1C,0x1C,0x00}},
+{LCM_SEND(8), {6, 0, 0xF0,0x55,0xAA,0x52,0x00,0x00}},
+};
+
+static LCM_Init_Code change_fps_60[] = {
+{LCM_SEND(8), {6, 0, 0xF0,0x55,0xAA,0x52,0x08,0x00}},
+{LCM_SEND(8), {6, 0, 0xBD,0x01,0x84,0x1C,0x1C,0x00}},
+{LCM_SEND(8), {6, 0, 0xF0,0x55,0xAA,0x52,0x00,0x00}},
+};
+
+static int32_t nt35510_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+
+ pr_debug(KERN_DEBUG "nt35510_mipi_init\n");
+
+ mipi_set_cmd_mode();
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((init->tag & LCM_TAG_MASK));
+ }
+ init++;
+ }
+ return 0;
+}
+
+static uint32_t nt35510_readid(struct panel_spec *self)
+{
+ /*Jessica TODO: need read id*/
+ return 0x10;
+}
+
+static int32_t nt35510_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i = 0;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+
+ printk(KERN_DEBUG "nt35516_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((sleep_in_out->tag & LCM_TAG_MASK));
+ }
+ sleep_in_out++;
+ }
+ return 0;
+}
+
+static int32_t nt35510_change_fps(struct panel_spec *self, int fps_level)
+{
+ int32_t i = 0;
+ LCM_Init_Code *change_fps = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+
+ printk(KERN_DEBUG "nt35510_change_fps, fps_level = %d\n", fps_level);
+
+ if(fps_level < 50){
+ change_fps = change_fps_40;
+ size = ARRAY_SIZE(change_fps_40);
+ }else{
+ change_fps = change_fps_60;
+ size = ARRAY_SIZE(change_fps_60);
+ }
+
+ for(i = 0; i <size ; i++){
+ tag = (change_fps->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(change_fps->data, (change_fps->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((change_fps->tag & LCM_TAG_MASK));
+ }
+ change_fps++;
+ }
+ return 0;
+
+}
+
+static struct panel_operations lcd_nt35510_mipi_operations = {
+ .panel_init = nt35510_mipi_init,
+ .panel_readid = nt35510_readid,
+ .panel_enter_sleep = nt35510_enter_sleep,
+ .panel_change_fps= nt35510_change_fps,
+};
+
+static struct timing_rgb lcd_nt35510_mipi_timing = {
+ .hfp = 20, /* unit: pixel */
+ .hbp = 20,
+ .hsync = 4,
+ .vfp = 10, /*unit: line*/
+ .vbp = 10,
+ .vsync = 6,
+};
+
+static struct info_mipi lcd_nt35510_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_CMD,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq = 500*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_nt35510_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_nt35510_mipi_spec = {
+ .width = 480,
+ .height = 800,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_nt35510_mipi_info
+ },
+ .ops = &lcd_nt35510_mipi_operations,
+};
+
+
+struct panel_cfg lcd_nt35510_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x10,
+ .lcd_name = "lcd_nt35510_mipi",
+ .panel = &lcd_nt35510_mipi_spec,
+};
+
+static int __init lcd_nt35510_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_nt35510_mipi);
+}
+
+subsys_initcall(lcd_nt35510_mipi_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_nt35512_mipi.c b/drivers/video/sprdfb/lcd/lcd_nt35512_mipi.c
new file mode 100644
index 00000000..f17864e8
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_nt35512_mipi.c
@@ -0,0 +1,183 @@
+/* drivers/video/sc8825/lcd_nt35516_mipi.c
+ *
+ * Support for nt35516 mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+//#define LCD_Delay(ms) uDelay(ms*1000)
+
+#define MAX_DATA 56
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+
+{LCM_SEND(8), {6, 0, 0xF0,0x55,0xAA,0x52,0x08,0x01}},
+
+{LCM_SEND(6), {4, 0, 0xB0,0x09,0x09,0x09}},
+{LCM_SEND(6), {4, 0, 0xB6,0x34,0x34,0x34}},
+{LCM_SEND(6), {4, 0, 0xB1,0x09,0x09,0x09}},
+{LCM_SEND(6), {4, 0, 0xB7,0x24,0x24,0x24}},
+{LCM_SEND(6), {4, 0, 0xB3,0x05,0x05,0x05}},
+{LCM_SEND(6), {4, 0, 0xB9,0x24,0x24,0x24}},
+
+{LCM_SEND(2), {0xBF,0x01}},
+
+{LCM_SEND(6), {4, 0, 0xB5,0x03,0x03,0x03}},
+{LCM_SEND(6), {4, 0, 0xBA,0x24,0x24,0x24}},
+{LCM_SEND(2), {0xC2,0x01}},
+{LCM_SEND(6), {4, 0, 0xBC,0x00,0x90,0x00}},
+{LCM_SEND(6), {4, 0, 0xBD,0x00,0x90,0x00}},
+
+{LCM_SEND(5), {3, 0, 0xBE,0x00,0x57}},
+
+{LCM_SEND(55), {53, 0, 0xD1,0x00,0x01,0x00,0x1D,0x00,0x48,0x00,0x64,0x00,0x7E,0x00,0xB1,0x00,0xD3,0x01,0x07,0x01,0x35,0x01,0x7B,0x01,0xB3,0x02,0x03,0x02,0x48,0x02,0x49,0x02,0x88,0x02,0xC7,0x02,0xF3,0x03,0x21,0x03,0x46,0x03,0x74,0x03,0x8F,0x03,0xA3,0x03,0xAC,0x03,0xB7,0x03,0xBF,0x03,0xFE}},
+{LCM_SEND(55), {53, 0, 0xD2,0x00,0x01,0x00,0x1D,0x00,0x48,0x00,0x64,0x00,0x7E,0x00,0xB1,0x00,0xD3,0x01,0x07,0x01,0x35,0x01,0x7B,0x01,0xB3,0x02,0x03,0x02,0x48,0x02,0x49,0x02,0x88,0x02,0xC7,0x02,0xF3,0x03,0x21,0x03,0x46,0x03,0x74,0x03,0x8F,0x03,0xA3,0x03,0xAC,0x03,0xB7,0x03,0xBF,0x03,0xFE}},
+{LCM_SEND(55), {53, 0, 0xD3,0x00,0x01,0x00,0x1D,0x00,0x48,0x00,0x64,0x00,0x7E,0x00,0xB1,0x00,0xD3,0x01,0x07,0x01,0x35,0x01,0x7B,0x01,0xB3,0x02,0x03,0x02,0x48,0x02,0x49,0x02,0x88,0x02,0xC7,0x02,0xF3,0x03,0x21,0x03,0x46,0x03,0x74,0x03,0x8F,0x03,0xA3,0x03,0xAC,0x03,0xB7,0x03,0xBF,0x03,0xFE}},
+{LCM_SEND(55), {53, 0, 0xD4,0x00,0x01,0x00,0x1D,0x00,0x48,0x00,0x64,0x00,0x7E,0x00,0xB1,0x00,0xD3,0x01,0x07,0x01,0x35,0x01,0x7B,0x01,0xB3,0x02,0x03,0x02,0x48,0x02,0x49,0x02,0x88,0x02,0xC7,0x02,0xF3,0x03,0x21,0x03,0x46,0x03,0x74,0x03,0x8F,0x03,0xA3,0x03,0xAC,0x03,0xB7,0x03,0xBF,0x03,0xFE}},
+{LCM_SEND(55), {53, 0, 0xD5,0x00,0x01,0x00,0x1D,0x00,0x48,0x00,0x64,0x00,0x7E,0x00,0xB1,0x00,0xD3,0x01,0x07,0x01,0x35,0x01,0x7B,0x01,0xB3,0x02,0x03,0x02,0x48,0x02,0x49,0x02,0x88,0x02,0xC7,0x02,0xF3,0x03,0x21,0x03,0x46,0x03,0x74,0x03,0x8F,0x03,0xA3,0x03,0xAC,0x03,0xB7,0x03,0xBF,0x03,0xFE}},
+{LCM_SEND(55), {53, 0, 0xD6,0x00,0x01,0x00,0x1D,0x00,0x48,0x00,0x64,0x00,0x7E,0x00,0xB1,0x00,0xD3,0x01,0x07,0x01,0x35,0x01,0x7B,0x01,0xB3,0x02,0x03,0x02,0x48,0x02,0x49,0x02,0x88,0x02,0xC7,0x02,0xF3,0x03,0x21,0x03,0x46,0x03,0x74,0x03,0x8F,0x03,0xA3,0x03,0xAC,0x03,0xB7,0x03,0xBF,0x03,0xFE}},
+
+{LCM_SEND(8), {6, 0, 0xF0,0x55,0xAA,0x52,0x08,0x00}},
+
+{LCM_SEND(2), {0xB6,0x0A}},
+{LCM_SEND(5), {3, 0, 0xB7,0x00,0x00}},
+{LCM_SEND(7), {5, 0, 0xB8,0x01,0x05,0x05,0x05}},
+{LCM_SEND(2), {0xBA,0x01}},
+{LCM_SEND(6), {4, 0, 0xBC,0x00,0x00,0x00}},
+//{LCM_SEND(8), {6, 0, 0xBD,0x01,0x4D,0x07,0x31,0x00}},
+//{LCM_SEND(8), {6, 0, 0xBE,0x01,0x84,0x07,0x31,0x00}},
+//{LCM_SEND(8), {6, 0, 0xBF,0x01,0x84,0x07,0x31,0x00}},
+{LCM_SEND(6), {4, 0, 0xCC,0x03,0x00,0x00}},
+{LCM_SEND(5), {3, 0, 0xB1,0xFC,0x00}},
+{LCM_SEND(2), {0x35,0x00}}, // Tearing Effect On
+{LCM_SEND(2), {0x36,0xC2}},
+{LCM_SEND(2), {0x3A, 0x77}},
+
+
+
+{LCM_SEND(1), {0x11}}, // sleep out
+{LCM_SLEEP(120),},
+{LCM_SEND(1), {0x29}}, // display on
+{LCM_SLEEP(100),},
+{LCM_SEND(1), {0x2c}}, // normal on
+};
+
+//static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in = {LCM_SEND(1), {0x10}};
+
+static LCM_Init_Code sleep_out = {LCM_SEND(1), {0x11}};
+
+static int32_t nt35512_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+
+ pr_debug(KERN_DEBUG "nt35512_init\n");
+
+ mipi_set_cmd_mode();
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((init->tag & LCM_TAG_MASK));
+ }
+ init++;
+ }
+ return 0;
+}
+
+static uint32_t nt35512_readid(struct panel_spec *self)
+{
+ /*Jessica TODO: need read id*/
+ return 0x12;
+}
+
+static struct panel_operations lcd_nt35512_mipi_operations = {
+ .panel_init = nt35516_mipi_init,
+ .panel_readid = nt35516_readid,
+};
+
+static struct timing_rgb lcd_nt35512_mipi_timing = {
+ .hfp = 200, /* unit: pixel */
+ .hbp = 200,
+ .hsync = 8,
+ .vfp = 10, /*unit: line*/
+ .vbp = 10,
+ .vsync = 6,
+};
+
+static struct info_mipi lcd_nt35512_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq = 500*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_nt35512_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_nt35512_mipi_spec = {
+ .width = 480,
+ .height = 800,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_nt35512_mipi_info
+ },
+ .ops = &lcd_nt35512_mipi_operations,
+};
+
+struct panel_cfg lcd_nt35512_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x12,
+ .lcd_name = "lcd_nt35516_mipi",
+ .panel = &lcd_nt35516_mipi_spec,
+};
+
+static int __init lcd_nt35512_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_nt35516_mipi);
+}
+
+subsys_initcall(lcd_nt35512_mipi_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_nt35516_mcu.c b/drivers/video/sprdfb/lcd/lcd_nt35516_mcu.c
new file mode 100644
index 00000000..af2df710
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_nt35516_mcu.c
@@ -0,0 +1,585 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+static int32_t nt35516_init(struct panel_spec *self)
+{
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ pr_debug("nt35516_init\n");
+
+ send_cmd(0xFF00); send_data(0x00AA); /*AA*/
+ send_cmd(0xFF01); send_data(0x0055);/*55*/
+ send_cmd(0xFF02); send_data(0x0025);/*08*/
+ send_cmd(0xFF03); send_data(0x0001);/*01*/
+
+ send_cmd(0xF300); send_data(0x0002);
+ send_cmd(0xF303); send_data(0x0015);
+
+ /*ENABPAGE 0*/
+ send_cmd(0xF000); send_data(0x0055); /*Manufacture Command Set Control*/
+ send_cmd(0xF001); send_data(0x00AA);
+ send_cmd(0xF002); send_data(0x0052);
+ send_cmd(0xF003); send_data(0x0008);
+ send_cmd(0xF004); send_data(0x0000);
+
+ send_cmd(0xB800); send_data(0x0001);
+ send_cmd(0xB801); send_data(0x0002);
+ send_cmd(0xB802); send_data(0x0002);
+ send_cmd(0xB803); send_data(0x0002);
+
+ send_cmd(0xBC00); send_data(0x0005); /*Zig-Zag Inversion*/
+ send_cmd(0xBC01); send_data(0x0005);
+ send_cmd(0xBC02); send_data(0x0005);
+
+ send_cmd(0xBD00);send_data(0x0001);
+ send_cmd(0xBD01);send_data(0x0063);//54fps
+ send_cmd(0xBD02);send_data(0x0010);
+ send_cmd(0xBD03);send_data(0x0038);
+ send_cmd(0xBD04);send_data(0x0001);
+
+
+ send_cmd(0x4C00); send_data(0x0011); /*DB4=1,Enable Vivid Color,DB4=0 Disable Vivid Color*/
+
+ /* ENA PAGE 1*/
+ send_cmd(0xF000); send_data(0x0055); /*Manufacture Command Set Control */
+ send_cmd(0xF001); send_data(0x00AA);
+ send_cmd(0xF002); send_data(0x0052);
+ send_cmd(0xF003); send_data(0x0008);
+ send_cmd(0xF004); send_data(0x0001);/*Page1*/
+
+ send_cmd(0xB000); send_data(0x0005); /*Setting AVDD Voltage 6V*/
+ send_cmd(0xB001); send_data(0x0005);
+ send_cmd(0xB002); send_data(0x0005);
+
+ send_cmd(0xB600); send_data(0x0044); /* Setting AVEE boosting time 2.5*vpnl */
+ send_cmd(0xB601); send_data(0x0044);
+ send_cmd(0xB602); send_data(0x0044);
+
+ send_cmd(0xB100); send_data(0x0005); /*Setting AVEE Voltage -6V*/
+ send_cmd(0xB101); send_data(0x0005);
+ send_cmd(0xB102); send_data(0x0005);
+
+ /*Sett AVEE boosting time -2.5NL*/
+ send_cmd(0xB700); send_data(0x0034);
+ send_cmd(0xB701); send_data(0x0034);
+ send_cmd(0xB702); send_data(0x0034);
+
+ /*Sett VGLX boosting time AVEVDD */
+ send_cmd(0xBA00); send_data(0x0014); /*0x24 --> 0x14*/
+ send_cmd(0xBA01); send_data(0x0014);
+ send_cmd(0xBA02); send_data(0x0014);
+
+ /*Gammoltage */
+ send_cmd(0xBC00); send_data(0x0000);
+ send_cmd(0xBC01); send_data(0x00A0);/*VGMP 0x88=4.7V 0x78=4.5V 0xA0=5.0V */
+ send_cmd(0xBC02); send_data(0x0000);/*VGSP*/
+
+ //Gammoltage */
+ send_cmd(0xBD00); send_data(0x0000);
+ send_cmd(0xBD01); send_data(0x00A0);/*VGMN 0x88=-4.7V 0x78=-4.5V 0xA0=-5.0V*/
+ send_cmd(0xBD02); send_data(0x0000);/*VGSN*/
+
+ send_cmd(0xBE00); send_data(0x0057); /* Setting VCOM Offset Voltage 0x4E\u017eÄΪ0x57 20111019 LIYAN*/
+
+ /*GAMMED Positive*/
+ send_cmd(0xD100); send_data(0x0000);
+ send_cmd(0xD101); send_data(0x0032);
+ send_cmd(0xD102); send_data(0x0000);
+ send_cmd(0xD103); send_data(0x0041);
+ send_cmd(0xD104); send_data(0x0000);
+ send_cmd(0xD105); send_data(0x0054);
+ send_cmd(0xD106); send_data(0x0000);
+ send_cmd(0xD107); send_data(0x0067);
+ send_cmd(0xD108); send_data(0x0000);
+ send_cmd(0xD109); send_data(0x007A);
+ send_cmd(0xD10A); send_data(0x0000);
+ send_cmd(0xD10B); send_data(0x0098);
+ send_cmd(0xD10C); send_data(0x0000);
+ send_cmd(0xD10D); send_data(0x00B0);
+ send_cmd(0xD10E); send_data(0x0000);
+ send_cmd(0xD10F); send_data(0x00DB);
+ send_cmd(0xD200); send_data(0x0001);
+ send_cmd(0xD201); send_data(0x0001);
+ send_cmd(0xD202); send_data(0x0001);
+ send_cmd(0xD203); send_data(0x003F);
+ send_cmd(0xD204); send_data(0x0001);
+ send_cmd(0xD205); send_data(0x0070);
+ send_cmd(0xD206); send_data(0x0001);
+ send_cmd(0xD207); send_data(0x00B4);
+ send_cmd(0xD208); send_data(0x0001);
+ send_cmd(0xD209); send_data(0x00EC);
+ send_cmd(0xD20A); send_data(0x0001);
+ send_cmd(0xD20B); send_data(0x00ED);
+ send_cmd(0xD20C); send_data(0x0002);
+ send_cmd(0xD20D); send_data(0x001E);
+ send_cmd(0xD20E); send_data(0x0002);
+ send_cmd(0xD20F); send_data(0x0051);
+ send_cmd(0xD300); send_data(0x0002);
+ send_cmd(0xD301); send_data(0x006C);
+ send_cmd(0xD302); send_data(0x0002);
+ send_cmd(0xD303); send_data(0x008D);
+ send_cmd(0xD304); send_data(0x0002);
+ send_cmd(0xD305); send_data(0x00A5);
+ send_cmd(0xD306); send_data(0x0002);
+ send_cmd(0xD307); send_data(0x00C9);
+ send_cmd(0xD308); send_data(0x0002);
+ send_cmd(0xD309); send_data(0x00EA);
+ send_cmd(0xD30A); send_data(0x0003);
+ send_cmd(0xD30B); send_data(0x0019);
+ send_cmd(0xD30C); send_data(0x0003);
+ send_cmd(0xD30D); send_data(0x0045);
+ send_cmd(0xD30E); send_data(0x0003);
+ send_cmd(0xD30F); send_data(0x007A);
+ send_cmd(0xD400); send_data(0x0003);
+ send_cmd(0xD401); send_data(0x00B0);
+ send_cmd(0xD402); send_data(0x0003);
+ send_cmd(0xD403); send_data(0x00F4);
+
+ /*Posie Gamma for GREEN*/
+ send_cmd(0xD500); send_data(0x0000);
+ send_cmd(0xD501); send_data(0x0037);
+ send_cmd(0xD502); send_data(0x0000);
+ send_cmd(0xD503); send_data(0x0041);
+ send_cmd(0xD504); send_data(0x0000);
+ send_cmd(0xD505); send_data(0x0054);
+ send_cmd(0xD506); send_data(0x0000);
+ send_cmd(0xD507); send_data(0x0067);
+ send_cmd(0xD508); send_data(0x0000);
+ send_cmd(0xD509); send_data(0x007A);
+ send_cmd(0xD50A); send_data(0x0000);
+ send_cmd(0xD50B); send_data(0x0098);
+ send_cmd(0xD50C); send_data(0x0000);
+ send_cmd(0xD50D); send_data(0x00B0);
+ send_cmd(0xD50E); send_data(0x0000);
+ send_cmd(0xD50F); send_data(0x00DB);
+ send_cmd(0xD600); send_data(0x0001);
+ send_cmd(0xD601); send_data(0x0001);
+ send_cmd(0xD602); send_data(0x0001);
+ send_cmd(0xD603); send_data(0x003F);
+ send_cmd(0xD604); send_data(0x0001);
+ send_cmd(0xD605); send_data(0x0070);
+ send_cmd(0xD606); send_data(0x0001);
+ send_cmd(0xD607); send_data(0x00B4);
+ send_cmd(0xD608); send_data(0x0001);
+ send_cmd(0xD609); send_data(0x00EC);
+ send_cmd(0xD60A); send_data(0x0001);
+ send_cmd(0xD60B); send_data(0x00ED);
+ send_cmd(0xD60C); send_data(0x0002);
+ send_cmd(0xD60D); send_data(0x001E);
+ send_cmd(0xD60E); send_data(0x0002);
+ send_cmd(0xD60F); send_data(0x0051);
+ send_cmd(0xD700); send_data(0x0002);
+ send_cmd(0xD701); send_data(0x006C);
+ send_cmd(0xD702); send_data(0x0002);
+ send_cmd(0xD703); send_data(0x008D);
+ send_cmd(0xD704); send_data(0x0002);
+ send_cmd(0xD705); send_data(0x00A5);
+ send_cmd(0xD706); send_data(0x0002);
+ send_cmd(0xD707); send_data(0x00C9);
+ send_cmd(0xD708); send_data(0x0002);
+ send_cmd(0xD709); send_data(0x00EA);
+ send_cmd(0xD70A); send_data(0x0003);
+ send_cmd(0xD70B); send_data(0x0019);
+ send_cmd(0xD70C); send_data(0x0003);
+ send_cmd(0xD70D); send_data(0x0045);
+ send_cmd(0xD70E); send_data(0x0003);
+ send_cmd(0xD70F); send_data(0x007A);
+ send_cmd(0xD800); send_data(0x0003);
+ send_cmd(0xD801); send_data(0x00A0);
+ send_cmd(0xD802); send_data(0x0003);
+ send_cmd(0xD803); send_data(0x00F4);
+
+ /*Posie Gamma for BLUE*/
+ send_cmd(0xD900); send_data(0x0000);
+ send_cmd(0xD901); send_data(0x0032);
+ send_cmd(0xD902); send_data(0x0000);
+ send_cmd(0xD903); send_data(0x0041);
+ send_cmd(0xD904); send_data(0x0000);
+ send_cmd(0xD905); send_data(0x0054);
+ send_cmd(0xD906); send_data(0x0000);
+ send_cmd(0xD907); send_data(0x0067);
+ send_cmd(0xD908); send_data(0x0000);
+ send_cmd(0xD909); send_data(0x007A);
+ send_cmd(0xD90A); send_data(0x0000);
+ send_cmd(0xD90B); send_data(0x0098);
+ send_cmd(0xD90C); send_data(0x0000);
+ send_cmd(0xD90D); send_data(0x00B0);
+ send_cmd(0xD90E); send_data(0x0000);
+ send_cmd(0xD90F); send_data(0x00DB);
+ send_cmd(0xDD00); send_data(0x0001);
+ send_cmd(0xDD01); send_data(0x0001);
+ send_cmd(0xDD02); send_data(0x0001);
+ send_cmd(0xDD03); send_data(0x003F);
+ send_cmd(0xDD04); send_data(0x0001);
+ send_cmd(0xDD05); send_data(0x0070);
+ send_cmd(0xDD06); send_data(0x0001);
+ send_cmd(0xDD07); send_data(0x00B4);
+ send_cmd(0xDD08); send_data(0x0001);
+ send_cmd(0xDD09); send_data(0x00EC);
+ send_cmd(0xDD0A); send_data(0x0001);
+ send_cmd(0xDD0B); send_data(0x00ED);
+ send_cmd(0xDD0C); send_data(0x0002);
+ send_cmd(0xDD0D); send_data(0x001E);
+ send_cmd(0xDD0E); send_data(0x0002);
+ send_cmd(0xDD0F); send_data(0x0051);
+ send_cmd(0xDE00); send_data(0x0002);
+ send_cmd(0xDE01); send_data(0x006C);
+ send_cmd(0xDE02); send_data(0x0002);
+ send_cmd(0xDE03); send_data(0x008D);
+ send_cmd(0xDE04); send_data(0x0002);
+ send_cmd(0xDE05); send_data(0x00A5);
+ send_cmd(0xDE06); send_data(0x0002);
+ send_cmd(0xDE07); send_data(0x00C9);
+ send_cmd(0xDE08); send_data(0x0002);
+ send_cmd(0xDE09); send_data(0x00EA);
+ send_cmd(0xDE0A); send_data(0x0003);
+ send_cmd(0xDE0B); send_data(0x0019);
+ send_cmd(0xDE0C); send_data(0x0003);
+ send_cmd(0xDE0D); send_data(0x0045);
+ send_cmd(0xDE0E); send_data(0x0003);
+ send_cmd(0xDE0F); send_data(0x007A);
+ send_cmd(0xDF00); send_data(0x0003);
+ send_cmd(0xDF01); send_data(0x00A0);
+ send_cmd(0xDF02); send_data(0x0003);
+ send_cmd(0xDF03); send_data(0x00F4);
+
+ /*Negae Gamma for RED*/
+ send_cmd(0xE000); send_data(0x0000);
+ send_cmd(0xE001); send_data(0x0032);
+ send_cmd(0xE002); send_data(0x0000);
+ send_cmd(0xE003); send_data(0x0041);
+ send_cmd(0xE004); send_data(0x0000);
+ send_cmd(0xE005); send_data(0x0054);
+ send_cmd(0xE006); send_data(0x0000);
+ send_cmd(0xE007); send_data(0x0067);
+ send_cmd(0xE008); send_data(0x0000);
+ send_cmd(0xE009); send_data(0x007A);
+ send_cmd(0xE00A); send_data(0x0000);
+ send_cmd(0xE00B); send_data(0x0098);
+ send_cmd(0xE00C); send_data(0x0000);
+ send_cmd(0xE00D); send_data(0x00B0);
+ send_cmd(0xE00E); send_data(0x0000);
+ send_cmd(0xE00F); send_data(0x00DB);
+ send_cmd(0xE100); send_data(0x0001);
+ send_cmd(0xE101); send_data(0x0001);
+ send_cmd(0xE102); send_data(0x0001);
+ send_cmd(0xE103); send_data(0x003F);
+ send_cmd(0xE104); send_data(0x0001);
+ send_cmd(0xE105); send_data(0x0070);
+ send_cmd(0xE106); send_data(0x0001);
+ send_cmd(0xE107); send_data(0x00B4);
+ send_cmd(0xE108); send_data(0x0001);
+ send_cmd(0xE109); send_data(0x00EC);
+ send_cmd(0xE10A); send_data(0x0001);
+ send_cmd(0xE10B); send_data(0x00ED);
+ send_cmd(0xE10C); send_data(0x0002);
+ send_cmd(0xE10D); send_data(0x001E);
+ send_cmd(0xE10E); send_data(0x0002);
+ send_cmd(0xE10F); send_data(0x0051);
+ send_cmd(0xE200); send_data(0x0002);
+ send_cmd(0xE201); send_data(0x006C);
+ send_cmd(0xE202); send_data(0x0002);
+ send_cmd(0xE203); send_data(0x008D);
+ send_cmd(0xE204); send_data(0x0002);
+ send_cmd(0xE205); send_data(0x00A5);
+ send_cmd(0xE206); send_data(0x0002);
+ send_cmd(0xE207); send_data(0x00C9);
+ send_cmd(0xE208); send_data(0x0002);
+ send_cmd(0xE209); send_data(0x00EA);
+ send_cmd(0xE20A); send_data(0x0003);
+ send_cmd(0xE20B); send_data(0x0019);
+ send_cmd(0xE20C); send_data(0x0003);
+ send_cmd(0xE20D); send_data(0x0045);
+ send_cmd(0xE20E); send_data(0x0003);
+ send_cmd(0xE20F); send_data(0x007A);
+ send_cmd(0xE300); send_data(0x0003);
+ send_cmd(0xE301); send_data(0x00A0);
+ send_cmd(0xE302); send_data(0x0003);
+ send_cmd(0xE303); send_data(0x00F4);
+
+ /*Negae Gamma for GERREN*/
+ send_cmd(0xE400); send_data(0x0000);
+ send_cmd(0xE401); send_data(0x0032);
+ send_cmd(0xE402); send_data(0x0000);
+ send_cmd(0xE403); send_data(0x0041);
+ send_cmd(0xE404); send_data(0x0000);
+ send_cmd(0xE405); send_data(0x0054);
+ send_cmd(0xE406); send_data(0x0000);
+ send_cmd(0xE407); send_data(0x0067);
+ send_cmd(0xE408); send_data(0x0000);
+ send_cmd(0xE409); send_data(0x007A);
+ send_cmd(0xE40A); send_data(0x0000);
+ send_cmd(0xE40B); send_data(0x0098);
+ send_cmd(0xE40C); send_data(0x0000);
+ send_cmd(0xE40D); send_data(0x00B0);
+ send_cmd(0xE40E); send_data(0x0000);
+ send_cmd(0xE40F); send_data(0x00DB);
+ send_cmd(0xE500); send_data(0x0001);
+ send_cmd(0xE501); send_data(0x0001);
+ send_cmd(0xE502); send_data(0x0001);
+ send_cmd(0xE503); send_data(0x003F);
+ send_cmd(0xE504); send_data(0x0001);
+ send_cmd(0xE505); send_data(0x0070);
+ send_cmd(0xE506); send_data(0x0001);
+ send_cmd(0xE507); send_data(0x00B4);
+ send_cmd(0xE508); send_data(0x0001);
+ send_cmd(0xE509); send_data(0x00EC);
+ send_cmd(0xE50A); send_data(0x0001);
+ send_cmd(0xE50B); send_data(0x00ED);
+ send_cmd(0xE50C); send_data(0x0002);
+ send_cmd(0xE50D); send_data(0x001E);
+ send_cmd(0xE50E); send_data(0x0002);
+ send_cmd(0xE50F); send_data(0x0051);
+ send_cmd(0xE600); send_data(0x0002);
+ send_cmd(0xE601); send_data(0x006C);
+ send_cmd(0xE602); send_data(0x0002);
+ send_cmd(0xE603); send_data(0x008D);
+ send_cmd(0xE604); send_data(0x0002);
+ send_cmd(0xE605); send_data(0x00A5);
+ send_cmd(0xE606); send_data(0x0002);
+ send_cmd(0xE607); send_data(0x00C9);
+ send_cmd(0xE608); send_data(0x0002);
+ send_cmd(0xE609); send_data(0x00EA);
+ send_cmd(0xE60A); send_data(0x0003);
+ send_cmd(0xE60B); send_data(0x0019);
+ send_cmd(0xE60C); send_data(0x0003);
+ send_cmd(0xE60D); send_data(0x0045);
+ send_cmd(0xE60E); send_data(0x0003);
+ send_cmd(0xE60F); send_data(0x007A);
+ send_cmd(0xE700); send_data(0x0003);
+ send_cmd(0xE701); send_data(0x00A0);
+ send_cmd(0xE702); send_data(0x0003);
+ send_cmd(0xE703); send_data(0x00F4);
+
+ /*Negae Gamma for BLUE*/
+ send_cmd(0xE800); send_data(0x0000);
+ send_cmd(0xE801); send_data(0x0032);
+ send_cmd(0xE802); send_data(0x0000);
+ send_cmd(0xE803); send_data(0x0041);
+ send_cmd(0xE804); send_data(0x0000);
+ send_cmd(0xE805); send_data(0x0054);
+ send_cmd(0xE806); send_data(0x0000);
+ send_cmd(0xE807); send_data(0x0067);
+ send_cmd(0xE808); send_data(0x0000);
+ send_cmd(0xE809); send_data(0x007A);
+ send_cmd(0xE80A); send_data(0x0000);
+ send_cmd(0xE80B); send_data(0x0098);
+ send_cmd(0xE80C); send_data(0x0000);
+ send_cmd(0xE80D); send_data(0x00B0);
+ send_cmd(0xE80E); send_data(0x0000);
+ send_cmd(0xE80F); send_data(0x00DB);
+ send_cmd(0xE900); send_data(0x0001);
+ send_cmd(0xE901); send_data(0x0001);
+ send_cmd(0xE902); send_data(0x0001);
+ send_cmd(0xE903); send_data(0x003F);
+ send_cmd(0xE904); send_data(0x0001);
+ send_cmd(0xE905); send_data(0x0070);
+ send_cmd(0xE906); send_data(0x0001);
+ send_cmd(0xE907); send_data(0x00B4);
+ send_cmd(0xE908); send_data(0x0001);
+ send_cmd(0xE909); send_data(0x00EC);
+ send_cmd(0xE90A); send_data(0x0001);
+ send_cmd(0xE90B); send_data(0x00ED);
+ send_cmd(0xE90C); send_data(0x0002);
+ send_cmd(0xE90D); send_data(0x001E);
+ send_cmd(0xE90E); send_data(0x0002);
+ send_cmd(0xE90F); send_data(0x0051);
+ send_cmd(0xEA00); send_data(0x0002);
+ send_cmd(0xEA01); send_data(0x006C);
+ send_cmd(0xEA02); send_data(0x0002);
+ send_cmd(0xEA03); send_data(0x008D);
+ send_cmd(0xEA04); send_data(0x0002);
+ send_cmd(0xEA05); send_data(0x00A5);
+ send_cmd(0xEA06); send_data(0x0002);
+ send_cmd(0xEA07); send_data(0x00C9);
+ send_cmd(0xEA08); send_data(0x0002);
+ send_cmd(0xEA09); send_data(0x00EA);
+ send_cmd(0xEA0A); send_data(0x0003);
+ send_cmd(0xEA0B); send_data(0x0019);
+ send_cmd(0xEA0C); send_data(0x0003);
+ send_cmd(0xEA0D); send_data(0x0045);
+ send_cmd(0xEA0E); send_data(0x0003);
+ send_cmd(0xEA0F); send_data(0x007A);
+ send_cmd(0xEB00); send_data(0x0003);
+ send_cmd(0xEB01); send_data(0x00A0);
+ send_cmd(0xEB02); send_data(0x0003);
+ send_cmd(0xEB03); send_data(0x00F4);
+
+ send_cmd(0x3A00); send_data(0x0007);
+
+ send_cmd(0x3500); send_data(0x0000);
+
+ send_cmd(0x1100); /* Sleep out*/
+ LCD_DelayMS(120);
+ send_cmd(0x2900); /* Display On*/
+
+ send_cmd(0x2900); /* Display On*/
+ return 0;
+}
+
+static int32_t nt35516_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ return 0;
+
+ if(is_sleep==1){
+ send_cmd(0x2800);
+ LCD_DelayMS(200);
+ send_cmd(0x1000);
+ LCD_DelayMS(200);
+ /*Lcd_EnvidOnOff(0);*//*RGB TIMENG OFF*/
+ /*LCD_Delay(200);*/
+ }else{
+ /*Lcd_EnvidOnOff(1);*//*RGB TIMENG ON*/
+ /*LCD_Delay(200);*/
+ /*LCDinit_TFT();*/
+ /*LCD_Delay(200);*/
+ }
+
+ return 0;
+}
+
+
+
+
+static int32_t nt35516_set_window(struct panel_spec *self,
+ uint16_t left, uint16_t top, uint16_t right, uint16_t bottom)
+{
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ pr_debug("nt35516_set_window: %d, %d, %d, %d\n",left, top, right, bottom);
+
+ send_cmd(0x2A00); send_data((left>>8));// set left address
+ send_cmd(0x2A01); send_data((left&0xff));
+ send_cmd(0x2A02); send_data((right>>8));// set right address
+ send_cmd(0x2A03); send_data((right&0xff));
+
+ send_cmd(0x2B00); send_data((top>>8));// set left address
+ send_cmd(0x2B01); send_data((top&0xff));
+ send_cmd(0x2B02); send_data((bottom>>8));// set bottom address
+ send_cmd(0x2B03); send_data((bottom&0xff));
+
+ send_cmd(0x2C00);
+
+ return 0;
+}
+static int32_t nt35516_invalidate(struct panel_spec *self)
+{
+ pr_debug("nt35516_invalidate\n");
+
+ return self->ops->panel_set_window(self, 0, 0,
+ self->width - 1, self->height - 1);
+}
+
+
+
+static int32_t nt35516_invalidate_rect(struct panel_spec *self,
+ uint16_t left, uint16_t top,
+ uint16_t right, uint16_t bottom)
+{
+ pr_debug("nt35516_invalidate_rect \n");
+
+ return self->ops->panel_set_window(self, left, top,
+ right, bottom);
+}
+
+static uint32_t nt35516_read_id(struct panel_spec *self)
+{
+ int32_t id = 0;
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ read_data_t read_data = self->info.mcu->ops->read_data;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ //Get ID
+ send_cmd(0xF000); send_data(0x0055); /*Manufacture Command Set Control */
+ send_cmd(0xF001); send_data(0x00AA);
+ send_cmd(0xF002); send_data(0x0052);
+ send_cmd(0xF003); send_data(0x0008);
+ send_cmd(0xF004); send_data(0x0001);/*Page1*/
+
+ send_cmd(0xc501); //0xc500
+ id = read_data();
+
+ return id;
+}
+
+static struct panel_operations lcd_nt35516_operations = {
+ .panel_init = nt35516_init,
+ .panel_set_window = nt35516_set_window,
+ .panel_invalidate_rect= nt35516_invalidate_rect,
+ .panel_invalidate = nt35516_invalidate,
+ .panel_enter_sleep = nt35516_enter_sleep,
+ .panel_readid = nt35516_read_id
+};
+
+static struct timing_mcu lcd_nt35516_timing[] = {
+[MCU_LCD_REGISTER_TIMING] = { // read/write register timing
+ .rcss = 15, // 15ns
+ .rlpw = 60,
+ .rhpw = 60,
+ .wcss = 10,
+ .wlpw = 35,
+ .whpw = 35,
+ },
+[MCU_LCD_GRAM_TIMING] = { // read/write gram timing
+ .rcss = 15, // 15ns
+ .rlpw = 60,
+ .rhpw = 60,
+ .wcss = 0,
+ .wlpw = 16,
+ .whpw = 16,
+ },
+};
+
+static struct info_mcu lcd_nt35516_info = {
+ .bus_mode = LCD_BUS_8080,
+ .bus_width = 24,
+ .bpp = 24, /*RGB88*/
+ .timing = lcd_nt35516_timing,
+ .ops = NULL,
+};
+
+//lcd_panel_nt35516
+struct panel_spec lcd_nt35516_spec = {
+ .width = 540,
+ .height = 960,
+ .type = LCD_MODE_MCU,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mcu = &lcd_nt35516_info
+ },
+ .ops = &lcd_nt35516_operations,
+};
+
+struct panel_cfg lcd_nt35516 = {
+ /* this panel may on both CS0/1 */
+ .dev_id = SPRDFB_UNDEFINELCD_ID,
+ .lcd_id = 0x16,
+ .lcd_name = "lcd_nt35516",
+ .panel = &lcd_nt35516_spec,
+};
+
+static int __init lcd_nt35516_init(void)
+{
+ return sprdfb_panel_register(&lcd_nt35516);
+}
+
+subsys_initcall(lcd_nt35516_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_nt35516_mipi.c b/drivers/video/sprdfb/lcd/lcd_nt35516_mipi.c
new file mode 100644
index 00000000..0fa94268
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_nt35516_mipi.c
@@ -0,0 +1,441 @@
+/* drivers/video/sc8825/lcd_nt35516_mipi.c
+ *
+ * Support for nt35516 mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+//#define LCD_Delay(ms) uDelay(ms*1000)
+
+#define MAX_DATA 48
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+#if 1
+// NT35516, LGD
+// VCC=2.8V, IOVCC=1.8V
+{LCM_SEND(7), {5, 0, 0xFF,0xAA,0x55,0x25,0x01}},
+{LCM_SEND(38), {36, 0, 0xF2,0x00,0x00,0x4A,0x0A,0xA8,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x01,0x51,
+ 0x00,0x01,0x00,0x01}},
+{LCM_SEND(10), {8, 0, 0xF3,0x02,0x03,0x07,0x45,0x88,0xD1,0x0D}},
+// Manufacture Command Set for Page 0
+{LCM_SEND(8), {6, 0, 0xF0,0x55,0xAA,0x52,0x08,0x00}},
+{LCM_SEND(6), {4, 0, 0xB1,0x7C,0x00,0x00}}, // command/video mode
+#if (defined CONFIG_FB_SCX35) || (defined CONFIG_FB_SCX30G)
+{LCM_SEND(6), {4, 0, 0xB1,0x7C,0x06,0x00}}, // command/video mode,rotate 180^M
+#else
+ {LCM_SEND(6), {4, 0, 0xB1,0x7C,0x00,0x00}}, // command/video mode
+#endif
+{LCM_SEND(7), {5, 0, 0xB8,0x01,0x02,0x02,0x02}},
+{LCM_SEND(6), {4, 0, 0xBC,0x00,0x00,0x00}}, // inversion
+{LCM_SEND(9), {7, 0, 0xC9,0x63,0x06,0x0D,0x1A,0x17,0x00}},
+// Manufacture Command Set for Page 1
+{LCM_SEND(8), {6, 0, 0xF0,0x55,0xAA,0x52,0x08,0x01}},
+{LCM_SEND(6), {4, 0, 0xB0,0x05,0x05,0x05}},
+{LCM_SEND(6), {4, 0, 0xB1,0x05,0x05,0x05}},
+{LCM_SEND(6), {4, 0, 0xB2,0x01,0x01,0x01}},
+{LCM_SEND(6), {4, 0, 0xB3,0x0D,0x0D,0x0D}},
+{LCM_SEND(6), {4, 0, 0xB4,0x09,0x09,0x09}},
+{LCM_SEND(6), {4, 0, 0xB6,0x44,0x44,0x44}},
+{LCM_SEND(6), {4, 0, 0xB7,0x34,0x34,0x34}},
+{LCM_SEND(6), {4, 0, 0xB8,0x10,0x10,0x10}},
+{LCM_SEND(6), {4, 0, 0xB9,0x36,0x36,0x36}},
+{LCM_SEND(6), {4, 0, 0xBA,0x24,0x24,0x24}},
+{LCM_SEND(6), {4, 0, 0xBC,0x00,0xD0,0x00}},
+{LCM_SEND(6), {4, 0, 0xBD,0x00,0xD0,0x00}},
+{LCM_SEND(2), {0xBE,0x5D}},
+{LCM_SEND(5), {3, 0, 0xC0,0x04,0x00}},
+{LCM_SEND(2), {0xCA,0x00}},
+// Gradient Control for Gamma Voltage
+{LCM_SEND(7), {5, 0, 0xD0,0x0A,0x10,0x0D,0x0F}},
+{LCM_SEND(19), {17, 0, 0xD1,0x00,0xA7,0x01,0x0F,0x01,0x34,0x01,0x49,0x01,0x56,0x01,0x75,0x01,0x8F,0x01,0xB7}},
+{LCM_SEND(19), {17, 0, 0xD2,0x01,0xD1,0x02,0x03,0x02,0x23,0x02,0x57,0x02,0x85,0x02,0x87,0x02,0xAA,0x02,0xE1}},
+{LCM_SEND(19), {17, 0, 0xD3,0x03,0x04,0x03,0x31,0x03,0x42,0x03,0x6D,0x03,0x83,0x03,0x9C,0x03,0xAA,0x03,0xCD}},
+{LCM_SEND(7), {5, 0, 0xD4,0x03,0xEF,0x03,0xFF}},
+{LCM_SEND(19), {17, 0, 0xD5,0x00,0xA7,0x01,0x0F,0x01,0x34,0x01,0x49,0x01,0x56,0x01,0x75,0x01,0x8F,0x01,0xB7}},
+{LCM_SEND(19), {17, 0, 0xD6,0x01,0xD1,0x02,0x03,0x02,0x23,0x02,0x57,0x02,0x85,0x02,0x87,0x02,0xAA,0x02,0xE1}},
+{LCM_SEND(19), {17, 0, 0xD7,0x03,0x04,0x03,0x31,0x03,0x42,0x03,0x6D,0x03,0x83,0x03,0x9C,0x03,0xAA,0x03,0xCD}},
+{LCM_SEND(7), {5, 0, 0xD8,0x03,0xEF,0x03,0xFF}},
+{LCM_SEND(19), {17, 0, 0xD9,0x00,0xA7,0x01,0x0F,0x01,0x34,0x01,0x49,0x01,0x56,0x01,0x75,0x01,0x8F,0x01,0xB7}},
+{LCM_SEND(19), {17, 0, 0xDD,0x01,0xD1,0x02,0x03,0x02,0x23,0x02,0x57,0x02,0x85,0x02,0x87,0x02,0xAA,0x02,0xE1}},
+{LCM_SEND(19), {17, 0, 0xDE,0x03,0x04,0x03,0x31,0x03,0x42,0x03,0x6D,0x03,0x83,0x03,0x9C,0x03,0xAA,0x03,0xCD}},
+{LCM_SEND(7), {5, 0, 0xDF,0x03,0xEF,0x03,0xFF}},
+{LCM_SEND(19), {17, 0, 0xE0,0x00,0xA7,0x01,0x0F,0x01,0x34,0x01,0x49,0x01,0x56,0x01,0x75,0x01,0x8F,0x01,0xB7}},
+{LCM_SEND(19), {17, 0, 0xE1,0x01,0xD1,0x02,0x03,0x02,0x23,0x02,0x57,0x02,0x85,0x02,0x87,0x02,0xAA,0x02,0xE1}},
+{LCM_SEND(19), {17, 0, 0xE2,0x03,0x04,0x03,0x31,0x03,0x42,0x03,0x6D,0x03,0x83,0x03,0x9C,0x03,0xAA,0x03,0xCD}},
+{LCM_SEND(7), {5, 0, 0xE3,0x03,0xEF,0x03,0xFF}},
+{LCM_SEND(19), {17, 0, 0xE4,0x00,0xA7,0x01,0x0F,0x01,0x34,0x01,0x49,0x01,0x56,0x01,0x75,0x01,0x8F,0x01,0xB7}},
+{LCM_SEND(19), {17, 0, 0xE5,0x01,0xD1,0x02,0x03,0x02,0x23,0x02,0x57,0x02,0x85,0x02,0x87,0x02,0xAA,0x02,0xE1}},
+{LCM_SEND(19), {17, 0, 0xE6,0x03,0x04,0x03,0x31,0x03,0x42,0x03,0x6D,0x03,0x83,0x03,0x9C,0x03,0xAA,0x03,0xCD}},
+{LCM_SEND(7), {5, 0, 0xE7,0x03,0xEF,0x03,0xFF}},
+{LCM_SEND(19), {17, 0, 0xE8,0x00,0xA7,0x01,0x0F,0x01,0x34,0x01,0x49,0x01,0x56,0x01,0x75,0x01,0x8F,0x01,0xB7}},
+{LCM_SEND(19), {17, 0, 0xE9,0x01,0xD1,0x02,0x03,0x02,0x23,0x02,0x57,0x02,0x85,0x02,0x87,0x02,0xAA,0x02,0xE1}},
+{LCM_SEND(19), {17, 0, 0xEA,0x03,0x04,0x03,0x31,0x03,0x42,0x03,0x6D,0x03,0x83,0x03,0x9C,0x03,0xAA,0x03,0xCD}},
+{LCM_SEND(7), {5, 0, 0xEB,0x03,0xEF,0x03,0xFF}},
+// User Command Set
+{LCM_SEND(2), {0x35,0x00}}, // Tearing Effect On
+{LCM_SEND(5), {3, 0, 0x44, 0x03, 0x98}}, //set te scan line to 920
+{LCM_SEND(2), {0x3A,0x77}}, // Interface Pixel Format
+{LCM_SEND(2), {0x36,0x00}}, // Memory Data Access Control
+{LCM_SEND(1), {0x22}}, // all pixel off
+{LCM_SEND(1), {0x11}}, // sleep out
+{LCM_SLEEP(120)},
+{LCM_SEND(1), {0x29}}, // display on
+{LCM_SLEEP(100)},
+{LCM_SEND(2), {0x13,0x00}}, // normal on
+#endif
+
+#if 0
+{LCM_SEND(7), {0x5, 0, 0xFF, 0xAA, 0x55, 0x25, 0x01}},
+{LCM_SEND(7), {0x5, 0, 0xF3, 0x02, 0x03, 0x07, 0x15}},
+{LCM_SEND(8), {0x6, 0, 0xF0, 0x55, 0xAA, 0x52, 0x08, 0x00}},
+//{LCM_SEND(8), {0x06, 0, 0xF0,0x55,0xAA,0x52,0x08,0x00}},
+//{LCM_SEND(8), {0x06, 0, 0xBD,0x02,0xC8,0x14,0x3C,0x01}},
+{LCM_SEND(2), {0xB1, 0xFC}},
+
+{LCM_SEND(7), {0x5, 0, 0xB8, 0x01, 0x02, 0x02, 0x02}},
+{LCM_SEND(6), {0x4, 0, 0xBC, 0x05, 0x05, 0x05}}, //Zig-Zag Inversion
+{LCM_SEND(8), {0x6, 0, 0xF0, 0x55, 0xAA, 0x52, 0x08, 0x01}},
+{LCM_SEND(6), {0x4, 0, 0xB0, 0x05, 0x05, 0x05}},
+{LCM_SEND(6), {0x4, 0, 0xB1, 0x05, 0x05, 0x05}},
+{LCM_SEND(6), {0x4, 0, 0xB6, 0x34, 0x34, 0x34}},
+{LCM_SEND(6), {0x4, 0, 0xB7, 0x24, 0x24, 0x24}},
+{LCM_SEND(6), {0x4, 0, 0xB3, 0x10, 0x10, 0x10}},
+{LCM_SEND(6), {0x4, 0, 0xB9, 0x34, 0x34, 0x34}},
+{LCM_SEND(6), {0x4, 0, 0xB4, 0x0A, 0x0A, 0x0A}},
+{LCM_SEND(6), {0x4, 0, 0xBA, 0x14, 0x14, 0x14}},
+{LCM_SEND(6), {0x4, 0, 0xBC, 0x00, 0xA0, 0x00}},
+{LCM_SEND(6), {0x4, 0, 0xBD, 0x00, 0xA0, 0x00}},
+{LCM_SEND(2), {0xBE, 0x4E}},
+
+{LCM_SEND(19),{17, 0, 0xD1, 0x00, 0x32, 0x00, 0x41, 0x00, 0x54, 0x00, 0x67, 0x00, 0x7A, 0x00, 0x98, 0x00, 0xB0, 0x00, 0xDB}},
+{LCM_SEND(19),{17, 0, 0xD2, 0x01, 0x01, 0x01, 0x3F, 0x01, 0x70, 0x01, 0xB4, 0x01, 0xEC, 0x01, 0xED, 0x02, 0x1E, 0x02, 0x51}},
+{LCM_SEND(19),{17, 0, 0xD3, 0x02, 0x6C, 0x02, 0x8D, 0x02, 0xA5, 0x02, 0xC9, 0x02, 0xEA, 0x03, 0x19, 0x03, 0x45, 0x03, 0x7A}},
+{LCM_SEND(7), { 5, 0, 0xD4, 0x03, 0xB0, 0x03, 0xF4}},
+{LCM_SEND(19),{17, 0, 0xD5, 0x00, 0x32, 0x00, 0x41, 0x00, 0x54, 0x00, 0x67, 0x00, 0x7A, 0x00, 0x98, 0x00, 0xB0, 0x00, 0xDB}},
+{LCM_SEND(19),{17, 0, 0xD6, 0x01, 0x01, 0x01, 0x3F, 0x01, 0x70, 0x01, 0xB4, 0x01, 0xEC, 0x01, 0xED, 0x02, 0x1E, 0x02, 0x51}},
+{LCM_SEND(19),{17, 0, 0xD7, 0x02, 0x6C, 0x02, 0x8D, 0x02, 0xA5, 0x02, 0xC9, 0x02, 0xEA, 0x03, 0x19, 0x03, 0x45, 0x03, 0x7A}},
+{LCM_SEND(7), {0x7, 0, 0xD8, 0x03, 0xB0, 0x03, 0xF4}},
+{LCM_SEND(19),{17, 0, 0xD9, 0x00, 0x32, 0x00, 0x41, 0x00, 0x54, 0x00, 0x67, 0x00, 0x7A, 0x00, 0x98, 0x00, 0xB0, 0x00, 0xDB}},
+{LCM_SEND(19),{17, 0,0xDD, 0x01, 0x01, 0x01, 0x3F, 0x01, 0x70, 0x01, 0xB4, 0x01, 0xEC, 0x01, 0xED, 0x02, 0x1E, 0x02, 0x51}},
+{LCM_SEND(19),{17, 0, 0xDE, 0x02, 0x6C, 0x02, 0x8D, 0x02, 0xA5, 0x02, 0xC9, 0x02, 0xEA, 0x03, 0x19, 0x03, 0x45, 0x03, 0x7A}},
+{LCM_SEND(7), {0x5, 0, 0xDF, 0x03, 0xB0, 0x03, 0xF4}},
+{LCM_SEND(19),{17, 0, 0xE0, 0x00, 0x32, 0x00, 0x41, 0x00, 0x54, 0x00, 0x67, 0x00, 0x7A, 0x00, 0x98, 0x00, 0xB0, 0x00, 0xDB}},
+{LCM_SEND(19),{17, 0 ,0xE1, 0x01, 0x01, 0x01, 0x3F, 0x01, 0x70, 0x01, 0xB4, 0x01, 0xEC, 0x01, 0xED, 0x02, 0x1E, 0x02, 0x51}},
+{LCM_SEND(19),{17, 0,0xE2, 0x02, 0x6C, 0x02, 0x8D, 0x02, 0xA5, 0x02, 0xC9, 0x02, 0xEA, 0x03, 0x19, 0x03, 0x45, 0x03, 0x7A}},
+{LCM_SEND(7), {5, 0, 0xE3, 0x03, 0xB0, 0x03, 0xF4}},
+{LCM_SEND(19),{17, 0, 0xE4, 0x00, 0x32, 0x00, 0x41, 0x00, 0x54, 0x00, 0x67, 0x00, 0x7A, 0x00, 0x98, 0x00, 0xB0, 0x00, 0xDB}},
+{LCM_SEND(19),{17, 0,0xE5, 0x01, 0x01, 0x01, 0x3F, 0x01, 0x70, 0x01, 0xB4, 0x01, 0xEC, 0x01, 0xED, 0x02, 0x1E, 0x02, 0x51}},
+{LCM_SEND(19),{17, 0, 0xE6, 0x02, 0x6C, 0x02, 0x8D, 0x02, 0xA5, 0x02, 0xC9, 0x02, 0xEA, 0x03, 0x19, 0x03, 0x45, 0x03, 0x7A}},
+{LCM_SEND(7), {5, 0, 0xE7, 0x03, 0xB0, 0x03, 0xF4}},
+{LCM_SEND(19),{17 , 0, 0xE8, 0x00, 0x32, 0x00, 0x41, 0x00, 0x54, 0x00, 0x67, 0x00, 0x7A, 0x00, 0x98, 0x00, 0xB0, 0x00, 0xDB}},
+{LCM_SEND(19),{17, 0, 0xE9, 0x01, 0x01, 0x01, 0x3F, 0x01, 0x70, 0x01, 0xB4, 0x01, 0xEC, 0x01, 0xED, 0x02, 0x1E, 0x02, 0x51}},
+{LCM_SEND(19),{17, 0, 0xEA, 0x02, 0x6C, 0x02, 0x8D, 0x02, 0xA5, 0x02, 0xC9, 0x02, 0xEA, 0x03, 0x19, 0x03, 0x45, 0x03, 0x7A}},
+{LCM_SEND(7), {0x5, 0, 0xEB, 0x03, 0xB0, 0x03, 0xF4}},
+{LCM_SEND(2), {0x3A, 0x77}},
+{LCM_SEND(2), {0x35, 0x00}},
+{LCM_SEND(2), {0x4C, 0x11}},
+
+#endif
+#if 0
+{LCM_SEND(1), {0x11}},//0x11
+{LCM_SLEEP(200),},
+{LCM_SEND(1), {0x29}},//0x29
+#endif
+};
+
+//static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+{LCM_SEND(1), {0x28}},
+{LCM_SLEEP(10)},
+{LCM_SEND(1), {0x10}},
+{LCM_SLEEP(120)},
+//{LCM_SEND(2), {0x4f, 0x01}}, /* this code may cause not resume bug*/
+};
+
+static LCM_Init_Code sleep_out[] = {
+{LCM_SEND(1), {0x11}},
+{LCM_SLEEP(120)},
+{LCM_SEND(1), {0x29}},
+{LCM_SLEEP(20)},
+};
+
+static LCM_Force_Cmd_Code rd_prep_code[]={
+ {0x39, {LCM_SEND(8), {0x6, 0, 0xF0, 0x55, 0xAA, 0x52, 0x08, 0x01}}},
+ {0x37, {LCM_SEND(2), {0x3, 0}}},
+};
+
+static LCM_Force_Cmd_Code rd_prep_code_1[]={
+ {0x37, {LCM_SEND(2), {0x1, 0}}},
+};
+static int32_t nt35516_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+
+ pr_debug(KERN_DEBUG "nt35516_mipi_init\n");
+
+ mipi_set_cmd_mode();
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((init->tag & LCM_TAG_MASK));
+ }
+ init++;
+ }
+ return 0;
+}
+
+static uint32_t nt35516_readid(struct panel_spec *self)
+{
+ /*Jessica TODO: need read id*/
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code;
+ uint8_t read_data[3] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("lcd_nt35516_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,1);
+
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }
+ rd_prepare++;
+ }
+ read_rtn = mipi_force_read(0xc5, 3,(uint8_t *)read_data);
+ printk("lcd_nt35516_mipi read id 0xc5 value is 0x%x, 0x%x, 0x%x!\n", read_data[0], read_data[1], read_data[2]);
+
+ if((0x55 == read_data[0])&&(0x16 == read_data[1])){
+ printk("lcd_nt35516_mipi read id success!\n");
+ mipi_eotp_set(1,1);
+ return 0x16;
+ }
+ }
+ mipi_eotp_set(1,1);
+ return 0x0;
+}
+
+static int32_t nt35516_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i = 0;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+
+ printk(KERN_DEBUG "nt35516_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((sleep_in_out->tag & LCM_TAG_MASK));
+ }
+ sleep_in_out++;
+ }
+ return 0;
+}
+
+static uint32_t nt35516_readpowermode(struct panel_spec *self)
+{
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code_1;
+ uint8_t read_data[1] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_debug("lcd_nt35516_mipi read power mode!\n");
+ mipi_eotp_set(0,1);
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code_1;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code_1); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }
+ rd_prepare++;
+ }
+ read_rtn = mipi_force_read(0x0A, 1,(uint8_t *)read_data);
+ //printk("lcd_nt35516 mipi read power mode 0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+ if((0x9c == read_data[0]) && (0 == read_rtn)){
+ pr_debug("lcd_nt35516_mipi read power mode success!\n");
+ mipi_eotp_set(1,1);
+ return 0x9c;
+ }
+ }
+
+ printk("lcd_nt35516 mipi read power mode fail!0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+ mipi_eotp_set(1,1);
+ return 0x0;
+}
+
+static int32_t nt35516_check_esd(struct panel_spec *self)
+{
+ uint32_t power_mode;
+
+#ifndef FB_CHECK_ESD_IN_VFP
+ mipi_set_lp_mode_t mipi_set_data_lp_mode = self->info.mipi->ops->mipi_set_data_lp_mode;
+ mipi_set_hs_mode_t mipi_set_data_hs_mode = self->info.mipi->ops->mipi_set_data_hs_mode;
+ mipi_set_lp_mode_t mipi_set_lp_mode = self->info.mipi->ops->mipi_set_lp_mode;
+ mipi_set_hs_mode_t mipi_set_hs_mode = self->info.mipi->ops->mipi_set_hs_mode;
+ uint16_t work_mode = self->info.mipi->work_mode;
+#endif
+
+ pr_debug("nt35516_check_esd!\n");
+#ifndef FB_CHECK_ESD_IN_VFP
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_lp_mode();
+ }else{
+ mipi_set_data_lp_mode();
+ }
+#endif
+ power_mode = nt35516_readpowermode(self);
+ //power_mode = 0x0;
+#ifndef FB_CHECK_ESD_IN_VFP
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_hs_mode();
+ }else{
+ mipi_set_data_hs_mode();
+ }
+#endif
+ if(power_mode == 0x9c){
+ pr_debug("nt35516_check_esd OK!\n");
+ return 1;
+ }else{
+ printk("nt35516_check_esd fail!(0x%x)\n", power_mode);
+ return 0;
+ }
+}
+
+static struct panel_operations lcd_nt35516_mipi_operations = {
+ .panel_init = nt35516_mipi_init,
+ .panel_readid = nt35516_readid,
+ .panel_enter_sleep = nt35516_enter_sleep,
+ .panel_esd_check = nt35516_check_esd,
+};
+
+static struct timing_rgb lcd_nt35516_mipi_timing = {
+ .hfp = 20, /* unit: pixel */
+ .hbp = 20,
+ .hsync = 20,//4,
+ .vfp = 10, /*unit: line*/
+ .vbp = 10,
+ .vsync = 6,
+};
+
+static struct info_mipi lcd_nt35516_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 3,
+ .phy_feq = 500*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_nt35516_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_nt35516_mipi_spec = {
+ .width = 540,
+ .height = 960,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .is_clean_lcd = true,
+ .info = {
+ .mipi = &lcd_nt35516_mipi_info
+ },
+ .ops = &lcd_nt35516_mipi_operations,
+};
+
+struct panel_cfg lcd_nt35516_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x16,
+ .lcd_name = "lcd_nt35516_mipi",
+ .panel = &lcd_nt35516_mipi_spec,
+};
+
+static int __init lcd_nt35516_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_nt35516_mipi);
+}
+
+subsys_initcall(lcd_nt35516_mipi_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_nt35516_rgb_i2c.c b/drivers/video/sprdfb/lcd/lcd_nt35516_rgb_i2c.c
new file mode 100644
index 00000000..cdbfd220
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_nt35516_rgb_i2c.c
@@ -0,0 +1,623 @@
+/* drivers/video/sc8825/lcd_nt35516_i2c.c
+ *
+ * Support for nt35516 i2c LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+#define NT35516_I2C_ADDR 0x4C
+#define NT35516_I2C_DATA_LENGHT 0x2
+#define NT35516_I2C_ACK 0x01
+//#define Set_NT35516_I2C_Send(len, data) I2C_WriteCmdArr(NT35516_I2C_ADDR, data ,len, NT35516_I2C_ACK)
+#define Set_NT35516_I2C_Send(len, data) i2c_write_burst(data ,len)
+#define LCDI2C_ID_ADDR 0xDB00
+
+#define NT35516_MAX_PARAM 4
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[NT35516_MAX_PARAM];
+}LCM_Init_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+ {LCM_SEND(4), {0xFF, 0x00, 0x00, 0xAA}},//AA
+ {LCM_SEND(4), {0xFF, 0x01, 0x00, 0x55}},//55
+ {LCM_SEND(4), {0xFF, 0x02, 0x00, 0x25}},//08
+ {LCM_SEND(4), {0xFF, 0x03, 0x00, 0x01}},//01
+ {LCM_SEND(4), {0xF3, 0x00, 0x00, 0x02}},
+ {LCM_SEND(4), {0xF3, 0x03, 0x00, 0x15}},
+ {LCM_SEND(4), {0xF0, 0x00, 0x00, 0x55}}, //Manufacture Command Set Control
+ {LCM_SEND(4), {0xF0, 0x01, 0x00, 0xAA}},
+ {LCM_SEND(4), {0xF0, 0x02, 0x00, 0x52}},
+ {LCM_SEND(4), {0xF0, 0x03, 0x00, 0x08}},
+ {LCM_SEND(4), {0xF0, 0x04, 0x00, 0x00}},
+ {LCM_SEND(4), {0xB8, 0x00, 0x00, 0x01}},
+ {LCM_SEND(4), {0xB8, 0x01, 0x00, 0x02}},
+ {LCM_SEND(4), {0xB8, 0x02, 0x00, 0x02}},
+ {LCM_SEND(4), {0xB8, 0x03, 0x00, 0x02}},
+ {LCM_SEND(4), {0xBC, 0x00, 0x00, 0x05}}, //Zig-Zag Inversion
+ {LCM_SEND(4), {0xBC, 0x01, 0x00, 0x05}},
+ {LCM_SEND(4), {0xBC, 0x02, 0x00, 0x05}},
+ {LCM_SEND(4), {0x4C, 0x00, 0x00, 0x11}}, //DB4=1,Enable Vivid Color,DB4=0 Disable Vivid Color
+ {LCM_SEND(4), {0xF0, 0x00, 0x00, 0x55}}, //Manufacture Command Set Control
+ {LCM_SEND(4), {0xF0, 0x01, 0x00, 0xAA}},
+ {LCM_SEND(4), {0xF0, 0x02, 0x00, 0x52}},
+ {LCM_SEND(4), {0xF0, 0x03, 0x00, 0x08}},
+ {LCM_SEND(4), {0xF0, 0x04, 0x00, 0x01}},//Page1
+ {LCM_SEND(4), {0xB0, 0x00, 0x00, 0x05}}, // Setting AVDD Voltage 6V
+ {LCM_SEND(4), {0xB0, 0x01, 0x00, 0x05}},
+ {LCM_SEND(4), {0xB0, 0x02, 0x00, 0x05}},
+ {LCM_SEND(4), {0xB6, 0x00, 0x00, 0x44}}, // Setting AVEE boosting time 2.5*vpnl
+ {LCM_SEND(4), {0xB6, 0x01, 0x00, 0x44}},
+ {LCM_SEND(4), {0xB6, 0x02, 0x00, 0x44}},
+ {LCM_SEND(4), {0xB1, 0x00, 0x00, 0x05}}, // Setting AVEE Voltage -6V
+ {LCM_SEND(4), {0xB1, 0x01, 0x00, 0x05}},
+ {LCM_SEND(4), {0xB1, 0x02, 0x00, 0x05}},
+ {LCM_SEND(4), {0xB7, 0x00, 0x00, 0x34}},
+ {LCM_SEND(4), {0xB7, 0x01, 0x00, 0x34}},
+ {LCM_SEND(4), {0xB7, 0x02, 0x00, 0x34}},
+ {LCM_SEND(4), {0xBA, 0x00, 0x00, 0x14}}, //0x24 --> 0x14
+ {LCM_SEND(4), {0xBA, 0x01, 0x00, 0x14}},
+ {LCM_SEND(4), {0xBA, 0x02, 0x00, 0x14}},
+ {LCM_SEND(4), {0xBC, 0x00, 0x00, 0x00}},
+ {LCM_SEND(4), {0xBC, 0x01, 0x00, 0xA0}},//VGMP 0x88=4.7V 0x78=4.5V 0xA0=5.0V
+ {LCM_SEND(4), {0xBC, 0x02, 0x00, 0x00}},//VGSP
+ {LCM_SEND(4), {0xBD, 0x00, 0x00, 0x00}},
+ {LCM_SEND(4), {0xBD, 0x01, 0x00, 0xA0}},//VGMN 0x88=-4.7V 0x78=-4.5V 0xA0=-5.0V
+ {LCM_SEND(4), {0xBD, 0x02, 0x00, 0x00}},//VGSN
+ {LCM_SEND(4), {0xBE, 0x00, 0x00, 0x57}}, // Setting VCOM Offset Voltage 0x4E¸ÄΪ0x57 20111019 LIYAN
+ {LCM_SEND(4), {0xD1, 0x00, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD1, 0x01, 0x00, 0x32}},
+ {LCM_SEND(4), {0xD1, 0x02, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD1, 0x03, 0x00, 0x41}},
+ {LCM_SEND(4), {0xD1, 0x04, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD1, 0x05, 0x00, 0x54}},
+ {LCM_SEND(4), {0xD1, 0x06, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD1, 0x07, 0x00, 0x67}},
+ {LCM_SEND(4), {0xD1, 0x08, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD1, 0x09, 0x00, 0x7A}},
+ {LCM_SEND(4), {0xD1, 0x0A, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD1, 0x0B, 0x00, 0x98}},
+ {LCM_SEND(4), {0xD1, 0x0C, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD1, 0x0D, 0x00, 0xB0}},
+ {LCM_SEND(4), {0xD1, 0x0E, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD1, 0x0F, 0x00, 0xDB}},
+ {LCM_SEND(4), {0xD2, 0x00, 0x00, 0x01}},
+ {LCM_SEND(4), {0xD2, 0x01, 0x00, 0x01}},
+ {LCM_SEND(4), {0xD2, 0x02, 0x00, 0x01}},
+ {LCM_SEND(4), {0xD2, 0x03, 0x00, 0x3F}},
+ {LCM_SEND(4), {0xD2, 0x04, 0x00, 0x01}},
+ {LCM_SEND(4), {0xD2, 0x05, 0x00, 0x70}},
+ {LCM_SEND(4), {0xD2, 0x06, 0x00, 0x01}},
+ {LCM_SEND(4), {0xD2, 0x07, 0x00, 0xB4}},
+ {LCM_SEND(4), {0xD2, 0x08, 0x00, 0x01}},
+ {LCM_SEND(4), {0xD2, 0x09, 0x00, 0xEC}},
+ {LCM_SEND(4), {0xD2, 0x0A, 0x00, 0x01}},
+ {LCM_SEND(4), {0xD2, 0x0B, 0x00, 0xED}},
+ {LCM_SEND(4), {0xD2, 0x0C, 0x00, 0x02}},
+ {LCM_SEND(4), {0xD2, 0x0D, 0x00, 0x1E}},
+ {LCM_SEND(4), {0xD2, 0x0E, 0x00, 0x02}},
+ {LCM_SEND(4), {0xD2, 0x0F, 0x00, 0x51}},
+ {LCM_SEND(4), {0xD3, 0x00, 0x00, 0x02}},
+ {LCM_SEND(4), {0xD3, 0x01, 0x00, 0x6C}},
+ {LCM_SEND(4), {0xD3, 0x02, 0x00, 0x02}},
+ {LCM_SEND(4), {0xD3, 0x03, 0x00, 0x8D}},
+ {LCM_SEND(4), {0xD3, 0x04, 0x00, 0x02}},
+ {LCM_SEND(4), {0xD3, 0x05, 0x00, 0xA5}},
+ {LCM_SEND(4), {0xD3, 0x06, 0x00, 0x02}},
+ {LCM_SEND(4), {0xD3, 0x07, 0x00, 0xC9}},
+ {LCM_SEND(4), {0xD3, 0x08, 0x00, 0x02}},
+ {LCM_SEND(4), {0xD3, 0x09, 0x00, 0xEA}},
+ {LCM_SEND(4), {0xD3, 0x0A, 0x00, 0x03}},
+ {LCM_SEND(4), {0xD3, 0x0B, 0x00, 0x19}},
+ {LCM_SEND(4), {0xD3, 0x0C, 0x00, 0x03}},
+ {LCM_SEND(4), {0xD3, 0x0D, 0x00, 0x45}},
+ {LCM_SEND(4), {0xD3, 0x0E, 0x00, 0x03}},
+ {LCM_SEND(4), {0xD3, 0x0F, 0x00, 0x7A}},
+ {LCM_SEND(4), {0xD4, 0x00, 0x00, 0x03}},
+ {LCM_SEND(4), {0xD4, 0x01, 0x00, 0xB0}},
+ {LCM_SEND(4), {0xD4, 0x02, 0x00, 0x03}},
+ {LCM_SEND(4), {0xD4, 0x03, 0x00, 0xF4}},
+ {LCM_SEND(4), {0xD5, 0x00, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD5, 0x01, 0x00, 0x37}},
+ {LCM_SEND(4), {0xD5, 0x02, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD5, 0x03, 0x00, 0x41}},
+ {LCM_SEND(4), {0xD5, 0x04, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD5, 0x05, 0x00, 0x54}},
+ {LCM_SEND(4), {0xD5, 0x06, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD5, 0x07, 0x00, 0x67}},
+ {LCM_SEND(4), {0xD5, 0x08, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD5, 0x09, 0x00, 0x7A}},
+ {LCM_SEND(4), {0xD5, 0x0A, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD5, 0x0B, 0x00, 0x98}},
+ {LCM_SEND(4), {0xD5, 0x0C, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD5, 0x0D, 0x00, 0xB0}},
+ {LCM_SEND(4), {0xD5, 0x0E, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD5, 0x0F, 0x00, 0xDB}},
+ {LCM_SEND(4), {0xD6, 0x00, 0x00, 0x01}},
+ {LCM_SEND(4), {0xD6, 0x01, 0x00, 0x01}},
+ {LCM_SEND(4), {0xD6, 0x02, 0x00, 0x01}},
+ {LCM_SEND(4), {0xD6, 0x03, 0x00, 0x3F}},
+ {LCM_SEND(4), {0xD6, 0x04, 0x00, 0x01}},
+ {LCM_SEND(4), {0xD6, 0x05, 0x00, 0x70}},
+ {LCM_SEND(4), {0xD6, 0x06, 0x00, 0x01}},
+ {LCM_SEND(4), {0xD6, 0x07, 0x00, 0xB4}},
+ {LCM_SEND(4), {0xD6, 0x08, 0x00, 0x01}},
+ {LCM_SEND(4), {0xD6, 0x09, 0x00, 0xEC}},
+ {LCM_SEND(4), {0xD6, 0x0A, 0x00, 0x01}},
+ {LCM_SEND(4), {0xD6, 0x0B, 0x00, 0xED}},
+ {LCM_SEND(4), {0xD6, 0x0C, 0x00, 0x02}},
+ {LCM_SEND(4), {0xD6, 0x0D, 0x00, 0x1E}},
+ {LCM_SEND(4), {0xD6, 0x0E, 0x00, 0x02}},
+ {LCM_SEND(4), {0xD6, 0x0F, 0x00, 0x51}},
+ {LCM_SEND(4), {0xD7, 0x00, 0x00, 0x02}},
+ {LCM_SEND(4), {0xD7, 0x01, 0x00, 0x6C}},
+ {LCM_SEND(4), {0xD7, 0x02, 0x00, 0x02}},
+ {LCM_SEND(4), {0xD7, 0x03, 0x00, 0x8D}},
+ {LCM_SEND(4), {0xD7, 0x04, 0x00, 0x02}},
+ {LCM_SEND(4), {0xD7, 0x05, 0x00, 0xA5}},
+ {LCM_SEND(4), {0xD7, 0x06, 0x00, 0x02}},
+ {LCM_SEND(4), {0xD7, 0x07, 0x00, 0xC9}},
+ {LCM_SEND(4), {0xD7, 0x08, 0x00, 0x02}},
+ {LCM_SEND(4), {0xD7, 0x09, 0x00, 0xEA}},
+ {LCM_SEND(4), {0xD7, 0x0A, 0x00, 0x03}},
+ {LCM_SEND(4), {0xD7, 0x0B, 0x00, 0x19}},
+ {LCM_SEND(4), {0xD7, 0x0C, 0x00, 0x03}},
+ {LCM_SEND(4), {0xD7, 0x0D, 0x00, 0x45}},
+ {LCM_SEND(4), {0xD7, 0x0E, 0x00, 0x03}},
+ {LCM_SEND(4), {0xD7, 0x0F, 0x00, 0x7A}},
+ {LCM_SEND(4), {0xD8, 0x00, 0x00, 0x03}},
+ {LCM_SEND(4), {0xD8, 0x01, 0x00, 0xA0}},
+ {LCM_SEND(4), {0xD8, 0x02, 0x00, 0x03}},
+ {LCM_SEND(4), {0xD8, 0x03, 0x00, 0xF4}},
+ {LCM_SEND(4), {0xD9, 0x00, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD9, 0x01, 0x00, 0x32}},
+ {LCM_SEND(4), {0xD9, 0x02, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD9, 0x03, 0x00, 0x41}},
+ {LCM_SEND(4), {0xD9, 0x04, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD9, 0x05, 0x00, 0x54}},
+ {LCM_SEND(4), {0xD9, 0x06, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD9, 0x07, 0x00, 0x67}},
+ {LCM_SEND(4), {0xD9, 0x08, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD9, 0x09, 0x00, 0x7A}},
+ {LCM_SEND(4), {0xD9, 0x0A, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD9, 0x0B, 0x00, 0x98}},
+ {LCM_SEND(4), {0xD9, 0x0C, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD9, 0x0D, 0x00, 0xB0}},
+ {LCM_SEND(4), {0xD9, 0x0E, 0x00, 0x00}},
+ {LCM_SEND(4), {0xD9, 0x0F, 0x00, 0xDB}},
+ {LCM_SEND(4), {0xDD, 0x00, 0x00, 0x01}},
+ {LCM_SEND(4), {0xDD, 0x01, 0x00, 0x01}},
+ {LCM_SEND(4), {0xDD, 0x02, 0x00, 0x01}},
+ {LCM_SEND(4), {0xDD, 0x03, 0x00, 0x3F}},
+ {LCM_SEND(4), {0xDD, 0x04, 0x00, 0x01}},
+ {LCM_SEND(4), {0xDD, 0x05, 0x00, 0x70}},
+ {LCM_SEND(4), {0xDD, 0x06, 0x00, 0x01}},
+ {LCM_SEND(4), {0xDD, 0x07, 0x00, 0xB4}},
+ {LCM_SEND(4), {0xDD, 0x08, 0x00, 0x01}},
+ {LCM_SEND(4), {0xDD, 0x09, 0x00, 0xEC}},
+ {LCM_SEND(4), {0xDD, 0x0A, 0x00, 0x01}},
+ {LCM_SEND(4), {0xDD, 0x0B, 0x00, 0xED}},
+ {LCM_SEND(4), {0xDD, 0x0C, 0x00, 0x02}},
+ {LCM_SEND(4), {0xDD, 0x0D, 0x00, 0x1E}},
+ {LCM_SEND(4), {0xDD, 0x0E, 0x00, 0x02}},
+ {LCM_SEND(4), {0xDD, 0x0F, 0x00, 0x51}},
+ {LCM_SEND(4), {0xDE, 0x00, 0x00, 0x02}},
+ {LCM_SEND(4), {0xDE, 0x01, 0x00, 0x6C}},
+ {LCM_SEND(4), {0xDE, 0x02, 0x00, 0x02}},
+ {LCM_SEND(4), {0xDE, 0x03, 0x00, 0x8D}},
+ {LCM_SEND(4), {0xDE, 0x04, 0x00, 0x02}},
+ {LCM_SEND(4), {0xDE, 0x05, 0x00, 0xA5}},
+ {LCM_SEND(4), {0xDE, 0x06, 0x00, 0x02}},
+ {LCM_SEND(4), {0xDE, 0x07, 0x00, 0xC9}},
+ {LCM_SEND(4), {0xDE, 0x08, 0x00, 0x02}},
+ {LCM_SEND(4), {0xDE, 0x09, 0x00, 0xEA}},
+ {LCM_SEND(4), {0xDE, 0x0A, 0x00, 0x03}},
+ {LCM_SEND(4), {0xDE, 0x0B, 0x00, 0x19}},
+ {LCM_SEND(4), {0xDE, 0x0C, 0x00, 0x03}},
+ {LCM_SEND(4), {0xDE, 0x0D, 0x00, 0x45}},
+ {LCM_SEND(4), {0xDE, 0x0E, 0x00, 0x03}},
+ {LCM_SEND(4), {0xDE, 0x0F, 0x00, 0x7A}},
+ {LCM_SEND(4), {0xDF, 0x00, 0x00, 0x03}},
+ {LCM_SEND(4), {0xDF, 0x01, 0x00, 0xA0}},
+ {LCM_SEND(4), {0xDF, 0x02, 0x00, 0x03}},
+ {LCM_SEND(4), {0xDF, 0x03, 0x00, 0xF4}},
+ {LCM_SEND(4), {0xE0, 0x00, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE0, 0x01, 0x00, 0x32}},
+ {LCM_SEND(4), {0xE0, 0x02, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE0, 0x03, 0x00, 0x41}},
+ {LCM_SEND(4), {0xE0, 0x04, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE0, 0x05, 0x00, 0x54}},
+ {LCM_SEND(4), {0xE0, 0x06, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE0, 0x07, 0x00, 0x67}},
+ {LCM_SEND(4), {0xE0, 0x08, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE0, 0x09, 0x00, 0x7A}},
+ {LCM_SEND(4), {0xE0, 0x0A, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE0, 0x0B, 0x00, 0x98}},
+ {LCM_SEND(4), {0xE0, 0x0C, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE0, 0x0D, 0x00, 0xB0}},
+ {LCM_SEND(4), {0xE0, 0x0E, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE0, 0x0F, 0x00, 0xDB}},
+ {LCM_SEND(4), {0xE1, 0x00, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE1, 0x01, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE1, 0x02, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE1, 0x03, 0x00, 0x3F}},
+ {LCM_SEND(4), {0xE1, 0x04, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE1, 0x05, 0x00, 0x70}},
+ {LCM_SEND(4), {0xE1, 0x06, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE1, 0x07, 0x00, 0xB4}},
+ {LCM_SEND(4), {0xE1, 0x08, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE1, 0x09, 0x00, 0xEC}},
+ {LCM_SEND(4), {0xE1, 0x0A, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE1, 0x0B, 0x00, 0xED}},
+ {LCM_SEND(4), {0xE1, 0x0C, 0x00, 0x02}},
+ {LCM_SEND(4), {0xE1, 0x0D, 0x00, 0x1E}},
+ {LCM_SEND(4), {0xE1, 0x0E, 0x00, 0x02}},
+ {LCM_SEND(4), {0xE1, 0x0F, 0x00, 0x51}},
+ {LCM_SEND(4), {0xE2, 0x00, 0x00, 0x02}},
+ {LCM_SEND(4), {0xE2, 0x01, 0x00, 0x6C}},
+ {LCM_SEND(4), {0xE2, 0x02, 0x00, 0x02}},
+ {LCM_SEND(4), {0xE2, 0x03, 0x00, 0x8D}},
+ {LCM_SEND(4), {0xE2, 0x04, 0x00, 0x02}},
+ {LCM_SEND(4), {0xE2, 0x05, 0x00, 0xA5}},
+ {LCM_SEND(4), {0xE2, 0x06, 0x00, 0x02}},
+ {LCM_SEND(4), {0xE2, 0x07, 0x00, 0xC9}},
+ {LCM_SEND(4), {0xE2, 0x08, 0x00, 0x02}},
+ {LCM_SEND(4), {0xE2, 0x09, 0x00, 0xEA}},
+ {LCM_SEND(4), {0xE2, 0x0A, 0x00, 0x03}},
+ {LCM_SEND(4), {0xE2, 0x0B, 0x00, 0x19}},
+ {LCM_SEND(4), {0xE2, 0x0C, 0x00, 0x03}},
+ {LCM_SEND(4), {0xE2, 0x0D, 0x00, 0x45}},
+ {LCM_SEND(4), {0xE2, 0x0E, 0x00, 0x03}},
+ {LCM_SEND(4), {0xE2, 0x0F, 0x00, 0x7A}},
+ {LCM_SEND(4), {0xE3, 0x00, 0x00, 0x03}},
+ {LCM_SEND(4), {0xE3, 0x01, 0x00, 0xA0}},
+ {LCM_SEND(4), {0xE3, 0x02, 0x00, 0x03}},
+ {LCM_SEND(4), {0xE3, 0x03, 0x00, 0xF4}},
+ {LCM_SEND(4), {0xE4, 0x00, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE4, 0x01, 0x00, 0x32}},
+ {LCM_SEND(4), {0xE4, 0x02, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE4, 0x03, 0x00, 0x41}},
+ {LCM_SEND(4), {0xE4, 0x04, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE4, 0x05, 0x00, 0x54}},
+ {LCM_SEND(4), {0xE4, 0x06, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE4, 0x07, 0x00, 0x67}},
+ {LCM_SEND(4), {0xE4, 0x08, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE4, 0x09, 0x00, 0x7A}},
+ {LCM_SEND(4), {0xE4, 0x0A, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE4, 0x0B, 0x00, 0x98}},
+ {LCM_SEND(4), {0xE4, 0x0C, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE4, 0x0D, 0x00, 0xB0}},
+ {LCM_SEND(4), {0xE4, 0x0E, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE4, 0x0F, 0x00, 0xDB}},
+ {LCM_SEND(4), {0xE5, 0x00, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE5, 0x01, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE5, 0x02, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE5, 0x03, 0x00, 0x3F}},
+ {LCM_SEND(4), {0xE5, 0x04, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE5, 0x05, 0x00, 0x70}},
+ {LCM_SEND(4), {0xE5, 0x06, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE5, 0x07, 0x00, 0xB4}},
+ {LCM_SEND(4), {0xE5, 0x08, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE5, 0x09, 0x00, 0xEC}},
+ {LCM_SEND(4), {0xE5, 0x0A, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE5, 0x0B, 0x00, 0xED}},
+ {LCM_SEND(4), {0xE5, 0x0C, 0x00, 0x02}},
+ {LCM_SEND(4), {0xE5, 0x0D, 0x00, 0x1E}},
+ {LCM_SEND(4), {0xE5, 0x0E, 0x00, 0x02}},
+ {LCM_SEND(4), {0xE5, 0x0F, 0x00, 0x51}},
+ {LCM_SEND(4), {0xE6, 0x00, 0x00, 0x02}},
+ {LCM_SEND(4), {0xE6, 0x01, 0x00, 0x6C}},
+ {LCM_SEND(4), {0xE6, 0x02, 0x00, 0x02}},
+ {LCM_SEND(4), {0xE6, 0x03, 0x00, 0x8D}},
+ {LCM_SEND(4), {0xE6, 0x04, 0x00, 0x02}},
+ {LCM_SEND(4), {0xE6, 0x05, 0x00, 0xA5}},
+ {LCM_SEND(4), {0xE6, 0x06, 0x00, 0x02}},
+ {LCM_SEND(4), {0xE6, 0x07, 0x00, 0xC9}},
+ {LCM_SEND(4), {0xE6, 0x08, 0x00, 0x02}},
+ {LCM_SEND(4), {0xE6, 0x09, 0x00, 0xEA}},
+ {LCM_SEND(4), {0xE6, 0x0A, 0x00, 0x03}},
+ {LCM_SEND(4), {0xE6, 0x0B, 0x00, 0x19}},
+ {LCM_SEND(4), {0xE6, 0x0C, 0x00, 0x03}},
+ {LCM_SEND(4), {0xE6, 0x0D, 0x00, 0x45}},
+ {LCM_SEND(4), {0xE6, 0x0E, 0x00, 0x03}},
+ {LCM_SEND(4), {0xE6, 0x0F, 0x00, 0x7A}},
+ {LCM_SEND(4), {0xE7, 0x00, 0x00, 0x03}},
+ {LCM_SEND(4), {0xE7, 0x01, 0x00, 0xA0}},
+ {LCM_SEND(4), {0xE7, 0x02, 0x00, 0x03}},
+ {LCM_SEND(4), {0xE7, 0x03, 0x00, 0xF4}},
+ {LCM_SEND(4), {0xE8, 0x00, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE8, 0x01, 0x00, 0x32}},
+ {LCM_SEND(4), {0xE8, 0x02, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE8, 0x03, 0x00, 0x41}},
+ {LCM_SEND(4), {0xE8, 0x04, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE8, 0x05, 0x00, 0x54}},
+ {LCM_SEND(4), {0xE8, 0x06, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE8, 0x07, 0x00, 0x67}},
+ {LCM_SEND(4), {0xE8, 0x08, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE8, 0x09, 0x00, 0x7A}},
+ {LCM_SEND(4), {0xE8, 0x0A, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE8, 0x0B, 0x00, 0x98}},
+ {LCM_SEND(4), {0xE8, 0x0C, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE8, 0x0D, 0x00, 0xB0}},
+ {LCM_SEND(4), {0xE8, 0x0E, 0x00, 0x00}},
+ {LCM_SEND(4), {0xE8, 0x0F, 0x00, 0xDB}},
+ {LCM_SEND(4), {0xE9, 0x00, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE9, 0x01, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE9, 0x02, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE9, 0x03, 0x00, 0x3F}},
+ {LCM_SEND(4), {0xE9, 0x04, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE9, 0x05, 0x00, 0x70}},
+ {LCM_SEND(4), {0xE9, 0x06, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE9, 0x07, 0x00, 0xB4}},
+ {LCM_SEND(4), {0xE9, 0x08, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE9, 0x09, 0x00, 0xEC}},
+ {LCM_SEND(4), {0xE9, 0x0A, 0x00, 0x01}},
+ {LCM_SEND(4), {0xE9, 0x0B, 0x00, 0xED}},
+ {LCM_SEND(4), {0xE9, 0x0C, 0x00, 0x02}},
+ {LCM_SEND(4), {0xE9, 0x0D, 0x00, 0x1E}},
+ {LCM_SEND(4), {0xE9, 0x0E, 0x00, 0x02}},
+ {LCM_SEND(4), {0xE9, 0x0F, 0x00, 0x51}},
+ {LCM_SEND(4), {0xEA, 0x00, 0x00, 0x02}},
+ {LCM_SEND(4), {0xEA, 0x01, 0x00, 0x6C}},
+ {LCM_SEND(4), {0xEA, 0x02, 0x00, 0x02}},
+ {LCM_SEND(4), {0xEA, 0x03, 0x00, 0x8D}},
+ {LCM_SEND(4), {0xEA, 0x04, 0x00, 0x02}},
+ {LCM_SEND(4), {0xEA, 0x05, 0x00, 0xA5}},
+ {LCM_SEND(4), {0xEA, 0x06, 0x00, 0x02}},
+ {LCM_SEND(4), {0xEA, 0x07, 0x00, 0xC9}},
+ {LCM_SEND(4), {0xEA, 0x08, 0x00, 0x02}},
+ {LCM_SEND(4), {0xEA, 0x09, 0x00, 0xEA}},
+ {LCM_SEND(4), {0xEA, 0x0A, 0x00, 0x03}},
+ {LCM_SEND(4), {0xEA, 0x0B, 0x00, 0x19}},
+ {LCM_SEND(4), {0xEA, 0x0C, 0x00, 0x03}},
+ {LCM_SEND(4), {0xEA, 0x0D, 0x00, 0x45}},
+ {LCM_SEND(4), {0xEA, 0x0E, 0x00, 0x03}},
+ {LCM_SEND(4), {0xEA, 0x0F, 0x00, 0x7A}},
+ {LCM_SEND(4), {0xEB, 0x00, 0x00, 0x03}},
+ {LCM_SEND(4), {0xEB, 0x01, 0x00, 0xA0}},
+ {LCM_SEND(4), {0xEB, 0x02, 0x00, 0x03}},
+ {LCM_SEND(4), {0xEB, 0x03, 0x00, 0xF4}},
+ {LCM_SEND(4), {0x3A, 0x00, 0x00, 0x07}},
+ {LCM_SEND(4), {0x35, 0x00, 0x00, 0x00}},
+
+ {LCM_SEND(2), {0x11, 0x00}},
+};
+
+static LCM_Init_Code disp_on = {LCM_SEND(2), {0x29, 0x00}};
+
+#if 0
+LCD_ERR_E Set_NT35516_I2C_Read(uint16 addr, uint32 addr_len, uint16* data, uint32 data_len)
+{
+ uint32 rtn=LCD_ERR_NONE;
+ uint8 cmd[2]={0x00};
+ uint8 value[4]={0x00};
+ //uint8 value=0;
+
+ cmd[0]=(uint8)((addr>>0x08)&0xff);
+ cmd[1]=(uint8)(addr&0xff);
+
+ rtn=I2C_WriteCmdArr(NT35516_I2C_ADDR, cmd, addr_len, NT35516_I2C_ACK);
+ rtn=I2C_ReadCmdArr(NT35516_I2C_ADDR, value, data_len,NT35516_I2C_ACK );
+
+ *data=(value[0]<<0x08)|value[1];
+ // *data = value;
+ return rtn;
+}
+#endif
+
+static int32_t nt35516_rgb_i2c_init(struct panel_spec *self)
+{
+ unsigned int i = 0;
+ unsigned int tag;
+ uint16_t data=0x00;
+ uint16_t data1=0x00;
+ uint16_t data2=0x00;
+ LCM_Init_Code *init = init_data;
+
+ i2c_write_8bits_t i2c_write_8bits = self->info.rgb->bus_info.i2c->ops->i2c_write_8bits;
+ i2c_read_8bits_t i2c_read_8bits = self->info.rgb->bus_info.i2c->ops->i2c_read_8bits;
+ i2c_write_16bits_t i2c_write_16bits = self->info.rgb->bus_info.i2c->ops->i2c_write_16bits;
+ i2c_read_16bits_t i2c_read_16bits = self->info.rgb->bus_info.i2c->ops->i2c_read_16bits;
+ i2c_write_burst_t i2c_write_burst = self->info.rgb->bus_info.i2c->ops->i2c_write_burst;
+
+ printk(KERN_DEBUG "nt35516_rgb_i2c_init\n");
+
+
+ // Set_NT35516_I2C_Read(LCDI2C_ID_ADDR, 2, &data, 2);
+ i2c_read_16bits(0xda00, false, &data, false);
+ i2c_read_16bits(0xdb00, false, &data1, false);
+ i2c_read_16bits(0xdc00, false, &data2, false);
+
+ for (i = 0 ; i < ARRAY_SIZE(init_data); i++ ) {
+ tag = (init->tag >> 24);
+ if (tag & LCM_TAG_SEND) {
+ Set_NT35516_I2C_Send((init->tag & LCM_TAG_MASK) , init->data);
+ printk(KERN_DEBUG "send one i2c data!\n");
+ } else if (tag & LCM_TAG_SLEEP) {
+ udelay((init->tag & LCM_TAG_MASK)*1000);
+ printk(KERN_DEBUG "delay!\n");
+ }
+ init++;
+ }
+ udelay(200);
+ // while(1)
+ // {
+ printk(KERN_DEBUG "send disp_on!\n");
+ Set_NT35516_I2C_Send((disp_on.tag & LCM_TAG_MASK) , disp_on.data);
+ // }
+
+ //I2C_ReadCmd(0xDB00,pCmd,NT35516_I2C_ACK);
+ //Set_NT35516_I2C_Read(0xdb00, 2, &data, 2);
+ printk(KERN_DEBUG "nt35516_rgb_i2c_init finish\n");
+
+ return 0;
+}
+
+static uint32_t nt35516_rgb_i2c_readid(struct panel_spec *self)
+{
+ /*Jessica TODO: need read id*/
+ return 0x16;
+}
+
+#if 0
+void NT35516_RGB_I2C_set_display_window(
+ uint16 left, // start Horizon address
+ uint16 right, // end Horizon address
+ uint16 top, // start Vertical address
+ uint16 bottom // end Vertical address
+ )
+{
+ unsigned char data[4];
+ data[0] = 0x2A;
+ data[1] = 0x00; data[2] = (left>>8);
+ Set_NT35516_I2C_Send(3, data);
+
+ data[1] = 0x01; data[2] = (left&0xff);
+ Set_NT35516_I2C_Send(3, data);
+
+ data[1] = 0x02; data[2] = (right>>8);
+ Set_NT35516_I2C_Send(3, data);
+
+ data[1] = 0x03; data[2] = (right&0xff);
+ Set_NT35516_I2C_Send(3, data);
+
+ data[0] = 0x2B;
+
+ data[1] = 0x00; data[2] = (top>>8);
+ Set_NT35516_I2C_Send(3, data);
+
+ data[1] = 0x01; data[2] = (top&0xff);
+ Set_NT35516_I2C_Send(3, data);
+
+ data[1] = 0x02; data[2] = (bottom>>8);
+ Set_NT35516_I2C_Send(3, data);
+
+ data[1] = 0x03; data[2] = (bottom&0xff);
+ Set_NT35516_I2C_Send(3, data);
+
+}
+
+LCD_ERR_E NT35516_RGB_I2C_EnterSleep(BOOLEAN is_sleep)
+{
+ unsigned char data[4];
+ if(is_sleep==1)
+ {
+ data[0] = 0x28;data[1] = 0x00;
+ Set_NT35516_I2C_Send(2, data);
+ LCD_Delay(200);
+
+ data[0] = 0x10;data[1] = 0x00;
+ Set_NT35516_I2C_Send(2, data);
+ LCD_Delay(200);
+ //Lcd_EnvidOnOff(0);//RGB TIMENG OFF
+ //LCD_Delay(200);
+ }
+ else
+ {
+ //Lcd_EnvidOnOff(1);//RGB TIMENG ON
+ //LCD_Delay(200);
+ //LCDinit_TFT();
+ //LCD_Delay(200);
+
+ }
+
+ return 0;
+}
+
+LCD_ERR_E NT35516_RGB_I2C_SetDisplayWindow(
+ uint16 left, //left of the window
+ uint16 top, //top of the window
+ uint16 right, //right of the window
+ uint16 bottom //bottom of the window
+ )
+{
+ unsigned char data[4];
+ //NT35516_RGB_I2C_set_display_window(left, right, top, bottom);
+ data[0] = 0x2C; data[1] = 0x00;
+ Set_NT35516_I2C_Send(2, data);
+ return TRUE;
+}
+#endif
+
+
+
+static struct panel_operations lcd_nt35516_rgb_i2c_operations = {
+ .panel_init = nt35516_rgb_i2c_init,
+ .panel_readid = nt35516_rgb_i2c_readid,
+};
+
+static struct timing_rgb lcd_nt35516_rgb_timing = {
+ .hfp = 16, /* unit: pixel */
+ .hbp = 16,
+ .hsync = 1,
+ .vfp = 16, /*unit: line*/
+ .vbp = 16,
+ .vsync = 1,
+};
+
+static struct i2c_info lcd_nt35516_rgb_i2c_info = {
+ .i2c_addr = NT35516_I2C_ADDR,
+ .ops = NULL,
+};
+
+static struct info_rgb lcd_nt35516_rgb_info = {
+ .cmd_bus_mode = SPRDFB_RGB_BUS_TYPE_I2C,
+ .video_bus_width = 24, /*18,16*/
+ .h_sync_pol = SPRDFB_POLARITY_NEG, //SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_NEG, //SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .timing = &lcd_nt35516_rgb_timing,
+ .bus_info = {
+ .i2c = &lcd_nt35516_rgb_i2c_info,
+ }
+};
+
+struct panel_spec lcd_nt35516_rgb_i2c_spec = {
+ .width = 540,
+ .height = 960,
+ .type = LCD_MODE_RGB,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .rgb = &lcd_nt35516_rgb_info
+ },
+ .ops = &lcd_nt35516_rgb_i2c_operations,
+};
+
+struct panel_cfg lcd_nt35516_rgb_i2c = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x16,
+ .lcd_name = "lcd_nt35516_rgb_i2c",
+ .panel = &lcd_nt35516_rgb_i2c_spec,
+};
+
+static int __init lcd_nt35516_rgb_i2c_init(void)
+{
+ return sprdfb_panel_register(&lcd_nt35516_rgb_i2c);
+}
+
+subsys_initcall(lcd_nt35516_rgb_i2c_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_nt35516_rgb_spi.c b/drivers/video/sprdfb/lcd/lcd_nt35516_rgb_spi.c
new file mode 100755
index 00000000..0ca42500
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_nt35516_rgb_spi.c
@@ -0,0 +1,624 @@
+/* drivers/video/sc8825/lcd_nt35516_spi.c
+ *
+ * Support for nt35516 spi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+#define NT35516_SpiWriteCmd(cmd) \
+{ \
+ spi_send_cmd((cmd & 0xFF));\
+}
+
+#define NT35516_SpiWriteData(data)\
+{ \
+ spi_send_data((data & 0xFF));\
+}
+
+static int32_t nt35516_rgb_spi_init(struct panel_spec *self)
+{
+ uint32_t data = 0;
+ spi_send_cmd_t spi_send_cmd = self->info.rgb->bus_info.spi->ops->spi_send_cmd;
+ spi_send_data_t spi_send_data = self->info.rgb->bus_info.spi->ops->spi_send_data;
+ spi_read_t spi_read = self->info.rgb->bus_info.spi->ops->spi_read;
+
+ // NT35516 + AUO 4.29'
+ // VCC=IOVCC=3.3V RGB_24Bit
+
+ //NT35516_SpiWriteCmd(0xDB00);
+ //spi_read(&data);
+
+ //TEST Commands
+
+ NT35516_SpiWriteCmd(0xFF);
+ NT35516_SpiWriteData(0xAA);//AA
+ NT35516_SpiWriteData(0x55);//55
+ NT35516_SpiWriteData(0x25);//08
+ NT35516_SpiWriteData(0x01);//01
+
+ //NT35516_SpiWriteCmd(0xFA0F); NT35516_SpiWriteData(0x20);
+
+ //NT35516_SpiWriteCmd(0xF300); NT35516_SpiWriteData(0x02);
+ //NT35516_SpiWriteCmd(0xF303); NT35516_SpiWriteData(0x15);
+
+ //ENABLE PAGE 0
+ NT35516_SpiWriteCmd(0xF0);
+ NT35516_SpiWriteData(0x55); //Manufacture Command Set Control
+ NT35516_SpiWriteData(0xAA);
+ NT35516_SpiWriteData(0x52);
+ NT35516_SpiWriteData(0x08);
+ NT35516_SpiWriteData(0x00);
+
+ NT35516_SpiWriteCmd(0xB8);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x02);
+
+ //NT35516_SpiWriteCmd(0xBC00); NT35516_SpiWriteData(0x05); //Zig-Zag Inversion
+ //NT35516_SpiWriteCmd(0xBC01); NT35516_SpiWriteData(0x05);
+ //NT35516_SpiWriteCmd(0xBC02); NT35516_SpiWriteData(0x05);
+
+ //NT35516_SpiWriteCmd(0x4C00); NT35516_SpiWriteData(0x11); //DB4=1,Enable Vivid Color,DB4=0 Disable Vivid Color
+
+ // ENABLE PAGE 1
+ NT35516_SpiWriteCmd(0xF0);
+ NT35516_SpiWriteData(0x55); //Manufacture Command Set Control
+ NT35516_SpiWriteData(0xAA);
+ NT35516_SpiWriteData(0x52);
+ NT35516_SpiWriteData(0x08);
+ NT35516_SpiWriteData(0x01);//Page1
+
+ NT35516_SpiWriteCmd(0xB0);
+ NT35516_SpiWriteData(0x05); // Setting AVDD Voltage 6V
+ NT35516_SpiWriteData(0x05);
+ NT35516_SpiWriteData(0x05);
+
+ NT35516_SpiWriteCmd(0xB6);
+ NT35516_SpiWriteData(0x44); // Setting AVEE boosting time 2.5*vpnl
+ NT35516_SpiWriteData(0x44);
+ NT35516_SpiWriteData(0x44);
+
+ NT35516_SpiWriteCmd(0xB1);
+ NT35516_SpiWriteData(0x05); // Setting AVEE Voltage -6V
+ NT35516_SpiWriteData(0x05);
+ NT35516_SpiWriteData(0x05);
+
+ //Setting AVEE boosting time -2.5xVPNL
+ NT35516_SpiWriteCmd(0xB7);
+ NT35516_SpiWriteData(0x34);
+ NT35516_SpiWriteData(0x34);
+ NT35516_SpiWriteData(0x34);
+
+ //Setting VGLX boosting time AVEE-AVDD
+ NT35516_SpiWriteCmd(0xBA);
+ NT35516_SpiWriteData(0x14); //0x24 --> 0x14
+ NT35516_SpiWriteData(0x14);
+ NT35516_SpiWriteData(0x14);
+
+ //Gamma Voltage
+ NT35516_SpiWriteCmd(0xBC);
+ NT35516_SpiWriteData(0x00);
+NT35516_SpiWriteData(0xA0);//VGMP 0x88=4.7V 0x78=4.5V 0xA0=5.0V
+NT35516_SpiWriteData(0x00);//VGSP
+
+ //Gamma Voltage
+ NT35516_SpiWriteCmd(0xBD);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0xA0);//VGMN 0x88=-4.7V 0x78=-4.5V 0xA0=-5.0V
+ NT35516_SpiWriteData(0x00);//VGSN
+
+ NT35516_SpiWriteCmd(0xBE);
+ NT35516_SpiWriteData(0x57); // Setting VCOM Offset Voltage 0x4E¸ÄΪ0x57 20111019 LIYAN
+
+ //GAMMA RED Positive
+ NT35516_SpiWriteCmd(0xD1);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x32);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x41);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x54);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x67);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x7A);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x98);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0xB0);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0xDB);
+
+ NT35516_SpiWriteCmd(0xD2);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x3F);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x70);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0xB4);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0xEC);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0xED);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x1E);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x51);
+
+ NT35516_SpiWriteCmd(0xD3);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x6C);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x8D);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0xA5);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0xC9);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0xEA);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0x19);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0x45);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0x7A);
+
+ NT35516_SpiWriteCmd(0xD4);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0xB0);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0xF4);
+
+ //Positive Gamma for GREEN
+ NT35516_SpiWriteCmd(0xD5);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x37);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x41);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x54);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x67);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x7A);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x98);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0xB0);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0xDB);
+
+ NT35516_SpiWriteCmd(0xD6);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x3F);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x70);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0xB4);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0xEC);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0xED);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x1E);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x51);
+
+ NT35516_SpiWriteCmd(0xD7);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x6C);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x8D);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0xA5);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0xC9);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0xEA);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0x19);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0x45);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0x7A);
+
+ NT35516_SpiWriteCmd(0xD8);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0xA0);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0xF4);
+
+ //Positive Gamma for BLUE
+ NT35516_SpiWriteCmd(0xD9);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x32);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x41);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x54);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x67);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x7A);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x98);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0xB0);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0xDB);
+
+ NT35516_SpiWriteCmd(0xDD);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x3F);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x70);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0xB4);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0xEC);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0xED);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x1E);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x51);
+
+ NT35516_SpiWriteCmd(0xDE);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x6C);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x8D);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0xA5);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0xC9);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0xEA);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0x19);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0x45);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0x7A);
+
+ NT35516_SpiWriteCmd(0xDF);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0xA0);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0xF4);
+
+ //Negative Gamma for RED
+ NT35516_SpiWriteCmd(0xE0);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x32);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x41);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x54);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x67);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x7A);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x98);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0xB0);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0xDB);
+
+ NT35516_SpiWriteCmd(0xE1);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x3F);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x70);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0xB4);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0xEC);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0xED);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x1E);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x51);
+
+ NT35516_SpiWriteCmd(0xE2);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x6C);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x8D);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0xA5);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0xC9);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0xEA);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0x19);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0x45);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0x7A);
+
+ NT35516_SpiWriteCmd(0xE3);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0xA0);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0xF4);
+
+ //Negative Gamma for GERREN
+ NT35516_SpiWriteCmd(0xE4);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x32);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x41);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x54);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x67);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x7A);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x98);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0xB0);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0xDB);
+
+ NT35516_SpiWriteCmd(0xE5);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x3F);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x70);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0xB4);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0xEC);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0xED);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x1E);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x51);
+
+ NT35516_SpiWriteCmd(0xE6);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x6C);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x8D);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0xA5);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0xC9);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0xEA);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0x19);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0x45);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0x7A);
+
+ NT35516_SpiWriteCmd(0xE7);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0xA0);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0xF4);
+
+ //Negative Gamma for BLUE
+ NT35516_SpiWriteCmd(0xE8);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x32);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x41);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x54);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x67);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x7A);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0x98);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0xB0);
+ NT35516_SpiWriteData(0x00);
+ NT35516_SpiWriteData(0xDB);
+
+ NT35516_SpiWriteCmd(0xE9);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x3F);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0x70);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0xB4);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0xEC);
+ NT35516_SpiWriteData(0x01);
+ NT35516_SpiWriteData(0xED);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x1E);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x51);
+
+ NT35516_SpiWriteCmd(0xEA);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x6C);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0x8D);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0xA5);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0xC9);
+ NT35516_SpiWriteData(0x02);
+ NT35516_SpiWriteData(0xEA);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0x19);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0x45);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0x7A);
+
+ NT35516_SpiWriteCmd(0xEB);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0xA0);
+ NT35516_SpiWriteData(0x03);
+ NT35516_SpiWriteData(0xF4);
+
+ NT35516_SpiWriteCmd(0x3A); NT35516_SpiWriteData(0x77);
+
+ NT35516_SpiWriteCmd(0x35); NT35516_SpiWriteData(0x00);
+
+ NT35516_SpiWriteCmd(0x11); // Sleep out
+ mdelay(140);
+
+ NT35516_SpiWriteCmd(0x29); // Display On
+ mdelay(10);
+}
+
+static uint32_t nt35516_rgb_spi_readid(struct panel_spec *self)
+{
+ /*Jessica TODO: need read id*/
+ return 0x16;
+}
+
+#if 0
+void NT35516_RGB_SPI_set_display_window(
+ uint16 left, // start Horizon address
+ uint16 right, // end Horizon address
+ uint16 top, // start Vertical address
+ uint16 bottom // end Vertical address
+ )
+{
+ NT35516_SpiWriteCmd(0x2A00); NT35516_SpiWriteData((left>>8));// set left address
+ NT35516_SpiWriteCmd(0x2A01); NT35516_SpiWriteData((left&0xff));
+ NT35516_SpiWriteCmd(0x2A02); NT35516_SpiWriteData((right>>8));// set right address
+ NT35516_SpiWriteCmd(0x2A03); NT35516_SpiWriteData((right&0xff));
+
+ NT35516_SpiWriteCmd(0x2B00); NT35516_SpiWriteData((top>>8));// set left address
+ NT35516_SpiWriteCmd(0x2B01); NT35516_SpiWriteData((top&0xff));
+ NT35516_SpiWriteCmd(0x2B02); NT35516_SpiWriteData((bottom>>8));// set bottom address
+ NT35516_SpiWriteCmd(0x2B03); NT35516_SpiWriteData((bottom&0xff));
+}
+
+LCD_ERR_E NT35516_RGB_SPI_EnterSleep(BOOLEAN is_sleep)
+{
+ if(is_sleep==1)
+ {
+ NT35516_SpiWriteCmd(0x28);
+ LCD_Delay(200);
+ NT35516_SpiWriteCmd(0x10);
+ LCD_Delay(200);
+ //Lcd_EnvidOnOff(0);//RGB TIMENG OFF
+ //LCD_Delay(200);
+
+ }
+ else
+ {
+ //Lcd_EnvidOnOff(1);//RGB TIMENG ON
+ //LCD_Delay(200);
+ //LCDinit_TFT();
+ //LCD_Delay(200);
+
+ }
+
+ return 0;
+}
+
+LCD_ERR_E NT35516_RGB_SPI_SetDisplayWindow(
+ uint16 left, //left of the window
+ uint16 top, //top of the window
+ uint16 right, //right of the window
+ uint16 bottom //bottom of the window
+ )
+{
+ //NT35516_RGB_SPI_set_display_window(left, right, top, bottom);
+
+ NT35516_SpiWriteCmd(0x2C);
+ return TRUE;
+}
+#endif
+
+
+static struct panel_operations lcd_nt35516_rgb_spi_operations = {
+ .panel_init = nt35516_rgb_spi_init,
+ .panel_readid = nt35516_rgb_spi_readid,
+};
+
+static struct timing_rgb lcd_nt35516_rgb_timing = {
+ .hfp = 30, /* unit: pixel */
+ .hbp = 16,
+ .hsync = 1,
+ .vfp = 16, /*unit: line*/
+ .vbp = 16,
+ .vsync = 1,
+};
+
+static struct spi_info lcd_nt35516_rgb_spi_info = {
+ .ops = NULL,
+};
+
+static struct info_rgb lcd_nt35516_rgb_info = {
+ .cmd_bus_mode = SPRDFB_RGB_BUS_TYPE_SPI,
+ .video_bus_width = 24, /*18,16*/
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .timing = &lcd_nt35516_rgb_timing,
+ .bus_info = {
+ .spi = &lcd_nt35516_rgb_spi_info,
+ }
+};
+
+struct panel_spec lcd_nt35516_rgb_spi_spec = {
+ .width = 540,
+ .height = 960,
+ .type = LCD_MODE_RGB,
+ .direction = LCD_DIRECT_NORMAL,
+#ifdef CONFIG_FB_SCX15
+ .fps = 56,
+#endif
+ .info = {
+ .rgb = &lcd_nt35516_rgb_info
+ },
+ .ops = &lcd_nt35516_rgb_spi_operations,
+};
+
+struct panel_cfg lcd_nt35516_rgb_spi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x16,
+ .lcd_name = "lcd_nt35516_rgb_spi",
+ .panel = &lcd_nt35516_rgb_spi_spec,
+};
+static int __init lcd_nt35516_rgb_spi_init(void)
+{
+ return sprdfb_panel_register(&lcd_nt35516_rgb_spi);
+}
+
+subsys_initcall(lcd_nt35516_rgb_spi_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_nt35596h_mipi.c b/drivers/video/sprdfb/lcd/lcd_nt35596h_mipi.c
new file mode 100644
index 00000000..ea7da76f
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_nt35596h_mipi.c
@@ -0,0 +1,841 @@
+/* drivers/video/sprdfb/lcd_nt35516_mipi.c
+ *
+ * Support for nt35516 mipi LCD device
+ *
+ * Copyright (C) 2015 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+
+#define MAX_DATA 10
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+
+{LCM_SEND(2), {0xFF,0x05}},
+{LCM_SEND(2), {0xFB,0x01}},
+{LCM_SEND(2), {0xc5,0x01}}, //Turn On NT50198
+
+{LCM_SLEEP(25)},
+{LCM_SEND(2), {0xFF,0xEE}},
+{LCM_SEND(2), {0xFB,0x01}},
+{LCM_SEND(2), {0x1F,0x45}},
+{LCM_SEND(2), {0x24,0x4F}},
+{LCM_SEND(2), {0x38,0xC8}},
+{LCM_SEND(2), {0x39,0x2C}},
+{LCM_SEND(2), {0x1E,0xBB}},
+{LCM_SEND(2), {0x1D,0x0F}},
+{LCM_SEND(2), {0x7E,0xB1}},
+{LCM_SEND(2), {0xFF,0x00}},
+{LCM_SEND(2), {0xFB,0x01}},
+{LCM_SEND(2), {0x35,0x01}},
+{LCM_SEND(2), {0xFF,0x01}},
+{LCM_SEND(2), {0xFB,0x01}},
+{LCM_SEND(2), {0x00,0x01}},
+{LCM_SEND(2), {0x01,0x55}},
+{LCM_SEND(2), {0x02,0x40}},
+{LCM_SEND(2), {0x05,0x40}},
+{LCM_SEND(2), {0x06,0x4A}},
+{LCM_SEND(2), {0x07,0x24}},
+{LCM_SEND(2), {0x08,0x0C}},
+{LCM_SEND(2), {0x0B,0x87}},
+{LCM_SEND(2), {0x0C,0x87}},
+{LCM_SEND(2), {0x0E,0xB0}},
+{LCM_SEND(2), {0x0F,0xB3}},
+{LCM_SEND(2), {0x11,0x10}},
+{LCM_SEND(2), {0x12,0x10}},
+{LCM_SEND(2), {0x13,0x05}},
+{LCM_SEND(2), {0x14,0x4A}},
+{LCM_SEND(2), {0x15,0x18}},
+{LCM_SEND(2), {0x16,0x18}},
+{LCM_SEND(2), {0x18,0x00}},
+{LCM_SEND(2), {0x19,0x77}},
+{LCM_SEND(2), {0x1A,0x55}},
+{LCM_SEND(2), {0x1B,0x13}},
+{LCM_SEND(2), {0x1C,0x00}},
+{LCM_SEND(2), {0x1D,0x00}},
+{LCM_SEND(2), {0x1E,0x13}},
+{LCM_SEND(2), {0x1F,0x00}},
+{LCM_SEND(2), {0x23,0x00}},
+{LCM_SEND(2), {0x24,0x00}},
+{LCM_SEND(2), {0x25,0x00}},
+{LCM_SEND(2), {0x26,0x00}},
+{LCM_SEND(2), {0x27,0x00}},
+{LCM_SEND(2), {0x28,0x00}},
+{LCM_SEND(2), {0x35,0x00}},
+{LCM_SEND(2), {0x66,0x00}},
+{LCM_SEND(2), {0x58,0x82}},
+{LCM_SEND(2), {0x59,0x02}},
+{LCM_SEND(2), {0x5a,0x02}},
+{LCM_SEND(2), {0x5B,0x02}},
+{LCM_SEND(2), {0x5C,0x82}},
+{LCM_SEND(2), {0x5D,0x82}},
+{LCM_SEND(2), {0x5E,0x02}},
+{LCM_SEND(2), {0x5F,0x02}},
+{LCM_SEND(2), {0x72,0x31}},
+{LCM_SEND(2), {0xFF,0x05}},
+{LCM_SEND(2), {0xFB,0x01}},
+{LCM_SEND(2), {0x00,0x01}},
+{LCM_SEND(2), {0x01,0x0B}},
+{LCM_SEND(2), {0x02,0x0C}},
+{LCM_SEND(2), {0x03,0x09}},
+{LCM_SEND(2), {0x04,0x0a}},
+{LCM_SEND(2), {0x05,0x00}},
+{LCM_SEND(2), {0x06,0x0F}},
+{LCM_SEND(2), {0x07,0x10}},
+{LCM_SEND(2), {0x08,0x00}},
+{LCM_SEND(2), {0x09,0x00}},
+{LCM_SEND(2), {0x0A,0x00}},
+{LCM_SEND(2), {0x0B,0x00}},
+{LCM_SEND(2), {0x0C,0x00}},
+{LCM_SEND(2), {0x0d,0x13}},
+{LCM_SEND(2), {0x0e,0x15}},
+{LCM_SEND(2), {0x0f,0x17}},
+{LCM_SEND(2), {0x10,0x01}},
+{LCM_SEND(2), {0x11,0x0b}},
+{LCM_SEND(2), {0x12,0x0c}},
+{LCM_SEND(2), {0x13,0x09}},
+{LCM_SEND(2), {0x14,0x0a}},
+{LCM_SEND(2), {0x15,0x00}},
+{LCM_SEND(2), {0x16,0x0f}},
+{LCM_SEND(2), {0x17,0x10}},
+{LCM_SEND(2), {0x18,0x00}},
+{LCM_SEND(2), {0x19,0x00}},
+{LCM_SEND(2), {0x1a,0x00}},
+{LCM_SEND(2), {0x1b,0x00}},
+{LCM_SEND(2), {0x1c,0x00}},
+{LCM_SEND(2), {0x1d,0x13}},
+{LCM_SEND(2), {0x1e,0x15}},
+{LCM_SEND(2), {0x1f,0x17}},
+{LCM_SEND(2), {0x20,0x00}},
+{LCM_SEND(2), {0x21,0x03}},
+{LCM_SEND(2), {0x22,0x01}},
+{LCM_SEND(2), {0x23,0x40}},
+{LCM_SEND(2), {0x24,0x40}},
+{LCM_SEND(2), {0x25,0xed}},
+{LCM_SEND(2), {0x29,0x58}},
+{LCM_SEND(2), {0x2a,0x12}},
+{LCM_SEND(2), {0x2b,0x01}},
+{LCM_SEND(2), {0x4b,0x06}},
+{LCM_SEND(2), {0x4c,0x11}},
+{LCM_SEND(2), {0x4d,0x20}},
+{LCM_SEND(2), {0x4e,0x02}},
+{LCM_SEND(2), {0x4f,0x02}},
+{LCM_SEND(2), {0x50,0x20}},
+{LCM_SEND(2), {0x51,0x61}},
+{LCM_SEND(2), {0x52,0x01}},
+{LCM_SEND(2), {0x53,0x63}},
+{LCM_SEND(2), {0x54,0x77}},
+{LCM_SEND(2), {0x55,0xed}},
+{LCM_SEND(2), {0x5b,0x00}},
+{LCM_SEND(2), {0x5c,0x00}},
+{LCM_SEND(2), {0x5d,0x00}},
+{LCM_SEND(2), {0x5e,0x00}},
+{LCM_SEND(2), {0x5f,0x15}},
+{LCM_SEND(2), {0x60,0x75}},
+{LCM_SEND(2), {0x61,0x00}},
+{LCM_SEND(2), {0x62,0x00}},
+{LCM_SEND(2), {0x63,0x00}},
+{LCM_SEND(2), {0x64,0x00}},
+{LCM_SEND(2), {0x65,0x00}},
+{LCM_SEND(2), {0x66,0x00}},
+{LCM_SEND(2), {0x67,0x00}},
+{LCM_SEND(2), {0x68,0x04}},
+{LCM_SEND(2), {0x69,0x00}},
+{LCM_SEND(2), {0x6a,0x00}},
+{LCM_SEND(2), {0x6c,0x40}},
+{LCM_SEND(2), {0x75,0x01}},
+{LCM_SEND(2), {0x76,0x01}},
+{LCM_SEND(2), {0x7a,0x80}},
+{LCM_SEND(2), {0x7b,0xc5}},
+{LCM_SEND(2), {0x7c,0xd8}},
+{LCM_SEND(2), {0x7d,0x60}},
+{LCM_SEND(2), {0x7f,0x15}},
+{LCM_SEND(2), {0x80,0x81}},
+{LCM_SEND(2), {0x83,0x05}},
+{LCM_SEND(2), {0x93,0x08}},
+{LCM_SEND(2), {0x94,0x10}},
+{LCM_SEND(2), {0x8a,0x00}},
+{LCM_SEND(2), {0x9b,0x0f}},
+{LCM_SEND(2), {0xea,0xff}},
+{LCM_SEND(2), {0xec,0x00}},
+
+{LCM_SEND(2), {0xff,0x01}}, //GAMMA
+{LCM_SEND(2), {0xfb,0x01}},
+{LCM_SEND(2), {0x75,0x00}},
+{LCM_SEND(2), {0x76,0x18}},
+{LCM_SEND(2), {0x77,0x00}},
+{LCM_SEND(2), {0x78,0x38}},
+{LCM_SEND(2), {0x79,0x00}},
+{LCM_SEND(2), {0x7a,0x65}},
+{LCM_SEND(2), {0x7b,0x00}},
+{LCM_SEND(2), {0x7c,0x84}},
+{LCM_SEND(2), {0x7d,0x00}},
+{LCM_SEND(2), {0x7e,0x9b}},
+{LCM_SEND(2), {0x7f,0x00}},
+{LCM_SEND(2), {0x80,0xaf}},
+{LCM_SEND(2), {0x81,0x00}},
+{LCM_SEND(2), {0x82,0xc1}},
+{LCM_SEND(2), {0x83,0x00}},
+{LCM_SEND(2), {0x84,0xd2}},
+{LCM_SEND(2), {0x85,0x00}},
+{LCM_SEND(2), {0x86,0xdf}},
+{LCM_SEND(2), {0x87,0x01}},
+{LCM_SEND(2), {0x88,0x11}},
+{LCM_SEND(2), {0x89,0x01}},
+{LCM_SEND(2), {0x8a,0x38}},
+{LCM_SEND(2), {0x8b,0x01}},
+{LCM_SEND(2), {0x8c,0x76}},
+{LCM_SEND(2), {0x8d,0x01}},
+{LCM_SEND(2), {0x8e,0xa7}},
+{LCM_SEND(2), {0x8f,0x01}},
+{LCM_SEND(2), {0x90,0xf3}},
+{LCM_SEND(2), {0x91,0x02}},
+{LCM_SEND(2), {0x92,0x2f}},
+{LCM_SEND(2), {0x93,0x02}},
+{LCM_SEND(2), {0x94,0x30}},
+{LCM_SEND(2), {0x95,0x02}},
+{LCM_SEND(2), {0x96,0x66}},
+{LCM_SEND(2), {0x97,0x02}},
+{LCM_SEND(2), {0x98,0xa0}},
+{LCM_SEND(2), {0x99,0x02}},
+{LCM_SEND(2), {0x9a,0xc5}},
+{LCM_SEND(2), {0x9b,0x02}},
+{LCM_SEND(2), {0x9c,0xf8}},
+{LCM_SEND(2), {0x9d,0x03}},
+{LCM_SEND(2), {0x9e,0x1b}},
+{LCM_SEND(2), {0x9f,0x03}},
+{LCM_SEND(2), {0xa0,0x46}},
+{LCM_SEND(2), {0xa2,0x03}},
+{LCM_SEND(2), {0xa3,0x52}},
+{LCM_SEND(2), {0xa4,0x03}},
+{LCM_SEND(2), {0xa5,0x62}},
+{LCM_SEND(2), {0xa6,0x03}},
+{LCM_SEND(2), {0xa7,0x71}},
+{LCM_SEND(2), {0xa9,0x03}},
+{LCM_SEND(2), {0xaa,0x83}},
+{LCM_SEND(2), {0xab,0x03}},
+{LCM_SEND(2), {0xac,0x94}},
+{LCM_SEND(2), {0xad,0x03}},
+{LCM_SEND(2), {0xae,0xa3}},
+{LCM_SEND(2), {0xaf,0x03}},
+{LCM_SEND(2), {0xb0,0xad}},
+{LCM_SEND(2), {0xb1,0x03}},
+{LCM_SEND(2), {0xb2,0xcc}},
+{LCM_SEND(2), {0xb3,0x00}},
+{LCM_SEND(2), {0xb4,0x18}},
+{LCM_SEND(2), {0xb5,0x00}},
+{LCM_SEND(2), {0xb6,0x38}},
+{LCM_SEND(2), {0xb7,0x00}},
+{LCM_SEND(2), {0xb8,0x65}},
+{LCM_SEND(2), {0xb9,0x00}},
+{LCM_SEND(2), {0xba,0x84}},
+{LCM_SEND(2), {0xbb,0x00}},
+{LCM_SEND(2), {0xbc,0x9b}},
+{LCM_SEND(2), {0xbd,0x00}},
+{LCM_SEND(2), {0xbe,0xaf}},
+{LCM_SEND(2), {0xbf,0x00}},
+{LCM_SEND(2), {0xc0,0xc1}},
+{LCM_SEND(2), {0xc1,0x00}},
+{LCM_SEND(2), {0xc2,0xd2}},
+{LCM_SEND(2), {0xc3,0x00}},
+{LCM_SEND(2), {0xc4,0xdf}},
+{LCM_SEND(2), {0xc5,0x01}},
+{LCM_SEND(2), {0xc6,0x11}},
+{LCM_SEND(2), {0xc7,0x01}},
+{LCM_SEND(2), {0xc8,0x38}},
+{LCM_SEND(2), {0xc9,0x01}},
+{LCM_SEND(2), {0xca,0x76}},
+{LCM_SEND(2), {0xcb,0x01}},
+{LCM_SEND(2), {0xcc,0xa7}},
+{LCM_SEND(2), {0xcd,0x01}},
+{LCM_SEND(2), {0xce,0xf3}},
+{LCM_SEND(2), {0xcf,0x02}},
+{LCM_SEND(2), {0xd0,0x2f}},
+{LCM_SEND(2), {0xd1,0x02}},
+{LCM_SEND(2), {0xd2,0x30}},
+{LCM_SEND(2), {0xd3,0x02}},
+{LCM_SEND(2), {0xd4,0x66}},
+{LCM_SEND(2), {0xd5,0x02}},
+{LCM_SEND(2), {0xd6,0xa0}},
+{LCM_SEND(2), {0xd7,0x02}},
+{LCM_SEND(2), {0xd8,0xc5}},
+{LCM_SEND(2), {0xd9,0x02}},
+{LCM_SEND(2), {0xda,0xf8}},
+{LCM_SEND(2), {0xdb,0x03}},
+{LCM_SEND(2), {0xdc,0x1b}},
+{LCM_SEND(2), {0xdd,0x03}},
+{LCM_SEND(2), {0xde,0x46}},
+{LCM_SEND(2), {0xdf,0x03}},
+{LCM_SEND(2), {0xe0,0x52}},
+{LCM_SEND(2), {0xe1,0x03}},
+{LCM_SEND(2), {0xe2,0x62}},
+{LCM_SEND(2), {0xe3,0x03}},
+{LCM_SEND(2), {0xe4,0x71}},
+{LCM_SEND(2), {0xe5,0x03}},
+{LCM_SEND(2), {0xe6,0x83}},
+{LCM_SEND(2), {0xe7,0x03}},
+{LCM_SEND(2), {0xe8,0x94}},
+{LCM_SEND(2), {0xe9,0x03}},
+{LCM_SEND(2), {0xea,0xa3}},
+{LCM_SEND(2), {0xeb,0x03}},
+{LCM_SEND(2), {0xec,0xad}},
+{LCM_SEND(2), {0xed,0x03}},
+{LCM_SEND(2), {0xee,0xcc}},
+{LCM_SEND(2), {0xef,0x00}},
+{LCM_SEND(2), {0xf0,0x18}},
+{LCM_SEND(2), {0xf1,0x00}},
+{LCM_SEND(2), {0xf2,0x38}},
+{LCM_SEND(2), {0xf3,0x00}},
+{LCM_SEND(2), {0xf4,0x65}},
+{LCM_SEND(2), {0xf5,0x00}},
+{LCM_SEND(2), {0xf6,0x84}},
+{LCM_SEND(2), {0xf7,0x00}},
+{LCM_SEND(2), {0xf8,0x9b}},
+{LCM_SEND(2), {0xf9,0x00}},
+{LCM_SEND(2), {0xfa,0xaf}},
+{LCM_SEND(2), {0xff,0x02}},
+{LCM_SEND(2), {0xfb,0x01}},
+{LCM_SEND(2), {0x00,0x00}},
+{LCM_SEND(2), {0x01,0xc1}},
+{LCM_SEND(2), {0x02,0x00}},
+{LCM_SEND(2), {0x03,0xd2}},
+{LCM_SEND(2), {0x04,0x00}},
+{LCM_SEND(2), {0x05,0xdf}},
+{LCM_SEND(2), {0x06,0x01}},
+{LCM_SEND(2), {0x07,0x11}},
+{LCM_SEND(2), {0x08,0x01}},
+{LCM_SEND(2), {0x09,0x38}},
+{LCM_SEND(2), {0x0a,0x01}},
+{LCM_SEND(2), {0x0b,0x76}},
+{LCM_SEND(2), {0x0c,0x01}},
+{LCM_SEND(2), {0x0d,0xa7}},
+{LCM_SEND(2), {0x0e,0x01}},
+{LCM_SEND(2), {0x0f,0xf3}},
+{LCM_SEND(2), {0x10,0x02}},
+{LCM_SEND(2), {0x11,0x2f}},
+{LCM_SEND(2), {0x12,0x02}},
+{LCM_SEND(2), {0x13,0x30}},
+{LCM_SEND(2), {0x14,0x02}},
+{LCM_SEND(2), {0x15,0x66}},
+{LCM_SEND(2), {0x16,0x02}},
+{LCM_SEND(2), {0x17,0xa0}},
+{LCM_SEND(2), {0x18,0x02}},
+{LCM_SEND(2), {0x19,0xc5}},
+{LCM_SEND(2), {0x1a,0x02}},
+{LCM_SEND(2), {0x1b,0xf8}},
+{LCM_SEND(2), {0x1c,0x03}},
+{LCM_SEND(2), {0x1d,0x1b}},
+{LCM_SEND(2), {0x1e,0x03}},
+{LCM_SEND(2), {0x1f,0x46}},
+{LCM_SEND(2), {0x20,0x03}},
+{LCM_SEND(2), {0x21,0x52}},
+{LCM_SEND(2), {0x22,0x03}},
+{LCM_SEND(2), {0x23,0x62}},
+{LCM_SEND(2), {0x24,0x03}},
+{LCM_SEND(2), {0x25,0x71}},
+{LCM_SEND(2), {0x26,0x03}},
+{LCM_SEND(2), {0x27,0x83}},
+{LCM_SEND(2), {0x28,0x03}},
+{LCM_SEND(2), {0x29,0x94}},
+{LCM_SEND(2), {0x2a,0x03}},
+{LCM_SEND(2), {0x2b,0xa3}},
+{LCM_SEND(2), {0x2d,0x03}},
+{LCM_SEND(2), {0x2f,0xad}},
+{LCM_SEND(2), {0x30,0x03}},
+{LCM_SEND(2), {0x31,0xcc}},
+{LCM_SEND(2), {0x32,0x00}},
+{LCM_SEND(2), {0x33,0x18}},
+{LCM_SEND(2), {0x34,0x00}},
+{LCM_SEND(2), {0x35,0x38}},
+{LCM_SEND(2), {0x36,0x00}},
+{LCM_SEND(2), {0x37,0x65}},
+{LCM_SEND(2), {0x38,0x00}},
+{LCM_SEND(2), {0x39,0x84}},
+{LCM_SEND(2), {0x3a,0x00}},
+{LCM_SEND(2), {0x3b,0x9b}},
+{LCM_SEND(2), {0x3d,0x00}},
+{LCM_SEND(2), {0x3f,0xaf}},
+{LCM_SEND(2), {0x40,0x00}},
+{LCM_SEND(2), {0x41,0xc1}},
+{LCM_SEND(2), {0x42,0x00}},
+{LCM_SEND(2), {0x43,0xd2}},
+{LCM_SEND(2), {0x44,0x00}},
+{LCM_SEND(2), {0x45,0xdf}},
+{LCM_SEND(2), {0x46,0x01}},
+{LCM_SEND(2), {0x47,0x11}},
+{LCM_SEND(2), {0x48,0x01}},
+{LCM_SEND(2), {0x49,0x38}},
+{LCM_SEND(2), {0x4a,0x01}},
+{LCM_SEND(2), {0x4b,0x76}},
+{LCM_SEND(2), {0x4c,0x01}},
+{LCM_SEND(2), {0x4d,0xa7}},
+{LCM_SEND(2), {0x4e,0x01}},
+{LCM_SEND(2), {0x4f,0xf3}},
+{LCM_SEND(2), {0x50,0x02}},
+{LCM_SEND(2), {0x51,0x2f}},
+{LCM_SEND(2), {0x52,0x02}},
+{LCM_SEND(2), {0x53,0x30}},
+{LCM_SEND(2), {0x54,0x02}},
+{LCM_SEND(2), {0x55,0x66}},
+{LCM_SEND(2), {0x56,0x02}},
+{LCM_SEND(2), {0x58,0xa0}},
+{LCM_SEND(2), {0x59,0x02}},
+{LCM_SEND(2), {0x5a,0xc5}},
+{LCM_SEND(2), {0x5b,0x02}},
+{LCM_SEND(2), {0x5c,0xf8}},
+{LCM_SEND(2), {0x5d,0x03}},
+{LCM_SEND(2), {0x5e,0x1b}},
+{LCM_SEND(2), {0x5f,0x03}},
+{LCM_SEND(2), {0x60,0x46}},
+{LCM_SEND(2), {0x61,0x03}},
+{LCM_SEND(2), {0x62,0x52}},
+{LCM_SEND(2), {0x63,0x03}},
+{LCM_SEND(2), {0x64,0x62}},
+{LCM_SEND(2), {0x65,0x03}},
+{LCM_SEND(2), {0x66,0x71}},
+{LCM_SEND(2), {0x67,0x03}},
+{LCM_SEND(2), {0x68,0x83}},
+{LCM_SEND(2), {0x69,0x03}},
+{LCM_SEND(2), {0x6a,0x94}},
+{LCM_SEND(2), {0x6b,0x03}},
+{LCM_SEND(2), {0x6c,0xa3}},
+{LCM_SEND(2), {0x6d,0x03}},
+{LCM_SEND(2), {0x6e,0xad}},
+{LCM_SEND(2), {0x6f,0x03}},
+{LCM_SEND(2), {0x70,0xcc}},
+{LCM_SEND(2), {0x71,0x00}},
+{LCM_SEND(2), {0x72,0x18}},
+{LCM_SEND(2), {0x73,0x00}},
+{LCM_SEND(2), {0x74,0x38}},
+{LCM_SEND(2), {0x75,0x00}},
+{LCM_SEND(2), {0x76,0x65}},
+{LCM_SEND(2), {0x77,0x00}},
+{LCM_SEND(2), {0x78,0x84}},
+{LCM_SEND(2), {0x79,0x00}},
+{LCM_SEND(2), {0x7a,0x9b}},
+{LCM_SEND(2), {0x7b,0x00}},
+{LCM_SEND(2), {0x7c,0xaf}},
+{LCM_SEND(2), {0x7d,0x00}},
+{LCM_SEND(2), {0x7e,0xc1}},
+{LCM_SEND(2), {0x7f,0x00}},
+{LCM_SEND(2), {0x80,0xd2}},
+{LCM_SEND(2), {0x81,0x00}},
+{LCM_SEND(2), {0x82,0xdf}},
+{LCM_SEND(2), {0x83,0x01}},
+{LCM_SEND(2), {0x84,0x11}},
+{LCM_SEND(2), {0x85,0x01}},
+{LCM_SEND(2), {0x86,0x38}},
+{LCM_SEND(2), {0x87,0x01}},
+{LCM_SEND(2), {0x88,0x76}},
+{LCM_SEND(2), {0x89,0x01}},
+{LCM_SEND(2), {0x8a,0xa7}},
+{LCM_SEND(2), {0x8b,0x01}},
+{LCM_SEND(2), {0x8c,0xf3}},
+{LCM_SEND(2), {0x8d,0x02}},
+{LCM_SEND(2), {0x8e,0x2f}},
+{LCM_SEND(2), {0x8f,0x02}},
+{LCM_SEND(2), {0x90,0x30}},
+{LCM_SEND(2), {0x91,0x02}},
+{LCM_SEND(2), {0x92,0x66}},
+{LCM_SEND(2), {0x93,0x02}},
+{LCM_SEND(2), {0x94,0xa0}},
+{LCM_SEND(2), {0x95,0x02}},
+{LCM_SEND(2), {0x96,0xc5}},
+{LCM_SEND(2), {0x97,0x02}},
+{LCM_SEND(2), {0x98,0xf8}},
+{LCM_SEND(2), {0x99,0x03}},
+{LCM_SEND(2), {0x9a,0x1b}},
+{LCM_SEND(2), {0x9b,0x03}},
+{LCM_SEND(2), {0x9c,0x46}},
+{LCM_SEND(2), {0x9d,0x03}},
+{LCM_SEND(2), {0x9e,0x52}},
+{LCM_SEND(2), {0x9f,0x03}},
+{LCM_SEND(2), {0xa0,0x62}},
+{LCM_SEND(2), {0xa2,0x03}},
+{LCM_SEND(2), {0xa3,0x71}},
+{LCM_SEND(2), {0xa4,0x03}},
+{LCM_SEND(2), {0xa5,0x83}},
+{LCM_SEND(2), {0xa6,0x03}},
+{LCM_SEND(2), {0xa7,0x94}},
+{LCM_SEND(2), {0xa9,0x03}},
+{LCM_SEND(2), {0xaa,0xa3}},
+{LCM_SEND(2), {0xab,0x03}},
+{LCM_SEND(2), {0xac,0xad}},
+{LCM_SEND(2), {0xad,0x03}},
+{LCM_SEND(2), {0xae,0xcc}},
+{LCM_SEND(2), {0xaf,0x00}},
+{LCM_SEND(2), {0xb0,0x18}},
+{LCM_SEND(2), {0xb1,0x00}},
+{LCM_SEND(2), {0xb2,0x38}},
+{LCM_SEND(2), {0xb3,0x00}},
+{LCM_SEND(2), {0xb4,0x65}},
+{LCM_SEND(2), {0xb5,0x00}},
+{LCM_SEND(2), {0xb6,0x84}},
+{LCM_SEND(2), {0xb7,0x00}},
+{LCM_SEND(2), {0xb8,0x9b}},
+{LCM_SEND(2), {0xb9,0x00}},
+{LCM_SEND(2), {0xba,0xaf}},
+{LCM_SEND(2), {0xbb,0x00}},
+{LCM_SEND(2), {0xbc,0xc1}},
+{LCM_SEND(2), {0xbd,0x00}},
+{LCM_SEND(2), {0xbe,0xd2}},
+{LCM_SEND(2), {0xbf,0x00}},
+{LCM_SEND(2), {0xc0,0xdf}},
+{LCM_SEND(2), {0xc1,0x01}},
+{LCM_SEND(2), {0xc2,0x11}},
+{LCM_SEND(2), {0xc3,0x01}},
+{LCM_SEND(2), {0xc4,0x38}},
+{LCM_SEND(2), {0xc5,0x01}},
+{LCM_SEND(2), {0xc6,0x76}},
+{LCM_SEND(2), {0xc7,0x01}},
+{LCM_SEND(2), {0xc8,0xa7}},
+{LCM_SEND(2), {0xc9,0x01}},
+{LCM_SEND(2), {0xca,0xf3}},
+{LCM_SEND(2), {0xcb,0x02}},
+{LCM_SEND(2), {0xcc,0x2f}},
+{LCM_SEND(2), {0xcd,0x02}},
+{LCM_SEND(2), {0xce,0x30}},
+{LCM_SEND(2), {0xcf,0x02}},
+{LCM_SEND(2), {0xd0,0x66}},
+{LCM_SEND(2), {0xd1,0x02}},
+{LCM_SEND(2), {0xd2,0xa0}},
+{LCM_SEND(2), {0xd3,0x02}},
+{LCM_SEND(2), {0xd4,0xc5}},
+{LCM_SEND(2), {0xd6,0xf8}},
+{LCM_SEND(2), {0xd7,0x03}},
+{LCM_SEND(2), {0xd8,0x1b}},
+{LCM_SEND(2), {0xd9,0x03}},
+{LCM_SEND(2), {0xda,0x46}},
+{LCM_SEND(2), {0xdb,0x03}},
+{LCM_SEND(2), {0xdc,0x52}},
+{LCM_SEND(2), {0xdd,0x03}},
+{LCM_SEND(2), {0xde,0x62}},
+{LCM_SEND(2), {0xdf,0x03}},
+{LCM_SEND(2), {0xe0,0x71}},
+{LCM_SEND(2), {0xe1,0x03}},
+{LCM_SEND(2), {0xe2,0x83}},
+{LCM_SEND(2), {0xe3,0x03}},
+{LCM_SEND(2), {0xe4,0x94}},
+{LCM_SEND(2), {0xe5,0x03}},
+{LCM_SEND(2), {0xe6,0xa3}},
+{LCM_SEND(2), {0xe7,0x03}},
+{LCM_SEND(2), {0xe8,0xad}},
+{LCM_SEND(2), {0xe9,0x03}},
+{LCM_SEND(2), {0xea,0xcc}}, //GAMMA END
+
+{LCM_SEND(2), {0xff,0x01}},
+{LCM_SEND(2), {0xfb,0x01}},
+{LCM_SEND(2), {0xff,0x02}},
+{LCM_SEND(2), {0xfb,0x01}},
+{LCM_SEND(2), {0xff,0x04}},
+{LCM_SEND(2), {0xfb,0x01}},
+{LCM_SEND(2), {0xff,0x00}},
+{LCM_SEND(2), {0xD3,0x05}}, //VBP VFP VSPW
+{LCM_SEND(2), {0xD4,0x04}},
+
+{LCM_SEND(1), {0x11}}, //sleep out
+{LCM_SLEEP(150)},
+
+{LCM_SEND(2), {0xff,0x00}}, //Tearing Effect Line ON
+{LCM_SEND(2), {0x35,0x00}},
+
+{LCM_SEND(1), {0x29}}, //display on
+{LCM_SLEEP(100)},
+
+{LCM_SEND(2), {0x51,0x00}}, //CABC setting
+{LCM_SEND(2), {0x5e,0x00}},
+{LCM_SEND(2), {0x53,0x2c}},
+{LCM_SEND(2), {0x55,0x00}},
+};
+
+//static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+{LCM_SEND(1), {0x28}},
+{LCM_SLEEP(10)},
+{LCM_SEND(1), {0x10}},
+{LCM_SLEEP(120)},
+//{LCM_SEND(2), {0x4f, 0x01}}, /* this code may cause not resume bug*/
+};
+
+static LCM_Init_Code sleep_out[] = {
+{LCM_SEND(1), {0x11}},
+{LCM_SLEEP(120)},
+{LCM_SEND(1), {0x29}},
+{LCM_SLEEP(20)},
+};
+
+static LCM_Force_Cmd_Code rd_prep_code[]={
+// {0x39, {LCM_SEND(8), {0x6, 0, 0xF0, 0x55, 0xAA, 0x52, 0x08, 0x01}}},
+ {0x37, {LCM_SEND(2), {0x3, 0}}},
+};
+
+static LCM_Force_Cmd_Code rd_prep_code_1[]={
+ {0x37, {LCM_SEND(2), {0x1, 0}}},
+};
+static int32_t nt35596h_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+
+ pr_debug(KERN_DEBUG "sprdfb:nt35596h_mipi_init\n");
+
+ mipi_set_cmd_mode();
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((init->tag & LCM_TAG_MASK));
+ }
+ init++;
+ }
+ return 0;
+}
+
+static uint32_t nt35596h_readid(struct panel_spec *self)
+{
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code;
+ uint8_t read_data[3] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("sprdfb:lcd_nt35596h_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,1);
+
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }
+ rd_prepare++;
+ }
+ read_rtn = mipi_force_read(0xF4, 1,(uint8_t *)read_data);
+ printk("lcd_nt35596h_mipi read id 0xF4 value is 0x%x, 0x%x, 0x%x!\n", read_data[0], read_data[1], read_data[2]);
+
+ if(0x96 == read_data[0]){
+ printk("lcd_nt35596h_mipi read id success!\n");
+ mipi_eotp_set(1,1);
+ return 0x96;
+ }
+ }
+ mipi_eotp_set(1,1);
+ return 0x0;
+}
+
+static int32_t nt35596h_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i = 0;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+
+ printk(KERN_DEBUG "nt35596h_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((sleep_in_out->tag & LCM_TAG_MASK));
+ }
+ sleep_in_out++;
+ }
+ return 0;
+}
+
+static uint32_t nt35596h_readpowermode(struct panel_spec *self)
+{
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code_1;
+ uint8_t read_data[1] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_debug("lcd_nt35596h_mipi read power mode!\n");
+ mipi_eotp_set(0,1);
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code_1;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code_1); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }
+ rd_prepare++;
+ }
+ read_rtn = mipi_force_read(0x0A, 1,(uint8_t *)read_data);
+ //printk("lcd_nt35516 mipi read power mode 0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+ if(0x08 == read_data[0]){
+ pr_debug("lcd_nt35596h_mipi read power mode success!\n");
+ mipi_eotp_set(1,1);
+ return 0x9c;
+ }
+ }
+
+ printk("lcd_nt35596h mipi read power mode fail!0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+ mipi_eotp_set(1,1);
+ return 0x0;
+}
+
+static int32_t nt35596h_check_esd(struct panel_spec *self)
+{
+ uint32_t power_mode;
+
+#ifndef FB_CHECK_ESD_IN_VFP
+ mipi_set_lp_mode_t mipi_set_data_lp_mode = self->info.mipi->ops->mipi_set_data_lp_mode;
+ mipi_set_hs_mode_t mipi_set_data_hs_mode = self->info.mipi->ops->mipi_set_data_hs_mode;
+ mipi_set_lp_mode_t mipi_set_lp_mode = self->info.mipi->ops->mipi_set_lp_mode;
+ mipi_set_hs_mode_t mipi_set_hs_mode = self->info.mipi->ops->mipi_set_hs_mode;
+ uint16_t work_mode = self->info.mipi->work_mode;
+#endif
+
+ pr_debug("nt35596h_check_esd!\n");
+#ifndef FB_CHECK_ESD_IN_VFP
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_lp_mode();
+ }else{
+ mipi_set_data_lp_mode();
+ }
+#endif
+ power_mode = nt35596h_readpowermode(self);
+ //power_mode = 0x0;
+#ifndef FB_CHECK_ESD_IN_VFP
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_hs_mode();
+ }else{
+ mipi_set_data_hs_mode();
+ }
+#endif
+ if(power_mode == 0x9c){
+ pr_debug("nt35596h_check_esd OK!\n");
+ return 1;
+ }else{
+ printk("nt35596h_check_esd fail!(0x%x)\n", power_mode);
+ return 0;
+ }
+}
+
+static struct panel_operations lcd_nt35596h_mipi_operations = {
+ .panel_init = nt35596h_mipi_init,
+ .panel_readid = nt35596h_readid,
+ .panel_enter_sleep = nt35596h_enter_sleep,
+ .panel_esd_check = nt35596h_check_esd,
+};
+
+static struct timing_rgb lcd_nt35596h_mipi_timing = {
+ .hfp = 20, /* unit: pixel */
+ .hbp = 20,
+ .hsync = 20,//4,
+ .vfp = 10, /*unit: line*/
+ .vbp = 10,
+ .vsync = 6,
+};
+
+static struct info_mipi lcd_nt35596h_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 4,
+ .phy_feq = 1000*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_nt35596h_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_nt35596h_mipi_spec = {
+ .width = 1080,
+ .height = 1920,
+ .fps = 40,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .is_clean_lcd = true,
+ .info = {
+ .mipi = &lcd_nt35596h_mipi_info
+ },
+ .ops = &lcd_nt35596h_mipi_operations,
+};
+
+struct panel_cfg lcd_nt35596h_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x96,
+ .lcd_name = "lcd_nt35596h_mipi",
+ .panel = &lcd_nt35596h_mipi_spec,
+};
+
+static int __init lcd_nt35596h_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_nt35596h_mipi);
+}
+
+subsys_initcall(lcd_nt35596h_mipi_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_nt51017_goyal_mipi.c b/drivers/video/sprdfb/lcd/lcd_nt51017_goyal_mipi.c
new file mode 100755
index 00000000..1f081bee
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_nt51017_goyal_mipi.c
@@ -0,0 +1,296 @@
+/* drivers/video/sprdfb/lcd_nt51017_mipi.c
+ *
+ * Support for nt51017 mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+#include <mach/gpio.h>
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 150
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+
+
+
+static LCM_Init_Code init_data[] = {
+ {LCM_SEND(2), {0x83, 0x96} },
+ {LCM_SEND(2), {0x84, 0x69} },
+ {LCM_SEND(2), {0x92, 0x19} },
+ {LCM_SEND(2), {0x83, 0x00} },
+ {LCM_SEND(2), {0x84, 0x00} },
+ {LCM_SEND(2), {0x96, 0x00} },
+
+};
+
+
+static LCM_Init_Code sleep_in[] = {
+
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(170)},
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(170)},
+
+};
+
+
+static int32_t nt51017_mipi_init(struct panel_spec *self)
+{
+
+ if (gpio_request(232, "LED_EN0")) {
+ printk("Failed ro request LCD_BL GPIO_%d \n",232);
+ return -ENODEV;
+ }
+ gpio_direction_output(232, 1);
+ gpio_set_value(232, 1);
+
+ if (gpio_request(233, "LED_EN1")) {
+ printk("Failed ro request LCD_BL GPIO_%d \n",233);
+ return -ENODEV;
+ }
+ gpio_direction_output(233, 1);
+ gpio_set_value(233, 1);
+
+ mdelay(200);
+
+ int32_t i;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("lcd_nt51017_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ mdelay(init->tag & LCM_TAG_MASK);//udelay((init->tag & LCM_TAG_MASK) * 1000);
+ }
+ init++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t nt51017_readid(struct panel_spec *self)
+{
+#if 0
+ uint32 j =0;
+ uint8_t read_data[4] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("lcd_nt51017_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x01;
+ param[1] = 0x00;
+ mipi_force_write(0x37, param, 2);
+ read_rtn = mipi_force_read(0xda,1,&read_data[0]);
+ printk("lcd_nt51017_mipi read id 0xda value is 0x%x!\n",read_data[0]);
+
+ read_rtn = mipi_force_read(0xdb,1,&read_data[1]);
+ printk("lcd_nt51017_mipi read id 0xdb value is 0x%x!\n",read_data[1]);
+
+ read_rtn = mipi_force_read(0xdc,1,&read_data[2]);
+ printk("lcd_nt51017_mipi read id 0xdc value is 0x%x!\n",read_data[2]);
+
+ if((0x55 == read_data[0])&&(0xbf == read_data[1] || 0xc0 == read_data[1] || 0xbe == read_data[1])&&(0x90 == read_data[2])){
+ printk("lcd_nt51017_mipi read id success!\n");
+ return 0x8369;
+ }
+ }
+
+ mipi_eotp_set(0,0);
+
+ printk("lcd_s6d77a1_mipi read id failed!\n");
+ return 0;
+#endif
+ return 0x51017;
+}
+
+static int32_t nt51017_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i = 0;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel nt51017_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(sleep_in_out->tag & LCM_TAG_MASK);
+ }
+ sleep_in_out++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static int32_t nt51017_before_resume(struct panel_spec *self, uint8_t is_sleep)
+{
+ gpio_set_value(152, 1);
+ gpio_set_value(155, 1);
+ gpio_set_value(232, 1);
+ gpio_set_value(233, 1);
+}
+
+static int32_t nt51017_after_suspend(struct panel_spec *self, uint8_t is_sleep)
+{
+ gpio_set_value(152, 0);
+ gpio_set_value(155, 0);
+ gpio_set_value(232, 0);
+ gpio_set_value(233, 0);
+}
+
+static struct panel_operations lcd_nt51017_mipi_operations = {
+ .panel_init = nt51017_mipi_init,
+ .panel_readid = nt51017_readid,
+ .panel_enter_sleep = nt51017_enter_sleep,
+ .panel_before_resume = nt51017_before_resume,
+ .panel_after_suspend = nt51017_after_suspend,
+};
+
+static struct timing_rgb lcd_nt51017_mipi_timing = {
+
+ .hfp = 80, /* unit: pixel */
+ .hbp = 80,
+ .hsync = 1,
+ .vfp = 18, /*unit: line*/
+ .vbp = 23,
+ .vsync = 1,
+
+};
+
+
+static struct info_mipi lcd_nt51017_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 4,
+ .phy_feq =481*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_nt51017_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_nt51017_mipi_spec = {
+ .width = 800,
+ .height =1280,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .suspend_mode = SEND_SLEEP_CMD,
+ .info = {
+ .mipi = &lcd_nt51017_mipi_info
+ },
+ .ops = &lcd_nt51017_mipi_operations,
+};
+struct panel_cfg lcd_nt51017_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x51017,
+ .lcd_name = "lcd_nt51017_mipi",
+ .panel = &lcd_nt51017_mipi_spec,
+};
+
+
+static int __init lcd_nt51017_mipi_init(void)
+{
+ if (gpio_request(152, "LCD_3V3")) {
+ printk("Failed ro request LCD_3V3 GPIO_%d \n",152);
+ return -ENODEV;
+ }
+ if (gpio_request(155, "BL_EN")) {
+ printk("Failed ro request BL_EN GPIO_%d \n",155);
+ return -ENODEV;
+ }
+ if (gpio_request(232, "CABC_EN0")) {
+ printk("Failed ro request CABC_EN0 GPIO_%d \n",232);
+ return -ENODEV;
+ }
+ if (gpio_request(233, "CABC_EN1")) {
+ printk("Failed ro request CABC_EN1 GPIO_%d \n",233);
+ return -ENODEV;
+ }
+ gpio_direction_output(152, 1);
+ gpio_direction_output(155, 1);
+ gpio_direction_output(232, 1);
+ gpio_direction_output(233, 1);
+
+ return sprdfb_panel_register(&lcd_nt51017_mipi);
+}
+
+subsys_initcall(lcd_nt51017_mipi_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_nt51017_mipi_lvds.c b/drivers/video/sprdfb/lcd/lcd_nt51017_mipi_lvds.c
new file mode 100644
index 00000000..e5689072
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_nt51017_mipi_lvds.c
@@ -0,0 +1,589 @@
+/* drivers/video/sprdfb/lcd_nt51017_mipi_lvds.c
+ *
+ * Support for nt51017 lvds LCD device
+ *
+ * Copyright (C) 2013 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+//#include <asm/arch/sprd_lcd.h>
+//#include <asm/arch/sprd_i2c.h>
+#include <linux/kernel.h>
+//#include <linux/bug.h>
+#include <linux/delay.h>
+//#include <linux/platform_device.h>
+#include <linux/i2c.h>
+//#include <include/asm/gpio.h>
+//#include "sp8830_i2c.h"
+#include "../sprdfb_panel.h"
+
+//#define printk printf
+
+//#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+/***************** Important Macro! *****************/
+/* For TI! ONLY ONE of the flowing marco can be defined! */
+//#define LINES_ALL_RIGHT_TI
+#define LINES_ONLY_CLK_RIGHT_TI
+
+/* For CHIPONE! ONLY ONE of the flowing marco can be defined! */
+#if 1
+#define LINES_ALL_WRONG_C1
+#else // 5735A-2 v1.0.1
+#define LINES_ALL_RIGHT_C1
+#endif
+/***************** Important Macro! *****************/
+
+struct bridge_ops {
+ int32_t (*init)(struct panel_spec *self);
+ int32_t (*suspend)(struct panel_spec *self);
+};
+
+static struct bridge_ops b_ops = {
+ .init = NULL,
+ .suspend = NULL,
+};
+
+
+#define I2CID_BRIDGE 2
+#define I2C_NT50366_ADDR_WRITE 0x9E /* NT50169 100_1111 0 */
+#define I2C_NT51017_ADDR_WRITE 0xD0 /* NT51017 110_1000 0 */
+#define I2C_BRIDGE_ADDR_WRITE0 0x2C /* 0 010_1100 ADDR=Low */
+#define I2C_BRIDGE_ADDR_WRITE1 0x2D /* 0 010_1101 ADDR=High */
+#define I2C_BRIDGE_ADDR I2C_BRIDGE_ADDR_WRITE0
+
+
+#define GPIOID_LCMRSTN 103 /* should modify pinmap */
+#define GPIOID_STBYB 230 /* should modify pinmap */
+#define GPIOID_BRIDGE_EN 231
+#define GPIOID_VDDPWR 232
+#define GPIOID_ADDR 234 /* should modify pinmap */
+#define GPIOID_LCDPWR 235
+
+#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+extern int gpio_direction_output(unsigned gpio, int value);
+extern int gpio_request(unsigned gpio, const char *label);
+extern void gpio_free(unsigned gpio);
+
+const static __u8 i2c_msg_buf_ti[][2] = {
+ {0x09, 0x00},
+ {0x0A, 0x03},
+ {0x0B, 0x18},
+ {0x0D, 0x00},
+ {0x10, 0x26},
+ {0x11, 0x00},
+ {0x12, 0x31},
+ {0x13, 0x00},
+#ifdef LINES_ALL_RIGHT_TI
+ {0x18, 0x18},/* all the line is right */
+#elif defined LINES_ONLY_CLK_RIGHT_TI
+ {0x18, 0xF8},/* only clock line is right */
+#endif
+ {0x19, 0x0C},/* 0x00 */
+ {0x1A, 0x03},
+ {0x1B, 0x00},
+ {0x20, 0x00},
+ {0x21, 0x03},
+ {0x22, 0x00},
+ {0x23, 0x00},
+ {0x24, 0x00},
+ {0x25, 0x00},
+ {0x26, 0x00},
+ {0x27, 0x00},
+ {0x28, 0x20},
+ {0x29, 0x00},
+ {0x2A, 0x00},
+ {0x2B, 0x00},
+ {0x2C, 0x04},/*0x04*/
+ {0x2D, 0x00},
+ {0x2E, 0x00},
+ {0x2F, 0x00},
+ {0x30, 0x04},/*0x04*/
+ {0x31, 0x00},
+ {0x32, 0x00},
+ {0x33, 0x00},
+ {0x34, 0x4C},
+ {0x35, 0x00},
+ {0x36, 0x00},
+ {0x37, 0x00},
+ {0x38, 0x00},
+ {0x39, 0x00},
+ {0x3A, 0x00},
+ {0x3B, 0x00},
+ {0x3C, 0x00},
+ {0x3D, 0x00},
+ {0x3E, 0x00},
+};
+const static __u8 i2c_msg_buf_c1[][2] = {
+ /*{0x10, 0x4E},add*/
+ {0x20, 0x00},
+ {0x21, 0x00},
+ {0x22, 0x43},
+ {0x23, 0x28},
+ {0x24, 0x04},
+ {0x25, 0x4C},
+ {0x26, 0x00},
+ {0x27, 0x12},
+ {0x28, 0x04},/*0x02*/
+ {0x29, 0x13},
+ {0x2A, 0x01},
+ {0x34, 0xF0},/*add*/
+ {0x36, 0x50},/*add*/
+ {0x86, 0x2B},
+ {0xB5, 0xA0},
+ {0x51, 0x20},
+ {0x56, 0x92},
+ {0x69, 0x1C},/*0x1F*/
+ {0x6B, 0x22},
+ {0x5C, 0xFF},
+ {0xB6, 0x20},
+#ifdef LINES_ALL_RIGHT_C1
+ {0x13, 0x10},
+#elif defined LINES_ONLY_CLK_RIGHT_C1
+ {0x13, 0x1F},
+#elif defined LINES_ALL_WRONG_C1
+ {0x13, 0x5F},
+#endif
+ /*{0x10, 0x47},add*/
+ /*{0x2A, 0x31},modify*/
+ /*{0x2E, 0x40},add*/
+ /*{0x2F, 0x40},add*/
+ {0x09, 0x10},
+ /*{0x7B, 0xF2},*/
+ /*{0x7C, 0xF3},*/
+};
+
+static struct i2c_msg msg_w = {
+ .addr = I2C_BRIDGE_ADDR,
+ .flags = 0,
+ .len = 2,
+ .buf = NULL,
+};
+
+static struct i2c_msg msg_r[] = {
+ [0] = {
+ .addr = I2C_BRIDGE_ADDR,
+ .flags = 0,
+ .len = 1,
+ .buf = NULL,
+ },
+ [1] = {
+ .addr = I2C_BRIDGE_ADDR,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = NULL,
+ },
+};
+
+static int32_t sn65dsi83_reg_read(struct panel_spec *self)
+{
+ __u8 reg[] = {0x09,0x0A,0x0B,0x0D,0x10,0x11,0x12,0x13,0x18,0x19,0x1A,0x1B,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E};
+ __u8 val[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
+ int32_t ret_i2c = 0;
+ int32_t i = 0;
+ struct i2c_adapter *adap = i2c_get_adapter(I2CID_BRIDGE);
+
+ for (i=0; i<ARRAY_SIZE(reg); i++){
+ msg_r[0].buf = &reg[i];
+ msg_r[1].buf = &val[i];
+ ret_i2c = i2c_transfer(adap, &msg_r, 2);
+ LCD_PRINT("kernel Read All Regs! SendMsgNum=%d, Reg=0x%x, Src=0x%x,Read=0x%x,\n", ret_i2c,reg[i],i2c_msg_buf_ti[2*i+1],val[i]);
+ }
+
+ LCD_PRINT("kernel sn65dsi83_reg_read! adap_addr=0x%x, name=%s, nr=%d\n", adap, adap->name, adap->nr);
+
+ return 0;
+}
+
+/* set pin, return 0:OK, other value:failed */
+static int32_t set_en_pin(struct panel_spec *self, uint8_t value, uint8_t delays)//value 0 : set low, value not 0 : set high
+{
+ static uint8_t gpio_is_requested = 0;
+
+ /* request gpio */
+ if (!gpio_is_requested){
+ if (gpio_request(GPIOID_BRIDGE_EN, "BRIDGE_EN")){
+ printk("kernel GPIO%d requeste failed!\n",GPIOID_BRIDGE_EN);
+ return 1;
+ }
+ gpio_is_requested = 1;
+ }
+
+ if (value) {//set high
+ gpio_direction_output(GPIOID_BRIDGE_EN, 0);
+ msleep(delays);
+ gpio_direction_output(GPIOID_BRIDGE_EN, 1);
+ } else {//set low
+ gpio_direction_output(GPIOID_BRIDGE_EN, 0);
+ gpio_free(GPIOID_BRIDGE_EN);
+ gpio_is_requested = 0;
+ }
+
+ return 0;
+}
+
+/* Init SN65DSI83 */
+static int32_t sn65dsi83_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ int32_t ret_i2c = 0;
+
+ __u8 i2c_msg_buf_pll_en[] = {0x0D, i2c_msg_buf_ti[3][1]|0x01};// PLL_EN (CSR 0x0D.0)
+ __u8 i2c_msg_buf_soft_reset[] = {0x09, i2c_msg_buf_ti[0][1]|0x01};// SOFT_RESET (CSR 0x09.0)
+
+ struct i2c_adapter *adap = i2c_get_adapter(I2CID_BRIDGE);
+
+ mipi_set_lp_mode_t mipi_set_lp_mode = self->info.mipi->ops->mipi_set_lp_mode;/* u-boot\arch\arm\include\asm\arch\sprd_lcd.h */
+ mipi_set_hs_mode_t mipi_set_hs_mode = self->info.mipi->ops->mipi_set_hs_mode;
+ mipi_set_video_mode_t mipi_set_video_mode = self->info.mipi->ops->mipi_set_video_mode;
+
+ /* step 1 : All DSI into LP11*/
+ mipi_set_lp_mode();
+
+ /* step 2 : Set EN*/
+ if (set_en_pin(self, 1, 30)){
+ printk("kernel Set EN failed!\n");
+ return 0;
+ }
+
+ /* step 3 : Delay*/
+ udelay(2000);
+
+ /* step 4 : init CSR reg*/
+ for (i=0; i<ARRAY_SIZE(i2c_msg_buf_ti); i++) {
+ msg_w.buf = i2c_msg_buf_ti[i];
+ ret_i2c = i2c_transfer(adap, &msg_w, 1);
+ }
+
+ /* step 5 : Start the DSI video stream */
+ mipi_set_hs_mode();
+ mipi_set_video_mode();
+ udelay(1000);
+
+ /* step 6 : Set the PLL_EN bit(CSR 0x0D.0) */
+ msg_w.buf = i2c_msg_buf_pll_en;
+ ret_i2c = i2c_transfer(adap, &msg_w, 1);
+
+ /* step 7 : Wait for the PLL_LOCK bit to be set(CSR 0x0A.7) */
+ udelay(1000);
+
+ /* step 8 : Set the SOFT_RESET bit (CSR 0x09.0) */
+ msg_w.buf = i2c_msg_buf_soft_reset;
+ ret_i2c = i2c_transfer(adap, &msg_w, 1);
+
+ return 0;
+}
+
+static int32_t chipone_init(struct panel_spec *self)
+{
+ int32_t ret_i2c = 0;
+ int32_t i = 0;
+
+ struct i2c_adapter *adap = i2c_get_adapter(I2CID_BRIDGE);
+
+ /* Set EN pin */
+ if (set_en_pin(self, 1, 10)){
+ printk("kernel Set EN failed!\n");
+ return 0;
+ }
+ udelay(1000);
+
+ /* init chipone */
+ for (i=0; i<ARRAY_SIZE(i2c_msg_buf_c1); i++) {
+ msg_w.buf = i2c_msg_buf_c1[i];
+ ret_i2c = i2c_transfer(adap, &msg_w, 1);
+ }
+
+ return 0;
+}
+
+/* reset sn65dsi83 */
+static int32_t sn65dsi83_suspend(struct panel_spec *self)
+{
+ __u8 i2c_msg_buf_pll_en[] = {0x0D, i2c_msg_buf_ti[3][1] & 0xFE};// PLL_EN (CSR 0x0D.0)
+ int32_t ret_i2c = 0;
+
+ struct i2c_adapter *adap = i2c_get_adapter(I2CID_BRIDGE);
+
+ LCD_PRINT("kernel sn65dsi83_suspend! adap_addr=0x%x, name=%s, nr=%d\n", adap, adap->name, adap->nr);
+
+ /*1. Clear the PLL_EN bit to 0(CSR 0x0D.0*/
+ msg_w.buf = i2c_msg_buf_pll_en;
+ ret_i2c = i2c_transfer(adap, &msg_w, 1);
+
+ /* set EN to 0 */
+ if (set_en_pin(self, 0, 1)){
+ printk("kernel Set EN failed!\n");
+ return 0;
+ }
+
+ return 0;
+}
+
+static int32_t chipone_suspend(struct panel_spec *self)
+{
+ /* set EN to 0 */
+ if (set_en_pin(self, 0, 1)){
+ printk("kernel Set EN failed!\n");
+ return 0;
+ }
+ return 0;
+}
+
+static int32_t nt51017_power(struct panel_spec *self, uint8_t power)//0:power down, 1:power up
+{
+ static uint8_t is_requested = 0;
+
+ if(!is_requested){//should request gpio
+ if (gpio_request(GPIOID_VDDPWR, "VDDPWR")){
+ printk("kernel GPIO%d requeste failed!\n", GPIOID_VDDPWR);
+ return 0;
+ }
+
+ if (gpio_request(GPIOID_LCDPWR, "LCDPWR")){
+ printk("kernel GPIO%d requeste failed!\n", GPIOID_LCDPWR);
+ return 0;
+ }
+
+ is_requested = 1;
+ }
+
+ if (is_requested){
+ gpio_direction_output(GPIOID_VDDPWR, power);
+ gpio_direction_output(GPIOID_LCDPWR, power);
+
+ if (!power){//power down, should free gpio
+ gpio_free(GPIOID_VDDPWR);
+ gpio_free(GPIOID_LCDPWR);
+ is_requested = 0;
+ }
+ }
+
+ return 0;
+}
+
+static int32_t get_bridge_info(struct panel_spec *self)
+{
+ __u8 reg = 0x00;
+ __u8 flag = 0xFF;
+ int32_t ret_i2c = 0;
+
+ struct i2c_adapter *adap = i2c_get_adapter(I2CID_BRIDGE);
+
+ if (set_en_pin(self, 1, 30)){
+ printk("kernel Set EN failed!\n");
+ return 1;
+ }
+
+ if (gpio_request(GPIOID_ADDR, "ADDR")){
+ printk("kernel GPIO%d requeste failed!\n", GPIOID_ADDR);
+ return 1;
+ }
+ gpio_direction_output(GPIOID_ADDR, 0);// drive ADDR to low
+ udelay(1000);
+
+ msg_r[0].buf = &reg;
+ msg_r[1].buf = &flag;
+ ret_i2c = i2c_transfer(adap, &msg_r, 2);
+ if (0 == ret_i2c){
+ printk("get_bridge_info, I2C Read Failed!\n");
+ return 1;
+ }
+
+ if (0x35 == flag){//TI
+ b_ops.init = sn65dsi83_init;
+ b_ops.suspend = sn65dsi83_suspend;
+ } else if (0xC1 == flag) {//ChipOne
+ b_ops.init = chipone_init;
+ b_ops.suspend = chipone_suspend;
+ } else {
+ printk("get_bridge_info, Unknown bridge! flag=0x%x\n", flag);
+ gpio_free(GPIOID_ADDR);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int32_t nt51017_mipi_lvds_init(struct panel_spec *self)
+{
+ LCD_PRINT("kernel nt51017_mipi_lvds_init\n");
+
+ /* init */
+ if (b_ops.init) {
+ b_ops.init(self);
+ } else {
+ if (get_bridge_info(self)){//get bridge info fail
+ printk("Get bridge info fail!\n");
+ return 0;
+ } else {
+ b_ops.init(self);
+ }
+ }
+
+ /* power up */
+ nt51017_power(self, 1);
+
+ LCD_PRINT("kernel nt51017_mipi_lvds_init over!\n");
+
+ return 0;
+}
+
+static int32_t nt51017_mipi_lvds_reset(struct panel_spec *self)
+{
+ LCD_PRINT("kernel nt51017_mipi_lvds_reset\n");
+
+ return 0;
+}
+
+static int32_t nt51017_mipi_lvds_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ LCD_PRINT("kernel nt51017_mipi_lvds_enter_sleep! is_sleep=%d\n",is_sleep);
+
+ if (is_sleep){//sleep in
+ nt51017_power(self, 0);// power down
+ if (b_ops.suspend) {
+ b_ops.suspend(self);
+ } else {
+ if (get_bridge_info(self)){
+ printk("Get bridge info fail when suspend!\n");
+ return 0;
+ } else {
+ b_ops.suspend(self);
+ }
+ }
+ } else {//sleep out
+ nt51017_power(self, 1);// power up
+ if (b_ops.init) {
+ b_ops.init(self);
+ } else {
+ if (get_bridge_info(self)){//get bridge info fail
+ printk("Get bridge info fail!\n");
+ return 0;
+ } else {
+ b_ops.init(self);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static uint32_t nt51017_mipi_lvds_after_suspend(struct panel_spec *self)
+{
+ nt51017_power(self, 0);// power down
+
+ if (b_ops.suspend) {
+ b_ops.suspend(self);
+ }else {
+ if (get_bridge_info(self)){
+ printk("Get bridge info fail when suspend!\n");
+ return 0;
+ } else {
+ b_ops.suspend(self);
+ }
+ }
+
+ LCD_PRINT("kernel nt51017_mipi_lvds_after_suspend\n");
+
+ return 0;
+}
+
+static uint32_t nt51017_mipi_lvds_before_resume(struct panel_spec *self)
+{
+ LCD_PRINT("kernel nt51017_mipi_lvds_before_resume\n");
+
+ return 0;
+}
+
+static uint32_t nt51017_mipi_lvds_readid(struct panel_spec *self)
+{
+ LCD_PRINT("kernel nt51017_mipi_lvds_readid\n");
+
+ return 0xC749;/*51017*/
+}
+
+static int32_t nt51017_mipi_lvds_check_esd(struct panel_spec *self)
+{
+ LCD_PRINT("kernel nt51017_mipi_lvds_check_esd\n");
+
+ return 1;
+}
+
+static struct panel_operations lcd_nt51017_mipi_lvds_operations = {
+ .panel_init = nt51017_mipi_lvds_init,
+ .panel_reset = NULL,//nt51017_mipi_lvds_reset,
+ .panel_enter_sleep = nt51017_mipi_lvds_enter_sleep,
+ .panel_after_suspend = nt51017_mipi_lvds_after_suspend,
+ .panel_before_resume = NULL,
+ .panel_readid = nt51017_mipi_lvds_readid,
+ .panel_esd_check = NULL,
+};
+
+static struct timing_rgb lcd_nt51017_mipi_lvds_timing = {
+ .hfp = 110, /* unit: pixel */
+ .hbp = 76,
+ .hsync = 4,//4
+ .vfp = 18, /*unit: line*/
+ .vbp = 19,
+ .vsync = 4,
+};
+
+static struct info_mipi lcd_nt51017_mipi_lvds_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 4,
+ .phy_feq = 512*1000,/*494*/
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_nt51017_mipi_lvds_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_nt51017_mipi_lvds_spec = {
+ //.cap = PANEL_CAP_NOT_TEAR_SYNC,
+ .width = 768,
+ .height = 1024,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .is_clean_lcd = true,//bug 273509
+ .info = {
+ .mipi = &lcd_nt51017_mipi_lvds_info
+ },
+ .ops = &lcd_nt51017_mipi_lvds_operations,
+};
+
+struct panel_cfg lcd_nt51017_mipi_lvds = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0xC749,
+ .lcd_name = "lcd_nt51017_mipi_lvds",
+ .panel = &lcd_nt51017_mipi_lvds_spec,
+};
+
+static int __init lcd_nt51017_mipi_lvds_init(void)
+{
+ return sprdfb_panel_register(&lcd_nt51017_mipi_lvds);
+}
+
+subsys_initcall(lcd_nt51017_mipi_lvds_init);
+
+
diff --git a/drivers/video/sprdfb/lcd/lcd_otm1283a_mipi.c b/drivers/video/sprdfb/lcd/lcd_otm1283a_mipi.c
new file mode 100644
index 00000000..06875681
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_otm1283a_mipi.c
@@ -0,0 +1,560 @@
+/* drivers/video/sprdfb/lcd_otm1283a_mipi.c
+ *
+ * Support for otm1283a mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+//#define printk printf
+
+#define LCD_DEBUG
+//#define THREE_LANE_SUPPORT
+
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 48
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Force_Cmd_Code rd_prep_code[]={
+ {0x37, {LCM_SEND(2), {0x5, 0}}},
+};
+
+static LCM_Force_Cmd_Code rd_prep_code_1[]={
+ {0x37, {LCM_SEND(2), {0x1, 0}}},
+};
+
+static LCM_Init_Code sleep_in[] = {
+{LCM_SEND(1), {0x28}},
+{LCM_SLEEP(10)},
+{LCM_SEND(1), {0x10}},
+{LCM_SLEEP(120)},
+};
+
+static LCM_Init_Code sleep_out[] = {
+{LCM_SEND(1), {0x11}},
+{LCM_SLEEP(120)},
+{LCM_SEND(1), {0x29}},
+{LCM_SLEEP(20)},
+};
+
+static LCM_Init_Code init_data[] = {
+ {LCM_SEND(2),{0x00,0x00}},
+ {LCM_SEND(6),{4,0,0xFF,0x12,0x83,0x01}},
+ {LCM_SEND(2),{0x00,0x80}},
+
+ {LCM_SEND(5),{3,0,0xFF,0x12,0x83}},
+
+#ifdef THREE_LANE_SUPPORT
+ {LCM_SEND(2),{0x00,0x92}},
+ {LCM_SEND(5),{3,0,0xFF,0x20,0x02}}, //0x20:3lane 0x30:4lanes
+#endif
+ //---------------PANEL setting -----------//
+ {LCM_SEND(2),{0x00,0x80}},
+ {LCM_SEND(10),{8,0,0xC0,0x00,0x64,0x00,0x10,0x10,0x00,0x64}},
+ {LCM_SEND(2),{0x00,0x87}},
+ {LCM_SEND(5),{3,0,0xC0,0x10,0x10}},
+ {LCM_SEND(2),{0x00,0x90}},
+ {LCM_SEND(9),{7,0,0xC0,0x00,0x5C,0x00,0x01,0x00,0x04}},
+ {LCM_SEND(2),{0x00,0xA4}},
+ {LCM_SEND(2),{0xC0,0x22}},
+ {LCM_SEND(2),{0x00,0xB3}},
+ {LCM_SEND(5),{3,0,0xC0,0x00,0x50}},
+ {LCM_SEND(2),{0x00,0xB4}},
+ {LCM_SEND(2),{0xC0,0x55}},
+ {LCM_SEND(2),{0x00,0x81}},
+ //if(!TC358768_Gen_write_1A_1P(0xC1,0x55)) return -1;//xufei 2013-08-26 delete
+ //or
+ {LCM_SEND(2),{0xC1,0x66}},
+ {LCM_SEND(2),{0x00,0x90}},
+ {LCM_SEND(2),{0xC4,0x49}},
+ {LCM_SEND(2),{0x00,0x00}},
+ {LCM_SEND(2),{0x35,0x01}},
+ {LCM_SEND(2),{0x00,0x00}},
+ {LCM_SEND(2),{0x36,0x00}},
+ //-----------------POWER SETTING-----------------
+ {LCM_SEND(2),{0x00,0xA0}},
+ {LCM_SEND(10),{8,0,0xC4,0x05,0x10,0x06,0x02,0x05,0x15,0x10}},
+ {LCM_SEND(2),{0x00,0xA7}},
+ {LCM_SEND(10),{8,0,0xC4,0x05,0x10,0x07,0x02,0x05,0x15,0x10}},
+ {LCM_SEND(2),{0x00,0xB0}},
+ {LCM_SEND(5),{3,0,0xC4,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0x91}},
+ {LCM_SEND(5),{3,0,0xC5,0x46,0x40}},
+ {LCM_SEND(2),{0x00,0x00}},
+ {LCM_SEND(5),{3,0,0xD8,0xC7,0xC7}},
+ {LCM_SEND(2),{0x00,0x00}},
+ {LCM_SEND(2),{0xD9,0x6B}},
+ {LCM_SEND(2),{0x00,0x81}},
+ {LCM_SEND(2),{0xC4,0x82}},
+ {LCM_SEND(2),{0x00,0xB0}},
+
+ //if(!TC358768_Gen_write_1A_2P(0xC5,0x04,0xB8)) return -1;//xufei 2013-08-26 delete
+ //or
+ {LCM_SEND(5),{3,0,0xC5,0x04,0x58}},
+ {LCM_SEND(2),{0x00,0xBB}},
+ {LCM_SEND(2),{0xC5,0x80}},
+ {LCM_SEND(2),{0x00,0x82}},
+ {LCM_SEND(2),{0xC4,0x02}},
+ {LCM_SEND(2),{0x00,0xC6}},
+ {LCM_SEND(2),{0xB0,0x03}},
+ {LCM_SEND(2),{0x00,0xB1}},
+ {LCM_SEND(2),{0xC6,0x03}},
+ //-----------------CONTROL SETTING---------------
+ {LCM_SEND(2),{0x00,0x00}},
+ {LCM_SEND(2),{0xD0,0x40}},
+ {LCM_SEND(2),{0x00,0x00}},
+ {LCM_SEND(5),{3,0,0xD1,0x00,0x00}},
+ //-----------------PANEL TIMING STATE-------------------
+ {LCM_SEND(2),{0x00,0x80}},
+ {LCM_SEND(10),{8,0,0xCB,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0x87}},
+ {LCM_SEND(6),{4,0,0xCB,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0x90}},
+ {LCM_SEND(10),{8,0,0xCB,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0x97}},
+ {LCM_SEND(10),{8,0,0xCB,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0x9E}},
+ {LCM_SEND(2),{0xCB,0x00}},
+ {LCM_SEND(2),{0x00,0xA0}},
+ {LCM_SEND(10),{8,0,0xCB,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0xA7}},
+ {LCM_SEND(10),{8,0,0xCB,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0xAE}},
+ {LCM_SEND(2),{0xCB,0x00}},
+ {LCM_SEND(2),{0x00,0xB0}},
+ {LCM_SEND(10),{8,0,0xCB,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0xB7}},
+ {LCM_SEND(10),{8,0,0xCB,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0xBE}},
+ {LCM_SEND(2),{0xCB,0x00}},
+ {LCM_SEND(2),{0x00,0xC0}},
+ {LCM_SEND(10),{8,0,0xCB,0x05,0x05,0x05,0x05,0x05,0x05,0x00}},
+ {LCM_SEND(2),{0x00,0xC7}},
+ {LCM_SEND(10),{8,0,0xCB,0x00,0x00,0x00,0x05,0x05,0x00,0x05}},
+ {LCM_SEND(2),{0x00,0xCE}},
+ {LCM_SEND(2),{0xCB,0x05}},
+ {LCM_SEND(2),{0x00,0xD0}},
+ {LCM_SEND(10),{8,0,0xCB,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0xD7}},
+ {LCM_SEND(10),{8,0,0xCB,0x05,0x05,0x05,0x05,0x05,0x05,0x00}},
+ {LCM_SEND(2),{0x00,0xDE}},
+ {LCM_SEND(2),{0xCB,0x00}},
+ {LCM_SEND(2),{0x00,0xE0}},
+ {LCM_SEND(10),{8,0,0xCB,0x00,0x00,0x05,0x05,0x00,0x05,0x05}},
+ {LCM_SEND(2),{0x00,0xE7}},
+ {LCM_SEND(10),{8,0,0xCB,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0xF0}},
+ {LCM_SEND(10),{8,0,0xCB,0xff,0xff,0xff,0xff,0xff,0xff,0xff}},
+ {LCM_SEND(2),{0x00,0xF7}},
+ {LCM_SEND(6),{4,0,0xCB,0xff,0xff,0xff,0xff}},
+ //--------------PANEL PAD MAPPING-------------
+ {LCM_SEND(2),{0x00,0x80}},
+ {LCM_SEND(10),{8,0,0xCC,0x0E,0x10,0x0A,0x0C,0x02,0x04,0x00}},
+ {LCM_SEND(2),{0x00,0x87}},
+ {LCM_SEND(10),{8,0,0xCC,0x00,0x00,0x00,0x2E,0x2D,0x00,0x29}},
+ {LCM_SEND(2),{0x00,0x8E}},
+ {LCM_SEND(2),{0xCC,0x2A}},
+ {LCM_SEND(2),{0x00,0x90}},
+ {LCM_SEND(10),{8,0,0xCC,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0x97}},
+ {LCM_SEND(10),{8,0,0xCC,0x0D,0x0F,0x09,0x0B,0x01,0x03,0x00}},
+ {LCM_SEND(2),{0x00,0x9E}},
+ {LCM_SEND(2),{0xCC,0x00}},
+
+ {LCM_SEND(2),{0x00,0xA0}},
+ {LCM_SEND(10),{8,0,0xCC,0x00,0x00,0x2E,0x2D,0x00,0x29,0x2A}},
+ {LCM_SEND(2),{0x00,0xA7}},
+ {LCM_SEND(10),{8,0,0xCC,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0xB0}},
+ {LCM_SEND(10),{8,0,0xCC,0x0B,0x09,0x0F,0x0D,0x03,0x01,0x00}},
+ {LCM_SEND(2),{0x00,0xB7}},
+ {LCM_SEND(10),{8,0,0xCC,0x00,0x00,0x00,0x2D,0x2E,0x00,0x29}},
+ {LCM_SEND(2),{0x00,0xBE}},
+ {LCM_SEND(2),{0xCC,0x2A}},
+ {LCM_SEND(2),{0x00,0xC0}},
+ {LCM_SEND(10),{8,0,0xCC,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0xC7}},
+ {LCM_SEND(10),{8,0,0xCC,0x0C,0x0A,0x10,0x0E,0x04,0x02,0x00}},
+ {LCM_SEND(2),{0x00,0xCE}},
+ {LCM_SEND(2),{0xCC,0x00}},
+ {LCM_SEND(2),{0x00,0xD0}},
+ {LCM_SEND(10),{8,0,0xCC,0x00,0x00,0x2D,0x2E,0x00,0x29,0x2A}},
+ {LCM_SEND(2),{0x00,0xD7}},
+ {LCM_SEND(10),{8,0,0xCC,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ //-----------PANEL TIMING SETTING
+ {LCM_SEND(2),{0x00,0x80}},
+ {LCM_SEND(10),{8,0,0xCE,0x8B,0x03,0x18,0x8A,0x03,0x18,0x89}},
+ {LCM_SEND(2),{0x00,0x87}},
+ {LCM_SEND(8),{6,0,0xCE,0x03,0x18,0x88,0x03,0x18}},
+ {LCM_SEND(2),{0x00,0x90}},
+ {LCM_SEND(10),{8,0,0xCE,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0x97}},
+ {LCM_SEND(10),{8,0,0xCE,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0xA0}},
+ {LCM_SEND(10),{8,0,0xCE,0x38,0x07,0x05,0x00,0x00,0x48,0x00}},
+ {LCM_SEND(2),{0x00,0xA7}},
+ {LCM_SEND(10),{8,0,0xCE,0x38,0x06,0x05,0x01,0x00,0x48,0x00}},
+ {LCM_SEND(2),{0x00,0xB0}},
+ {LCM_SEND(10),{8,0,0xCE,0x38,0x05,0x05,0x02,0x00,0x48,0x00}},
+ {LCM_SEND(2),{0x00,0xB7}},
+ {LCM_SEND(10),{8,0,0xCE,0x38,0x04,0x05,0x03,0x00,0x48,0x00}},
+ {LCM_SEND(2),{0x00,0xC0}},
+ {LCM_SEND(10),{8,0,0xCE,0x38,0x03,0x05,0x04,0x00,0x48,0x00}},
+ {LCM_SEND(2),{0x00,0xC7}},
+ {LCM_SEND(10),{8,0,0xCE,0x38,0x02,0x05,0x05,0x00,0x48,0x00}},
+ {LCM_SEND(2),{0x00,0xD0}},
+ {LCM_SEND(10),{8,0,0xCE,0x38,0x01,0x05,0x06,0x00,0x48,0x00}},
+ {LCM_SEND(2),{0x00,0xD7}},
+ {LCM_SEND(10),{8,0,0xCE,0x38,0x00,0x05,0x07,0x00,0x48,0x00}},
+ {LCM_SEND(2),{0x00,0x80}},
+ {LCM_SEND(10),{8,0,0xCF,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0x87}},
+ {LCM_SEND(10),{8,0,0xCF,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0x90}},
+ {LCM_SEND(10),{8,0,0xCF,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0x97}},
+ {LCM_SEND(10),{8,0,0xCF,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0xA0}},
+ {LCM_SEND(10),{8,0,0xCF,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0xA7}},
+ {LCM_SEND(10),{8,0,0xCF,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0xB0}},
+ {LCM_SEND(10),{8,0,0xCF,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0xB7}},
+ {LCM_SEND(10),{8,0,0xCF,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0xC0}},
+ {LCM_SEND(10),{8,0,0xCF,0x02,0x01,0x20,0x20,0x00,0x00,0x01}},
+ {LCM_SEND(2),{0x00,0xC7}},
+ {LCM_SEND(6),{4,0,0xCF,0x81,0x00,0x03,0x08}},
+ {LCM_SEND(2),{0x00,0xB5}},
+ {LCM_SEND(9),{7,0,0xC5,0x00,0x6F,0xFF,0x00,0x6F,0xFF}},
+ //-----------------FOR POWER IC--------------------------
+ {LCM_SEND(2),{0x00,0x90}},
+ {LCM_SEND(6),{4,0,0xF5,0x02,0x11,0x02,0x11}},
+ {LCM_SEND(2),{0x00,0x90}},
+ {LCM_SEND(2),{0xC5,0x50}},
+ {LCM_SEND(2),{0x00,0x94}},
+ {LCM_SEND(2),{0xC5,0x66}},
+ //-----------------VGL01/02----------------------------------
+ {LCM_SEND(2),{0x00,0xB2}},
+ {LCM_SEND(5),{3,0,0xF5,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0xB4}},
+ {LCM_SEND(5),{3,0,0xF5,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0xB6}},
+ {LCM_SEND(5),{3,0,0xF5,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0xB8}},
+ {LCM_SEND(5),{3,0,0xF5,0x00,0x00}},
+ {LCM_SEND(2),{0x00,0x94}},
+ {LCM_SEND(2),{0xF5,0x02}},
+ {LCM_SEND(2),{0x00,0xBA}},
+ {LCM_SEND(2),{0xF5,0x03}},
+ {LCM_SEND(2),{0x00,0xB4}},
+ {LCM_SEND(2),{0xC5,0xC0}},
+ {LCM_SEND(2),{0x00,0xc6}},
+ {LCM_SEND(2),{0xB0,0x03}},
+ //spread frame range
+ {LCM_SEND(2),{0x00,0xA0}},
+ {LCM_SEND(2),{0xC1,0x02}},
+ {LCM_SEND(2),{0x00,0xA3}},
+ {LCM_SEND(2),{0xC1,0xF0}},
+ //-----------------GAMMA------------------------------
+ {LCM_SEND(2),{0x00,0x00}},
+ {LCM_SEND(10),{8,0,0xE1,0x00,0x0d,0x14,0x0d,0x06,0x0e,0x0a}},
+ {LCM_SEND(10),{8,0,0xE1,0x09,0x05,0x08,0x0f,0x08,0x0f,0x10}},
+ {LCM_SEND(5),{3,0,0xE1,0x0a,0x05}},
+ {LCM_SEND(2),{0x00,0x00}},
+ {LCM_SEND(10),{8,0,0xE2,0x00,0x0d,0x14,0x0d,0x06,0x0e,0x0a}},
+ {LCM_SEND(10),{8,0,0xE2,0x09,0x05,0x08,0x0f,0x08,0x0f,0x10}},
+ {LCM_SEND(5),{3,0,0xE2,0x0a,0x05}},
+
+ {LCM_SEND(1), {0x11}}, // sleep out
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1), {0x29}}, // display on
+ {LCM_SLEEP(50),}, //30, 100
+ {LCM_SEND(1), {0x2C}}, // normal on
+};
+
+static int32_t otm1283a_mipi_init(struct panel_spec *self)
+{
+ int32_t i;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("otm1283a_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(1,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ mdelay((init->tag & LCM_TAG_MASK));
+ }
+ init++;
+ }
+ mipi_eotp_set(1,1);
+ return 0;
+}
+
+static uint32_t otm1283a_readid(struct panel_spec *self)
+{
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code;
+ uint8_t read_data[5] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("lcd_otm1283a_mipi read id!\n");
+ return 0x1283;
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(1,0);
+
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ mdelay((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }
+ rd_prepare++;
+ }
+
+ read_rtn = mipi_force_read(0xa1, 5,(uint8_t *)read_data);
+ LCD_PRINT("lcd_otm1283a_mipi read id 0xa1 value is 0x%x, 0x%x, 0x%x, 0x%x, 0x%x!\n",
+ read_data[0], read_data[1], read_data[2], read_data[3], read_data[4]);
+
+ mipi_eotp_set(1,1);
+
+ if((0x01 == read_data[0])&&(0x8b == read_data[1])&&(0x12 == read_data[2])&&(0x83 == read_data[3])&&(0xff == read_data[4])){
+ LCD_PRINT("lcd_otm1283a_mipi read id success!\n");
+ return 0x1283;
+ }
+ }
+
+ printk("lcd_otm1283a_mipi identify fail!\n");
+ return 0;
+}
+
+static uint32_t otm1283a_readpowermode(struct panel_spec *self)
+{
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code_1;
+ uint8_t read_data[1] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_debug("lcd_otm1283a_mipi read power mode!\n");
+ mipi_eotp_set(0,1);
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code_1;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code_1); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }
+ rd_prepare++;
+ }
+ read_rtn = mipi_force_read(0x0A, 1,(uint8_t *)read_data);
+// printk("lcd_otm1283a_mipi read power mode 0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+ if((0x9c == read_data[0]) && (0 == read_rtn)){
+ pr_debug("lcd_otm1283a_mipi read power mode success!\n");
+ mipi_eotp_set(1,1);
+ return 0x9c;
+ }
+ }
+
+ printk("lcd_otm1283a_mipi read power mode fail!0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+ mipi_eotp_set(1,1);
+ return 0x0;
+}
+
+static int32_t otm1283a_check_esd(struct panel_spec *self)
+{
+ uint32_t power_mode;
+
+ mipi_set_lp_mode_t mipi_set_data_lp_mode = self->info.mipi->ops->mipi_set_data_lp_mode;
+ mipi_set_hs_mode_t mipi_set_data_hs_mode = self->info.mipi->ops->mipi_set_data_hs_mode;
+ mipi_set_lp_mode_t mipi_set_lp_mode = self->info.mipi->ops->mipi_set_lp_mode;
+ mipi_set_hs_mode_t mipi_set_hs_mode = self->info.mipi->ops->mipi_set_hs_mode;
+ uint16_t work_mode = self->info.mipi->work_mode;
+
+ pr_debug("otm1283a_check_esd!\n");
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_lp_mode();
+ }else{
+ mipi_set_data_lp_mode();
+ }
+ power_mode = otm1283a_readpowermode(self);
+ //power_mode = 0x0;
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_hs_mode();
+ }else{
+ mipi_set_data_hs_mode();
+ }
+ if(power_mode == 0x9c){
+ pr_debug("otm1283a_check_esd OK!\n");
+ return 1;
+ }else{
+ printk("otm1283a_check_esd fail!(0x%x)\n", power_mode);
+ return 0;
+ }
+}
+
+static int32_t otm1283a_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk(KERN_DEBUG "otm1283a_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+ mipi_eotp_set(1,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((sleep_in_out->tag & LCM_TAG_MASK));
+ }
+ sleep_in_out++;
+ }
+ mipi_eotp_set(1,1);
+
+ return 0;
+}
+
+static struct panel_operations lcd_otm1283a_mipi_operations = {
+ .panel_init = otm1283a_mipi_init,
+ .panel_readid = otm1283a_readid,
+ .panel_esd_check = otm1283a_check_esd,
+ .panel_enter_sleep = otm1283a_enter_sleep,
+};
+
+static struct timing_rgb lcd_otm1283a_mipi_timing = {
+ .hfp =32,
+ .hbp = 4,
+ .hsync =8,
+ .vfp = 17,
+ .vbp = 18,
+ .vsync = 7,
+};
+
+static struct info_mipi lcd_otm1283a_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+#ifdef THREE_LANE_SUPPORT
+ .lan_number = 3,
+ .phy_feq = 550*1000,
+#else
+ .lan_number = 4,
+ .phy_feq = 500*1000,
+#endif
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_otm1283a_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_otm1283a_mipi_spec = {
+ .width = 720,
+ .height = 1280,
+ .fps = 60,
+ .reset_timing = {5,40,20},
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+// .suspend_mode = SEND_SLEEP_CMD,
+ .info = {
+ .mipi = &lcd_otm1283a_mipi_info
+ },
+ .ops = &lcd_otm1283a_mipi_operations,
+};
+
+struct panel_cfg lcd_otm1283a_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x1283,
+ .lcd_name = "lcd_otm1283a_mipi",
+ .panel = &lcd_otm1283a_mipi_spec,
+};
+
+static int __init lcd_otm1283_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_otm1283a_mipi);
+}
+
+subsys_initcall(lcd_otm1283_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_otm8019a_mipi.c b/drivers/video/sprdfb/lcd/lcd_otm8019a_mipi.c
new file mode 100644
index 00000000..a9ac2829
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_otm8019a_mipi.c
@@ -0,0 +1,516 @@
+/* drivers/video/sprdfb/lcd_otm8019a_mipi.c
+ *
+ * Support for otm8019a mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+//#define printk printf
+
+#define LCD_DEBUG
+//#define THREE_LANE_SUPPORT
+
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 48
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Force_Cmd_Code rd_prep_code[]={
+ {0x37, {LCM_SEND(2), {0x5, 0}}},
+};
+
+static LCM_Force_Cmd_Code rd_prep_code_1[]={
+ {0x37, {LCM_SEND(2), {0x1, 0}}},
+};
+
+static LCM_Init_Code sleep_in[] = {
+{LCM_SEND(1), {0x28}},
+{LCM_SLEEP(10)},
+{LCM_SEND(1), {0x10}},
+{LCM_SLEEP(120)},
+};
+
+static LCM_Init_Code sleep_out[] = {
+{LCM_SEND(1), {0x11}},
+{LCM_SLEEP(120)},
+{LCM_SEND(1), {0x29}},
+{LCM_SLEEP(20)},
+};
+
+static LCM_Init_Code init_data[] = {
+ {LCM_SEND(2), {0x00, 0x00} },
+ {LCM_SEND(6), {4, 0, 0xFF, 0x80, 0x19, 0x01} },
+
+ {LCM_SEND(2), {0x00, 0x80} },
+ {LCM_SEND(5), {3, 0, 0xFF, 0x80, 0x19} },
+
+ {LCM_SEND(2), {0x00, 0x03} },
+ {LCM_SEND(2), {0xFF, 0x01} },
+
+ {LCM_SEND(2), {0x00, 0x00} },
+ {LCM_SEND(5), {3, 0, 0xD8, 0x7F, 0X7F} },/*6f*/
+
+ {LCM_SEND(2), {0x00, 0x082} },
+ {LCM_SEND(2), {0xC5, 0xB0} },
+
+ {LCM_SEND(2), {0x00, 0xA1} },
+ {LCM_SEND(2), {0xC1, 0x08} },
+
+ {LCM_SEND(2), {0x00, 0xA3} },
+ {LCM_SEND(2), {0xC0, 0x1B} },
+
+ {LCM_SEND(2), {0x00, 0xB4} },
+ {LCM_SEND(2), {0xC0, 0x77} },
+
+ {LCM_SEND(2), {0x00, 0x81} },
+ {LCM_SEND(2), {0xC4, 0x83} },
+
+ {LCM_SEND(2), {0x00, 0x90} },
+ {LCM_SEND(6), {4, 0, 0xC5, 0x4E, 0xA7, 0x01} },
+
+ {LCM_SEND(2), {0x00, 0xB1} },
+ {LCM_SEND(2), {0xC5, 0xA9} },
+
+ {LCM_SEND(2), {0x00, 0x00} },
+ {LCM_SEND(2), {0xD9, 0x17} },
+
+ {LCM_SEND(2), {0x00, 0x80} },
+ {LCM_SEND(2), {0xD8, 0x58} },
+
+/***************Gamma 2.2********************/
+ {LCM_SEND(2), {0x00, 0x00} },
+ {LCM_SEND(23), {21, 0, 0xE1, 0x00, 0x06, 0x14, 0x25, 0x3d, 0x4e, 0x5a,
+ 0x8d, 0x7c, 0x91, 0x75, 0x64, 0x7d, 0x69, 0x6e, 0x67, 0x5f, 0x55,
+ 0x5c, 0x02} },
+
+ {LCM_SEND(2), {0x00, 0x00} },
+ {LCM_SEND(23), {21, 0, 0xE2, 0x00, 0x06, 0x14, 0x25, 0x3d, 0x4e, 0x5a,
+ 0x8d, 0x7b, 0x91, 0x75, 0x64, 0x7d, 0x69, 0x6e, 0x67, 0x5f, 0x55,
+ 0x5c, 0x02} },
+/********************************************/
+/***************Gamma 2.5********************/
+ {LCM_SEND(2), {0x00, 0x00} },
+ {LCM_SEND(23), {21, 0, 0xE1, 0x00, 0x02, 0x07, 0x12, 0x22, 0x37, 0x41,
+ 0x78, 0x6b, 0x85, 0x7f, 0x6b, 0x82, 0x6b, 0x71, 0x69, 0x61, 0x58,
+ 0x4c, 0x00} },
+
+ {LCM_SEND(2), {0x00, 0x00} },
+ {LCM_SEND(23), {21, 0, 0xE2, 0x00, 0x02, 0x07, 0x12, 0x22, 0x37, 0x41,
+ 0x78, 0x6b, 0x85, 0x7f, 0x6b, 0x82, 0x6b, 0x71, 0x69, 0x61, 0x58,
+ 0x4c, 0x00} },
+/********************************************/
+
+ {LCM_SEND(2), {0x00, 0xA7} },
+ {LCM_SEND(2), {0xB3, 0x00} },
+
+ {LCM_SEND(2), {0x00, 0x92} },
+ {LCM_SEND(2), {0xB3, 0x45} },
+
+ {LCM_SEND(2), {0x00, 0x90} },
+ {LCM_SEND(2), {0xB3, 0x02} },
+
+ {LCM_SEND(2), {0x00, 0x00} },
+ {LCM_SEND(2), {0x36, 0x00} },
+
+ {LCM_SEND(2), {0x00, 0x90} },
+ {LCM_SEND(9), {7, 0, 0xC0, 0x00, 0x15, 0x00, 0x00, 0x00, 0x03} },
+
+ {LCM_SEND(2), {0x00, 0xA0} },
+ {LCM_SEND(2), {0xC1, 0xE8} },
+
+ {LCM_SEND(2), {0x00, 0xA6} },
+ {LCM_SEND(6), {4, 0, 0xC1, 0x01, 0x00, 0x00} },
+
+ {LCM_SEND(2), {0x00, 0x80} },
+ {LCM_SEND(9), {7, 0, 0xCE, 0x87, 0x03, 0x00, 0x86, 0x03, 0x00} },
+ {LCM_SLEEP(2)},
+
+ {LCM_SEND(2), {0x00, 0x90} },
+ {LCM_SEND(9), {7, 0, 0xCE, 0x33, 0x54, 0x00, 0x33, 0x55, 0x00} },
+ {LCM_SLEEP(2)},
+
+ {LCM_SEND(2), {0x00, 0xA0} },
+ {LCM_SEND(17), {15, 0, 0xCE, 0x38, 0x03, 0x03, 0x58, 0x00, 0x00, 0x00,
+ 0x38, 0x02, 0x03, 0x59, 0x00, 0x00, 0x00} },
+ {LCM_SLEEP(2)},
+
+ {LCM_SEND(2), {0x00, 0xB0} },
+ {LCM_SEND(17), {15, 0, 0xCE, 0x38, 0x01, 0x03, 0x5A, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x03, 0x5B, 0x00, 0x00, 0x00} },
+ {LCM_SLEEP(2)},
+
+ {LCM_SEND(2), {0x00, 0xC0} },
+ {LCM_SEND(17), {15, 0, 0xCE, 0x30, 0x00, 0x03, 0x5C, 0x00, 0x00, 0x00,
+ 0x30, 0x01, 0x03, 0x5D, 0x00, 0x00, 0x00} },
+ {LCM_SLEEP(2)},
+
+ {LCM_SEND(2), {0x00, 0xD0} },
+ {LCM_SEND(17), {15, 0, 0xCE, 0x38, 0x05, 0x03, 0x5E, 0x00, 0x00, 0x00,
+ 0x38, 0x04, 0x03, 0x5F, 0x00, 0x00, 0x00} },
+ {LCM_SLEEP(2)},
+
+ {LCM_SEND(2), {0x00, 0xC0} },
+ {LCM_SEND(13), {11, 0, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x80, 0x00, 0x09} },
+
+ {LCM_SEND(2), {0x00, 0xC0} },
+ {LCM_SEND(18), {16, 0, 0xCB, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
+ 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00} },
+
+ {LCM_SEND(2), {0x00, 0xD0} },
+ {LCM_SEND(18), {16, 0, 0xCB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00} },
+
+ {LCM_SEND(2), {0x00, 0xE0} },
+ {LCM_SEND(13), {11, 0, 0xCB, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00} },
+
+ {LCM_SEND(2), {0x00, 0x80} },
+ {LCM_SEND(13), {11, 0, 0xCC, 0x00, 0x26, 0x25, 0x02, 0x06, 0x00, 0x00,
+ 0x0A, 0x0E, 0x0C} },
+
+ {LCM_SEND(2), {0x00, 0x90} },
+ {LCM_SEND(18), {16, 0, 0xCC, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+
+ {LCM_SEND(2), {0x00, 0xA0} },
+ {LCM_SEND(18), {16, 0, 0xCC, 0x0f, 0x0b, 0x0d, 0x09, 0x00, 0x00, 0x05,
+ 0x01, 0x25, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00} },
+
+ {LCM_SEND(2), {0x00, 0xB0} },
+ {LCM_SEND(13), {11, 0, 0xCC, 0x00, 0x25, 0x26, 0x05, 0x01, 0x00, 0x00,
+ 0x0D, 0x09, 0x0B} },
+
+ {LCM_SEND(2), {0x00, 0xC0} },
+ {LCM_SEND(18), {16, 0, 0xCC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+
+ {LCM_SEND(2), {0x00, 0xD0} },
+ {LCM_SEND(18), {16, 0, 0xCC, 0x10, 0x0c, 0x0a, 0x0e, 0x00, 0x00, 0x02,
+ 0x06, 0x26, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00} },
+
+/*-----------------AUTO SHIFT-------------------*/
+ {LCM_SEND(2), {0x00, 0x98} },
+ {LCM_SEND(2), {0xC0, 0x00} },
+ {LCM_SEND(2), {0x00, 0xA9} },
+ {LCM_SEND(2), {0xC0, 0x06} },
+ {LCM_SEND(2), {0x00, 0xB0} },
+ {LCM_SEND(6), {4, 0, 0xC1, 0x20, 0x00, 0x00} },
+ {LCM_SEND(2), {0x00, 0xE1} },
+ {LCM_SEND(5), {3, 0, 0xC0, 0x40, 0x18} },
+/*----------------------------------------------*/
+ {LCM_SEND(2), {0x00, 0x80} },
+ {LCM_SEND(2), {0xC4, 0x30} }, /*source blanking area=GND*/
+
+ {LCM_SEND(2), {0x00, 0x80} },
+ {LCM_SEND(5), {3, 0, 0xC1, 0x03, 0x33} },
+
+ {LCM_SEND(2), {0x00, 0x90} },
+ {LCM_SEND(2), {0xB6, 0xB4} },/*command fia*/
+ {LCM_SLEEP(10)},
+
+ {LCM_SEND(2), {0x00, 0x00} },
+ {LCM_SEND(2), {0xfb, 0x01} },
+
+ {LCM_SEND(2), {0x00, 0x00} },
+ {LCM_SEND(2), {4, 0, 0xFF, 0xFF, 0xFF, 0xFF} },
+
+ {LCM_SEND(1), {0x11} }, /*sleep out*/
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1), {0x29} }, /*display on*/
+ {LCM_SLEEP(5)}, /*30, 100 ,50*/
+ {LCM_SEND(1), {0x2C} } /*normal on*/
+};
+
+static int32_t otm8019a_mipi_init(struct panel_spec *self)
+{
+ int32_t i;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode =
+ self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("otm8019a_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(1,0);
+
+ for (i = 0; i < ARRAY_SIZE(init_data); i++) {
+ tag = (init->tag >> 24);
+ if (tag & LCM_TAG_SEND) {
+ mipi_gen_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ } else if (tag & LCM_TAG_SLEEP) {
+ mdelay((init->tag & LCM_TAG_MASK));
+ }
+ init++;
+ }
+ mipi_eotp_set(1,1);
+ return 0;
+}
+
+static uint32_t otm8019a_readid(struct panel_spec *self)
+{
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code;
+ uint8_t read_data[5] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode =
+ self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("lcd_otm8019a_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(1, 0);
+
+ for (j = 0; j < 4; j++) {
+ rd_prepare = rd_prep_code;
+ for (i = 0; i < ARRAY_SIZE(rd_prep_code); i++) {
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if (tag & LCM_TAG_SEND)
+ mipi_force_write(rd_prepare->datatype,
+ rd_prepare->real_cmd_code.data,
+ (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ else if (tag & LCM_TAG_SLEEP)
+ mdelay((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ rd_prepare++;
+ }
+
+ read_rtn = mipi_force_read(0xa1, 5, (uint8_t *)read_data);
+ LCD_PRINT("lcd_otm8019a_mipi read id 0xa1 value is 0x%x, 0x%x, 0x%x, 0x%x, 0x%x!\n",
+ read_data[0], read_data[1], read_data[2], read_data[3],
+ read_data[4]);
+
+ mipi_eotp_set(1, 1);
+
+ if ((0x01 == read_data[0]) && (0x8b == read_data[1]) &&
+ (0x80 == read_data[2]) && (0x19 == read_data[3]) &&
+ (0xff == read_data[4])) {
+ LCD_PRINT("lcd_otm8019a_mipi read id success!\n");
+ return 0x8019;
+ }
+ }
+
+ printk(KERN_ERR "lcd_otm8019a_mipi identify fail!\n");
+ return 0;
+}
+
+static uint32_t otm8019a_readpowermode(struct panel_spec *self)
+{
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code_1;
+ uint8_t read_data[1] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_debug("lcd_otm8019a_mipi read power mode!\n");
+ mipi_eotp_set(0, 1);
+ for (j = 0; j < 4; j++) {
+ rd_prepare = rd_prep_code_1;
+ for (i = 0; i < ARRAY_SIZE(rd_prep_code_1); i++) {
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if (tag & LCM_TAG_SEND)
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data,
+ (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ else if (tag & LCM_TAG_SLEEP)
+ msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ rd_prepare++;
+ }
+ read_rtn = mipi_force_read(0x0A, 1, (uint8_t *)read_data);
+ /*printk("lcd_otm80193a_mipi read power mode 0x0A value is 0x%x!,
+ read result(%d)\n", read_data[0], read_rtn);*/
+ if ((0x9c == read_data[0]) && (0 == read_rtn)) {
+ pr_debug("lcd_otm8019a_mipi read power mode success!\n");
+ mipi_eotp_set(1, 1);
+ return 0x9c;
+ }
+ }
+
+ printk(KERN_ERR "lcd_otm8019a_mipi read power mode fail!0x0A value is 0x%x!, read result(%d)\n",
+ read_data[0], read_rtn);
+ mipi_eotp_set(1, 1);
+ return 0x0;
+}
+
+static int32_t otm8019a_check_esd(struct panel_spec *self)
+{
+ uint32_t power_mode;
+
+#ifndef FB_CHECK_ESD_IN_VFP
+ mipi_set_lp_mode_t mipi_set_data_lp_mode =
+ self->info.mipi->ops->mipi_set_data_lp_mode;
+ mipi_set_hs_mode_t mipi_set_data_hs_mode =
+ self->info.mipi->ops->mipi_set_data_hs_mode;
+ mipi_set_lp_mode_t mipi_set_lp_mode = self->info.mipi->ops->mipi_set_lp_mode;
+ mipi_set_hs_mode_t mipi_set_hs_mode = self->info.mipi->ops->mipi_set_hs_mode;
+ uint16_t work_mode = self->info.mipi->work_mode;
+#endif
+
+ pr_debug("otm8019a_check_esd!\n");
+#ifndef FB_CHECK_ESD_IN_VFP
+ if (SPRDFB_MIPI_MODE_CMD == work_mode)
+ mipi_set_lp_mode();
+ else
+ mipi_set_data_lp_mode();
+#endif
+ power_mode = otm8019a_readpowermode(self);
+ //power_mode = 0x0;
+#ifndef FB_CHECK_ESD_IN_VFP
+ if (SPRDFB_MIPI_MODE_CMD == work_mode)
+ mipi_set_hs_mode();
+ else
+ mipi_set_data_hs_mode();
+#endif
+ if (power_mode == 0x9c) {
+ pr_debug("otm8019a_check_esd OK!\n");
+ return 1;
+ } else {
+ printk(KERN_ERR "otm8019a_check_esd fail!(0x%x)\n", power_mode);
+ return 0;
+ }
+}
+
+static int32_t otm8019a_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk(KERN_DEBUG "otm8019a_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if (is_sleep) {
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ } else {
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+ mipi_eotp_set(1, 0);
+
+ for (i = 0; i < size; i++) {
+ tag = (sleep_in_out->tag >> 24);
+ if (tag & LCM_TAG_SEND)
+ mipi_gen_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ else if (tag & LCM_TAG_SLEEP)
+ msleep((sleep_in_out->tag & LCM_TAG_MASK));
+ sleep_in_out++;
+ }
+ mipi_eotp_set(1, 1);
+
+ return 0;
+}
+
+static struct panel_operations lcd_otm8019a_mipi_operations = {
+ .panel_init = otm8019a_mipi_init,
+ .panel_readid = otm8019a_readid,
+ .panel_esd_check = otm8019a_check_esd,
+ .panel_enter_sleep = otm8019a_enter_sleep,
+};
+
+static struct timing_rgb lcd_otm8019a_mipi_timing = {
+ .hfp = 48, /*46*/
+ .hbp = 48, /*44*/
+ .hsync = 8,
+ .vfp = 16, /*14*/
+ .vbp = 16,
+ .vsync = 8,/* 2*/
+};
+
+static struct info_mipi lcd_otm8019a_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq = 500*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_otm8019a_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_otm8019a_mipi_spec = {
+ .width = 480,
+ .height = 854,
+ .fps = 60,
+ .reset_timing = {5, 40, 20},
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .is_clean_lcd = true,
+ /*.suspend_mode = SEND_SLEEP_CMD,*/
+ .info = {
+ .mipi = &lcd_otm8019a_mipi_info
+ },
+ .ops = &lcd_otm8019a_mipi_operations,
+};
+
+struct panel_cfg lcd_otm8019a_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x8019,
+ .lcd_name = "lcd_otm8019a_mipi",
+ .panel = &lcd_otm8019a_mipi_spec,
+};
+
+static int __init lcd_otm8019a_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_otm8019a_mipi);
+}
+
+subsys_initcall(lcd_otm8019a_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_otm_8018b_mipi.c b/drivers/video/sprdfb/lcd/lcd_otm_8018b_mipi.c
new file mode 100644
index 00000000..7651fd4e
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_otm_8018b_mipi.c
@@ -0,0 +1,296 @@
+/* drivers/video/sc8825/lcd_otm8018b_mipi.c
+ *
+ * Support for otm8018b mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+//#define LCD_Delay(ms) uDelay(ms*1000)
+
+#define MAX_DATA 48
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+#if 1
+{LCM_SEND(6), {4, 0, 0xff,0x80,0x09,0x01}},
+
+{LCM_SEND(2), {0x00,0x80}},
+{LCM_SEND(5), {3, 0, 0xff,0x80,0x09}},
+
+{LCM_SEND(2), {0x00,0x03}},
+{LCM_SEND(2), {0xFF,0x01}},
+
+{LCM_SEND(2), {0x00,0xB4}},
+{LCM_SEND(2), {0xC0,0x10}},
+
+{LCM_SEND(2), {0x00,0x82}},
+{LCM_SEND(2), {0xC5,0xA3}},
+
+{LCM_SEND(2), {0x00,0x90}},
+{LCM_SEND(5), {3, 0, 0xC5,0xC6,0x76}},
+
+{LCM_SEND(2), {0x00,0x00}},
+{LCM_SEND(5), {3, 0, 0xD8,0x75,0x73}},
+
+{LCM_SEND(2), {0x00,0x00}},
+{LCM_SEND(2), {0xD9,0x4E}},
+
+/*-------------Gamma+ ------*/
+{LCM_SEND(2), {0x00,0x00}},
+{LCM_SEND(19), {17, 0, 0xE1,0x0C,0x0D,0x11,0x10,0x0A,0x1B,0x0B,0x0B,0x00,0x03,0x03,0x05,0x0D,0x24,0x21,0x05}},
+
+{LCM_SEND(2), {0x00,0x00}},
+{LCM_SEND(19), {17, 0, 0xE2,0x0C,0x0D,0x11,0x12,0x0E,0x1D,0x0B,0x0B,0x00,0x03,0x03,0x05,0x0D,0x25,0x21,0x05}},
+
+{LCM_SEND(2), {0x00,0x81}},
+{LCM_SEND(2), {0xC1,0x66}},
+{LCM_SEND(2), {0x00,0xA1}},
+{LCM_SEND(2), {0xC1,0x08}},
+
+{LCM_SEND(2), {0x00,0x89}},
+{LCM_SEND(2), {0xC4,0x08}},
+
+{LCM_SEND(2), {0x00,0xA2}},
+{LCM_SEND(6), {4, 0, 0xC0,0x1B,0x00,0x02}},
+
+{LCM_SEND(2), {0x00,0x81}},
+{LCM_SEND(2), {0xC4,0x83}},
+
+{LCM_SEND(2), {0x00,0x92}},
+{LCM_SEND(2), {0xC5,0x01}},
+
+{LCM_SEND(2), {0x00,0xB1}},
+{LCM_SEND(2), {0xC5,0xA9}},
+
+/*C09x : mck_shift1/mck_shift2/mck_shift3*/
+{LCM_SEND(2), {0x00,0x90}},
+{LCM_SEND(9), {7, 0, 0xC0,0x00,0x44,0x00,0x00,0x00,0x03}},
+
+/*C1Ax : hs_shift/vs_shift*/
+{LCM_SEND(2), {0x00,0xA6}},
+{LCM_SEND(6), {4, 0, 0xC1,0x00,0x00,0x00}},
+
+//CE8x : vst1, vst2, vst3, vst4
+{LCM_SEND(2), {0x00,0x80}},
+{LCM_SEND(15), {13, 0, 0xCE,0x87,0x03,0x00,0x85,0x03,0x00,0x86,0x03,0x00,0x84,0x03,0x00}},
+
+//CEAx : clka1, clka2
+{LCM_SEND(2), {0x00,0xA0}},
+{LCM_SEND(17), {15, 0, 0xCE,0x38,0x03,0x03,0x58,0x00,0x00,0x00,0x38,0x02,0x03,0x59,0x00,0x00,0x00}},
+
+//CEBx : clka3, clka4
+{LCM_SEND(2), {0x00,0xB0}},
+{LCM_SEND(17), {15, 0, 0xCE,0x38,0x01,0x03,0x5A,0x00,0x00,0x00,0x38,0x00,0x03,0x5B,0x00,0x00,0x00}},
+
+//CECx : clkb1, clkb2
+{LCM_SEND(2), {0x00,0xC0}},
+{LCM_SEND(17), {15, 0, 0xCE,0x30,0x00,0x03,0x5C,0x00,0x00,0x00,0x30,0x01,0x03,0x5D,0x00,0x00,0x00}},
+
+//CEDx : clkb3, clkb4
+{LCM_SEND(2), {0x00,0xD0}},
+{LCM_SEND(17), {15, 0, 0xCE,0x30,0x02,0x03,0x5E,0x00,0x00,0x00,0x30,0x03,0x03,0x5F,0x00,0x00,0x00}},
+
+{LCM_SEND(2), {0x00, 0xC7}},
+{LCM_SEND(2), {0xCF, 0x00}},
+
+{LCM_SEND(2), {0x00, 0xC9}},
+{LCM_SEND(2), {0xCF, 0x00}},
+
+{LCM_SEND(2), {0x00, 0xC4}},
+{LCM_SEND(9), {7, 0, 0xCB,0x04,0x04,0x04,0x04,0x04,0x04}},
+
+{LCM_SEND(2), {0x00, 0xD9}},
+{LCM_SEND(9), {7, 0, 0xCB,0x04,0x04,0x04,0x04,0x04,0x04}},
+
+{LCM_SEND(2), {0x00, 0x84}},
+{LCM_SEND(9), {7, 0, 0xCC,0x0C,0x0A,0x10,0x0E,0x03,0x04}},
+
+{LCM_SEND(2), {0x00,0x9E}},
+{LCM_SEND(2), {0xCC,0x0B}},
+
+{LCM_SEND(2), {0x00,0xA0}},
+{LCM_SEND(8), {6, 0, 0xCC,0x09,0x0F,0x0D,0x01,0x02}},
+
+{LCM_SEND(2), {0x00,0xB4}},
+{LCM_SEND(9), {7, 0, 0xCC,0x0D,0x0F,0x09,0x0B,0x02,0x01}},
+
+{LCM_SEND(2), {0x00,0xCE}},
+{LCM_SEND(2), {0xCC,0x0E}},
+
+{LCM_SEND(2), {0x00,0xD0}},
+{LCM_SEND(8), {6, 0, 0xCC,0x10,0x0A,0x0C,0x04,0x03}},
+
+{LCM_SEND(2), {0x00,0x00}},
+{LCM_SEND(2), {0x3A,0x77}},
+
+{LCM_SEND(2), {0x11, 0x00}}, // sleep out
+{LCM_SLEEP(200),},
+{LCM_SEND(2), {0x29, 0x00}}, // display on
+
+{LCM_SEND(1), {0x2C}}, // normal on
+
+#endif
+
+};
+
+//static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+{LCM_SEND(1), {0x28}},
+{LCM_SLEEP(10)},
+{LCM_SEND(1), {0x10}},
+{LCM_SLEEP(120)},
+};
+
+static LCM_Init_Code sleep_out[] = {
+{LCM_SEND(1), {0x11}},
+{LCM_SLEEP(120)},
+{LCM_SEND(1), {0x29}},
+{LCM_SLEEP(20)},
+};
+
+static int32_t otm8018b_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+
+ pr_debug(KERN_DEBUG "otm8018b_mipi_init\n");
+
+ mipi_set_cmd_mode();
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((init->tag & LCM_TAG_MASK));
+ }
+ init++;
+ }
+ return 0;
+}
+
+static uint32_t otm8018b_readid(struct panel_spec *self)
+{
+ /*Jessica TODO: need read id*/
+ return 0x18;
+}
+
+static int32_t otm8018b_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i = 0;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+
+ printk(KERN_DEBUG "otm8018b_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((sleep_in_out->tag & LCM_TAG_MASK));
+ }
+ sleep_in_out++;
+ }
+ return 0;
+}
+
+static struct panel_operations lcd_otm8018b_mipi_operations = {
+ .panel_init = otm8018b_mipi_init,
+ .panel_readid = otm8018b_readid,
+ .panel_enter_sleep = otm8018b_enter_sleep,
+};
+
+static struct timing_rgb lcd_otm8018b_mipi_timing = {
+ .hfp = 80, /* unit: pixel */
+ .hbp = 80,
+ .hsync = 6,
+ .vfp = 10, /*unit: line*/
+ .vbp = 10,
+ .vsync = 6,
+};
+
+static struct info_mipi lcd_otm8018b_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq = 500*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_POS,
+ .shut_down_pol = SPRDFB_POLARITY_POS,
+ .timing = &lcd_otm8018b_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_otm8018b_mipi_spec = {
+ .width = 480,
+ .height = 800,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_otm8018b_mipi_info
+ },
+ .ops = &lcd_otm8018b_mipi_operations,
+};
+
+struct panel_cfg lcd_otm8018b_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x18,
+ .lcd_name = "lcd_otm8018b_mipi",
+ .panel = &lcd_otm8018b_mipi_spec,
+};
+
+static int __init lcd_otm8018b_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_otm8018b_mipi);
+}
+
+subsys_initcall(lcd_otm8018b_mipi_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_rm68180_mipi.c b/drivers/video/sprdfb/lcd/lcd_rm68180_mipi.c
new file mode 100644
index 00000000..e100f38d
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_rm68180_mipi.c
@@ -0,0 +1,383 @@
+/* drivers/video/srpdfb/lcd_rm68180_mipi.c
+ *
+ * Support for rm68180 mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+//#define LCD_Delay(ms) uDelay(ms*1000)
+
+#define MAX_DATA 58
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Force_Cmd_Code rd_prep_code_1[]={
+ {0x37, {LCM_SEND(2), {0x1, 0}}},
+};
+
+static LCM_Init_Code init_data[] = {
+#if 1 //l901 shengjing rm68180
+ {LCM_SEND(8),{6,0,0xF0,0x55,0xAA,0x52,0x08,0x01}},
+ {LCM_SEND(6),{4,0,0xB0,0x0D,0x0D,0x0D}},
+ {LCM_SEND(6),{4,0,0xB1,0x05,0x05,0x05}},
+ {LCM_SEND(6),{4,0,0xB6,0x34,0x34,0x34}},
+ {LCM_SEND(6),{4,0,0xB7,0x34,0x34,0x34}},
+ {LCM_SEND(6),{4,0,0xB8,0x24,0x24,0x24}},
+ {LCM_SEND(6),{4,0,0xB9,0x34,0x34,0x34}},
+ {LCM_SEND(6),{4,0,0xBA,0x04,0x04,0x04}},
+ {LCM_SEND(6),{4,0,0xBC,0x00,0x90,0x00}},
+ {LCM_SEND(6),{4,0,0xBD,0x00,0x90,0x00}},
+ {LCM_SEND(5),{3,0,0xBE,0x00,0x75}},
+ {LCM_SEND(2),{0xCC,0x05}},
+ {LCM_SEND(55),{53,0,0xD1,0x00,0x00,0x00,0x01,0x00,0x18,0x00,0x3B,0x00,0x60,0x00,0x9E,0x00,0xCF,0x01,0x17,0x01,0x4B,0x01,0x93,0x01,0xC6,0x02,0x10,0x02,0x48,0x02,0x49,0x02,0x79,0x02,0xAA,0x02,0xC4,0x02,0xE4,0x02,0xF8,0x03,0x10,0x03,0x20,0x03,0x36,0x03,0x46,0x03,0x5C,0x03,0x8B,0x03,0xFF}},
+ {LCM_SEND(55),{53,0,0xD2,0x00,0x00,0x00,0x01,0x00,0x18,0x00,0x3B,0x00,0x60,0x00,0x9E,0x00,0xCF,0x01,0x17,0x01,0x4B,0x01,0x93,0x01,0xC6,0x02,0x10,0x02,0x48,0x02,0x49,0x02,0x79,0x02,0xAA,0x02,0xC4,0x02,0xE4,0x02,0xF8,0x03,0x10,0x03,0x20,0x03,0x36,0x03,0x46,0x03,0x5C,0x03,0x8B,0x03,0xFF}},
+ {LCM_SEND(55),{53,0,0xD3,0x00,0x00,0x00,0x01,0x00,0x18,0x00,0x3B,0x00,0x60,0x00,0x9E,0x00,0xCF,0x01,0x17,0x01,0x4B,0x01,0x93,0x01,0xC6,0x02,0x10,0x02,0x48,0x02,0x49,0x02,0x79,0x02,0xAA,0x02,0xC4,0x02,0xE4,0x02,0xF8,0x03,0x10,0x03,0x20,0x03,0x36,0x03,0x46,0x03,0x5C,0x03,0x8B,0x03,0xFF}},
+ {LCM_SEND(55),{53,0,0xD4,0x00,0x00,0x00,0x01,0x00,0x18,0x00,0x3B,0x00,0x60,0x00,0x9E,0x00,0xCF,0x01,0x17,0x01,0x4B,0x01,0x93,0x01,0xC6,0x02,0x10,0x02,0x48,0x02,0x49,0x02,0x79,0x02,0xAA,0x02,0xC4,0x02,0xE4,0x02,0xF8,0x03,0x10,0x03,0x20,0x03,0x36,0x03,0x46,0x03,0x5C,0x03,0x8B,0x03,0xFF}},
+ {LCM_SEND(55),{53,0,0xD5,0x00,0x00,0x00,0x01,0x00,0x18,0x00,0x3B,0x00,0x60,0x00,0x9E,0x00,0xCF,0x01,0x17,0x01,0x4B,0x01,0x93,0x01,0xC6,0x02,0x10,0x02,0x48,0x02,0x49,0x02,0x79,0x02,0xAA,0x02,0xC4,0x02,0xE4,0x02,0xF8,0x03,0x10,0x03,0x20,0x03,0x36,0x03,0x46,0x03,0x5C,0x03,0x8B,0x03,0xFF}},
+ {LCM_SEND(55),{53,0,0xD6,0x00,0x00,0x00,0x01,0x00,0x18,0x00,0x3B,0x00,0x60,0x00,0x9E,0x00,0xCF,0x01,0x17,0x01,0x4B,0x01,0x93,0x01,0xC6,0x02,0x10,0x02,0x48,0x02,0x49,0x02,0x79,0x02,0xAA,0x02,0xC4,0x02,0xE4,0x02,0xF8,0x03,0x10,0x03,0x20,0x03,0x36,0x03,0x46,0x03,0x5C,0x03,0x8B,0x03,0xFF}},
+ {LCM_SEND(8),{6,0,0xF0,0x55,0xAA,0x52,0x08,0x00}},
+ {LCM_SEND(2),{0xB1,0xFC}},
+ {LCM_SEND(2),{0xB4,0x10}},
+ {LCM_SEND(2),{0xB6,0x01}},
+ {LCM_SEND(7),{5,0,0xB8,0x01,0x04,0x04,0x04}},
+ {LCM_SEND(2),{0xBA,0x01}},
+ {LCM_SEND(6),{4,0,0xBC,0x02,0x02,0x02}},
+ {LCM_SEND(2),{0x3A,0x77}}, //0x55
+ {LCM_SEND(5),{3,0,0xC9,0xC0,0x01}},
+ {LCM_SEND(8),{6,0,0xF0,0x55,0xAA,0x52,0x08,0x02}},
+ {LCM_SEND(2),{0xF6,0x60}},
+ {LCM_SEND(2),{0x35,0x00}},
+ {LCM_SEND(2),{0x36,0x00}},
+ {LCM_SEND(5),{3,0,0x44,0x00,0x50}},
+ {LCM_SEND(8),{6,0,0xF0,0x55,0xAA,0x52,0x08,0x01}},
+ {LCM_SEND(7),{5,0,0x2A,0x00,0x00,0x01,0xDF}},
+ {LCM_SEND(7),{5,0,0x2B,0x00,0x00,0x03,0x1F}}, //0x355
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(100)},
+#endif
+};
+
+static LCM_Force_Cmd_Code rd_prep_code[]={
+ {0x39, {LCM_SEND(8), {0x6, 0, 0xF0, 0x55, 0xAA, 0x52, 0x08, 0x01}}},
+ {0x37, {LCM_SEND(2), {0x3, 0}}},
+};
+
+static LCM_Init_Code sleep_in[] = {
+{LCM_SEND(1), {0x28}},
+{LCM_SLEEP(120)},
+{LCM_SEND(1), {0x10}},
+{LCM_SLEEP(100)},
+{LCM_SEND(2), {0x4F,0x01}},
+//{LCM_SEND(2), {0x4f, 0x01}},
+};
+
+static LCM_Init_Code sleep_out[] = {
+{LCM_SEND(1), {0x11}},
+{LCM_SLEEP(120)},
+{LCM_SEND(1), {0x29}},
+{LCM_SLEEP(100)},
+};
+
+static int32_t rm68180_mipi_init(struct panel_spec *self)
+{
+ int32_t i;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_debug(KERN_DEBUG "rm68180_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(1,0);
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((init->tag & LCM_TAG_MASK));
+ }
+ init++;
+ }
+ mipi_eotp_set(1,1);
+ return 0;
+}
+
+static uint32_t rm68180_readid(struct panel_spec *self)
+{
+//{LCM_SEND(8), {6,0,0xF0,0x55,0xAA,0x52,0x08,0x01}},
+ /*Jessica TODO: need read id*/
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code;
+
+ uint8_t read_data[3] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("lcd_rm68180_mipi read id!\n");
+ mipi_set_cmd_mode();
+ mipi_eotp_set(1,0);
+ //mipi_force_read(0x0, 3,(uint8_t *)read_data);
+
+ for(j = 0; j < 4; j++){
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ udelay((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK) * 1000);
+ }
+ rd_prepare++;
+ }
+ read_rtn = mipi_force_read(0x04, 3,(uint8_t *)read_data);
+ printk("lcd_rm68180_mipi read id value is 0x%x, 0x%x, 0x%x!\n", read_data[0], read_data[1], read_data[2]);
+ //0x00 0x80 0x00
+ //return 0x80;
+ if((0x80 == read_data[1])){
+ self->info.mipi->ops->mipi_set_hs_mode();
+ printk("lcd_rm68180_mipi read id success!\n");
+ mipi_eotp_set(1,1);
+ return 0x80;
+ }
+ else
+ printk("lcd_rm68180_mipi read id failed!\n");
+
+ }
+ mipi_eotp_set(1,1);
+ return 0x00;
+}
+
+static uint32_t rm68180_readpowermode(struct panel_spec *self)
+{
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code_1;
+ uint8_t read_data[1] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_debug("lcd_rm68180_mipi read power mode!\n");
+ mipi_eotp_set(0,1);
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code_1;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code_1); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }
+ rd_prepare++;
+ }
+ read_rtn = mipi_force_read(0x0A, 1,(uint8_t *)read_data);
+ //printk("lcd_rm68180_mipi read power mode 0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+ if((0x9c == read_data[0]) && (0 == read_rtn)){
+ pr_debug("lcd_rm68180_mipi read power mode success!\n");
+ mipi_eotp_set(1,1);
+ return 0x9c;
+ }
+ }
+
+ printk("lcd_rm68180_mipi read power mode fail!0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+ mipi_eotp_set(1,1);
+ return 0x0;
+}
+
+static int32_t rm68180_check_esd(struct panel_spec *self)
+{
+ uint32_t power_mode;
+
+ mipi_set_lp_mode_t mipi_set_data_lp_mode = self->info.mipi->ops->mipi_set_data_lp_mode;
+ mipi_set_hs_mode_t mipi_set_data_hs_mode = self->info.mipi->ops->mipi_set_data_hs_mode;
+ mipi_set_lp_mode_t mipi_set_lp_mode = self->info.mipi->ops->mipi_set_lp_mode;
+ mipi_set_hs_mode_t mipi_set_hs_mode = self->info.mipi->ops->mipi_set_hs_mode;
+ uint16_t work_mode = self->info.mipi->work_mode;
+
+ pr_debug("rm68180_check_esd!\n");
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_lp_mode();
+ }else{
+ mipi_set_data_lp_mode();
+ }
+ power_mode = rm68180_readpowermode(self);
+ //power_mode = 0x0;
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_hs_mode();
+ }else{
+ mipi_set_data_hs_mode();
+ }
+ if(power_mode == 0x9c){
+ pr_debug("rm68180_check_esd OK!\n");
+ return 1;
+ }else{
+ printk("rm68180_check_esd fail!(0x%x)\n", power_mode);
+ return 0;
+ }
+}
+
+static int32_t rm68180_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+
+ printk(KERN_DEBUG "rm68180_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((sleep_in_out->tag & LCM_TAG_MASK));
+ }
+ sleep_in_out++;
+ }
+// printk(KERN_DEBUG "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy = %d\n", is_sleep);
+ //if (!is_sleep)
+// {
+// printk(KERN_DEBUG "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = %d\n", is_sleep);
+// mdelay(6000);
+// }
+ return 0;
+}
+
+static int32_t rm68180_mipi_after_suspend(struct panel_spec *self)
+{
+ return 0;
+}
+
+
+static struct panel_operations lcd_rm68180_mipi_operations = {
+ .panel_init = rm68180_mipi_init,
+ .panel_readid = rm68180_readid,
+ .panel_enter_sleep = rm68180_enter_sleep,
+ .panel_after_suspend = rm68180_mipi_after_suspend,
+ .panel_esd_check = rm68180_check_esd,
+};
+
+static struct timing_rgb lcd_rm68180_mipi_timing = {
+#if 1
+ .hfp = 20, /* unit: pixel */
+ .hbp = 20,
+ .hsync = 6,//4,
+ .vfp = 20, /*unit: line*/
+ .vbp = 20,
+ .vsync = 6,//6
+#else
+/*
+ .hfp = 120,
+ .hbp = 120,
+ .hsync = 60,
+ .vfp = 6,
+ .vbp = 6,
+ .vsync = 4,
+*/
+ .hfp =70,
+ .hbp = 40,
+ .hsync = 10,
+ .vfp = 10,
+ .vbp = 10,
+ .vsync = 12,
+#endif
+};
+
+static struct info_mipi lcd_rm68180_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq = 360*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_rm68180_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_rm68180_mipi_spec = {
+ .width = 480,
+ .height = 800, //854,
+ .fps = 60,
+ .reset_timing = {20,20,120},
+ //.suspend_mode = SEND_SLEEP_CMD,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .is_clean_lcd = true,
+ .info = {
+ .mipi = &lcd_rm68180_mipi_info
+ },
+ .ops = &lcd_rm68180_mipi_operations,
+};
+
+struct panel_cfg lcd_rm68180_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x80,
+ .lcd_name = "lcd_rm68180_mipi",
+ .panel = &lcd_rm68180_mipi_spec,
+};
+
+static int __init lcd_rm68180_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_rm68180_mipi);
+}
+
+subsys_initcall(lcd_rm68180_mipi_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_s6d0139.c b/drivers/video/sprdfb/lcd/lcd_s6d0139.c
new file mode 100644
index 00000000..9ed5f1e0
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_s6d0139.c
@@ -0,0 +1,244 @@
+/* drivers/video/sc8800g/sc8800g_lcd_s6d0139.c
+ *
+ * Support for s6d0139 LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+static int32_t s6d0139_init(struct panel_spec *self)
+{
+ send_cmd_data_t send_cmd_data = self->info.mcu->ops->send_cmd_data;
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+ pr_debug(KERN_DEBUG "s6d0139_init\n");
+
+ /* reset the lcd */
+ self->ops->panel_reset(self);
+ mdelay(100);
+ /* start init sequence */
+ send_cmd_data(0x0000, 0x0001);
+ mdelay(10);
+
+ send_cmd_data(0x0007, 0x0000);
+ send_cmd_data(0x0013, 0x0000);
+ send_cmd_data(0x0011, 0x2604);
+ send_cmd_data(0x0014, 0x1212);
+ send_cmd_data(0x0010, 0x3C00);
+ send_cmd_data(0x0013, 0x0040);
+ mdelay(10);
+ send_cmd_data(0x0013, 0x0060);
+ mdelay(50);
+ send_cmd_data(0x0013, 0x0070);
+ mdelay(40);
+ send_cmd_data(0x0001, 0x0127);
+ send_cmd_data(0x0002, 0x0700);
+ send_cmd_data(0x0003, 0x1030);
+ send_cmd_data(0x0007, 0x0000);
+ send_cmd_data(0x0008, 0x0404);
+ send_cmd_data(0x000B, 0x0200);
+ send_cmd_data(0x000C, 0x0000);
+ send_cmd_data(0x0015, 0x0000);
+
+ //gamma setting
+ send_cmd_data(0x0030, 0x0000);
+ send_cmd_data(0x0031, 0x0606);
+ send_cmd_data(0x0032, 0x0006);
+ send_cmd_data(0x0033, 0x0403);
+ send_cmd_data(0x0034, 0x0107);
+ send_cmd_data(0x0035, 0x0101);
+ send_cmd_data(0x0036, 0x0707);
+ send_cmd_data(0x0037, 0x0304);
+ send_cmd_data(0x0038, 0x0A00);
+ send_cmd_data(0x0039, 0x0706);
+ send_cmd_data(0x0040, 0x0000);
+ send_cmd_data(0x0041, 0x0000);
+ send_cmd_data(0x0042, 0x013F);
+ send_cmd_data(0x0043, 0x0000);
+ send_cmd_data(0x0044, 0x0000);
+ send_cmd_data(0x0045, 0x0000);
+ send_cmd_data(0x0046, 0xEF00);
+ send_cmd_data(0x0047, 0x013F);
+ send_cmd_data(0x0048, 0x0000);
+ send_cmd_data(0x0007, 0x0011);
+ mdelay(40);
+ send_cmd_data(0x0007, 0x0017);
+ send_cmd_data(0x0020, 0x0000);
+ send_cmd_data(0x0021, 0x0000);
+ mdelay(40);
+
+ send_cmd(0x0022);
+
+
+ if(1){
+ int i = 0;
+ for (i=0; i<320*240/3; i++)
+ send_data(0xf800);
+ for (i=0; i< 320*240/3; i++)
+ send_data(0x07e0);
+ for (i=0; i< 320*240/3; i++)
+ send_data(0x001f);
+ }
+
+ return 0;
+}
+
+static int32_t s6d0139_set_window(struct panel_spec *self,
+ uint16_t left, uint16_t top, uint16_t right, uint16_t bottom)
+{
+ send_cmd_data_t send_cmd_data = self->info.mcu->ops->send_cmd_data;
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ pr_debug(KERN_DEBUG "s6d0139_set_window\n");
+
+ send_cmd_data(0x46, ((right << 8) & 0xff00)|(left&0xff));
+ send_cmd_data(0x47, bottom);
+ send_cmd_data(0x48, top);
+
+ switch (self->direction) {
+ case LCD_DIRECT_NORMAL:
+ case LCD_DIRECT_ROT_270:
+ send_cmd_data(0x0020, left);
+ send_cmd_data(0x0021, top);
+ break;
+ case LCD_DIRECT_ROT_90:
+ case LCD_DIRECT_MIR_H:
+ send_cmd_data(0x0020, right);
+ send_cmd_data(0x0021, top);
+ break;
+ case LCD_DIRECT_ROT_180:
+ case LCD_DIRECT_MIR_HV:
+ send_cmd_data(0x0020, right);
+ send_cmd_data(0x0021, bottom);
+ break;
+ case LCD_DIRECT_MIR_V:
+ send_cmd_data(0x0020, left);
+ send_cmd_data(0x0021, bottom);
+ break;
+ default:
+ pr_debug(KERN_ERR "unknown lcd direction!\n");
+ break;
+ }
+
+ send_cmd(0x0022);
+
+ return 0;
+}
+
+static int32_t s6d0139_invalidate(struct panel_spec *self)
+{
+ pr_debug(KERN_DEBUG "s6d0139_invalidate\n");
+
+ return self->ops->panel_set_window(self, 0, 0,
+ self->width-1, self->height-1);
+
+}
+
+static int32_t s6d0139_set_direction(struct panel_spec *self, uint16_t direction)
+{
+ send_cmd_data_t send_cmd_data = self->info.mcu->ops->send_cmd_data;
+ pr_debug(KERN_DEBUG "s6d0139_set_direction\n");
+
+ switch (direction) {
+ case LCD_DIRECT_NORMAL:
+ send_cmd_data(0x0003, 0x1030);
+ break;
+ case LCD_DIRECT_ROT_90:
+ send_cmd_data(0x0003, 0x1028);
+ break;
+ case LCD_DIRECT_ROT_180:
+ case LCD_DIRECT_MIR_HV:
+ send_cmd_data(0x0003, 0x1000);
+ break;
+ case LCD_DIRECT_ROT_270:
+ send_cmd_data(0x0003, 0x1018);
+ break;
+ case LCD_DIRECT_MIR_H:
+ send_cmd_data(0x0003, 0x1020);
+ break;
+ case LCD_DIRECT_MIR_V:
+ send_cmd_data(0x0003, 0x1010);
+ break;
+ default:
+ pr_debug(KERN_ERR "unknown lcd direction!\n");
+ send_cmd_data(0x0003, 0x1030);
+ direction = LCD_DIRECT_NORMAL;
+ break;
+ }
+
+ self->direction = direction;
+
+ return 0;
+}
+
+static struct panel_operations lcd_s6d0139_operations = {
+ .panel_init = s6d0139_init,
+ .panel_set_window = s6d0139_set_window,
+ .panel_invalidate = s6d0139_invalidate,
+ .panel_set_direction = s6d0139_set_direction,
+};
+
+
+static struct timing_mcu lcd_s6d0139_timing[] = {
+[MCU_LCD_REGISTER_TIMING] = { /* read/write register timing (ns) */
+ .rcss = 15,
+ .rlpw = 250,
+ .rhpw = 250,
+ .wcss = 10,
+ .wlpw = 28,
+ .whpw = 28,
+ },
+[MCU_LCD_GRAM_TIMING] = { /* read/write gram timing (ns) */
+ .rcss = 25, /* 25 ns */
+ .rlpw = 70,
+ .rhpw = 70,
+ .wcss = 10,
+ .wlpw = 50,
+ .whpw = 50,
+ }
+};
+
+static struct info_mcu lcd_s6d0139_info = {
+ .bus_mode = LCD_BUS_8080,
+ .bus_width = 16,
+ .bpp = 16, /*RGB565*/
+ .timing = lcd_s6d0139_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_s6d0139_spec = {
+ .width = 240,
+ .height = 320,
+ .type = LCD_MODE_MCU,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mcu = &lcd_s6d0139_info
+ },
+ .ops = &lcd_s6d0139_operations,
+};
+
+struct panel_cfg lcd_s6d0139 = {
+ /* this panel may on both CS0/1 */
+ .dev_id = SPRDFB_UNDEFINELCD_ID,
+ .lcd_id = 0x139,
+ .lcd_name = "lcd_s6d0139",
+ .panel = &lcd_s6d0139_spec,
+};
+
+static int __init lcd_s6d0139_init(void)
+{
+ return sprdfb_panel_register(&lcd_s6d0139);
+}
+
+subsys_initcall(lcd_s6d0139_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_s6d77a1_pikeA_mipi.c b/drivers/video/sprdfb/lcd/lcd_s6d77a1_pikeA_mipi.c
new file mode 100644
index 00000000..9b186b7a
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_s6d77a1_pikeA_mipi.c
@@ -0,0 +1,330 @@
+/* drivers/video/sprdfb/lcd_s6d77a1_pikeA_mipi.c
+ *
+ * Support for s6d77a1 mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+#include <mach/gpio.h>
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 150
+
+#define PIKEA_J1_NBW_PANEL
+
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+
+#ifndef PIKEA_J1_NBW_PANEL
+ {LCM_SEND(1),{0x11}},
+ {LCM_SEND(5),{3,0,0xF0,0x5A,0x5A}},
+ {LCM_SEND(5),{3,0,0xFC,0xA5,0xA5}},
+ {LCM_SEND(5),{3,0,0xF1,0x5A,0xA5}},
+
+ {LCM_SEND(2),{0xB3, 0x01}},
+ {LCM_SEND(2),{0xB5, 0x10}},
+ {LCM_SEND(6),{4,0,0xBC,0x01,0x29,0x51}}, /* 141006 Battery detect function disabled */
+
+ /* MIPI SETTING */
+ {LCM_SEND(5),{3,0,0xE3,0x24,0x2C}},
+
+ /* Display Inversion Off */
+ {LCM_SEND(1),{0x21}},
+
+ /* Display Control */
+ {LCM_SEND(10), {8,0,0xF2,0x11,0x04,0x08,0x10,0x10,0x82,0x54}},
+
+ /* power control 1 */
+ {LCM_SEND(8),{6,0,0xF3,0x91,0x00,0x00,0x00,0x10}},
+
+ /* power control 2 */
+ {LCM_SEND(46),{44,0,0xF4,0x01,0x02,0x23,0x24,0x25,0x25,0x26,0x26,0x29,0x29,0x2C,0x2B,0x2C,0x07,0x08,0x05,0x04,0x04,0x01,0x01,0x22,0x0A,0x17,0x0F,0x11,0x23,0x0D,0x0A,0x0B,0x02,0x19,0x13,0x1E,0x1F,0x23,0x20,0x05,0x16,0x1A,0x16,0x1E,0x24,0x1E}},
+
+ /* power control 3 */
+ {LCM_SEND(31),{29,0,0xF5,0x28,0x28,0xB9,0x21,0x35,0x55,0x36,0x0A,0x00,0x39,0x00,0x00,0x0B,0x4B,0xC4,0xCB,0x4B,0x12,0x12,0x1A,0x00,0x10,0xE0,0xE2,0x0E,0x34,0x34,0x03}},
+
+ /* 9.4 */
+ {LCM_SEND(20),{18,0,0xFE,0x00,0x02,0x01,0x39,0x60,0x40,0x21,0x00,0x4B,0x00,0x80,0x00,0xF0,0x00,0x00,0x00,0x02}},
+
+ /* ASG EQ Control */
+ {LCM_SEND(13),{11,0,0xEE,0x00,0xA8,0x00,0xA8,0x00,0x00,0x00,0x00,0x00,0x00}},
+
+ {LCM_SEND(24),{22,0,0xEF,0x23,0x01,0x00,0x00,0x2A,0x49,0x08,0x27,0x21,0x40,0x10,0x28,0x02,0x21,0x21,0x03,0x03,0x40,0x00,0x08,0x00}},
+
+ /* Panel Gate Control */
+ {LCM_SEND(33),{31,0,0xF7,0x02,0x1B,0x0D,0x0D,0x09,0x09,0x0C,0x0C,0x08,0x08,0x04,0x06,0x1A,0x02,0x02,0x02,0x1B,0x0F,0x0F,0x0B,0x0B,0x0E,0x0E,0x0A,0x0A,0x05,0x07,0x1A,0x02,0x02}},
+
+ /* Source Control */
+ {LCM_SEND(9),{7,0,0xF6,0x63,0x25,0x15,0x00,0x00,0x2A}},
+
+ /* Memory Data Access Control */
+ {LCM_SEND(2),{0x36,0x10}},
+
+ /* Positive Gamma Control */
+ {LCM_SEND(20),{18,0,0xFA,0x0C,0x36,0x11,0x17,0x0E,0x14,0x19,0x18,0x1A,0x21,0x23,0x22,0x22,0x21,0x22,0x22,0x29}},
+
+ /* Negative Gamma Control */
+ {LCM_SEND(20),{18,0,0xFB,0x0C,0x36,0x12,0x17,0x0F,0x14,0x19,0x18,0x1A,0x21,0x24,0x22,0x23,0x21,0x22,0x22,0x29}},
+
+ /* display on */
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(120)},
+
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(120)},
+#else
+
+ {LCM_SEND(5), {3, 0x00, 0xF0, 0x5A, 0x5A} },
+ {LCM_SEND(5), {3, 0x00, 0xFC, 0xA5, 0xA5} },
+ {LCM_SEND(2), {0xB3, 0x01} },
+ {LCM_SEND(2), {0xB5, 0x10} },
+ {LCM_SEND(6), {4, 0x00, 0xBC, 0x00, 0x29, 0x51} },
+ {LCM_SEND(5), {3, 0x00, 0xE3, 0x24, 0x2C} },
+ {LCM_SEND(1), {0x21} },
+ {LCM_SEND(10), {8, 0x00, 0xF2, 0x11, 0x04, 0x08, 0x10, 0x10, 0x82, 0x54} },
+ {LCM_SEND(8), {6, 0x00, 0xF3, 0x91, 0x00, 0x00, 0x00, 0x10} },
+ {LCM_SEND(46), {44, 0x00, 0xF4, 0x01, 0x02, 0x23, 0x24, 0x25, 0x25, 0x26, 0x26, 0x29, 0x29, 0x2C, 0x2B, 0x2C,
+ 0x07, 0x08, 0x05, 0x04, 0x04, 0x01, 0x01, 0x22, 0x0A, 0x17, 0x0F, 0x11, 0x23, 0x0D, 0x0A, 0x0B,
+ 0x02, 0x19, 0x13, 0x1E, 0x1F, 0x23, 0x20, 0x05, 0x16, 0x1A, 0x16, 0x1E, 0x24, 0x1E} },
+ {LCM_SEND(31), {29, 0x00, 0xF5, 0x5A, 0x62, 0xB9, 0x21, 0x35, 0x55, 0x06, 0x08, 0x00, 0x39, 0x00, 0x00, 0x0B,
+ 0x4B, 0xC4, 0xCB, 0x4B, 0x12, 0x12, 0x1A, 0x00, 0x10, 0xE0, 0xE2, 0x0E, 0x34, 0x34, 0x03} },
+ {LCM_SEND(20), {18, 0x00, 0xFE, 0x00, 0x02, 0x01, 0x39, 0x60, 0x40, 0x21, 0x00, 0x4B, 0x00, 0x80, 0x00, 0xF0,
+ 0x00, 0x00, 0x00, 0x02} },
+ {LCM_SEND(13), {11, 0x00, 0xEE, 0x86, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+ {LCM_SEND(24), {22, 0x00, 0xEF, 0x34, 0x12, 0x00, 0x00, 0x0A, 0x29, 0x08, 0x27, 0x21, 0x40, 0x10, 0x28, 0x02,
+ 0x21, 0x21, 0x03, 0x03, 0x40, 0x00, 0x00, 0x00} },
+ {LCM_SEND(33), {31, 0x00, 0xF7, 0x02, 0x1B, 0x1A, 0x00, 0x01, 0x0D, 0x0D, 0x09, 0x09, 0x0C, 0x0C, 0x08, 0x08,
+ 0x04, 0x06, 0x02, 0x1B, 0x1A, 0x00, 0x01, 0x0F, 0x0F, 0x0B, 0x0B, 0x0E, 0x0E, 0x0A, 0x0A, 0x05, 0x07} },
+ {LCM_SEND(9), {7, 0x00, 0xF6, 0x63, 0x25, 0x15, 0x00, 0x00, 0x2E} },
+ {LCM_SEND(2), {0x36, 0x10} },
+ {LCM_SEND(20), {18, 0x00, 0xFA, 0x00, 0x3F, 0x09, 0x10, 0x08, 0x0D, 0x12, 0x12, 0x12, 0x18, 0x1B, 0x1B, 0x1D, 0x1E, 0x21, 0x25, 0x2D} },
+ {LCM_SEND(20), {18, 0x00, 0xFB, 0x00, 0x3F, 0x09, 0x11, 0x08, 0x0E, 0x13, 0x12, 0x13, 0x19, 0x1B, 0x1C, 0x1D, 0x1E, 0x21, 0x25, 0x2D} },
+ {LCM_SEND(10), {8, 0x00, 0xFD, 0x00, 0x10, 0x11, 0x20, 0x21, 0x1F, 0xCC} },
+ {LCM_SEND(5), {3, 0x00, 0xFC, 0x5A, 0x5A} },
+/* display on */
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1),{0x29}},
+ {LCM_SLEEP(120)},
+#endif
+
+};
+
+static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(150)}, //>150ms
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(150)}, //>150ms
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},//>120ms
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)}, //>20ms
+};
+static int32_t s6d77a1_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel s6d77a1_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t s6d77a1_readid(struct panel_spec *self)
+ {
+ uint8_t j =0;
+ uint8_t read_data[4] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("lcd_s6d77a1_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x03;
+ param[1] = 0x00;
+ mipi_force_write(0x37, param, 2);
+ read_rtn = mipi_force_read(0x04, 3, read_data);
+ LCD_PRINT("lcd_s6d77a1_mipi read id 0xda, 0xdb,0xdc is 0x%x,0x%x,0x%x!\n",
+ read_data[0], read_data[1], read_data[2]);
+ if ((0x55 == read_data[0]) && (0xB8 == read_data[1])
+ && (0x10 == read_data[2])) {
+ LCD_PRINT("lcd_s6d77a1_mipi read id success!\n");
+ return 0x55b810;
+ }
+ }
+
+ mipi_eotp_set(0,0);
+
+ LCD_PRINT("lcd_s6d77a1_mipi read id failed!\n");
+ return 0;
+
+}
+
+
+static int32_t s6d77a1_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i = 0;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel s6d77a1_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(sleep_in_out->tag & LCM_TAG_MASK);
+ }
+ sleep_in_out++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static struct panel_operations lcd_s6d77a1_mipi_operations = {
+ .panel_init = s6d77a1_mipi_init,
+ .panel_readid = s6d77a1_readid,
+ .panel_enter_sleep = s6d77a1_enter_sleep,
+};
+
+static struct timing_rgb lcd_s6d77a1_mipi_timing = {
+ .hfp = 84, /* unit: pixel */
+ .hbp = 90,
+ .hsync = 40,
+ .vfp = 16, /* unit: line */
+ .vbp = 12,
+ .vsync = 4,
+};
+
+
+static struct info_mipi lcd_s6d77a1_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq =481*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_s6d77a1_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_s6d77a1_mipi_spec = {
+ .width = 480,
+ .height = 800,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .is_clean_lcd = true,
+ .info = {
+ .mipi = &lcd_s6d77a1_mipi_info
+ },
+ .ops = &lcd_s6d77a1_mipi_operations,
+};
+struct panel_cfg lcd_s6d77a1_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x55b810,
+ .lcd_name = "lcd_s6d77a1_mipi",
+ .panel = &lcd_s6d77a1_mipi_spec,
+};
+
+
+static int __init lcd_s6d77a1_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_s6d77a1_mipi);
+}
+
+subsys_initcall(lcd_s6d77a1_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_s6d7aa0x62_t8_mipi.c b/drivers/video/sprdfb/lcd/lcd_s6d7aa0x62_t8_mipi.c
new file mode 100644
index 00000000..67f8df1b
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_s6d7aa0x62_t8_mipi.c
@@ -0,0 +1,350 @@
+/* drivers/video/sprdfb/lcd_hx8389b_mipi.c
+ *
+ * Support for hx8389b mipi LCD device
+ *
+ * Copyright (C) 2015 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+#include <linux/gpio.h>
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 150
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+
+ //Initializing Sequence(1)
+ {LCM_SEND(5), {3, 0, 0xF0, 0x5A, 0x5A} },
+ {LCM_SEND(5), {3, 0, 0xF1, 0x5A, 0x5A} },
+ {LCM_SEND(5), {3, 0, 0xFC, 0xA5, 0xA5} },
+ {LCM_SEND(5), {3, 0, 0xD0, 0x00, 0x10} },
+
+ //Initializing Sequence(2)
+ {LCM_SEND(2), {0xB1, 0x12} },
+ {LCM_SEND(7), {5, 0, 0xB2,0x14, 0x22, 0x2F, 0x18} },
+ {LCM_SEND(2), {0xB3, 0x11} },
+ {LCM_SEND(12), {10, 0, 0xBA,0x03,0x19,0x19,0x11,0x03,0x05,0x18,0x18,0x77} },
+ {LCM_SEND(6), {4, 0, 0xBC,0x00, 0x4E, 0x0B} },
+ {LCM_SEND(6), {4, 0, 0xC0,0x80, 0x80, 0x30} },
+ {LCM_SEND(2), {0xC1, 0x03} },
+ {LCM_SEND(2), {0xC2, 0x00} },
+ {LCM_SEND(6), {4, 0, 0xC3, 0x40,0x00, 0x28} },
+ {LCM_SEND(8), {6, 0, 0xE1, 0x03,0x10, 0x1C, 0xA0, 0x10} },
+ {LCM_SEND(11), {9, 0, 0xEE, 0xA5,0x00,0x98,0x00,0xA5,0x00,0x98,0x00} },
+ {LCM_SEND(8), {6, 0, 0xF2, 0x02,0x10, 0x10, 0x44, 0x10} },
+ {LCM_SEND(13), {11, 0, 0xF3, 0x01,0x93,0x20,0x22,0x80,0x05,0x25,0x3C,0x26,0x00} },
+ {LCM_SEND(48), {46, 0, 0xF4, 0x02,0x02,0x10,0x26,0x10,0x02,0x03,0x03,0x03,0x10,0x16,0x03, \
+ 0x00,0x0C,0x0C,0x03,0x04,0x05,0x13,0x1E,0x09,0x0A,0x05,0x05,0x01,0x04,0x02, \
+ 0x61,0x74,0x75,0x72,0x83,0x80,0x80,0x00,0x00,0x01,0x01,0x28,0x04,0x03,0x28, \
+ 0x01,0xD1,0x32} },
+ {LCM_SEND(35), {33, 0, 0xF7,0x01,0x1B,0x08,0x0C,0x09,0x0D,0x01,0x01,0x01,0x04,0x06,0x01,0x01, \
+ 0x00,0x00,0x1A,0x01,0x1B,0x0A,0x0E,0x0B,0x0F,0x01,0x01,0x01,0x05,0x07,0x01,0x01,
+ 0x00,0x00,0x1A} },
+ {LCM_SEND(9), {7, 0, 0xF6, 0x60,0x25, 0x05, 0x00, 0x00, 0x00} },
+ {LCM_SEND(8), {6, 0, 0xFD, 0x16,0x10, 0x11, 0x23, 0x09} },
+ {LCM_SEND(9), {7, 0, 0xFE, 0x00,0x02, 0x03, 0x21, 0x80, 0x78} },
+ {LCM_SEND(20), {18, 0, 0xEF,0x34,0x12,0x98,0xBA,0x10,0x80,0x24,0x80,0x80,0x80,0x00,0x00,0x00, \
+ 0x44,0xA0,0x82,0x00} },
+ {LCM_SEND(16), {14, 0, 0xCD,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E} },
+ {LCM_SEND(16), {14, 0, 0xCE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} },
+ {LCM_SEND(2), {0x51, 0xFF} },
+ {LCM_SEND(2), {0x53, 0x2C} },
+ {LCM_SEND(2), {0x55, 0x01} },
+
+ // Initializing Sequence(3)
+ {LCM_SEND(20), {18, 0, 0xFA,0x08,0x3F,0x0D,0x12,0x07,0x0C,0x11,0x0F,0x11,0x18,0x1D,0x1E,0x21,\
+ 0x23,0x24,0x27,0x30,} },
+ {LCM_SEND(20), {18, 0, 0xF8,0x08,0x3F,0x0C,0x12,0x07,0x0C,0x10,0x0F,0x11,0x18,0x1D,0x1E,0x21,\
+ 0x23,0x23,0x26,0x2F} },
+
+ // Initializing Sequence(1-1)
+ {LCM_SEND(5), {3, 0, 0xF0, 0xA5, 0xA5} },
+ {LCM_SEND(5), {3, 0, 0xF1, 0xA5, 0xA5} },
+ {LCM_SEND(5), {3, 0, 0xFC, 0x5A, 0x5A} },
+
+ // power on
+ {LCM_SEND(1), {0x11} },
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1), {0x29} },
+ {LCM_SLEEP(20)},
+
+};
+
+static LCM_Force_Cmd_Code rd_prep_code_1[]={
+ {0x37, {LCM_SEND(2), {0x1, 0}}},
+};
+
+static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(150)}, //>150ms
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(150)}, //>150ms
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},//>120ms
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)}, //>20ms
+};
+
+static int32_t s6d7aa0x62_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel s6d7aa0x62_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(init->data, (init->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t s6d7aa0x62_readid(struct panel_spec *self)
+{
+#if 0
+ uint32_t j =0;
+ uint8_t read_data[4] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("lcd_s6d7aa0x62_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x03;
+ param[1] = 0x00;
+ mipi_force_write(0x37, param, 2);
+ read_rtn = mipi_force_read(0x04,3, &read_data[0]);
+ LCD_PRINT("lcd_s6d7aa0x62_mipi read id 0x04 value is 0x%x, 0x%x, 0x%x!\n", read_data[0], read_data[1], read_data[2]);
+
+ if(0x83 == read_data[0] && 0x94 == read_data[1] && 0x1A == read_data[2]){
+ LCD_PRINT("s6d7aa0x62 success!\n");
+ return 0xaa62;
+ }
+ }
+
+ mipi_eotp_set(0,0);
+
+ return 0;
+#endif
+ return 0x6262;
+}
+
+static uint32_t s6d7aa0x62_readpowermode(struct panel_spec *self)
+{
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code_1;
+ uint8_t read_data[1] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_debug("lcd_s6d7aa0x62_mipi read power mode!\n");
+ mipi_eotp_set(0,0);
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code_1;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code_1); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }
+ rd_prepare++;
+ }
+ read_rtn = mipi_force_read(0x0A, 1,(uint8_t *)read_data);
+ pr_debug("lcd_hx8389b mipi read power mode 0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+ if((0x1c == read_data[0])){
+ //printk("lcd_hx8389b_mipi read power mode success!\n");
+ mipi_eotp_set(0,0);
+ return 0x1c;
+ }
+ }
+
+ printk("lcd_s6d7aa0x62 mipi read power mode fail!0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+ mipi_eotp_set(0,0);
+ return 0x0;
+}
+
+static int32_t s6d7aa0x62_check_esd(struct panel_spec *self)
+{
+ uint32_t power_mode;
+
+ mipi_set_lp_mode_t mipi_set_data_lp_mode = self->info.mipi->ops->mipi_set_data_lp_mode;
+ mipi_set_hs_mode_t mipi_set_data_hs_mode = self->info.mipi->ops->mipi_set_data_hs_mode;
+ mipi_set_lp_mode_t mipi_set_lp_mode = self->info.mipi->ops->mipi_set_lp_mode;
+ mipi_set_hs_mode_t mipi_set_hs_mode = self->info.mipi->ops->mipi_set_hs_mode;
+ uint16_t work_mode = self->info.mipi->work_mode;
+
+ pr_debug("s6d7aa0x62_check_esd!\n");
+#ifndef FB_CHECK_ESD_IN_VFP
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_lp_mode();
+ }else{
+ mipi_set_data_lp_mode();
+ }
+#endif
+ power_mode = s6d7aa0x62_readpowermode(self);
+ //power_mode = 0x0;
+#ifndef FB_CHECK_ESD_IN_VFP
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_hs_mode();
+ }else{
+ mipi_set_data_hs_mode();
+ }
+#endif
+ if(power_mode == 0x1c){
+ pr_debug("s6d7aa0x62_check_esd OK!\n");
+ return 1;
+ }else{
+ printk("s6d7aa0x62_check_esd fail!(0x%x)\n", power_mode);
+ return 0;
+ }
+}
+
+static struct panel_operations lcd_s6d7aa0x62_mipi_operations = {
+ .panel_init = s6d7aa0x62_mipi_init,
+ .panel_readid = s6d7aa0x62_readid,
+ .panel_esd_check = s6d7aa0x62_check_esd,
+};
+
+static struct timing_rgb lcd_s6d7aa0x62_mipi_timing = {
+ .hfp = 104, /* unit: pixel */
+ .hbp = 154,
+ .hsync = 1,
+ .vfp = 16, /*unit: line*/
+ .vbp = 12,
+ .vsync = 1,
+};
+
+
+static struct info_mipi lcd_s6d7aa0x62_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 4,
+ .phy_feq = 481*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_s6d7aa0x62_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_s6d7aa0x62_mipi_spec = {
+ .width = 720,
+ .height = 1280,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_s6d7aa0x62_mipi_info
+ },
+ .ops = &lcd_s6d7aa0x62_mipi_operations,
+};
+
+struct panel_cfg lcd_s6d7aa0x62_mipi = {
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x6262,
+ .lcd_name = "lcd_s6d7aa0x62_mipi",
+ .panel = &lcd_s6d7aa0x62_mipi_spec,
+};
+
+static int __init lcd_s6d7aa0x62_mipi_init(void)
+{
+#if 0
+ if (gpio_request(152, "LCD_3V3")) {
+ printk("Failed ro request LCD_3V3 GPIO_%d \n",152);
+ return -ENODEV;
+ }
+ if (gpio_request(155, "BL_EN")) {
+ printk("Failed ro request BL_EN GPIO_%d \n",155);
+ return -ENODEV;
+ }
+ if (gpio_request(232, "CABC_EN0")) {
+ printk("Failed ro request CABC_EN0 GPIO_%d \n",232);
+ return -ENODEV;
+ }
+ if (gpio_request(233, "CABC_EN1")) {
+ printk("Failed ro request CABC_EN1 GPIO_%d \n",233);
+ return -ENODEV;
+ }
+ gpio_direction_output(152, 1);
+ gpio_direction_output(155, 1);
+ gpio_direction_output(232, 1);
+ gpio_direction_output(233, 1);
+#endif
+ return sprdfb_panel_register(&lcd_s6d7aa0x62_mipi);
+}
+
+subsys_initcall(lcd_s6d7aa0x62_mipi_init);
+
+
diff --git a/drivers/video/sprdfb/lcd/lcd_sc7798_rgb_spi.c b/drivers/video/sprdfb/lcd/lcd_sc7798_rgb_spi.c
new file mode 100755
index 00000000..0b9d7a73
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_sc7798_rgb_spi.c
@@ -0,0 +1,561 @@
+/* drivers/video/sc8810/lcd_hx8363_rgb_spi.c
+ *
+ *
+ *
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+
+
+
+#define sc7798_SpiWriteCmd(cmd) \
+{ \
+ spi_send_cmd((cmd & 0xFF));\
+}
+
+#define sc7798_SpiWriteData(data)\
+{ \
+ spi_send_data((data & 0xFF));\
+}
+static int32_t sc7798_init(struct panel_spec *self)
+{
+ uint32_t test_data[8] = {0};
+ uint32_t left = 0;
+ uint32_t top = 0;
+ uint32_t right = 480;
+ uint32_t bottom = 800;
+ uint32_t data = 0;
+ spi_send_cmd_t spi_send_cmd = self->info.rgb->bus_info.spi->ops->spi_send_cmd;
+ spi_send_data_t spi_send_data = self->info.rgb->bus_info.spi->ops->spi_send_data;
+ spi_read_t spi_read = self->info.rgb->bus_info.spi->ops->spi_read;
+
+
+ printk("sc7798_init\n");
+
+ sc7798_SpiWriteCmd(0xB9);
+ sc7798_SpiWriteData(0xF1);
+ sc7798_SpiWriteData(0x08);
+ sc7798_SpiWriteData(0x00);
+
+ sc7798_SpiWriteCmd(0xBC);
+ sc7798_SpiWriteData(0x67);
+
+ sc7798_SpiWriteCmd(0x3A);
+ sc7798_SpiWriteData(0x70);
+
+ sc7798_SpiWriteCmd(0xB2);
+ sc7798_SpiWriteData(0x23);
+
+ sc7798_SpiWriteCmd(0xB4);
+ sc7798_SpiWriteData(0x00);
+
+ sc7798_SpiWriteCmd(0xB1);
+ sc7798_SpiWriteData(0x22);
+ sc7798_SpiWriteData(0x1B);
+ sc7798_SpiWriteData(0x1B);
+ sc7798_SpiWriteData(0xB7);
+ sc7798_SpiWriteData(0x22);
+ sc7798_SpiWriteData(0x02);
+ sc7798_SpiWriteData(0xA8);
+
+ sc7798_SpiWriteCmd(0xC6);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0xFF);
+
+ sc7798_SpiWriteCmd(0xCC);
+ sc7798_SpiWriteData(0x0C);
+
+ sc7798_SpiWriteCmd(0xE3);
+ sc7798_SpiWriteData(0x02);
+ sc7798_SpiWriteData(0x02);
+ sc7798_SpiWriteData(0x02);
+ sc7798_SpiWriteData(0x02);
+
+
+ sc7798_SpiWriteCmd(0xB8);
+ sc7798_SpiWriteData(0x07);
+ sc7798_SpiWriteData(0x22);
+
+ sc7798_SpiWriteCmd(0xB5);
+ sc7798_SpiWriteData(0x09);
+ sc7798_SpiWriteData(0x09);
+
+ sc7798_SpiWriteCmd(0xC0);
+ sc7798_SpiWriteData(0x73);
+ sc7798_SpiWriteData(0x50);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x08);
+ sc7798_SpiWriteData(0x70);
+
+ sc7798_SpiWriteCmd(0xB3);
+ sc7798_SpiWriteData(0x01);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x06);
+ sc7798_SpiWriteData(0x06);
+ sc7798_SpiWriteData(0x10);
+ sc7798_SpiWriteData(0x0A);
+ sc7798_SpiWriteData(0x45);
+ sc7798_SpiWriteData(0x40);
+
+ sc7798_SpiWriteCmd(0xB9);
+ sc7798_SpiWriteData(0xF1);
+ sc7798_SpiWriteData(0x08);
+ sc7798_SpiWriteData(0x00);
+
+ sc7798_SpiWriteCmd(0xE9);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x08);
+ sc7798_SpiWriteData(0x03);
+ sc7798_SpiWriteData(0x2F);
+ sc7798_SpiWriteData(0x89);
+ sc7798_SpiWriteData(0x6A);
+ sc7798_SpiWriteData(0x12);
+ sc7798_SpiWriteData(0x31);
+ sc7798_SpiWriteData(0x23);
+ sc7798_SpiWriteData(0x48);
+ sc7798_SpiWriteData(0x0C);
+ sc7798_SpiWriteData(0x89);
+ sc7798_SpiWriteData(0x6A);
+ sc7798_SpiWriteData(0x47);
+ sc7798_SpiWriteData(0x02);
+ sc7798_SpiWriteData(0x04);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x20);
+ sc7798_SpiWriteData(0x88);
+ sc7798_SpiWriteData(0x88);
+ sc7798_SpiWriteData(0x40);
+ sc7798_SpiWriteData(0x28);
+ sc7798_SpiWriteData(0x69);
+ sc7798_SpiWriteData(0x48);
+ sc7798_SpiWriteData(0x88);
+ sc7798_SpiWriteData(0x88);
+ sc7798_SpiWriteData(0x80);
+ sc7798_SpiWriteData(0x88);
+ sc7798_SpiWriteData(0x88);
+ sc7798_SpiWriteData(0x51);
+ sc7798_SpiWriteData(0x38);
+ sc7798_SpiWriteData(0x79);
+ sc7798_SpiWriteData(0x58);
+ sc7798_SpiWriteData(0x88);
+ sc7798_SpiWriteData(0x88);
+ sc7798_SpiWriteData(0x81);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+
+ sc7798_SpiWriteCmd(0xEA);
+ sc7798_SpiWriteData(0x88);
+ sc7798_SpiWriteData(0x88);
+ sc7798_SpiWriteData(0x37);
+ sc7798_SpiWriteData(0x59);
+ sc7798_SpiWriteData(0x18);
+ sc7798_SpiWriteData(0x18);
+ sc7798_SpiWriteData(0x88);
+ sc7798_SpiWriteData(0x88);
+ sc7798_SpiWriteData(0x85);
+ sc7798_SpiWriteData(0x88);
+ sc7798_SpiWriteData(0x88);
+ sc7798_SpiWriteData(0x26);
+ sc7798_SpiWriteData(0x49);
+ sc7798_SpiWriteData(0x08);
+ sc7798_SpiWriteData(0x08);
+ sc7798_SpiWriteData(0x88);
+ sc7798_SpiWriteData(0x88);
+ sc7798_SpiWriteData(0x84);
+ sc7798_SpiWriteData(0x30);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0xFF);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x50);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+
+ sc7798_SpiWriteCmd(0xE0);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x04);
+ sc7798_SpiWriteData(0x04);
+ sc7798_SpiWriteData(0x0A);
+ sc7798_SpiWriteData(0x18);
+ sc7798_SpiWriteData(0x2B);
+ sc7798_SpiWriteData(0x05);
+ sc7798_SpiWriteData(0x0C);
+ sc7798_SpiWriteData(0x11);
+ sc7798_SpiWriteData(0x16);
+ sc7798_SpiWriteData(0x18);
+ sc7798_SpiWriteData(0x16);
+ sc7798_SpiWriteData(0x16);
+ sc7798_SpiWriteData(0x15);
+ sc7798_SpiWriteData(0x19);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x04);
+ sc7798_SpiWriteData(0x04);
+ sc7798_SpiWriteData(0x0A);
+ sc7798_SpiWriteData(0x18);
+ sc7798_SpiWriteData(0x2C);
+ sc7798_SpiWriteData(0x05);
+ sc7798_SpiWriteData(0x0C);
+ sc7798_SpiWriteData(0x12);
+ sc7798_SpiWriteData(0x16);
+ sc7798_SpiWriteData(0x18);
+ sc7798_SpiWriteData(0x16);
+ sc7798_SpiWriteData(0x17);
+ sc7798_SpiWriteData(0x16);
+ sc7798_SpiWriteData(0x19);
+
+#if 0
+ sc7798_SpiWriteCmd(0xC1);
+ sc7798_SpiWriteData(0x01);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x03);
+ sc7798_SpiWriteData(0x0B);
+ sc7798_SpiWriteData(0x17);
+ sc7798_SpiWriteData(0x20);
+ sc7798_SpiWriteData(0x26);
+ sc7798_SpiWriteData(0x30);
+ sc7798_SpiWriteData(0x36);
+ sc7798_SpiWriteData(0x3F);
+ sc7798_SpiWriteData(0x48);
+ sc7798_SpiWriteData(0x50);
+ sc7798_SpiWriteData(0x58);
+ sc7798_SpiWriteData(0x5F);
+ sc7798_SpiWriteData(0x68);
+ sc7798_SpiWriteData(0x71);
+ sc7798_SpiWriteData(0x79);
+ sc7798_SpiWriteData(0x82);
+ sc7798_SpiWriteData(0x89);
+ sc7798_SpiWriteData(0x91);
+ sc7798_SpiWriteData(0x99);
+ sc7798_SpiWriteData(0xA1);
+ sc7798_SpiWriteData(0xA9);
+ sc7798_SpiWriteData(0xB0);
+ sc7798_SpiWriteData(0xB8);
+ sc7798_SpiWriteData(0xC0);
+ sc7798_SpiWriteData(0xC8);
+ sc7798_SpiWriteData(0xD0);
+ sc7798_SpiWriteData(0xD6);
+ sc7798_SpiWriteData(0xDC);
+ sc7798_SpiWriteData(0xE4);
+ sc7798_SpiWriteData(0xED);
+ sc7798_SpiWriteData(0xF7);
+ sc7798_SpiWriteData(0xFF);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0xC0);
+ sc7798_SpiWriteData(0x0A);
+ sc7798_SpiWriteData(0x80);
+ sc7798_SpiWriteData(0x30);
+ sc7798_SpiWriteData(0xE8);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x03);
+ sc7798_SpiWriteData(0x0B);
+ sc7798_SpiWriteData(0x17);
+ sc7798_SpiWriteData(0x20);
+ sc7798_SpiWriteData(0x27);
+ sc7798_SpiWriteData(0x30);
+ sc7798_SpiWriteData(0x37);
+ sc7798_SpiWriteData(0x40);
+ sc7798_SpiWriteData(0x48);
+ sc7798_SpiWriteData(0x50);
+ sc7798_SpiWriteData(0x58);
+ sc7798_SpiWriteData(0x5F);
+ sc7798_SpiWriteData(0x67);
+ sc7798_SpiWriteData(0x70);
+ sc7798_SpiWriteData(0x78);
+ sc7798_SpiWriteData(0x80);
+ sc7798_SpiWriteData(0x88);
+ sc7798_SpiWriteData(0x90);
+ sc7798_SpiWriteData(0x98);
+ sc7798_SpiWriteData(0xA0);
+ sc7798_SpiWriteData(0xA8);
+ sc7798_SpiWriteData(0xAF);
+ sc7798_SpiWriteData(0xB7);
+ sc7798_SpiWriteData(0xBF);
+ sc7798_SpiWriteData(0xC7);
+ sc7798_SpiWriteData(0xCF);
+ sc7798_SpiWriteData(0xD5);
+ sc7798_SpiWriteData(0xDC);
+ sc7798_SpiWriteData(0xE4);
+ sc7798_SpiWriteData(0xED);
+ sc7798_SpiWriteData(0xF7);
+ sc7798_SpiWriteData(0xFF);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0xC0);
+ sc7798_SpiWriteData(0x0A);
+ sc7798_SpiWriteData(0x80);
+ sc7798_SpiWriteData(0x30);
+ sc7798_SpiWriteData(0xE8);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x03);
+ sc7798_SpiWriteData(0x0D);
+ sc7798_SpiWriteData(0x19);
+ sc7798_SpiWriteData(0x23);
+ sc7798_SpiWriteData(0x29);
+ sc7798_SpiWriteData(0x31);
+ sc7798_SpiWriteData(0x38);
+ sc7798_SpiWriteData(0x41);
+ sc7798_SpiWriteData(0x48);
+ sc7798_SpiWriteData(0x4F);
+ sc7798_SpiWriteData(0x57);
+ sc7798_SpiWriteData(0x5D);
+ sc7798_SpiWriteData(0x65);
+ sc7798_SpiWriteData(0x6C);
+ sc7798_SpiWriteData(0x74);
+ sc7798_SpiWriteData(0x7B);
+ sc7798_SpiWriteData(0x84);
+ sc7798_SpiWriteData(0x8B);
+ sc7798_SpiWriteData(0x94);
+ sc7798_SpiWriteData(0x9B);
+ sc7798_SpiWriteData(0xA4);
+ sc7798_SpiWriteData(0xAA);
+ sc7798_SpiWriteData(0xB4);
+ sc7798_SpiWriteData(0xB9);
+ sc7798_SpiWriteData(0xC3);
+ sc7798_SpiWriteData(0xCC);
+ sc7798_SpiWriteData(0xD6);
+ sc7798_SpiWriteData(0xDC);
+ sc7798_SpiWriteData(0xE4);
+ sc7798_SpiWriteData(0xED);
+ sc7798_SpiWriteData(0xF7);
+ sc7798_SpiWriteData(0xFF);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0x00);
+ sc7798_SpiWriteData(0xC0);
+ sc7798_SpiWriteData(0x0A);
+ sc7798_SpiWriteData(0x80);
+ sc7798_SpiWriteData(0x30);
+ sc7798_SpiWriteData(0xE8);
+ sc7798_SpiWriteData(0x00);
+#endif
+
+ sc7798_SpiWriteCmd(0x11);
+ mdelay(120);
+ sc7798_SpiWriteCmd(0x29);
+}
+
+
+#if 1
+static int32_t sc7798_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ spi_send_cmd_t spi_send_cmd = self->info.rgb->bus_info.spi->ops->spi_send_cmd;
+ spi_send_data_t spi_send_data = self->info.rgb->bus_info.spi->ops->spi_send_data;
+
+ if(is_sleep==1){
+ //Sleep In
+ sc7798_SpiWriteCmd(0x28);
+ mdelay(120);
+ sc7798_SpiWriteCmd(0x10);
+ mdelay(10);
+ }else{
+ //Sleep Out
+ sc7798_SpiWriteCmd(0x11);
+ mdelay(120);
+ sc7798_SpiWriteCmd(0x29);
+ mdelay(10);
+ }
+
+ return 0;
+}
+
+
+
+
+static int32_t sc7798_set_window(struct panel_spec *self,
+ uint16_t left, uint16_t top, uint16_t right, uint16_t bottom)
+{
+ uint32_t *test_data[4] = {0};
+ spi_send_cmd_t spi_send_cmd = self->info.rgb->bus_info.spi->ops->spi_send_cmd;
+ spi_send_data_t spi_send_data = self->info.rgb->bus_info.spi->ops->spi_send_data;
+ spi_read_t spi_read = self->info.rgb->bus_info.spi->ops->spi_read;
+#if 0
+
+ printk("zxdbg add -hx8363_set_window: %d, %d, %d, %d\n",left, top, right, bottom);
+
+ sc7798_SpiWriteCmd(0x2A00);
+ sc7798_SpiWriteData((left>>8));// set left address
+ sc7798_SpiWriteData((left&0xff));
+ sc7798_SpiWriteData((right>>8));// set right address
+ sc7798_SpiWriteData((right&0xff));
+
+ sc7798_SpiWriteCmd(0x2B00);
+ sc7798_SpiWriteData((top>>8));// set left address
+ sc7798_SpiWriteData((top&0xff));
+ sc7798_SpiWriteData((bottom>>8));// set bottom address
+ sc7798_SpiWriteData((bottom&0xff));
+
+// HX8363_SpiWriteCmd(0x2C00);
+
+ sc7798_SpiWriteCmd(0x2A00);
+ spi_read(test_data);
+ spi_read(test_data+1);
+ sc7798_SpiWriteCmd(0x2B00);
+ spi_read(test_data+2);
+ spi_read(test_data+3);
+#endif
+// printk("zxdbg add -hx8363_read read: %x, %x, %x, %x\n",test_data[0], test_data[1], test_data[2], test_data[3]);
+
+ return 0;
+}
+
+static int32_t sc7798_invalidate(struct panel_spec *self)
+{
+// printk("hx8363_invalidate\n");
+
+ return self->ops->panel_set_window(self, 0, 0,
+ self->width - 1, self->height - 1);
+}
+
+
+
+static int32_t sc7798_invalidate_rect(struct panel_spec *self,
+ uint16_t left, uint16_t top,
+ uint16_t right, uint16_t bottom)
+{
+// printk("hx8363_invalidate_rect \n");
+
+ return self->ops->panel_set_window(self, left, top,
+ right, bottom);
+}
+
+
+#endif
+
+
+static int32_t sc7798_read_id(struct panel_spec *self)
+{
+#if 0
+ int32_t id = 0x62;
+ spi_send_cmd_t spi_send_cmd = self->info.rgb->bus_info.spi->ops->spi_send_cmd;
+ spi_send_data_t spi_send_data = self->info.rgb->bus_info.spi->ops->spi_send_data;
+ spi_read_t spi_read = self->info.rgb->bus_info.spi->ops->spi_read;
+/*
+ printk("sprdfb hx8363_read_id \n");
+ HX8363_SpiWriteCmd(0xB9); // SET password
+ HX8363_SpiWriteData(0xFF); //
+ HX8363_SpiWriteData(0x83); //
+ HX8363_SpiWriteData(0x63); //
+
+ HX8363_SpiWriteCmd(0xFE); // SET SPI READ INDEX
+ HX8363_SpiWriteData(0xF4); // GETHXID
+ HX8363_SpiWriteCmd(0xFF); // GET SPI READ
+
+ spi_read(&id);
+*/
+ id &= 0xff;
+ printk(" hx8363_read_id kernel id = %x\n",id);
+// return id;
+#endif
+ return 0x7798;
+}
+
+static struct panel_operations lcd_sc7798_rgb_spi_operations = {
+ .panel_init = sc7798_init,
+ .panel_set_window = sc7798_set_window,
+ .panel_invalidate_rect= sc7798_invalidate_rect,
+ .panel_invalidate = sc7798_invalidate,
+ .panel_enter_sleep = sc7798_enter_sleep,
+ .panel_readid = sc7798_read_id
+};
+
+static struct timing_rgb lcd_sc7798_rgb_timing = {
+ .hfp = 90,
+ .hbp = 70,
+ .hsync = 60,
+ .vfp = 8,
+ .vbp = 12,
+ .vsync = 4,
+
+};
+
+static struct spi_info lcd_sc7798_rgb_spi_info = {
+ .ops = NULL,
+};
+
+static struct info_rgb lcd_sc7798_rgb_info = {
+ .cmd_bus_mode = SPRDFB_RGB_BUS_TYPE_SPI,
+ .video_bus_width = 24, /*18,16*/
+ .h_sync_pol = SPRDFB_POLARITY_NEG,
+ .v_sync_pol = SPRDFB_POLARITY_NEG,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .timing = &lcd_sc7798_rgb_timing,
+ .bus_info = {
+ .spi = &lcd_sc7798_rgb_spi_info,
+ }
+};
+
+struct panel_spec lcd_panel_sc7798_rgb_spi_spec = {
+
+ .width = 480,
+ .height = 800,
+ .fps = 60,
+ .type = LCD_MODE_RGB,
+ .direction = LCD_DIRECT_NORMAL,
+ .is_clean_lcd = true,
+ .info = {
+ .rgb = &lcd_sc7798_rgb_info
+ },
+ .ops = &lcd_sc7798_rgb_spi_operations,
+};
+
+struct panel_cfg lcd_sc7798_rgb_spi_spec = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x7798,
+ .lcd_name = "lcd_sc7798_rgb_spi",
+ .panel = &lcd_panel_sc7798_rgb_spi_spec,
+};
+
+static int __init lcd_sc7798_rgb_spi_init(void)
+{
+ return sprdfb_panel_register(&lcd_sc7798_rgb_spi_spec);
+
+}
+
+subsys_initcall(lcd_sc7798_rgb_spi_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_sd7798d_mipi.c b/drivers/video/sprdfb/lcd/lcd_sd7798d_mipi.c
new file mode 100755
index 00000000..e377c3c5
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_sd7798d_mipi.c
@@ -0,0 +1,261 @@
+/* drivers/video/sprdfb/lcd_sc7798d_mipi.c
+ *
+ * Support for sc7798d mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+#include <mach/gpio.h>
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 150
+
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+ {LCM_SEND(6), {4, 0, 0xB9, 0xF1, 0x08, 0x00} },
+ /*{LCM_SLEEP(10)},*/
+ {LCM_SEND(10), {8, 0, 0xB1, 0x31, 0x0C, 0x0C, 0xA7, 0x33, 0x01, 0xB7} },
+ {LCM_SEND(6), {4, 0, 0xC6, 0x00, 0x00, 0xFD} },
+ {LCM_SEND(7), {5, 0, 0xE3, 0x03, 0x03, 0x03, 0x03} },
+ {LCM_SEND(5), {3, 0, 0xB8, 0x06, 0x22} },
+ {LCM_SLEEP(10)},
+ {LCM_SEND(21), {19, 0, 0xBA, 0x31, 0x00, 0x44, 0x25, 0x91, 0x0A, 0x00, 0x00, 0xC2, 0x34, 0x00, 0x00, 0x04, 0x02, 0x1D,
+ 0xB9, 0xEE, 0x40} },
+ {LCM_SEND(11), {9, 0, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0A, 0x25, 0x20} },
+ {LCM_SEND(2), {0xB4, 0x00} },
+ {LCM_SEND(2), {0xCC, 0x0E} },
+ {LCM_SEND(2), {0xBC, 0x67} },
+ {LCM_SEND(2), {0xB2, 0x03} },
+ {LCM_SEND(8), {6, 0, 0xC0, 0x73, 0x50, 0x00, 0x08, 0x70} },
+ {LCM_SEND(54), {52, 0, 0xE9, 0x00, 0x00, 0x06, 0x00, 0x00, 0x6E, 0x29, 0x12, 0x30, 0x00, 0x48, 0x08, 0x6E, 0x29, 0x47,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x89, 0x98, 0x33, 0x11, 0x77, 0x55,
+ 0x13, 0x00, 0x00, 0x89, 0x98, 0x22, 0x00, 0x66, 0x44, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,} },
+ {LCM_SEND(39), {37, 0, 0xEA, 0x00, 0x00, 0x98, 0x98, 0x44, 0x66, 0x00, 0x22, 0x20, 0x00, 0x00, 0x98, 0x98, 0x55, 0x77,
+ 0x11, 0x33, 0x31, 0x30, 0x00, 0x00, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,} },
+ {LCM_SEND(37), {35, 0, 0xE0, 0x01, 0x09, 0x0D, 0x2E, 0x36, 0x3F, 0x10, 0x31, 0x07, 0x0D, 0x11, 0x15, 0x13, 0x16, 0x15,
+ 0x32, 0x38, 0x01, 0x05, 0x05, 0x30, 0x35, 0x3F, 0x0E, 0x30, 0x04, 0x09, 0x0A, 0x0D, 0x12,
+ 0x0D, 0x0F, 0x2C, 0x35} },
+ {LCM_SEND(1), {0x11} },
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1), {0x29} },
+ {LCM_SLEEP(20)},
+
+};
+
+
+static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(150)}, //>150ms
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(150)}, //>150ms
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},//>120ms
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)}, //>20ms
+};
+static int32_t sc7798d_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel sc7798d_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t sc7798d_readid(struct panel_spec *self)
+{
+ int32_t j =0;
+ uint8_t read_data[3] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("kernel lcd_sc7798d_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x01;
+ param[1] = 0x00;
+ mipi_force_write(0x37, param, 2);
+ read_rtn = mipi_force_read(0xda,1,&read_data[0]);
+ read_rtn = mipi_force_read(0xdb,1,&read_data[1]);
+ read_rtn = mipi_force_read(0xdc,1,&read_data[2]);
+
+ if((0x55 == read_data[0])&&(0xB8 == read_data[1])&&(0xF0 == read_data[2]))
+ {
+ printk("lcd_sc7798d_mipi read id success!\n");
+ return 0x55b8f0;
+ }
+ }
+ mipi_eotp_set(0,0);
+ LCD_PRINT("lcd_sc7798d_mipi read id fail! 0xda,0xdb,0xdc is 0x%x,0x%x,0x%x!\n",read_data[0],read_data[1],read_data[2]);
+ return 0;
+}
+
+
+static int32_t sc7798d_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i = 0;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel sc7798d_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(sleep_in_out->tag & LCM_TAG_MASK);
+ }
+ sleep_in_out++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static struct panel_operations lcd_sc7798d_mipi_operations = {
+ .panel_init = sc7798d_mipi_init,
+ .panel_readid = sc7798d_readid,
+ .panel_enter_sleep = sc7798d_enter_sleep,
+};
+
+static struct timing_rgb lcd_sc7798d_mipi_timing = {
+ .hfp = 145, /* unit: pixel */
+ .hbp = 90,
+ .hsync = 70,
+ .vfp = 10, /*unit: line*/
+ .vbp = 12,
+ .vsync = 4,
+};
+
+
+static struct info_mipi lcd_sc7798d_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq =481*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_sc7798d_mipi_timing,
+ .ops = NULL,
+};
+struct panel_spec lcd_sc7798d_mipi_spec = {
+ .width = 480,
+ .height = 800,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_sc7798d_mipi_info
+ },
+ .ops = &lcd_sc7798d_mipi_operations,
+};
+struct panel_cfg lcd_sc7798d_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x55b8f0,
+ .lcd_name = "lcd_sc7798d_mipi",
+ .panel = &lcd_sc7798d_mipi_spec,
+};
+
+//temp code
+static int __init lcd_sc7798d_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_sc7798d_mipi);
+}
+
+subsys_initcall(lcd_sc7798d_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_sd7798d_mipi_sharkls_z3lte.c b/drivers/video/sprdfb/lcd/lcd_sd7798d_mipi_sharkls_z3lte.c
new file mode 100755
index 00000000..e377c3c5
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_sd7798d_mipi_sharkls_z3lte.c
@@ -0,0 +1,261 @@
+/* drivers/video/sprdfb/lcd_sc7798d_mipi.c
+ *
+ * Support for sc7798d mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+#include <mach/gpio.h>
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 150
+
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+ {LCM_SEND(6), {4, 0, 0xB9, 0xF1, 0x08, 0x00} },
+ /*{LCM_SLEEP(10)},*/
+ {LCM_SEND(10), {8, 0, 0xB1, 0x31, 0x0C, 0x0C, 0xA7, 0x33, 0x01, 0xB7} },
+ {LCM_SEND(6), {4, 0, 0xC6, 0x00, 0x00, 0xFD} },
+ {LCM_SEND(7), {5, 0, 0xE3, 0x03, 0x03, 0x03, 0x03} },
+ {LCM_SEND(5), {3, 0, 0xB8, 0x06, 0x22} },
+ {LCM_SLEEP(10)},
+ {LCM_SEND(21), {19, 0, 0xBA, 0x31, 0x00, 0x44, 0x25, 0x91, 0x0A, 0x00, 0x00, 0xC2, 0x34, 0x00, 0x00, 0x04, 0x02, 0x1D,
+ 0xB9, 0xEE, 0x40} },
+ {LCM_SEND(11), {9, 0, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0A, 0x25, 0x20} },
+ {LCM_SEND(2), {0xB4, 0x00} },
+ {LCM_SEND(2), {0xCC, 0x0E} },
+ {LCM_SEND(2), {0xBC, 0x67} },
+ {LCM_SEND(2), {0xB2, 0x03} },
+ {LCM_SEND(8), {6, 0, 0xC0, 0x73, 0x50, 0x00, 0x08, 0x70} },
+ {LCM_SEND(54), {52, 0, 0xE9, 0x00, 0x00, 0x06, 0x00, 0x00, 0x6E, 0x29, 0x12, 0x30, 0x00, 0x48, 0x08, 0x6E, 0x29, 0x47,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x89, 0x98, 0x33, 0x11, 0x77, 0x55,
+ 0x13, 0x00, 0x00, 0x89, 0x98, 0x22, 0x00, 0x66, 0x44, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,} },
+ {LCM_SEND(39), {37, 0, 0xEA, 0x00, 0x00, 0x98, 0x98, 0x44, 0x66, 0x00, 0x22, 0x20, 0x00, 0x00, 0x98, 0x98, 0x55, 0x77,
+ 0x11, 0x33, 0x31, 0x30, 0x00, 0x00, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,} },
+ {LCM_SEND(37), {35, 0, 0xE0, 0x01, 0x09, 0x0D, 0x2E, 0x36, 0x3F, 0x10, 0x31, 0x07, 0x0D, 0x11, 0x15, 0x13, 0x16, 0x15,
+ 0x32, 0x38, 0x01, 0x05, 0x05, 0x30, 0x35, 0x3F, 0x0E, 0x30, 0x04, 0x09, 0x0A, 0x0D, 0x12,
+ 0x0D, 0x0F, 0x2C, 0x35} },
+ {LCM_SEND(1), {0x11} },
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1), {0x29} },
+ {LCM_SLEEP(20)},
+
+};
+
+
+static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(1), {0x28}},
+ {LCM_SLEEP(150)}, //>150ms
+ {LCM_SEND(1), {0x10}},
+ {LCM_SLEEP(150)}, //>150ms
+};
+
+static LCM_Init_Code sleep_out[] = {
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},//>120ms
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(20)}, //>20ms
+};
+static int32_t sc7798d_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel sc7798d_mipi_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static uint32_t sc7798d_readid(struct panel_spec *self)
+{
+ int32_t j =0;
+ uint8_t read_data[3] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ LCD_PRINT("kernel lcd_sc7798d_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x01;
+ param[1] = 0x00;
+ mipi_force_write(0x37, param, 2);
+ read_rtn = mipi_force_read(0xda,1,&read_data[0]);
+ read_rtn = mipi_force_read(0xdb,1,&read_data[1]);
+ read_rtn = mipi_force_read(0xdc,1,&read_data[2]);
+
+ if((0x55 == read_data[0])&&(0xB8 == read_data[1])&&(0xF0 == read_data[2]))
+ {
+ printk("lcd_sc7798d_mipi read id success!\n");
+ return 0x55b8f0;
+ }
+ }
+ mipi_eotp_set(0,0);
+ LCD_PRINT("lcd_sc7798d_mipi read id fail! 0xda,0xdb,0xdc is 0x%x,0x%x,0x%x!\n",read_data[0],read_data[1],read_data[2]);
+ return 0;
+}
+
+
+static int32_t sc7798d_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i = 0;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_dcs_write_t mipi_dcs_write = self->info.mipi->ops->mipi_dcs_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("kernel sc7798d_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_dcs_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep(sleep_in_out->tag & LCM_TAG_MASK);
+ }
+ sleep_in_out++;
+ }
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+static struct panel_operations lcd_sc7798d_mipi_operations = {
+ .panel_init = sc7798d_mipi_init,
+ .panel_readid = sc7798d_readid,
+ .panel_enter_sleep = sc7798d_enter_sleep,
+};
+
+static struct timing_rgb lcd_sc7798d_mipi_timing = {
+ .hfp = 145, /* unit: pixel */
+ .hbp = 90,
+ .hsync = 70,
+ .vfp = 10, /*unit: line*/
+ .vbp = 12,
+ .vsync = 4,
+};
+
+
+static struct info_mipi lcd_sc7798d_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq =481*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_sc7798d_mipi_timing,
+ .ops = NULL,
+};
+struct panel_spec lcd_sc7798d_mipi_spec = {
+ .width = 480,
+ .height = 800,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_sc7798d_mipi_info
+ },
+ .ops = &lcd_sc7798d_mipi_operations,
+};
+struct panel_cfg lcd_sc7798d_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x55b8f0,
+ .lcd_name = "lcd_sc7798d_mipi",
+ .panel = &lcd_sc7798d_mipi_spec,
+};
+
+//temp code
+static int __init lcd_sc7798d_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_sc7798d_mipi);
+}
+
+subsys_initcall(lcd_sc7798d_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_ssd2075_mipi.c b/drivers/video/sprdfb/lcd/lcd_ssd2075_mipi.c
new file mode 100644
index 00000000..b2281be3
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_ssd2075_mipi.c
@@ -0,0 +1,375 @@
+/* drivers/video/sprdfb/lcd_ssd2075_mipi.c
+ *
+ * Support for ssd2075 mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+//#define printk printf
+
+#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 48
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+ {LCM_SEND(2),{0xE1,0x93}},
+ {LCM_SEND(2),{0xB3,0x00}},
+ //5inchGIP
+ {LCM_SEND(7),{5,0,0xB6,0x16,0x0F,0x00,0x77}}, //0x00
+ {LCM_SEND(11),{9,0,0xB8,0x00,0x06,0x08,0x00,0x07,0x09,0x23,0x04}},
+ {LCM_SEND(9),{7,0,0xB9,0x04,0x08,0x22,0xFF,0xFF,0x0F}},
+ {LCM_SEND(11),{9,0,0xBA,0x0E,0x0E,0x10,0x10,0x0A,0x0A,0x0C,0x0C}},
+ {LCM_SEND(11),{9,0,0xBB,0xA1,0xA1,0xA1,0xA1,0xA1,0xA1,0xA1,0xA1}},
+ {LCM_SEND(11),{9,0,0xBC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(11),{9,0,0xBD,0x0F,0x0F,0x11,0x11,0x0B,0x0B,0x0D,0x0D}},
+ {LCM_SEND(11),{9,0,0xBE,0xA1,0xA1,0xA1,0xA1,0xA1,0xA1,0xA1,0xA1}},
+ {LCM_SEND(11),{9,0,0xBF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {LCM_SEND(6),{4,0,0xB1,0x06,0x44,0x10}},
+ {LCM_SEND(8),{6,0,0xE0,0x11,0x02,0x04,0x00,0x01}},
+
+ //Gamma2.2
+ #if 1
+ {LCM_SEND(9),{7,0,0xD0,0x00,0x00,0x0E,0x0F,0x14,0x20}},
+ {LCM_SEND(8),{6,0,0xD1,0x1A,0x37,0x29,0x1B,0x08}},
+ {LCM_SEND(9),{7,0,0xD2,0x00,0x00,0x0E,0x0F,0x14,0x20}},
+ {LCM_SEND(8),{6,0,0xD3,0x1A,0x37,0x29,0x1B,0x08}},
+ {LCM_SEND(9),{7,0,0xD4,0x00,0x00,0x0E,0x0F,0x14,0x20}},
+ {LCM_SEND(8),{6,0,0xD5,0x1A,0x37,0x29,0x1B,0x08}},
+ {LCM_SEND(9),{7,0,0xD6,0x00,0x00,0x0E,0x0F,0x14,0x20}},
+ {LCM_SEND(8),{6,0,0xD7,0x1A,0x37,0x29,0x1B,0x08}},
+ {LCM_SEND(9),{7,0,0xD8,0x00,0x00,0x0E,0x0F,0x14,0x20}},
+ {LCM_SEND(8),{6,0,0xD9,0x1A,0x37,0x29,0x1B,0x08}},
+ {LCM_SEND(9),{7,0,0xDA,0x00,0x00,0x0E,0x0F,0x14,0x20}},
+ {LCM_SEND(8),{6,0,0xDB,0x1A,0x37,0x29,0x1B,0x08}},
+ #else
+ {LCM_SEND(9),{7,0,0xD0,0x00,0x00,0x1E,0x27,0x2D,0x35}},
+ {LCM_SEND(8),{6,0,0xD1,0x2D,0x27,0x1A,0x1B,0x0A}},
+ {LCM_SEND(9),{7,0,0xD2,0x00,0x00,0x1E,0x27,0x2D,0x35}},
+ {LCM_SEND(8),{6,0,0xD3,0x2D,0x27,0x1A,0x1B,0x0A}},
+ {LCM_SEND(9),{7,0,0xD4,0x00,0x00,0x1E,0x27,0x2D,0x35}},
+ {LCM_SEND(8),{6,0,0xD5,0x26,0x2B,0x23,0x1B,0x0A}},
+ {LCM_SEND(9),{7,0,0xD6,0x00,0x00,0x1E,0x27,0x2D,0x35}},
+ {LCM_SEND(8),{6,0,0xD7,0x2D,0x27,0x1A,0x1B,0x0A}},
+ {LCM_SEND(9),{7,0,0xD8,0x00,0x00,0x1E,0x27,0x2D,0x35}},
+ {LCM_SEND(8),{6,0,0xD9,0x2D,0x27,0x1A,0x1B,0x0A}},
+ {LCM_SEND(9),{7,0,0xDA,0x00,0x00,0x1E,0x27,0x2D,0x35}},
+ {LCM_SEND(8),{6,0,0xDB,0x2D,0x27,0x1A,0x1B,0x0A}},
+ #endif
+ {LCM_SEND(7),{5,0,0x70,0xD8,0x00,0xFF,0x80}},
+ {LCM_SEND(2),{0xFF,0x01}},
+
+ {LCM_SEND(5),{3,0,0xC6,0xCC,0x33}},//77->CC
+ {LCM_SEND(5),{3,0,0xDE,0x9D,0x30}},
+ {LCM_SEND(2),{0x14,0x00}},
+
+ {LCM_SEND(2),{0xE9,0x07}},
+ {LCM_SEND(5),{3,0,0xED,0x60,0x10}},
+ {LCM_SEND(2),{0xEC,0x12}},
+ {LCM_SEND(7),{5,0,0xCD,0x77,0x7B,0x34,0x08}},
+ {LCM_SEND(10),{8,0,0xC3,0x03,0x0D,0x34,0x05,0x01,0x44,0x54}},
+ {LCM_SEND(8),{6,0,0xC4,0x02,0x03,0x3D,0x3D,0x5A}}, // Vcom
+ {LCM_SEND(6),{4,0,0xCB,0xDF,0x80,0x00}},
+ {LCM_SEND(6),{4,0,0xEA,0x15,0x28,0x00}},
+ {LCM_SEND(7),{5,0,0xF0,0x38,0x00,0x00,0x00}},
+ {LCM_SEND(6),{4,0,0xC9,0x60,0x00,0x82}},
+ {LCM_SEND(11),{9,0,0xB5,0x00,0x05,0x05,0x1E,0x04,0x40,0x20,0xFC}},
+ {LCM_SEND(2),{0x36,0x0B}},//08->0B rotate 180
+ {LCM_SEND(2),{0x3A,0x70}},
+ {LCM_SEND(1),{0x11}},
+ {LCM_SLEEP(120)},
+ {LCM_SEND(1),{0x29}},
+};
+
+//static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+//static LCM_Init_Code sleep_in = {LCM_SEND(1), {0x10}};
+
+//static LCM_Init_Code sleep_out = {LCM_SEND(1), {0x11}};
+static LCM_Init_Code sleep_in[] = {
+{LCM_SEND(1), {0x28}},
+{LCM_SLEEP(10)},
+{LCM_SEND(1), {0x10}},
+{LCM_SLEEP(120)},
+{LCM_SEND(2), {0x4f, 0x01}},
+};
+
+static LCM_Init_Code sleep_out[] = {
+{LCM_SEND(1), {0x11}},
+{LCM_SLEEP(120)},
+{LCM_SEND(1), {0x29}},
+{LCM_SLEEP(20)},
+};
+
+static LCM_Force_Cmd_Code rd_prep_code_1[]={
+ {0x37, {LCM_SEND(2), {0x3, 0}}},
+};
+
+static int32_t ssd2075_mipi_init(struct panel_spec *self)
+{
+ int32_t i = 0;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("lcd_ssd2075_init\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(1,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((init->tag & LCM_TAG_MASK));
+ }
+ init++;
+ }
+ mipi_eotp_set(1,1);
+
+ return 0;
+}
+
+static uint32_t ssd2075_readid(struct panel_spec *self)
+{
+ int32_t j =0;
+ uint8_t read_data[10] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("lcd_ssd2075_mipi read id!\n");
+ mipi_set_cmd_mode();
+ mipi_eotp_set(1,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x0a;
+ param[1] = 0x00;
+ mipi_force_write(0x37, param, 2);
+ read_rtn = mipi_force_read(0xA1,10,(uint8_t *)read_data);
+ printk("lcd_ssd2075_mipi read id 0xA1 value is 0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x!\n", read_data[0], read_data[1], \
+ read_data[2], read_data[3],read_data[4], read_data[5],read_data[6], read_data[7],read_data[8], read_data[9]);
+
+ if((0x20 == read_data[0])&&(0x75 == read_data[1])){
+ printk("lcd_ssd2075_mipi read id success!\n");
+ mipi_eotp_set(1,1);
+ return 0x2075;
+ }
+ }
+ mipi_eotp_set(1,1);
+
+ return 0;
+}
+
+static int32_t ssd2075_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i = 0;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk(KERN_DEBUG "ssd2075_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+ mipi_eotp_set(1,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((sleep_in_out->tag & LCM_TAG_MASK));
+ }
+ sleep_in_out++;
+ }
+ mipi_eotp_set(1,1);
+
+ return 0;
+}
+
+static uint32_t ssd2075_readpowermode(struct panel_spec *self)
+{
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code_1;
+ uint8_t read_data[3] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+// pr_debug("lcd_ssd2075_mipi read power mode!\n");
+
+ mipi_eotp_set(0,1);
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code_1;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code_1); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }
+ rd_prepare++;
+ }
+ read_rtn = mipi_force_read(0xF5, 3,(uint8_t *)read_data);
+// printk("lcd_ssd2075 mipi read power mode 0xF5 value r[0]=0x%x,r[1]=0x%x,r[2]=0x%x! , read result(%d)\n", read_data[0],read_data[1],read_data[2],read_rtn);
+ if((0x0 == read_data[0]) && (0x0 == read_data[1]) && (0x0 == read_data[2]) && (0 == read_rtn)){
+ mipi_eotp_set(1,1);
+// pr_debug("lcd_ssd2075_mipi read power mode success!\n");
+ return 0xF5;
+ }
+ }
+ mipi_eotp_set(1,1);
+ printk("lcd_ssd2075 ssd2075_readpowermode fail! 0xF5 value r[0]=0x%x,r[1]=0x%x,r[2]=0x%x! , read result(%d)\n", read_data[0],\
+ read_data[1],read_data[2],read_rtn);
+ return 0x0;
+}
+
+static int32_t ssd2075_check_esd(struct panel_spec *self)
+{
+ uint32_t power_mode;
+
+ mipi_set_lp_mode_t mipi_set_data_lp_mode = self->info.mipi->ops->mipi_set_data_lp_mode;
+ mipi_set_hs_mode_t mipi_set_data_hs_mode = self->info.mipi->ops->mipi_set_data_hs_mode;
+ mipi_set_lp_mode_t mipi_set_lp_mode = self->info.mipi->ops->mipi_set_lp_mode;
+ mipi_set_hs_mode_t mipi_set_hs_mode = self->info.mipi->ops->mipi_set_hs_mode;
+ uint16_t work_mode = self->info.mipi->work_mode;
+
+// pr_debug("ssd2075_check_esd!\n");
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_lp_mode();
+ }else{
+ mipi_set_data_lp_mode();
+ }
+ power_mode = ssd2075_readpowermode(self);
+ //power_mode = 0x0;
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_hs_mode();
+ }else{
+ mipi_set_data_hs_mode();
+ }
+ if(power_mode == 0xF5){
+// pr_debug("ssd2075_check_esd OK!\n");
+ return 1;
+ }else{
+ printk("ssd2075_check_esd fail!(0x%x)\n", power_mode);
+ return 0;
+ }
+}
+
+static struct panel_operations lcd_ssd2075_mipi_operations = {
+ .panel_init = ssd2075_mipi_init,
+ .panel_readid = ssd2075_readid,
+ .panel_enter_sleep = ssd2075_enter_sleep,
+ .panel_esd_check = ssd2075_check_esd,
+};
+
+static struct timing_rgb lcd_ssd2075_mipi_timing = {
+ .hfp =50,
+ .hbp = 36,
+ .hsync =16,
+ .vfp = 12,
+ .vbp = 14,
+ .vsync = 2,
+};
+
+
+static struct info_mipi lcd_ssd2075_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 4,
+ .phy_feq =500*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_ssd2075_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_ssd2075_mipi_spec = {
+ .width = 720,
+ .height = 1280,
+ .fps = 60,
+ .reset_timing = {20,20,120},
+ .suspend_mode = SEND_SLEEP_CMD,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mipi = &lcd_ssd2075_mipi_info
+ },
+ .ops = &lcd_ssd2075_mipi_operations,
+};
+struct panel_cfg lcd_ssd2075_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x2075,
+ .lcd_name = "lcd_ssd2075_mipi",
+ .panel = &lcd_ssd2075_mipi_spec,
+};
+
+static int __init lcd_ssd2075_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_ssd2075_mipi);
+}
+
+subsys_initcall(lcd_ssd2075_mipi_init);
+
diff --git a/drivers/video/sprdfb/lcd/lcd_st7789v_mcu.c b/drivers/video/sprdfb/lcd/lcd_st7789v_mcu.c
new file mode 100644
index 00000000..f9538e90
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_st7789v_mcu.c
@@ -0,0 +1,336 @@
+/* drivers/video/sprdfb/lcd_st7789v.c
+ *
+ * Support for st7789v LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+#define ST7789V_BUS_WIDTH_8BIT // bus_width = 8
+
+static int32_t st7789v_init(struct panel_spec *self)
+ {
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ pr_debug("st7789v_init\n");
+ //Power setting sequence
+ send_cmd(0x11);
+ mdelay(120);
+
+#if defined(ST7789V_BUS_WIDTH_8BIT)
+ send_cmd(0xDF);
+ send_data(0x5A69);
+ send_data(0x0201);
+
+ send_cmd(0x36);
+ send_data(0x0000);
+
+ send_cmd(0x3a);
+ send_data(0x0500);
+
+ send_cmd(0x35);
+ send_data(0x0000);
+
+ send_cmd(0xd2);
+ send_data(0x4c00);
+
+ send_cmd(0xb2);
+ send_data(0x0404);
+ send_data(0x0033);
+ send_data(0x3300);
+
+ send_cmd(0xC6);
+ send_data(0x0A00);
+
+ send_cmd(0xb8);
+ send_data(0x2A2B);
+ send_data(0x0575);
+
+ send_cmd(0xb7);
+ send_data(0x7500);
+
+ send_cmd(0xbb);
+ send_data(0x1B00);
+
+ send_cmd(0xC2);
+ send_data(0x0100);
+
+ send_cmd(0xC3);
+ send_data(0x0b00);
+
+ send_cmd(0xC4);
+ send_data(0x2000);
+
+ send_cmd(0xd0);
+ send_data(0xa4a1);
+
+ send_cmd(0xE8);
+ send_data(0x8300);
+
+ send_cmd(0xE9);
+ send_data(0x0909);
+ send_data(0x0500);
+
+ send_cmd(0xC0);
+ send_data(0x2500);
+
+ send_cmd(0xb0);
+ send_data(0x00d0);
+
+ send_cmd(0xE0);
+ send_data(0xd00E);
+ send_data(0x1810);
+ send_data(0x0E2A);
+ send_data(0x3E54);
+ send_data(0x4C2B);
+ send_data(0x1716);
+ send_data(0x1D21);
+
+ send_cmd(0XE1);
+ send_data(0xd00E);
+ send_data(0x1710);
+ send_data(0x0E29);
+ send_data(0x3C44);
+ send_data(0x4D2C);
+ send_data(0x1615);
+ send_data(0x1E22);
+
+ send_cmd(0x29);
+#else // 16/18/24bit
+ send_cmd(0xB7); send_data(0x35);
+ send_cmd(0xBB); send_data(0x1A);
+ send_cmd(0xC2); send_data(0x01);
+ send_cmd(0xC3); send_data(0x0B);
+ send_cmd(0xC4); send_data(0x20);
+ send_cmd(0xD0); send_data(0xA4);send_data(0xA1);
+ send_cmd(0xE8); send_data(0x83);
+ send_cmd(0xE9); send_data(0x09);send_data(0x09);send_data(0x08);
+
+ //Init setting
+ send_cmd(0x36); send_data(0x00);
+ send_cmd(0x35); send_data(0x00);
+ send_cmd(0x3A); send_data(0x05);//0x06: 262k 0x05:65k
+ send_cmd(0xD2); send_data(0x4C);
+ send_cmd(0xB2);send_data(0x0C);send_data(0x0C);send_data(0x00);send_data(0x33);send_data(0x33);
+ send_cmd(0xC6); send_data(0x09);
+
+ //Gamma setting
+ send_cmd(0xE0);
+ send_data(0xD0);
+ send_data(0x02);
+ send_data(0x11);
+ send_data(0x12);
+ send_data(0x12);
+ send_data(0x2A);
+ send_data(0x3D);
+ send_data(0x44);
+ send_data(0x4C);
+ send_data(0x2B);
+ send_data(0x16);
+ send_data(0x14);
+ send_data(0x1E);
+ send_data(0x21);
+
+ send_cmd(0xE1);
+ send_data(0xD0);
+ send_data(0x02);
+ send_data(0x11);
+ send_data(0x11);
+ send_data(0x12);
+ send_data(0x2A);
+ send_data(0x3B);
+ send_data(0x44);
+ send_data(0x4C);
+ send_data(0x2B);
+ send_data(0x16);
+ send_data(0x15);
+ send_data(0x1E);
+ send_data(0x21);
+
+ send_cmd(0x29); //Display On
+#endif
+ return 0;
+}
+
+
+static int32_t st7789v_set_window(struct panel_spec *self,
+ uint16_t left, uint16_t top, uint16_t right, uint16_t bottom)
+{
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ send_data_t send_data = self->info.mcu->ops->send_data;
+
+ pr_debug("st7789v_set_window\n");
+
+#if defined(ST7789V_BUS_WIDTH_8BIT)
+ send_cmd(0x002A); // col
+ send_data(left);
+ send_data(right);
+
+ send_cmd(0x002B); // row
+ send_data(top);
+ send_data(bottom);
+ send_cmd(0x002C);
+#else // 16/18/24bit
+ send_cmd(0x2A); // col
+ send_data((left >> 8));
+ send_data((left & 0xFF));
+ send_data((right >> 8));
+ send_data((right & 0xFF));
+
+ send_cmd(0x2B); // row
+ send_data((top >> 8));
+ send_data((top & 0xFF));
+ send_data((bottom >> 8));
+ send_data((bottom & 0xFF));
+ send_cmd(0x2C);
+#endif
+
+ return 0;
+}
+
+
+static int32_t st7789v_invalidate(struct panel_spec *self)
+{
+ pr_debug("st7789v_invalidate\n");
+
+ return self->ops->panel_set_window(self, 0, 0,
+ self->width-1, self->height-1);
+}
+
+static int32_t st7789v_invalidate_rect(struct panel_spec *self,
+ uint16_t left, uint16_t top,
+ uint16_t right, uint16_t bottom)
+{
+
+ pr_debug("st7789v_invalidate_rect : (%d, %d, %d, %d)\n",left, top, right, bottom);
+
+ return self->ops->panel_set_window(self, left, top,
+ right, bottom);
+}
+
+static int32_t st7789v_set_direction(struct panel_spec *self, uint16_t direction)
+{
+
+ pr_debug("st7789v_set_direction\n");
+ return 0;
+}
+
+static int32_t st7789v_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ //send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+
+ if(is_sleep) {
+ //send_cmd(0x10);
+ mdelay(120);
+ }
+ else {
+ //send_cmd(0x11);
+ mdelay(120);
+ }
+ return 0;
+}
+
+#define LCD_MTP_ID 0x51a0f0
+static uint32_t st7789v_read_id(struct panel_spec *self)
+{
+ int32_t read_value = 0;
+
+ send_data_t send_cmd = self->info.mcu->ops->send_cmd;
+ read_data_t read_data = self->info.mcu->ops->read_data;
+
+ send_cmd(0x04);
+
+#if defined(ST7789V_BUS_WIDTH_8BIT)
+ read_value += (read_data() &0xff)<<16;
+ read_value += read_data();
+#else
+ read_data();
+ read_value += read_data()<< 16;
+ read_value += read_data()<< 8;
+ read_value += read_data();
+#endif
+ pr_debug("st7789v_read_id=%x\n",read_value);
+
+ if(read_value == LCD_MTP_ID)
+ read_value = 0x7789;
+
+ return read_value;
+}
+
+static struct panel_operations lcd_st7789v_operations = {
+ .panel_init = st7789v_init,
+ .panel_set_window = st7789v_set_window,
+ .panel_invalidate = st7789v_invalidate,
+ //.lcd_invalidate_rect = st7789v_invalidate_rect,
+ .panel_set_direction = st7789v_set_direction,
+ .panel_enter_sleep = st7789v_enter_sleep,
+ .panel_readid = st7789v_read_id,
+};
+
+static struct timing_mcu lcd_st7789v_timing[] = {
+ [MCU_LCD_REGISTER_TIMING] = {
+ .rcss = 45,
+ .rlpw = 60,
+ .rhpw = 100,
+ .wcss = 10,
+ .wlpw = 28,
+ .whpw = 28,
+ },
+ [MCU_LCD_GRAM_TIMING] = {
+ .rcss = 25, /* 25 ns */
+ .rlpw = 70,
+ .rhpw = 70,
+ .wcss = 10,
+ .wlpw = 28,
+ .whpw = 28,
+ }
+};
+
+
+static struct info_mcu lcd_st7789v_info = {
+ .bus_mode = LCD_BUS_8080,
+ .bus_width = 8, //16,
+ .bpp = 16, /*RGB565*/
+ .timing = &lcd_st7789v_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_panel_st7789v = {
+ .width = 240,
+ .height = 320,
+ .fps = 60,
+ .type = LCD_MODE_MCU,
+ .direction = LCD_DIRECT_NORMAL,
+ .info = {
+ .mcu = &lcd_st7789v_info
+ },
+ .ops = &lcd_st7789v_operations,
+};
+
+struct panel_cfg lcd_st7789v = {
+ /* this panel may on both CS0/1 */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x7789,
+ .lcd_name = "lcd_st7789v",
+ .panel = &lcd_panel_st7789v,
+};
+
+static int __init lcd_st7789v_init(void)
+{
+ return sprdfb_panel_register(&lcd_st7789v);
+}
+
+subsys_initcall(lcd_st7789v_init); \ No newline at end of file
diff --git a/drivers/video/sprdfb/lcd/lcd_t8861_mipi.c b/drivers/video/sprdfb/lcd/lcd_t8861_mipi.c
new file mode 100644
index 00000000..51e8a908
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_t8861_mipi.c
@@ -0,0 +1,485 @@
+/* drivers/video/sprdfb/lcd/lcd_t8861_mipi.c
+ *
+ * Support for t8861 mipi LCD device
+ *
+ * Copyright (C) 2010 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+
+//#define LCD_DEBUG
+#ifdef LCD_DEBUG
+#define LCD_PRINT printk
+#else
+#define LCD_PRINT(...)
+#endif
+
+#define MAX_DATA 48
+
+typedef struct LCM_Init_Code_tag {
+ unsigned int tag;
+ unsigned char data[MAX_DATA];
+}LCM_Init_Code;
+
+typedef struct LCM_force_cmd_code_tag{
+ unsigned int datatype;
+ LCM_Init_Code real_cmd_code;
+}LCM_Force_Cmd_Code;
+
+#define LCM_TAG_SHIFT 24
+#define LCM_TAG_MASK ((1 << 24) -1)
+#define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)
+#define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)
+//#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))
+
+#define LCM_TAG_SEND (1<< 0)
+#define LCM_TAG_SLEEP (1 << 1)
+
+static LCM_Init_Code init_data[] = {
+
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x01}},
+ {LCM_SLEEP(5)},
+
+ {LCM_SEND(2), {0x08,0x10}},
+
+ {LCM_SEND(2), {0x21,0x01}},
+
+ {LCM_SEND(2), {0x30,0x02}},
+ {LCM_SEND(2), {0x31,0x00}}, //0x02
+
+ {LCM_SEND(2), {0x60,0x07}},
+ {LCM_SEND(2), {0x61,0x06}},
+ {LCM_SEND(2), {0x62,0x06}},
+ {LCM_SEND(2), {0x63,0x04}},
+
+ {LCM_SEND(2), {0x40,0x14}},
+ {LCM_SEND(2), {0x41,0x44}},//22
+ {LCM_SEND(2), {0x42,0x01}},
+ {LCM_SEND(2), {0x43,0x89}},
+ {LCM_SEND(2), {0x44,0x89}},
+ {LCM_SEND(2), {0x45,0x1b}},
+ {LCM_SEND(2), {0x46,0x44}},
+ {LCM_SEND(2), {0x47,0x44}},
+
+ {LCM_SEND(2), {0x50,0x85}},
+ {LCM_SEND(2), {0x51,0x85}},
+ {LCM_SEND(2), {0x52,0x00}},
+ {LCM_SEND(2), {0x53,0x64}},//90
+
+ //{LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x01}},
+
+ {LCM_SEND(2), {0xA0,0x00}},
+ {LCM_SEND(2), {0xA1,0x00}},//01
+ {LCM_SEND(2), {0xA2,0x03}},//08
+ {LCM_SEND(2), {0xA3,0x0e}},//0e
+ {LCM_SEND(2), {0xA4,0x08}},//08
+ {LCM_SEND(2), {0xA5,0x1f}},//19
+ {LCM_SEND(2), {0xA6,0x0f}},//0b
+ {LCM_SEND(2), {0xA7,0x0b}},//0a
+ {LCM_SEND(2), {0xA8,0x03}},//02
+ {LCM_SEND(2), {0xA9,0x06}},//08
+ {LCM_SEND(2), {0xAA,0x05}},//04
+ {LCM_SEND(2), {0xAB,0x02}},//03
+ {LCM_SEND(2), {0xAC,0x0e}},//0a
+ {LCM_SEND(2), {0xAD,0x25}},//2c
+ {LCM_SEND(2), {0xAE,0x1d}},//28
+ {LCM_SEND(2), {0xAF,0x00}},
+
+ {LCM_SEND(2), {0xC0,0x00}},//00
+ {LCM_SEND(2), {0xC1,0x04}},//02
+ {LCM_SEND(2), {0xC2,0x0f}},//09
+ {LCM_SEND(2), {0xC3,0x10}},//0e
+ {LCM_SEND(2), {0xC4,0x0b}},//09
+ {LCM_SEND(2), {0xC5,0x1e}},//19
+ {LCM_SEND(2), {0xC6,0x09}},//0a
+ {LCM_SEND(2), {0xC7,0x0a}},//0a
+ {LCM_SEND(2), {0xC8,0x00}},//02
+ {LCM_SEND(2), {0xC9,0x0a}},//07
+ {LCM_SEND(2), {0xCA,0x01}},//05
+ {LCM_SEND(2), {0xCB,0x06}},//04
+ {LCM_SEND(2), {0xCC,0x09}},//0a
+ {LCM_SEND(2), {0xCD,0x2a}},//2d
+ {LCM_SEND(2), {0xCE,0x28}},//28
+ {LCM_SEND(2), {0xCF,0x00}},//00
+
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x06}},
+ {LCM_SEND(2), {0x00,0xa0}},
+ {LCM_SEND(2), {0x01,0x05}},
+ {LCM_SEND(2), {0x02,0x00}},
+ {LCM_SEND(2), {0x03,0x00}},
+ {LCM_SEND(2), {0x04,0x01}},
+ {LCM_SEND(2), {0x05,0x01}},
+ {LCM_SEND(2), {0x06,0x88}},
+ {LCM_SEND(2), {0x07,0x04}},
+ {LCM_SEND(2), {0x08,0x01}},
+ {LCM_SEND(2), {0x09,0x90}},
+ {LCM_SEND(2), {0x0A,0x04}},
+ {LCM_SEND(2), {0x0B,0x01}},
+ {LCM_SEND(2), {0x0C,0x01}},
+ {LCM_SEND(2), {0x0D,0x01}},
+ {LCM_SEND(2), {0x0E,0x00}},
+ {LCM_SEND(2), {0x0F,0x00}},
+
+ {LCM_SEND(2), {0x10,0x55}},
+ {LCM_SEND(2), {0x11,0x50}},
+ {LCM_SEND(2), {0x12,0x01}},
+ {LCM_SEND(2), {0x13,0x85}},
+ {LCM_SEND(2), {0x14,0x85}},
+ {LCM_SEND(2), {0x15,0xc0}},
+ {LCM_SEND(2), {0x16,0x0B}},
+ {LCM_SEND(2), {0x17,0x00}},
+ {LCM_SEND(2), {0x18,0x00}},
+ {LCM_SEND(2), {0x19,0x00}},
+ {LCM_SEND(2), {0x1A,0x00}},
+ {LCM_SEND(2), {0x1B,0x00}},
+ {LCM_SEND(2), {0x1C,0x00}},
+ {LCM_SEND(2), {0x1D,0x00}},
+
+ {LCM_SEND(2), {0x20,0x01}},
+ {LCM_SEND(2), {0x21,0x23}},
+ {LCM_SEND(2), {0x22,0x45}},
+ {LCM_SEND(2), {0x23,0x67}},
+ {LCM_SEND(2), {0x24,0x01}},
+ {LCM_SEND(2), {0x25,0x23}},
+ {LCM_SEND(2), {0x26,0x45}},
+ {LCM_SEND(2), {0x27,0x67}},
+
+ {LCM_SEND(2), {0x30,0x02}},
+ {LCM_SEND(2), {0x31,0x22}},
+ {LCM_SEND(2), {0x32,0x11}},
+ {LCM_SEND(2), {0x33,0xaa}},
+ {LCM_SEND(2), {0x34,0xbb}},
+ {LCM_SEND(2), {0x35,0x66}},
+ {LCM_SEND(2), {0x36,0x00}},
+ {LCM_SEND(2), {0x37,0x22}},
+ {LCM_SEND(2), {0x38,0x22}},
+ {LCM_SEND(2), {0x39,0x22}},
+ {LCM_SEND(2), {0x3A,0x22}},
+ {LCM_SEND(2), {0x3B,0x22}},
+ {LCM_SEND(2), {0x3C,0x22}},
+ {LCM_SEND(2), {0x3D,0x22}},
+ {LCM_SEND(2), {0x3E,0x22}},
+ {LCM_SEND(2), {0x3F,0x22}},
+
+ {LCM_SEND(2), {0x40,0x22}},
+ {LCM_SEND(2), {0x53,0x1a}},
+
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x07}},
+ {LCM_SEND(2), {0x18,0x1d}},
+ {LCM_SEND(2), {0x17,0x12}},
+
+ {LCM_SEND(2), {0x02,0x77}},
+
+ {LCM_SEND(2), {0xe1,0x79}},
+
+ {LCM_SEND(2), {0x06,0x13}},
+
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x00}},
+
+// {LCM_SEND(2), {0x35,0x00}},
+
+ {LCM_SEND(1), {0x11}},
+ {LCM_SLEEP(120)},
+
+ {LCM_SEND(1), {0x29}},
+ {LCM_SLEEP(1)},
+
+// {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x08}},
+
+};
+
+static LCM_Init_Code disp_on = {LCM_SEND(1), {0x29}};
+
+static LCM_Init_Code sleep_in[] = {
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x00}},
+ {LCM_SLEEP(1)},
+
+
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x00}},
+ {LCM_SLEEP(1)},
+
+{LCM_SEND(1), {0x28}},
+{LCM_SLEEP(120)},
+{LCM_SEND(1), {0x10}},
+{LCM_SLEEP(10)},
+ {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x01}},
+ {LCM_SLEEP(1)},
+
+ {LCM_SEND(2), {0x58,0x91}},
+
+};
+
+static LCM_Init_Code sleep_out[] = {
+{LCM_SEND(1), {0x11}},
+{LCM_SLEEP(120)},
+{LCM_SEND(1), {0x29}},
+{LCM_SLEEP(20)},
+};
+
+static LCM_Force_Cmd_Code rd_prep_code[]={
+ {0x39, {LCM_SEND(8), {0x6, 0, 0xFF, 0xFF, 0x98, 0x06,0x04,0x01}}},
+ {0x37, {LCM_SEND(2), {0x3, 0}}},
+};
+
+static LCM_Force_Cmd_Code rd_prep_code_1[]={
+ {0x37, {LCM_SEND(2), {0x1, 0}}},
+};
+static int32_t t8861_mipi_init(struct panel_spec *self)
+{
+ int32_t i;
+ LCM_Init_Code *init = init_data;
+ unsigned int tag;
+
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_debug(KERN_DEBUG "t8861_mipi_init\n");
+
+ msleep(2);
+ mipi_set_cmd_mode();
+ mipi_eotp_set(1,0);
+
+ for(i = 0; i < ARRAY_SIZE(init_data); i++){
+ tag = (init->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(init->data, (init->tag & LCM_TAG_MASK));
+ udelay(20);
+ }else if(tag & LCM_TAG_SLEEP){
+ //udelay((init->tag & LCM_TAG_MASK) * 1000);
+ msleep(init->tag & LCM_TAG_MASK);
+ }
+ init++;
+ }
+ mipi_eotp_set(1,1);
+
+ return 0;
+}
+
+static uint32_t t8861_readid(struct panel_spec *self)
+{
+ /*Jessica TODO: need read id*/
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code;
+ uint8_t read_data[3] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk("lcd_t8861_mipi read id!\n");
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(1,0);
+
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ udelay((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK) * 1000);
+ }
+ rd_prepare++;
+ }
+ read_rtn = mipi_force_read(0x02, 3,(uint8_t *)read_data);
+ printk("lcd_t8861_mipi read id 0xc5 value is 0x%x, 0x%x, 0x%x!\n", read_data[0], read_data[1], read_data[2]);
+
+ if((0x04 == read_data[0])){
+ printk("lcd_t8861_mipi read id success!\n");
+ mipi_eotp_set(1,1);
+ return 0x04;
+ }
+ }
+ mipi_eotp_set(1,1);
+ return 0x0;
+}
+
+static int32_t t8861_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ int32_t i;
+ LCM_Init_Code *sleep_in_out = NULL;
+ unsigned int tag;
+ int32_t size = 0;
+
+ mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ printk(KERN_DEBUG "t8861_enter_sleep, is_sleep = %d\n", is_sleep);
+
+ if(is_sleep){
+ sleep_in_out = sleep_in;
+ size = ARRAY_SIZE(sleep_in);
+ }else{
+ sleep_in_out = sleep_out;
+ size = ARRAY_SIZE(sleep_out);
+ }
+ mipi_eotp_set(1,0);
+
+ for(i = 0; i <size ; i++){
+ tag = (sleep_in_out->tag >>24);
+ if(tag & LCM_TAG_SEND){
+ mipi_gen_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ //udelay((sleep_in_out->tag & LCM_TAG_MASK) * 1000);
+ msleep((sleep_in_out->tag & LCM_TAG_MASK));
+ }
+ sleep_in_out++;
+ }
+ return 0;
+}
+
+static uint32_t t8861_readpowermode(struct panel_spec *self)
+{
+ int32_t i = 0;
+ uint32_t j =0;
+ LCM_Force_Cmd_Code * rd_prepare = rd_prep_code_1;
+ uint8_t read_data[1] = {0};
+ int32_t read_rtn = 0;
+ unsigned int tag = 0;
+ uint32_t reg_val_1 = 0;
+ uint32_t reg_val_2 = 0;
+
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_debug("lcd_t8861_mipi read power mode!\n");
+ mipi_eotp_set(0,1);
+
+ for(j = 0; j < 4; j++){
+ rd_prepare = rd_prep_code_1;
+ for(i = 0; i < ARRAY_SIZE(rd_prep_code_1); i++){
+ tag = (rd_prepare->real_cmd_code.tag >> 24);
+ if(tag & LCM_TAG_SEND){
+ mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));
+ }else if(tag & LCM_TAG_SLEEP){
+ udelay((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK) * 1000);
+ }
+ rd_prepare++;
+ }
+
+ read_rtn = mipi_force_read(0x0A, 1,(uint8_t *)read_data);
+ //printk("lcd_t8861 mipi read power mode 0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);
+
+ if((0x9c == read_data[0]) && (0 == read_rtn)){
+ pr_debug("lcd_t8861_mipi read power mode success!\n");
+ mipi_eotp_set(1,1);
+ return 0x9c;
+ }
+ }
+
+ mipi_eotp_set(1,1);
+ return 0x0;
+}
+
+
+static uint32_t t8861_check_esd(struct panel_spec *self)
+{
+ uint32_t power_mode;
+
+ pr_debug("t8861_check_esd!\n");
+ mipi_set_lp_mode_t mipi_set_data_lp_mode = self->info.mipi->ops->mipi_set_data_lp_mode;
+ mipi_set_hs_mode_t mipi_set_data_hs_mode = self->info.mipi->ops->mipi_set_data_hs_mode;
+
+ mipi_set_lp_mode_t mipi_set_lp_mode = self->info.mipi->ops->mipi_set_lp_mode;
+ mipi_set_hs_mode_t mipi_set_hs_mode = self->info.mipi->ops->mipi_set_hs_mode;
+ uint16_t work_mode = self->info.mipi->work_mode;
+
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_lp_mode();
+ }else{
+ mipi_set_data_lp_mode();
+ }
+ power_mode = t8861_readpowermode(self);
+ //power_mode = 0x0;
+ if(SPRDFB_MIPI_MODE_CMD==work_mode){
+ mipi_set_hs_mode();
+ }else{
+ mipi_set_data_hs_mode();
+ }
+ if(power_mode == 0x9c){
+ pr_debug("t8861_check_esd OK!\n");
+ return 1;
+ }else{
+ printk("t8861_check_esd fail!(0x%x)\n", power_mode);
+ return 0;
+ }
+}
+
+
+static struct panel_operations lcd_t8861_mipi_operations = {
+ .panel_init = t8861_mipi_init,
+ .panel_readid = t8861_readid,
+ .panel_enter_sleep = t8861_enter_sleep,
+ .panel_esd_check = t8861_check_esd,
+};
+
+static struct timing_rgb lcd_t8861_mipi_timing = {
+ .hfp = 60, /* unit: pixel */// 100
+ .hbp = 80,//80
+ .hsync = 60,//6
+ .vfp = 20, /*unit: line*/
+ .vbp = 14,
+ .vsync =6, //6,
+};
+
+static struct info_mipi lcd_t8861_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 2,
+ .phy_feq = 500*1000, //500->10MHz,400->8M in lp mode
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_t8861_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_t8861_mipi_spec = {
+ //.cap = PANEL_CAP_NOT_TEAR_SYNC,
+ .width = 480,
+ .height = 800,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .is_clean_lcd = true,
+ .info = {
+ .mipi = &lcd_t8861_mipi_info
+ },
+ .ops = &lcd_t8861_mipi_operations,
+};
+
+struct panel_cfg lcd_t8861_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x04,
+ .lcd_name = "lcd_t8861_mipi",
+ .panel = &lcd_t8861_mipi_spec,
+};
+
+static int __init lcd_t8861_mipi_init(void)
+{
+ return sprdfb_panel_register(&lcd_t8861_mipi);
+}
+
+subsys_initcall(lcd_t8861_mipi_init);
diff --git a/drivers/video/sprdfb/lcd/lcd_vx5b3d_mipi.c b/drivers/video/sprdfb/lcd/lcd_vx5b3d_mipi.c
new file mode 100755
index 00000000..94cc6486
--- /dev/null
+++ b/drivers/video/sprdfb/lcd/lcd_vx5b3d_mipi.c
@@ -0,0 +1,965 @@
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "../sprdfb_panel.h"
+#include <mach/gpio.h>
+#include <linux/i2c.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <mach/i2c-sprd.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/of_gpio.h>
+#define LCD_DEBUG
+#define pr_info printk
+#define LCD_PRINT printk
+#define MAX_DATA 100
+//#define QUICKLOGIC_DEBUG
+
+struct bridge_data {
+ u16 addr;
+ u32 data;
+}__attribute__ ((packed));
+
+struct vx5b3d_dt_data {
+ int gpio_bridge_en;
+ int gpio_bridge_rst;
+ int gpio_blic_en;
+ int gpio_lcd_3v3_en;
+};
+struct vx5b3d_dt_data *pdata = NULL;
+
+static struct i2c_client *g_client = NULL;
+struct regulator *lvds_1v8;
+struct regulator *lvds_3v3;
+struct panel_spec lcd_vx5b3d_mipi_spec;
+struct panel_spec *self = &lcd_vx5b3d_mipi_spec;
+struct i2c_driver quicklogic_i2c_driver;
+extern uint32_t sprdfb_panel_reset_all(void);
+
+#define QUICKLOGIC_MIPI_VENDOR_ID_1 0x5
+#define QUICKLOGIC_MIPI_VENDOR_ID_2 0x1
+#define QUICKLOGIC_MIPI_COMMAND_CSR_WRITE 0x40
+#define QUICKLOGIC_MIPI_COMMAND_CSR_OFFSET 0x41
+
+#define VX5B3D_I2C_RETRY_CNT (5)
+
+#define DELAY_CMD (0xFFFF)
+
+struct bridge_data vx5b3d_init[] = {
+ {0x700, 0x6C900040},
+ {0x704, 0x0003040A},
+ {0x70C, 0x00004604},
+ {0x710, 0x054D000B},
+ {0x714, 0x00000020},
+ {0x718, 0x00000102},
+ {0x71C, 0x00A8002F},
+ {0x720, 0x00000000},
+
+ {DELAY_CMD, 100}, /* For pll locking */
+ {0x154, 0x00000000},
+ {0x154, 0x80000000},
+ {DELAY_CMD, 100}, /* For pll locking */
+
+ {0x700, 0x6C900840},
+ {0x70C, 0x00005E56},
+ {0x718, 0x00000202},
+
+ {0x154, 0x00000000},
+ {0x154, 0x80000000},
+ {DELAY_CMD, 100}, /* For pll locking */
+
+ {0x37C, 0x00001063},
+ {0x380, 0x82A86030},
+ {0x384, 0x2861408B},
+ {0x388, 0x00130285},
+ {0x38C, 0x10630009},
+ {0x394, 0x400B82A8},
+ {0x600, 0x016CC78C},
+ {0x604, 0x3FFFFFE0},
+ {0x608, 0x00000D8C},
+ {0x154, 0x00000000},
+ {0x154, 0x80000000},
+ {0x120, 0x00000005},
+ {0x124, 0x1892C400},
+ {0x128, 0x00102806},
+ {0x12C, 0x00000062},
+ {0x130, 0x00003C18},
+ {0x134, 0x00000015},
+ {0x138, 0x00FF8000},
+ {0x13C, 0x00000000},
+
+ /*PWM 100 % duty ration*/
+ {0x114, 0x000c6302},
+
+ /*backlight duty ratio control when device is first bring up.*/
+ {0x160, 0x000007F8},
+ {0x164, 0x000002A8},
+ {0x138, 0x3fff0000},
+ {0x15C, 0x00000005},
+
+ {0x140, 0x00010000},
+ /*Add for power consumtion*/
+ {0x174, 0x00000000},
+ /*end*/
+
+ /*
+ slope = 2 / variance = 0x55550022
+ slope register [15,10]
+ */
+ {0x404, 0x55550822},
+
+ /*
+ To minimize the text effect
+ this value from 0xa to 0xf
+ */
+ {0x418, 0x555502ff},
+
+ /*
+ Disable brightnes issue Caused by IBC
+ read 4 bytes from address 0x410 to 0x413
+ 0x15E50300 is read value for 0x410 register
+ 0x5E50300= 0x15E50300 & 0xefffffff
+ */
+ {0x410, 0x05E50300},
+ /*...end*/
+ {0x20C, 0x00000124},
+ {0x21C, 0x00000000},
+ {0x224, 0x00000007},
+ {0x228, 0x00050001},
+ {0x22C, 0x0000FF03},
+ {0x230, 0x00000001},
+ {0x234, 0xCA033E10},
+ {0x238, 0x00000060},
+ {0x23C, 0x82E86030},
+ {0x244, 0x001E0285},
+ {0x258, 0x00060062},
+ /*vee strenght initialization*/
+ {0x400, 0x00000000},
+ {0x158, 0x00000000},
+ {0x158, 0x00000001},
+};
+
+static DEFINE_MUTEX(lock);
+#define QUICKLOGIC_MIPI_VENDOR_ID_1 0x5
+#define QUICKLOGIC_MIPI_VENDOR_ID_2 0x1
+#define QUICKLOGIC_MIPI_COMMAND_CSR_WRITE 0x40
+#define QUICKLOGIC_MIPI_COMMAND_CSR_OFFSET 0x41
+
+#define QUICKLOGIC_IIC_READ_CONTROL 0x0E
+#define QUICKLOGIC_IIC_WRITE_CONTROL 0x0A
+#define QUICKLOGIC_BYTE_I2C_RELEASE (0x0u)
+#define QUICKLOGIC_IIC_RELEASE {\
+ QUICKLOGIC_BYTE_I2C_RELEASE, \
+}
+
+#define QL_MIPI_PANEL_CMD_SIZE 255
+#define QL_VX_LCD_VC 0 /* dcs read/write */
+#define CONTROL_BYTE_DCS (0x08u)
+
+#define DTYPE_DCS_WRITE 0x05 /* short write, 0 parameter */
+#define DTYPE_DCS_WRITE1 0x15 /* short write, 1 parameter */
+#define DTYPE_DCS_READ 0x06 /* read */
+#define DTYPE_DCS_LWRITE 0x39 /* long write *//* generic read/write */
+#define DTYPE_GEN_WRITE 0x03 /* short write, 0 parameter */
+#define DTYPE_GEN_WRITE1 0x13 /* short write, 1 parameter */
+#define DTYPE_GEN_WRITE2 0x23 /* short write, 2 parameter */
+#define DTYPE_GEN_LWRITE 0x29 /* long write */
+#define DTYPE_GEN_READ 0x04 /* long read, 0 parameter */
+#define DTYPE_GEN_READ1 0x14 /* long read, 1 parameter */
+#define DTYPE_GEN_READ2 0x24 /* long read, 2 parameter */
+
+
+#define I2CID_BRIDGE 3
+#define I2C_NT50366_ADDR_WRITE 0x9E /* NT50366C 100_1111 0 */
+#define I2C_NT51017_ADDR_WRITE 0xD0 /* NT51017 110_1000 0 */
+#define I2C_BRIDGE_ADDR_WRITE0 0x58 /* 0101_100 0 ADDR=Low */
+#define I2C_BRIDGE_ADDR_WRITE1 0x5A /* 0101_101 0 ADDR=High */
+#define I2C_BRIDGE_ADDR I2C_BRIDGE_ADDR_WRITE0
+
+#define CONTROL_BYTE_GEN (0x09u)
+/**************************************************
+ * QUICKLOGIC MACRO FOR I2C *
+ ***************************************************/
+#define GEN_QL_CSR_OFFSET_LENGTH {\
+ CONTROL_BYTE_GEN, \
+ 0x29, /* Data ID */\
+ 0x05, /* Vendor Id 1 */\
+ 0x01, /* Vendor Id 2 */\
+ 0x41, /* Vendor Unique Command */\
+ 0x00, /* Address LS */\
+ 0x00, /* Address MS */\
+ 0x00, /* Length LS */\
+ 0x00, /* Length MS */\
+}
+
+#define GEN_QL_CSR_WRITE {\
+ CONTROL_BYTE_GEN, \
+ 0x29, /* Data ID */\
+ 0x05, /* Vendor Id 1 */\
+ 0x01, /* Vendor Id 2 */\
+ 0x40, /* Vendor Unique Command */\
+ 0x00, /* Address LS */\
+ 0x00, /* Address MS */\
+ 0x00, /* data LS */\
+ 0x00, \
+ 0x00, \
+ 0x00, /* data MS */\
+}
+
+
+int Quicklogic_i2c_read32(u16 reg, u32 *pval)
+{
+ int ret;
+ int status;
+ u8 address[3], data[4];
+
+ if (g_client == NULL) /* No global client pointer? */
+ return -EIO;
+
+ mutex_lock(&lock);
+ memset(data, 0, 4);
+ address[0] = (reg >> 8) & 0xff;
+ address[1] = reg & 0xff;
+ address[2] = 0xE;
+
+ ret = i2c_master_send(g_client, address, 3);
+ if (ret < 0) {
+ status = -EIO;
+ }
+ ret = i2c_master_recv(g_client, data, 4);
+ if (ret >= 0) {
+ status = 0;
+ *pval = data[0] | (data[1] << 8) | (data[2] << 16)
+ | (data[3] << 24);
+ } else
+ status = -EIO;
+
+ mutex_unlock(&lock);
+
+ return status;
+}
+EXPORT_SYMBOL(Quicklogic_i2c_read32);
+
+int Quicklogic_i2c_read(u32 addr, u32 *val, u32 data_size)
+{
+ u32 data;
+ char buf[] = GEN_QL_CSR_OFFSET_LENGTH;
+ char rx[10];
+ int ret = -1;
+ int write_size;
+
+ if (g_client == NULL) /* No global client pointer? */
+ return -EIO;
+
+ mutex_lock(&lock);
+
+ buf[5] = addr & 0xff;
+ buf[6] = (addr >> 8) & 0xff;
+ buf[7] = data_size & 0xff;
+ buf[8] = (data_size >> 8) & 0xff;
+
+ write_size = 9;
+
+ if ((ret = i2c_master_send( g_client,
+ (char*)(&buf[0]),
+ write_size )) != write_size) {
+ printk(KERN_ERR
+ "%s: i2c_master_send failed (%d)!\n", __func__, ret);
+ mutex_unlock(&lock);
+
+ return -EIO;
+ }
+
+ /*generic read request 0x24 to send generic read command */
+ write_size = 4;
+
+ buf[0] = CONTROL_BYTE_GEN;
+ buf[1] = 0x24; /* Data ID */
+ buf[2] = 0x05; /* Vendor Id 1 */
+ buf[3] = 0x01; /* Vendor Id 2 */
+
+ if ((ret = i2c_master_send(g_client,
+ (char*)(&buf[0]),
+ write_size )) != write_size) {
+
+ pr_info("i2c_master_send failed (%d)!\n", ret);
+ mutex_unlock(&lock);
+ return -EIO;
+ }
+
+ /*return number of bytes or error*/
+ if ((ret = i2c_master_recv(g_client,
+ (char*)(&rx[0]),
+ data_size )) != data_size) {
+
+ pr_info("i2c_master_recv failed (%d)!\n", ret);
+ mutex_unlock(&lock);
+ return -EIO;
+ }
+
+ data = rx[0];
+ if (data_size > 1)
+ data |= (rx[1] << 8);
+ if (data_size > 2)
+ data |= (rx[2] << 16) | (rx[3] << 24);
+
+ *val = data;
+
+ mutex_unlock(&lock);
+
+ pr_info("QX_read value0x%x=0x%x\n",addr,data);
+
+ return 0;
+
+}
+EXPORT_SYMBOL(Quicklogic_i2c_read);
+
+int Quicklogic_i2c_write32(u16 reg, u32 val)
+{
+ int status = 0;
+ /*int write_size;*/
+ char buf[] = GEN_QL_CSR_WRITE;
+
+ if (g_client == NULL) /* No global client pointer? */
+ return -EIO;
+
+ mutex_lock(&lock);
+
+ buf[5] = (uint8_t)reg; /* Address LS */
+ buf[6] = (uint8_t)(reg >> 8); /* Address MS */
+
+ buf[7] = val & 0xff;
+ buf[8] = (val >> 8) & 0xff;
+ buf[9] = (val >> 16) & 0xff;
+ buf[10] =(val >> 24) & 0xff;
+ status = i2c_master_send(g_client, (char *)(&buf[0]), 11);
+
+ if (status >= 0)
+ status = 0;
+ else {
+ printk("zyun: i2c write 32 single error! [0x%04x] -EIO\n", reg);
+ status = -EIO;
+ }
+
+ udelay(10);
+ mutex_unlock(&lock);
+
+ return status;
+
+}
+EXPORT_SYMBOL(Quicklogic_i2c_write32);
+
+int Quicklogic_i2c_release(void)
+{
+ int write_size;
+ int ret = 0;
+ char buf[] = QUICKLOGIC_IIC_RELEASE;
+
+ if (g_client == NULL) /* No global client pointer? */
+ return -1;
+
+ mutex_lock(&lock);
+
+ write_size = 1;
+
+ if ((ret = i2c_master_send( g_client,
+ (char*)(&buf[0]),
+ write_size )) != write_size)
+ pr_info("i2c_master_send failed (%d)!\n", ret);
+
+ mutex_unlock(&lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(Quicklogic_i2c_release);
+
+int Quicklogic_i2cTomipi_write(int dtype, int vit_com, u8 data_size, u8 *ptr )
+{
+ char buf[QL_MIPI_PANEL_CMD_SIZE];
+ int write_size;
+ int i;
+ int ret = -1;
+ int dtype_int;
+
+
+ if (g_client == NULL) /* No global client pointer? */
+ return -1;
+
+ if (data_size > (QL_MIPI_PANEL_CMD_SIZE - 10)) {
+ printk("data size (%d) too big, adjust the QL_MIPI_PANEL_CMD_SIZE!\n", data_size);
+ return ret;
+ }
+ dtype_int = dtype;
+
+ mutex_lock(&lock);
+
+ switch (dtype) {
+ case DTYPE_GEN_WRITE:
+ case DTYPE_GEN_LWRITE:
+ case DTYPE_GEN_WRITE1:
+ case DTYPE_GEN_WRITE2:
+ buf[0] = CONTROL_BYTE_GEN;
+ dtype_int = (data_size == 1) ? DTYPE_GEN_WRITE1 :
+ (data_size == 2) ? DTYPE_GEN_WRITE2 : DTYPE_GEN_LWRITE;
+ break;
+ case DTYPE_DCS_WRITE:
+ case DTYPE_DCS_LWRITE:
+ case DTYPE_DCS_WRITE1:
+ buf[0] = CONTROL_BYTE_DCS;
+ dtype_int = (data_size == 1) ? DTYPE_DCS_WRITE :
+ (data_size == 2) ? DTYPE_DCS_WRITE1 : DTYPE_DCS_LWRITE;
+ break;
+ default:
+ printk("Error unknown data type (0x%x).\n", dtype);
+ break;
+ }
+
+ buf[1] = ((vit_com & 0x3) << 6) | dtype_int ; /*vc, Data ID *//* Copy data */
+
+ /* Copy data */
+ for(i = 0; i < data_size; i++)
+ buf[2+i] = *ptr++;
+
+ write_size = data_size + 2;
+
+ if ((ret = i2c_master_send(g_client,(char*)(&buf[0]),write_size )) != write_size) {
+ printk("Quicklogic_i2c_write32 failed : %d\n", ret);
+
+ mutex_unlock(&lock);
+
+ return -EIO;
+ }
+
+ mutex_unlock(&lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(Quicklogic_i2cTomipi_write);
+
+int Quicklogic_i2cTomipi_read(int dtype, int vit_com, u8 data_size, u8 reg , u8 *pval)
+{
+ char buf[QL_MIPI_PANEL_CMD_SIZE];
+ char rx[10];
+ int write_size; int ret = -1; int dtype_int;
+
+ if (data_size > (QL_MIPI_PANEL_CMD_SIZE-10)) {
+ printk("data size (%d) too big, adjust the QL_MIPI_PANEL_CMD_SIZE!\n", data_size);
+ return ret;
+ }
+
+ dtype_int = dtype;
+
+ mutex_lock(&lock);
+
+ switch (dtype) {
+
+ case DTYPE_GEN_READ1: /*0x14*/
+ case DTYPE_GEN_READ2: /*0x24*/
+ buf[0] = CONTROL_BYTE_GEN;
+ break;
+
+ case DTYPE_DCS_READ: /*0x6*/
+ buf[0] = CONTROL_BYTE_DCS;
+ break;
+
+ default:
+ printk("Error unknown data type (0x%x).\n", dtype);
+ break;
+ }
+
+ buf[1] = ((vit_com & 0x3) << 6) | dtype_int ; /*vc, Data ID */
+
+ switch (dtype) {
+
+ case DTYPE_GEN_READ2: /* short read, 2 parameter */
+
+ write_size = 4;
+ buf[2] = reg;
+ buf[3] = 0;
+ break;
+
+ default:
+ buf[2] = reg;
+ break;
+ }
+
+ write_size = 3;
+
+ if ((ret = i2c_master_send(g_client,(char*)(&buf[0]),
+ write_size )) != write_size) {
+
+ printk("%s: i2c_master_send failed (%d)!\n", __func__, ret);
+
+ mutex_unlock(&lock);
+ return -EIO;
+ }
+
+ if ((ret = i2c_master_recv(g_client, (char*)(&rx[0]),
+ data_size )) != data_size) {
+
+ printk("%s: i2c_master_recv failed (%d)!\n", __func__, ret);
+
+ mutex_unlock(&lock);
+ return -EIO;
+ }
+
+ if (ret < 0)
+ printk("Quicklogic_i2c_read32 failed : %d\n", ret);
+
+ *pval = rx[0];
+
+ if (data_size > 1)
+ *pval |= (rx[1] << 8);
+ if (data_size > 2)
+ *pval |= (rx[2] << 16) | (rx[3] << 24);
+
+ printk("QuickBridge reg=[0x%x]..return=[0x%x]\n",reg,*pval);
+
+ mutex_unlock(&lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(Quicklogic_i2cTomipi_read);
+
+
+int vx5b3d_mipi_write32(struct panel_spec *self, u16 addr, u32 data)
+{
+ int i;
+ static u8 packet[] = {
+ 0x09, 0x00, /* data length */
+ QUICKLOGIC_MIPI_VENDOR_ID_1,
+ QUICKLOGIC_MIPI_VENDOR_ID_2,
+ QUICKLOGIC_MIPI_COMMAND_CSR_WRITE,
+ 0x0, 0x0, /* address 16bits */
+ 0x0, 0x0, 0x0, 0x0 /* data max 32bits */
+ };
+ mipi_dcs_write_t mipi_gen_write=
+ self->info.mipi->ops->mipi_gen_write;
+
+ for (i = 0; i < 2; i++)
+ packet[5 + i] = (u8)(addr >> (8 * i) & 0xff);
+
+ for (i = 0; i < 4; i++)
+ packet[7 + i] = (u8)((data >> (8 * i)) & 0xff);
+
+#ifdef VX5B3D_DEBUG
+ for (i = 0; i < ARRAY_SIZE(packet); i++)
+ printf("packet[%d] = 0x%02x\n", i, packet[i]);
+#endif
+
+ mipi_gen_write(packet, ARRAY_SIZE(packet));
+
+ udelay(1);
+
+ return 0;
+}
+
+int vx5b3d_mipi_write32_array(struct panel_spec *self,
+ struct bridge_data *b_data, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (b_data[i].addr == DELAY_CMD) {
+ mdelay(b_data[i].data);
+ continue;
+ }
+ vx5b3d_mipi_write32(self, b_data[i].addr, b_data[i].data);
+ }
+
+ return 0;
+}
+
+int vx5b3d_i2c_write32(u16 addr, u32 data)
+{
+ int ret, i;
+ int retry_cnt = VX5B3D_I2C_RETRY_CNT;
+
+ do {
+ ret = Quicklogic_i2c_write32(addr, data);
+ } while (--retry_cnt && ret);
+
+ if (!retry_cnt)
+ printk("zyun: vx5b3d_i2c_write32 failed![%d, addr:0x%04x, data:0x%08x] failed!!\n",
+ i, addr, data);
+
+ return ret;
+}
+
+int vx5b3d_i2c_write32_array(struct bridge_data *b_data, int len)
+{
+ int i, ret;
+
+ for (i = 0; i < len; i++) {
+ if (b_data[i].addr == DELAY_CMD) {
+ mdelay(b_data[i].data);
+ continue;
+ }
+ ret = vx5b3d_i2c_write32(b_data[i].addr, b_data[i].data);
+ }
+
+ return ret;
+}
+
+static u32 vx5b3d_i2c_read32(u16 addr)
+{
+ u32 buf;
+ Quicklogic_i2c_read(addr, &buf, 4);
+
+ return buf;
+}
+
+/*
+static u32 vx5b3d_compare(struct bridge_data *b_data, int len)
+{
+ int i;
+ u32 rd_data;
+
+ for (i = 0; i < len; i++) {
+ if (b_data[i].addr == DELAY_CMD) {
+ continue;
+ }
+ rd_data = vx5b3d_i2c_read32(b_data[i].addr);
+ if (rd_data != b_data[i].data)
+ pr_err("[0x%04x] rd_data:0x%x, data:0x%x - not match!!\n",
+ b_data[i].addr, rd_data, b_data[i].data);
+ }
+}
+*/
+
+static int32_t vx5b3d_power(int on)
+{
+ static int probe = 0;
+ if (!probe) {
+ gpio_request(pdata->gpio_lcd_3v3_en, "LCD_3V3_EN");
+ gpio_direction_output(pdata->gpio_lcd_3v3_en, 0);
+ if (gpio_request(pdata->gpio_bridge_en, "BRIDGE_EN")) {
+ printk("[%s] GPIO%d request failed!\n", "BRIDGE_EN", pdata->gpio_bridge_en);
+ return 0;
+ }
+ gpio_direction_output(pdata->gpio_bridge_en, 1);
+
+ if (gpio_request(pdata->gpio_bridge_rst, "BRIDGE_RST")){
+ printk("[%s] GPIO%d request failed!\n", "BRIDGE_RST", pdata->gpio_bridge_rst);
+ return 0;
+ }
+ gpio_direction_output(pdata->gpio_bridge_rst, 1);
+
+ if (gpio_request(pdata->gpio_blic_en, "BLIC_EN")) {
+ printk("[%s] GPIO%d request failed!\n", "BLIC_EN", pdata->gpio_blic_en);
+ return 0;
+ }
+ gpio_direction_output(pdata->gpio_blic_en, 1);
+
+ lvds_1v8 = regulator_get(NULL,"vddsim1");
+ if (IS_ERR(lvds_1v8)) {
+ lvds_1v8 = NULL;
+ pr_info("%s regulator 1v8 get failed!!\n", "vddsim1");
+ } else {
+ regulator_set_voltage(lvds_1v8, 1800000, 1800000);
+ regulator_enable(lvds_1v8);
+ }
+
+ lvds_3v3 = regulator_get(NULL,"vddwifipa");
+ if (IS_ERR(lvds_3v3)) {
+ lvds_3v3 = NULL;
+ pr_info("%s regulator 3v3 get failed!!\n", "vddwifipa");
+ } else {
+ regulator_set_voltage(lvds_3v3, 3300000, 3300000);
+ regulator_enable(lvds_3v3);
+ }
+ probe = 1;
+ }
+
+ printk("%s, on= %d\n", __func__, on);
+ if (on) {
+ gpio_set_value(pdata->gpio_lcd_3v3_en, 1);
+ gpio_set_value(pdata->gpio_bridge_en, 1);
+ regulator_enable(lvds_1v8);
+ regulator_enable(lvds_3v3);
+ udelay(20);
+ gpio_set_value(pdata->gpio_bridge_rst, 1);
+ udelay(20);
+ gpio_set_value(pdata->gpio_blic_en, 1);
+ } else {
+ gpio_set_value(pdata->gpio_lcd_3v3_en, 0);
+ gpio_set_value(pdata->gpio_bridge_rst, 0);
+ udelay(20);
+ regulator_disable(lvds_3v3);
+ regulator_disable(lvds_1v8);
+ gpio_set_value(pdata->gpio_bridge_en, 0);
+ gpio_set_value(pdata->gpio_blic_en, 0);
+ msleep(350);
+ }
+}
+
+static int32_t vx5b3d_mipi_init(struct panel_spec *self)
+{
+ mipi_set_lp_mode_t mipi_set_lp_mode =
+ self->info.mipi->ops->mipi_set_lp_mode;
+ mipi_set_video_mode_t mipi_set_video_mode =
+ self->info.mipi->ops->mipi_set_video_mode;
+
+ if (!g_client)
+ {
+ pr_info("zyun: g_client is NULL!\n");
+ return 0;
+ }
+ /* step 1 : All DSI into LP11*/
+
+ mipi_set_lp_mode();
+ vx5b3d_power(1);
+
+ /* step 3 : Delay*/
+ mdelay(10);
+#ifdef QUICKLOGIC_DEBUG
+ pr_info("[QUICKLOGIC] : VX5B3D INIT - START\n");
+ pr_info("[QUICKLOGIC] : VX5B3D INIT - Waiting...(10sec)\n");
+ mdelay(10 * 1000);
+
+ pr_info("[QUICKLOGIC] : START VX5B3D INIT - Waiting Done!!\n");
+#else
+// vx5b3d_mipi_write32_array(self, vx5b3d_init, ARRAY_SIZE(vx5b3d_init));
+ vx5b3d_i2c_write32_array(vx5b3d_init, ARRAY_SIZE(vx5b3d_init));
+#endif
+ /* step 5 : Start the DSI video stream */
+ mipi_set_video_mode();
+ mdelay(5);
+
+ printk("zyun: init done! 1 \n");
+ pr_info("[QUICKLOGIC] : VX5B3D INIT - DONE\n");
+ //vx5b3d_compare(vx5b3d_init, ARRAY_SIZE(vx5b3d_init));
+
+ return 0;
+}
+
+static uint32_t vx5b3d_readid(struct panel_spec *self)
+{
+ int32_t j =0;
+ uint8_t read_data[4] = {0};
+ int32_t read_rtn = 0;
+ uint8_t param[2] = {0};
+ mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;
+ mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;
+ mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;
+ mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;
+
+ pr_info("%s\n", __func__);
+
+ mipi_set_cmd_mode();
+ mipi_eotp_set(0,0);
+
+ for(j = 0; j < 4; j++){
+ param[0] = 0x01;
+ param[1] = 0x00;
+ mipi_force_write(0x04, param, 2);
+ read_rtn = mipi_force_read(0xda,1,&read_data[0]);
+ LCD_PRINT("lcd_vx5b3d_mipi read id 0xda value is 0x%x!\n",read_data[0]);
+ read_rtn = mipi_force_read(0xdb,1,&read_data[1]);
+ LCD_PRINT("lcd_vx5b3d_mipi read id 0xdb value is 0x%x!\n",read_data[1]);
+ read_rtn = mipi_force_read(0xdc,1,&read_data[2]);
+ LCD_PRINT("lcd_vx5b3d_mipi read id 0xdc value is 0x%x!\n",read_data[2]);
+
+ // if((0x55 == read_data[0])&&(0xbc == read_data[1])&&(0x90 == read_data[2])){
+ printk("lcd_vx5b3d_mipi read id success!\n");
+ return 0x8282;
+ // }
+ }
+
+ mipi_eotp_set(0,0);
+
+ return 0;
+}
+
+
+static int32_t vx5b3d_enter_sleep(struct panel_spec *self, uint8_t is_sleep)
+{
+ pr_info("%s\n", __func__);
+
+ vx5b3d_power(0);
+
+ return 0;
+}
+
+static struct panel_operations lcd_vx5b3d_mipi_operations = {
+ .panel_init = vx5b3d_mipi_init,
+ .panel_readid = vx5b3d_readid,
+ .panel_enter_sleep = vx5b3d_enter_sleep,
+};
+
+static struct timing_rgb lcd_vx5b3d_mipi_timing = {
+ .hfp = 123,
+ .hbp = 100,
+ .hsync = 120,
+ .vfp = 13,
+ .vbp = 10,
+ .vsync = 10,
+};
+
+
+static struct info_mipi lcd_vx5b3d_mipi_info = {
+ .work_mode = SPRDFB_MIPI_MODE_VIDEO,
+ .video_bus_width = 24, /*18,16*/
+ .lan_number = 4,
+ .phy_feq = 480*1000,
+ .h_sync_pol = SPRDFB_POLARITY_POS,
+ .v_sync_pol = SPRDFB_POLARITY_POS,
+ .de_pol = SPRDFB_POLARITY_POS,
+ .te_pol = SPRDFB_POLARITY_POS,
+ .color_mode_pol = SPRDFB_POLARITY_NEG,
+ .shut_down_pol = SPRDFB_POLARITY_NEG,
+ .timing = &lcd_vx5b3d_mipi_timing,
+ .ops = NULL,
+};
+
+struct panel_spec lcd_vx5b3d_mipi_spec = {
+ .width = 1024,
+ .height = 600,
+ .fps = 60,
+ .type = LCD_MODE_DSI,
+ .direction = LCD_DIRECT_NORMAL,
+ .suspend_mode = SEND_SLEEP_CMD,
+ .info = {
+ .mipi = &lcd_vx5b3d_mipi_info
+ },
+ .ops = &lcd_vx5b3d_mipi_operations,
+};
+struct panel_cfg lcd_vx5b3d_mipi = {
+ /* this panel can only be main lcd */
+ .dev_id = SPRDFB_MAINLCD_ID,
+ .lcd_id = 0x8282,
+ .lcd_name = "lcd_vx5b3d_mipi",
+ .panel = &lcd_vx5b3d_mipi_spec,
+};
+//temp code
+static int __init lcd_vx5b3d_mipi_init(void)
+{
+ printk("zyun: %s\n", __func__);
+ i2c_add_driver(&quicklogic_i2c_driver);
+ return sprdfb_panel_register(&lcd_vx5b3d_mipi);
+}
+subsys_initcall(lcd_vx5b3d_mipi_init);
+
+
+#ifdef CONFIG_OF
+static int vx5b3d_parse_dt(struct vx5b3d_dt_data *data, struct device *dev)
+{
+ struct device_node *dNode = dev->of_node;
+ if (dNode == NULL)
+ return -ENODEV;
+ pdata->gpio_bridge_en = of_get_named_gpio(dNode, "gpio_bridge_en", 0);
+ pdata->gpio_bridge_rst = of_get_named_gpio(dNode, "gpio_bridge_rst", 0);
+ pdata->gpio_blic_en= of_get_named_gpio(dNode, "gpio_backlight_en", 0);
+ pdata->gpio_lcd_3v3_en = of_get_named_gpio(dNode, "gpio_lcd_3v3_en", 0);
+ if(pdata->gpio_bridge_en < 0
+ || pdata->gpio_bridge_rst < 0
+ || pdata->gpio_blic_en < 0
+ || pdata->gpio_lcd_3v3_en < 0){
+ pr_err("[%s] - get gpio error: bridge_en:%d, bridge_rst:%d, blic_en:%d, lcd_3v3_en:%d\n",
+ __func__, pdata->gpio_bridge_en, pdata->gpio_bridge_rst, pdata->gpio_blic_en, pdata->gpio_lcd_3v3_en);
+ return -ENODEV;
+ }
+ return 0;
+}
+#endif
+
+static int __init quicklogic_probe(struct i2c_client *client,
+ const struct i2c_device_id * id)
+{
+ static is_i2c_init=false;
+ /*globle data, defined in this file*/
+ pdata = kzalloc(sizeof(struct vx5b3d_dt_data), GFP_KERNEL);
+ if(pdata == NULL){
+ pr_err("[%s] line %d kzalloc fail!\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+#ifdef CONFIG_OF
+ int ret = vx5b3d_parse_dt(pdata, &client->dev);
+ if(ret != 0){
+ return ret;
+ }
+#endif
+ if(is_i2c_init)
+ return 0;
+ if(client==NULL)
+ {
+ printk("zyun: I2C probe error!\n");
+ return 0;
+ }
+ else
+ {
+ is_i2c_init=true;
+ printk("zyun: i2c client, addr=0x%x, name = %s\n", client->addr, client->name);
+ }
+
+ g_client = client;
+ sprd_i2c_ctl_chg_clk(3, 400000); // up h/w i2c 1 400k
+ vx5b3d_power(1);
+
+ return 0;
+}
+static int __exit quicklogic_remove(struct i2c_client *client)
+{
+ pr_info("%s\n", __func__);
+
+ return 0;
+}
+
+
+#define QUICKLOGIC_DEV_NAME ("bridge")
+static struct i2c_device_id quicklogic_id_table[] = {
+ { QUICKLOGIC_DEV_NAME, 0 },
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, quicklogic_id_table);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static const struct dev_pm_ops quicklogic_pm_ops = {
+};
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id quicklogic_of_match[] = {
+ { .compatible = "quicklogic,i2c", },
+};
+#endif
+
+struct i2c_driver quicklogic_i2c_driver = {
+ .id_table = quicklogic_id_table,
+ .probe = quicklogic_probe,
+ .remove = __exit_p(quicklogic_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = QUICKLOGIC_DEV_NAME,
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ .pm = &quicklogic_pm_ops,
+#endif
+
+#ifdef CONFIG_OF
+ .of_match_table = quicklogic_of_match,
+#endif
+ },
+};
+
+static int __init quicklogic_init(void)
+{
+ pr_info("%s, add quicklogic i2c\n", __func__);
+// return i2c_add_driver(&quicklogic_i2c_driver);
+ return 0;
+}
+
+static void __exit quicklogic_exit(void)
+{
+ pr_info("%s, delete quicklogic i2c\n", __func__);
+ i2c_del_driver(&quicklogic_i2c_driver);
+}
+
+module_init(quicklogic_init);
+module_exit(quicklogic_exit);
+
+MODULE_DESCRIPTION("QuickLogic Bridge Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/sprdfb/spi/Makefile b/drivers/video/sprdfb/spi/Makefile
new file mode 100644
index 00000000..835dd11c
--- /dev/null
+++ b/drivers/video/sprdfb/spi/Makefile
@@ -0,0 +1,7 @@
+obj-$(CONFIG_FB_SC8825) := spi_simple_drv.o
+obj-$(CONFIG_FB_SCX35) := spi_simple_drv.o
+obj-$(CONFIG_FB_SCX30G) := spi_simple_drv.o
+obj-$(CONFIG_FB_SCX15) := spi_simple_drv.o
+ifeq ($(CONFIG_FB_SCX35L), y)
+obj-$(CONFIG_SPI) := spi_simple_drv.o
+endif
diff --git a/drivers/video/sprdfb/spi/spi_simple_drv.c b/drivers/video/sprdfb/spi/spi_simple_drv.c
new file mode 100644
index 00000000..51c23912
--- /dev/null
+++ b/drivers/video/sprdfb/spi/spi_simple_drv.c
@@ -0,0 +1,358 @@
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#ifdef CONFIG_OF
+#include <linux/fb.h>
+#endif
+
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/sci.h>
+#include <soc/sprd/sci_glb_regs.h>
+
+#include "spi_simple_drv.h"
+
+#ifdef CONFIG_OF
+#define FB_SPI_CLOCK ("fb_spi_clock")
+#define FB_SPI_CLOCK_PARENT ("fb_spi_clock_parent")
+#endif
+
+static u32 used_spi_reg_base;
+
+#ifdef CONFIG_OF
+static void SPI_Enable(struct device *device,bool is_en)
+#else
+static void SPI_Enable( uint32_t spi_id, bool is_en)
+#endif
+{
+ struct clk *spi_clk;
+
+#ifndef CONFIG_OF
+ switch (spi_id) {
+ case 0:
+ spi_clk = clk_get(NULL, "clk_spi0");
+ break;
+ case 1:
+ spi_clk = clk_get(NULL, "clk_spi1");
+ break;
+ case 2:
+ spi_clk = clk_get(NULL, "clk_spi2");
+ break;
+ default:
+ BUG_ON(1);
+ }
+#else
+ spi_clk = of_clk_get_by_name(device->of_node, FB_SPI_CLOCK);
+ if (IS_ERR(spi_clk)) {
+ printk(KERN_WARNING "sprdfb: get spi clock fail!\n");
+ return ;
+ } else {
+ pr_debug(KERN_INFO "sprdfb: get spi clock ok!\n");
+ }
+#endif
+ if(is_en)
+ {
+ clk_prepare_enable(spi_clk);
+ }
+ else
+ {
+ clk_disable_unprepare(spi_clk);
+ }
+}
+
+static void SPI_Reset( uint32_t spi_id)
+{
+ u32 rst_reg, rst_bit;
+
+ switch (spi_id) {
+ case 0:
+ rst_reg = REG_AP_APB_APB_RST;
+ rst_bit = BIT_SPI0_SOFT_RST;
+ break;
+ case 1:
+ rst_reg = REG_AP_APB_APB_RST;
+ rst_bit = BIT_SPI1_SOFT_RST;
+ break;
+ case 2:
+ rst_reg = REG_AP_APB_APB_RST;
+ rst_bit = BIT_SPI2_SOFT_RST;
+ break;
+ default:
+ BUG_ON(1);
+ }
+
+ sci_glb_set(rst_reg, rst_bit);
+ msleep(50);
+ sci_glb_clr(rst_reg, rst_bit);
+}
+
+/*just set the spi src clk = 26Mhz*/
+#ifdef CONFIG_OF
+static void SPI_ClkSetting(struct device *device)
+#else
+static void SPI_ClkSetting(uint32_t spi_id)
+#endif
+{
+ struct clk *spi_clk, *spi_src_clk;
+#ifndef CONFIG_OF
+ switch (spi_id) {
+ case 0:
+ spi_clk = clk_get(NULL, "clk_spi0");
+ break;
+ case 1:
+ spi_clk = clk_get(NULL, "clk_spi1");
+ break;
+ case 2:
+ spi_clk = clk_get(NULL, "clk_spi2");
+ break;
+ default:
+ BUG_ON(1);
+ }
+ spi_src_clk = clk_get(NULL, "ext_26m");
+#else
+ spi_clk = of_clk_get_by_name(device->of_node, FB_SPI_CLOCK);
+ if (IS_ERR(spi_clk)) {
+ printk(KERN_WARNING "sprdfb: get spi clock fail!\n");
+ return ;
+ } else {
+ pr_debug(KERN_INFO "sprdfb: get spi clock ok!\n");
+ }
+ spi_src_clk = of_clk_get_by_name(device->of_node, FB_SPI_CLOCK_PARENT);
+ if (IS_ERR(spi_src_clk)) {
+ printk(KERN_WARNING "sprdfb: get spi clock parent fail!\n");
+ return ;
+ } else {
+ pr_debug(KERN_INFO "sprdfb: get spi clock parent ok!\n");
+ }
+#endif
+ clk_set_parent(spi_clk, spi_src_clk);
+ clk_set_rate(spi_clk, SPI_DEF_SRC_CLK);
+}
+
+void SPI_SetCsLow( uint32_t spi_sel_csx , bool is_low)
+{
+ volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T*)(used_spi_reg_base);
+
+ if(is_low) {
+ spi_ctr_ptr->ctl0 &= ~((1<<spi_sel_csx)<<SPI_SEL_CS_SHIFT);
+ }
+ else
+ {
+ spi_ctr_ptr->ctl0 |= ((1<<spi_sel_csx)<<SPI_SEL_CS_SHIFT);
+ }
+}
+
+void SPI_SetCd( uint32_t cd)
+{
+ volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T*)(used_spi_reg_base);
+
+ if(cd == 0) {
+ spi_ctr_ptr->ctl8 &= ~(SPI_CD_MASK);
+ } else {
+ spi_ctr_ptr->ctl8 |= (SPI_CD_MASK);
+ }
+}
+
+#if 0
+static void SPI_SetSpiMode(uint32_t spi_mode)
+{
+ volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(used_spi_reg_base);
+ uint32_t temp = spi_ctr_ptr->ctl7;
+
+ temp &= ~SPI_MODE_MASK;
+ temp |= (spi_mode<<SPI_MODE_SHIFT);
+
+ spi_ctr_ptr->ctl7 = temp;
+}
+#endif
+
+void SPI_SetDatawidth(uint32_t datawidth)
+{
+ volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(used_spi_reg_base);
+ uint32_t temp = spi_ctr_ptr->ctl0;
+
+ if( 32 == datawidth )
+ {
+ spi_ctr_ptr->ctl0 &= ~0x7C;
+ return;
+ }
+
+ temp &= ~0x0000007C;
+ temp |= (datawidth<<2);
+
+ spi_ctr_ptr->ctl0 = temp;
+}
+
+static void SPI_SetTxLen(uint32_t data_len, uint32_t dummy_bitlen)
+{
+ volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(used_spi_reg_base);
+ uint32_t ctl8 = spi_ctr_ptr->ctl8;
+ uint32_t ctl9 = spi_ctr_ptr->ctl9;
+
+ data_len &= TX_MAX_LEN_MASK;
+
+ ctl8 &= ~((TX_DUMY_LEN_MASK<<4) | TX_DATA_LEN_H_MASK);
+ ctl9 &= ~( TX_DATA_LEN_L_MASK );
+
+ spi_ctr_ptr->ctl8 = (ctl8 | (dummy_bitlen<<4) | (data_len>>16));
+ spi_ctr_ptr->ctl9 = (ctl9 | (data_len&0xFFFF));
+}
+
+static void SPI_SetRxLen(uint32_t data_len, uint32_t dummy_bitlen)
+{
+ volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(used_spi_reg_base);
+ uint32_t ctl10 = spi_ctr_ptr->ctl10;
+ uint32_t ctl11 = spi_ctr_ptr->ctl11;
+
+ data_len &= RX_MAX_LEN_MASK;
+
+ ctl10 &= ~((RX_DUMY_LEN_MASK<<4) | RX_DATA_LEN_H_MASK);
+ ctl11 &= ~( RX_DATA_LEN_L_MASK );
+
+ spi_ctr_ptr->ctl10 = (ctl10 | (dummy_bitlen<<4) | (data_len>>16));
+ spi_ctr_ptr->ctl11 = (ctl11 | (data_len&0xFFFF));
+}
+
+static void SPI_TxReq( void )
+{
+ volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(used_spi_reg_base);
+
+ spi_ctr_ptr->ctl12 |= SW_TX_REQ_MASK;
+}
+
+static void SPI_RxReq( void )
+{
+ volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(used_spi_reg_base);
+
+ spi_ctr_ptr->ctl12 |= SW_RX_REQ_MASK;
+}
+
+static unsigned long SPRD_SPI0_BASE = 0xffffffff;
+static unsigned long SPRD_SPI1_BASE = 0xffffffff;
+static unsigned long SPRD_SPI2_BASE = 0xffffffff;
+
+#ifdef CONFIG_OF
+void SPI_Init(struct device *device, u32 spi_id, SPI_INIT_PARM *spi_parm)
+#else
+void SPI_Init(u32 spi_id, SPI_INIT_PARM *spi_parm)
+#endif
+{
+ volatile SPI_CTL_REG_T *spi_ctr_ptr;
+ u32 temp;
+
+#ifdef CONFIG_OF
+ SPI_ClkSetting(device);
+ SPI_Enable(device, true);
+#else
+ SPI_ClkSetting(spi_id);
+ SPI_Enable(spi_id, true);
+#endif
+
+ SPI_Reset(spi_id);
+
+ switch (spi_id) {
+ case 0:
+ used_spi_reg_base = SPRD_SPI0_BASE;
+ break;
+ case 1:
+ used_spi_reg_base = SPRD_SPI1_BASE;
+ break;
+ case 2:
+ used_spi_reg_base = SPRD_SPI2_BASE;
+ break;
+ default:
+ BUG_ON(1);
+ }
+
+ spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(used_spi_reg_base);
+
+ /*fixme, the spi_clk is 1Mhz*/
+ spi_ctr_ptr->clkd = (SPI_DEF_SRC_CLK / (SPI_DEF_CLK << 1)) - 1;
+
+ temp = 0;
+ temp |= (spi_parm->tx_edge << 1) |
+ (spi_parm->rx_edge << 0) |
+ (0x1 << 13) |
+ (spi_parm->msb_lsb_sel<< 7) ;
+ spi_ctr_ptr->ctl0 = temp;
+
+ spi_ctr_ptr->ctl1 |= BIT(12) | BIT(13);
+
+ /*rx fifo full watermark is 16*/
+ spi_ctr_ptr->ctl3 = 0x10;
+
+ /*set SPIMODE_3WIRE_9BIT_SDIO mode*/
+ spi_ctr_ptr->ctl7 &= ~(0x7 << 3);
+
+ spi_ctr_ptr->ctl7 |= SPIMODE_3WIRE_9BIT_SDIO << 3;
+}
+
+static void SPI_WaitTxFinish(void)
+{
+ volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(used_spi_reg_base);
+
+ while( !((spi_ctr_ptr->iraw)&BIT(8)) ) // IS tx finish
+ {
+ }
+ spi_ctr_ptr->iclr |= BIT(8);
+
+ // Wait for spi bus idle
+ while((spi_ctr_ptr->sts2)&BIT(8))
+ {
+ }
+ // Wait for tx real empty
+ while( !((spi_ctr_ptr->sts2)&BIT(7)) )
+ {
+ }
+}
+
+void SPI_WriteData(uint32_t data, uint32_t data_len, uint32_t dummy_bitlen)
+{
+ // uint32_t command;
+ volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(used_spi_reg_base);
+
+ // The unit of data_len is identical with buswidth
+ SPI_SetTxLen(data_len, dummy_bitlen);
+ SPI_TxReq( );
+
+ spi_ctr_ptr->data = data;
+
+ SPI_WaitTxFinish();
+}
+
+uint32_t SPI_ReadData( uint32_t data_len, uint32_t dummy_bitlen )
+{
+ uint32_t read_data=0, rxt_cnt=0;
+ volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(used_spi_reg_base);
+
+ // The unit of data_len is identical with buswidth
+ SPI_SetRxLen(data_len, dummy_bitlen);
+ SPI_RxReq( );
+
+ //Wait for spi receive finish
+ while( !((spi_ctr_ptr->iraw)&BIT(9)) )
+ {
+ //wait rxt fifo full
+ if((spi_ctr_ptr->iraw)&BIT(6))
+ {
+ rxt_cnt = (spi_ctr_ptr->ctl3)&0x1F;
+ printk("---FIFOFULL:rxt_cnt=0x%x", rxt_cnt);
+ while(rxt_cnt--)
+ {
+ read_data = spi_ctr_ptr->data;
+ printk("---FIFOFULL: SPI_ReadData =0x%x", read_data);
+ }
+ }
+ }
+
+ while((spi_ctr_ptr->sts2)&BIT(8))
+ {
+ }
+
+ while(data_len--)
+ {
+ read_data = spi_ctr_ptr->data;
+ printk("---Finish: SPI_ReadData =0x%x", read_data);
+ }
+
+ return (read_data);
+}
diff --git a/drivers/video/sprdfb/spi/spi_simple_drv.h b/drivers/video/sprdfb/spi/spi_simple_drv.h
new file mode 100644
index 00000000..07019387
--- /dev/null
+++ b/drivers/video/sprdfb/spi/spi_simple_drv.h
@@ -0,0 +1,178 @@
+#ifndef _SPI_TEST_H
+#define _SPI_TEST_H
+
+#include <linux/kernel.h>
+
+#define SPI0_ID 0
+#define SPI1_ID 1
+#define SPI2_ID 2
+#define SPI_USED_ID SPI2_ID
+
+#define CHN_SPI_INT 9
+#define DMA_SPI_TX 0x13
+
+#define SPI_TX_FIFO_DEPTH 16
+#define SPI_RX_FIFO_DEPTH 16
+#define SPI_INT_DIS_ALL 0
+#define SPI_RX_FULL_INT_EN BIT_6
+#define SPI_RX_FULL_INT_STS BIT_6
+#define SPI_RX_FULL_INT_CLR BIT_0
+#define SPI_RX_FIFO_REAL_EMPTY BIT_5
+#define SPI_S8_MODE_EN BIT_7
+#define SPI_CD_SEL 0x2 //cs1 is sel as cd signal
+
+/*
+ Define the SPI interface mode for LCM
+ */
+#define SPIMODE_DISABLE 0
+#define SPIMODE_3WIRE_9BIT_SDA 1 // 3 wire 9 bit, cd bit, SDI/SDO share one IO
+#define SPIMODE_3WIRE_9BIT_SDIO 2 // 3 wire 9 bit, cd bit, SDI, SDO
+#define SPIMODE_4WIRE_8BIT_SDA 3 // 4 wire 8 bit, cd pin, SDI/SDO share one IO
+#define SPIMODE_4WIRE_8BIT_SDIO 4 // 4 wire 8 bit, cd pin, SDI, SDO
+
+/*
+ Define the clk src for SPI mode
+ */
+#define SPICLK_SEL_192M 0
+#define SPICLK_SEL_154M 1
+#define SPICLK_SEL_96M 2
+#define SPICLK_SEL_26M 3
+
+/*
+ SPI CS sel in master mode
+ */
+#define SPI_SEL_CS0 0x0E //2'B1110
+#define SPI_SEL_CS1 0x0D //2'B1101
+#define SPI_SEL_CS2 0x0B //2'B1011
+#define SPI_SEL_CS3 0x07 //2'B0111
+
+#define TX_MAX_LEN_MASK 0xFFFFF
+#define TX_DUMY_LEN_MASK 0x3F //[09:04]
+#define TX_DATA_LEN_H_MASK 0x0F //[03:00]
+#define TX_DATA_LEN_L_MASK 0xFFFF //[15:00]
+#define SPI_MODE_SHIFT 3
+#define SPI_MODE_MASK (0x07<<SPI_MODE_SHIFT)
+#define SPI_CD_MASK BIT(15)
+#define SPI_SEL_CS_SHIFT 8
+
+#define SPI_DEF_SRC_CLK (26 * 1000 *1000)
+#define SPI_DEF_CLK (13 * 1000 * 1000)
+
+typedef enum
+{
+ TX_POS_EDGE = 0,
+ TX_NEG_EDGE
+}TX_EDGE;
+
+typedef enum
+{
+ RX_POS_EDGE = 0,
+ RX_NEG_EDGE
+}RX_EDGE;
+
+typedef enum
+{
+ TX_RX_MSB = 0,
+ TX_RX_LSB
+}MSB_LSB_SEL;
+
+typedef enum
+{
+ IDLE_MODE = 0,
+ RX_MODE,
+ TX_MODE,
+ RX_TX_MODE
+}TRANCIEVE_MODE;
+
+typedef enum
+{
+ NO_SWITCH = 0,
+ BYTE_SWITCH = 1,
+ HWORD_SWITCH = 2
+}SWT_MODE;
+
+typedef enum
+{
+ MASTER_MODE = 0,
+ SLAVE_MODE = 1
+}SPI_OPERATE_MODE_E;
+
+typedef enum
+{
+ DMA_DISABLE = 0,
+ DMA_ENABLE
+}DMA_EN;
+
+typedef enum
+{
+ CS_LOW = 0,
+ CS_HIGH
+}CS_SIGNAL;
+
+#define SW_RX_REQ_MASK BIT(0)
+#define SW_TX_REQ_MASK BIT(1)
+#define RX_MAX_LEN_MASK 0xFFFFFF
+#define RX_DUMY_LEN_MASK 0x3F
+#define RX_DATA_LEN_H_MASK 0x0F
+#define RX_DATA_LEN_L_MASK 0xFFFF
+
+typedef struct _init_param
+{
+ TX_EDGE tx_edge;
+ RX_EDGE rx_edge;
+ MSB_LSB_SEL msb_lsb_sel;
+ TRANCIEVE_MODE tx_rx_mode;
+ SWT_MODE switch_mode;
+ SPI_OPERATE_MODE_E op_mode;
+ uint32_t DMAsrcSize;
+ uint32_t DMAdesSize;
+ uint32_t clk_div;
+ uint8_t data_width;
+ uint8_t tx_empty_watermark;
+ uint8_t tx_full_watermark;
+ uint8_t rx_empty_watermark;
+ uint8_t rx_full_watermark;
+}SPI_INIT_PARM,*SPI_INIT_PARM_P;
+
+typedef struct
+{
+ uint32_t data; // Transmit word or Receive word
+ uint32_t clkd; // clock dividor register
+ uint32_t ctl0; // control register
+ uint32_t ctl1; // Receive Data full threshold/Receive Data full threshold
+ uint32_t ctl2; // 2-wire mode reigster
+ uint32_t ctl3; // transmit data interval
+ uint32_t ctl4; // transmit data interval
+ uint32_t ctl5; // transmit data interval
+ uint32_t ien; // interrutp enable register
+ uint32_t iclr; // interrupt clear register
+ uint32_t iraw; // interrupt clear register
+ uint32_t ists; // interrupt clear register
+ uint32_t sts1; // fifo cnt register, bit[5:0] for RX and [13:8] for TX
+ uint32_t sts2; // masked interrupt status register
+ uint32_t dsp_wait; // Used for DSP control
+ uint32_t sts3; // tx_empty_threshold and tx_full_threshold
+ uint32_t ctl6;
+ uint32_t sts4;
+ uint32_t fifo_rst;
+ uint32_t ctl7; // SPI_RX_HLD_EN : SPI_TX_HLD_EN : SPI_MODE
+ uint32_t sts5; // CSN_IN_ERR_SYNC2
+ uint32_t ctl8; // SPI_CD_BIT : SPI_TX_DUMY_LEN : SPI_TX_DATA_LEN_H
+ uint32_t ctl9; // SPI_TX_DATA_LEN_L
+ uint32_t ctl10; // SPI_RX_DATA_LEN_H : SPI_RX_DUMY_LEN
+ uint32_t ctl11; // SPI_RX_DATA_LEN_L
+ uint32_t ctl12; // SW_TX_REQ : SW_RX_REQ
+} SPI_CTL_REG_T;
+
+void SPI_SetCsLow( uint32_t spi_sel_csx , bool is_low);
+void SPI_SetCd( uint32_t cd);
+void SPI_SetDatawidth(uint32_t datawidth);
+#ifdef CONFIG_OF
+void SPI_Init(struct device *device, u32 spi_id, SPI_INIT_PARM *spi_parm);
+#else
+void SPI_Init(u32 spi_id, SPI_INIT_PARM *spi_parm);
+#endif
+void SPI_WriteData(uint32_t data, uint32_t data_len, uint32_t dummy_bitlen);
+uint32_t SPI_ReadData( uint32_t data_len, uint32_t dummy_bitlen );
+
+#endif /*_SPI_TEST_H*/
diff --git a/drivers/video/sprdfb/sprdfb.h b/drivers/video/sprdfb/sprdfb.h
new file mode 100644
index 00000000..52f095bd
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SPRDFB_H_
+#define _SPRDFB_H_
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include <linux/compat.h>
+#include <linux/workqueue.h>
+#include <linux/semaphore.h>
+#include <linux/wait.h>
+#ifdef CONFIG_FB_MMAP_CACHED
+#include <linux/mm_types.h>
+#endif
+
+#if ((!defined(CONFIG_FB_SCX35)) && (!defined(CONFIG_FB_SCX15)))
+#define FB_CHECK_ESD_IN_VFP
+#endif
+//#define FB_CHECK_ESD_BY_TE_SUPPORT
+#define BIT_PER_PIXEL_SURPPORT
+
+enum{
+ SPRDFB_PANEL_IF_DBI = 0,
+ SPRDFB_PANEL_IF_DPI,
+ SPRDFB_PANEL_IF_EDPI,
+ SPRDFB_PANEL_IF_LIMIT
+};
+
+enum {
+ SPRDFB_UNKNOWN = 0,
+ SPRDFB_DYNAMIC_PCLK = 0x1,
+ SPRDFB_DYNAMIC_FPS,
+ SPRDFB_DYNAMIC_MIPI_CLK,
+ SPRDFB_FORCE_FPS,
+ SPRDFB_FORCE_PCLK,
+};
+
+enum{
+ MCU_LCD_REGISTER_TIMING = 0,
+ MCU_LCD_GRAM_TIMING,
+ MCU_LCD_TIMING_KIND_MAX
+};
+
+enum{
+ RGB_LCD_H_TIMING = 0,
+ RGB_LCD_V_TIMING,
+ RGB_LCD_TIMING_KIND_MAX
+};
+
+
+#ifdef CONFIG_FB_LCD_OVERLAY_SUPPORT
+#define SPRD_LAYER_IMG (0x01) /*support YUV & RGB*/
+#define SPRD_LAYER_OSD (0x02) /*support RGB only*/
+
+enum {
+ SPRD_DATA_TYPE_YUV422 = 0,
+ SPRD_DATA_TYPE_YUV420,
+ SPRD_DATA_TYPE_YUV400,
+ SPRD_DATA_TYPE_RGB888,
+ SPRD_DATA_TYPE_RGB666,
+ SPRD_DATA_TYPE_RGB565,
+ SPRD_DATA_TYPE_RGB555,
+ SPRD_DATA_TYPE_LIMIT
+};
+
+enum{
+ SPRD_IMG_DATA_ENDIAN_B0B1B2B3 = 0,
+ SPRD_IMG_DATA_ENDIAN_B3B2B1B0,
+ SPRD_IMG_DATA_ENDIAN_B2B3B0B1,
+ SPRD_IMG_DATA_ENDIAN_B1B0B3B2,
+ SPRD_IMG_DATA_ENDIAN_LIMIT
+};
+
+enum{
+ SPRD_OVERLAY_STATUS_OFF = 0,
+ SPRD_OVERLAY_STATUS_ON,
+ SPRD_OVERLAY_STATUS_STARTED,
+ SPRD_OVERLAY_STATUS_MAX
+};
+
+enum{
+ SPRD_OVERLAY_DISPLAY_ASYNC = 0,
+ SPRD_OVERLAY_DISPLAY_SYNC,
+ SPRD_OVERLAY_DISPLAY_MAX
+};
+
+typedef struct overlay_rect {
+ uint16_t x;
+ uint16_t y;
+ uint16_t w;
+ uint16_t h;
+}overlay_rect;
+
+typedef struct overlay_info{
+ int layer_index;
+ int data_type;
+ int y_endian;
+ int uv_endian;
+ bool rb_switch;
+ overlay_rect rect;
+ unsigned char *buffer;
+}overlay_info;
+
+typedef struct overlay_display{
+ int layer_index;
+ overlay_rect rect;
+ int display_mode;
+}overlay_display;
+
+#ifdef CONFIG_COMPAT
+typedef struct overlay_info32{
+ int layer_index;
+ int data_type;
+ int y_endian;
+ int uv_endian;
+ bool rb_switch;
+ overlay_rect rect;
+ compat_caddr_t buffer;
+}overlay_info32;
+#endif
+#endif
+
+enum{
+ MIPI_PLL_TYPE_NONE = 0,
+ MIPI_PLL_TYPE_1,
+ MIPI_PLL_TYPE_2,
+ MIPI_PLL_TYPE_LIMIT
+};
+
+typedef struct fb_capability {
+ uint16_t need_light_sleep; /* enable light_sleep in fb driver*/
+ uint16_t mipi_pll_type; /* 0:none 1:for pike/pikel 2:for sharkl64/sharklT8*/
+}fb_capability;
+
+struct sprdfb_device {
+ struct fb_info *fb;
+ struct panel_spec *panel;
+ struct display_ctrl *ctrl;
+ void *logo_buffer_addr_v;
+ void *priv1;
+
+#ifdef CONFIG_OF
+ struct device *of_dev;
+#endif
+
+ uint16_t enable;
+ uint16_t dev_id; /*main_lcd, sub_lcd*/
+
+ uint32_t bpp; /*input bit per pixel*/
+
+ uint16_t panel_ready; /*panel has been inited by uboot*/
+ uint16_t panel_if_type; /*panel IF*/
+
+#ifdef CONFIG_FB_LOW_RES_SIMU
+ uint32_t display_width;
+ uint32_t display_height;
+#endif
+
+ union{
+ uint32_t mcu_timing[MCU_LCD_TIMING_KIND_MAX];
+ uint32_t rgb_timing[RGB_LCD_TIMING_KIND_MAX];
+ }panel_timing;
+
+ struct fb_capability capability;
+ uint32_t dpi_clock;
+ struct semaphore refresh_lock;
+ uint64_t frame_count;
+
+#ifdef CONFIG_FB_ESD_SUPPORT
+ struct delayed_work ESD_work;
+// struct semaphore ESD_lock;
+ uint32_t ESD_timeout_val;
+ bool ESD_work_start;
+ /*for debug only*/
+ uint32_t check_esd_time;
+ uint32_t panel_reset_time;
+ uint32_t reset_dsi_time;
+#ifdef FB_CHECK_ESD_BY_TE_SUPPORT
+ uint32_t esd_te_waiter;
+ wait_queue_head_t esd_te_queue;
+ uint32_t esd_te_done;
+#endif
+#endif
+
+ uint32_t logo_buffer_size;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
+};
+
+struct display_ctrl {
+ const char *name;
+
+ int32_t (*early_init) (struct sprdfb_device *dev);
+ int32_t (*init) (struct sprdfb_device *dev);
+ int32_t (*uninit) (struct sprdfb_device *dev);
+
+ int32_t (*refresh) (struct sprdfb_device *dev);
+ void (*logo_proc) (struct sprdfb_device *dev);
+
+ int32_t (*suspend) (struct sprdfb_device *dev);
+ int32_t (*resume) (struct sprdfb_device *dev);
+ int32_t (*update_clk) (struct sprdfb_device *dev);
+
+#ifdef CONFIG_FB_ESD_SUPPORT
+ int32_t (*ESD_check) (struct sprdfb_device *dev);
+#endif
+
+#ifdef CONFIG_FB_LCD_OVERLAY_SUPPORT
+ int32_t (*enable_overlay) (struct sprdfb_device *dev, struct overlay_info* info, int enable);
+ int32_t (*display_overlay) (struct sprdfb_device *dev, struct overlay_display* setting);
+#endif
+
+#ifdef CONFIG_FB_VSYNC_SUPPORT
+ int32_t (*wait_for_vsync) (struct sprdfb_device *dev);
+#endif
+
+#ifdef CONFIG_FB_MMAP_CACHED
+ void (*set_vma)(struct vm_area_struct *vma);
+#endif
+ int32_t (*is_refresh_done) (struct sprdfb_device *dev);
+
+};
+
+#ifndef ROUND
+#define ROUND(a, b) (((a) + (b) / 2) / (b))
+#endif
+
+/* function declaration begin */
+int sprdfb_create_sysfs(struct sprdfb_device *fb_dev);
+void sprdfb_remove_sysfs(struct sprdfb_device *fb_dev);
+
+#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING
+int sprdfb_dispc_chg_clk(struct sprdfb_device *fb_dev,
+ int type, u32 new_val);
+#else
+#define sprdfb_dispc_chg_clk(fb_dev, type, new_val) ( \
+{ \
+ int _ret = -ENXIO; \
+ pr_err("dynamical clock feature hasn't been enabled yet\n"); \
+ _ret; \
+} \
+)
+#endif
+
+#if !defined(CONFIG_FB_SCX15)
+int sprdfb_dsi_chg_dphy_freq(struct sprdfb_device *fb_dev,
+ u32 dphy_freq);
+int32_t dsi_dpi_init(struct sprdfb_device *dev);
+#else
+#define sprdfb_dsi_chg_dphy_freq(fb_dev, dphy_freq) ( \
+{ \
+ int _ret = -ENXIO; \
+ pr_err("this chip doesn't support for mipi dsi\n"); \
+ _ret; \
+} \
+)
+
+#define dsi_dpi_init(fb_dev) ( \
+{ \
+ int _ret = -ENXIO; \
+ pr_err("this chip doesn't support for mipi dsi\n"); \
+ _ret; \
+} \
+)
+#endif
+
+int sprdfb_chg_clk_intf(struct sprdfb_device *fb_dev,
+ int type, u32 new_val);
+/* Function declare begin */
+#ifdef CONFIG_SC_FPGA
+int sprdchip_lvds_init(void);
+#endif
+/* Function declare end */
+
+#endif
diff --git a/drivers/video/sprdfb/sprdfb_attr.c b/drivers/video/sprdfb/sprdfb_attr.c
new file mode 100644
index 00000000..a5d53581
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_attr.c
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2014 Spreadtrum Communications Inc.
+ *
+ * Author: Haibing.Yang <haibing.yang@spreadtrum.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "sprdfb: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include "sprdfb.h"
+#include "sprdfb_panel.h"
+
+
+struct attr_info {
+ struct sprdfb_device *fb_dev;
+ /* clock management */
+ u32 origin_pclk;
+ u32 curr_pclk;
+ u32 origin_fps;
+ u32 curr_fps;
+ u32 origin_mipi_clk;
+ u32 curr_mipi_clk;
+
+ struct semaphore sem;
+};
+
+static ssize_t sysfs_rd_current_pclk(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t sysfs_write_pclk(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+static ssize_t sysfs_rd_current_fps(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t sysfs_write_fps(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+static ssize_t sysfs_rd_current_mipi_clk(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t sysfs_write_mipi_clk(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+static ssize_t sysfs_rd_current_frame_count(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+#ifdef CONFIG_FB_ESD_SUPPORT
+static ssize_t sysfs_rd_current_esd(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t sysfs_write_esd(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+#endif
+
+static DEVICE_ATTR(dynamic_pclk, S_IRUGO | S_IWUSR, sysfs_rd_current_pclk,
+ sysfs_write_pclk);
+static DEVICE_ATTR(dynamic_fps, S_IRUGO | S_IWUSR, sysfs_rd_current_fps,
+ sysfs_write_fps);
+static DEVICE_ATTR(dynamic_mipi_clk, S_IRUGO | S_IWUSR,
+ sysfs_rd_current_mipi_clk, sysfs_write_mipi_clk);
+static DEVICE_ATTR(dynamic_frame_count, S_IRUGO,
+ sysfs_rd_current_frame_count, NULL);
+
+#ifdef CONFIG_FB_ESD_SUPPORT
+static DEVICE_ATTR(dynamic_esd, S_IRUGO | S_IWUSR,
+ sysfs_rd_current_esd, sysfs_write_esd);
+#endif
+
+static struct attribute *sprdfb_fs_attrs[] = {
+ &dev_attr_dynamic_pclk.attr,
+ &dev_attr_dynamic_fps.attr,
+ &dev_attr_dynamic_mipi_clk.attr,
+ &dev_attr_dynamic_frame_count.attr,
+
+#ifdef CONFIG_FB_ESD_SUPPORT
+ &dev_attr_dynamic_esd.attr,
+#endif
+ NULL,
+};
+
+static struct attribute_group sprdfb_attrs_group = {
+ .attrs = sprdfb_fs_attrs,
+};
+
+/**
+ * @fb_dev - sprdfb specific device
+ * @type: SPRDFB_DYNAMIC_PCLK, SPRDFB_DYNAMIC_FPS, SPRDFB_DYNAMIC_MIPI_CLK
+ * @new_val: new required fps, dpi clock or mipi clock
+ *
+ * If clk is set unsuccessfully, this function returns minus.
+ * It returns 0 if clk is set successfully.
+ */
+int sprdfb_chg_clk_intf(struct sprdfb_device *fb_dev,
+ int type, u32 new_val)
+{
+ int ret;
+ struct attr_info *attr = fb_dev->priv1;
+
+ down(&attr->sem);
+ ret = sprdfb_dispc_chg_clk(fb_dev, type, new_val);
+ up(&attr->sem);
+
+ return ret;
+}
+
+static ssize_t sysfs_rd_current_pclk(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct sprdfb_device *fb_dev = (struct sprdfb_device *)fbi->par;
+ struct attr_info *attr_info = fb_dev->priv1;
+
+ if (!fb_dev) {
+ pr_err("fb_dev can't be found\n");
+ return -ENXIO;
+ }
+ ret = snprintf(buf, PAGE_SIZE,
+ "current dpi_clk: %u\nnew dpi_clk: %u\norigin dpi_clk: %u\n",
+ fb_dev->dpi_clock, attr_info->curr_pclk,
+ attr_info->origin_pclk);
+
+ return ret;
+}
+
+static ssize_t sysfs_write_pclk(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ int divider;
+ u32 dpi_clk_src, new_pclk;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct sprdfb_device *fb_dev = (struct sprdfb_device *)fbi->par;
+ struct attr_info *attr_info = fb_dev->priv1;
+
+ sscanf(buf, "%u,%d\n", &dpi_clk_src, &divider);
+
+ if (divider == 0 && dpi_clk_src == 0) {
+ new_pclk = attr_info->origin_pclk;
+ goto DIRECT_GO;
+ }
+
+ if (divider < 1 || divider > 0xff || dpi_clk_src < 1) {
+ pr_err("divider:[%d], clk_src:[%d] is invalid\n",
+ divider, dpi_clk_src);
+ return count;
+ }
+
+ if (dpi_clk_src < 1000)
+ dpi_clk_src *= 1000000; /* MHz */
+
+ new_pclk = dpi_clk_src / divider;
+
+DIRECT_GO:
+ if (new_pclk == fb_dev->dpi_clock) {
+ /* Do nothing */
+ pr_warn("new pclk is the same as current pclk\n");
+ return count;
+ }
+
+ ret = sprdfb_chg_clk_intf(fb_dev, SPRDFB_DYNAMIC_PCLK, new_pclk);
+ if (ret) {
+ pr_err("%s: failed to change dpi clock. ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+ attr_info->curr_pclk = new_pclk;
+
+ return count;
+}
+
+static ssize_t sysfs_rd_current_fps(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct sprdfb_device *fb_dev = (struct sprdfb_device *)fbi->par;
+ struct attr_info *attr_info = fb_dev->priv1;
+ struct panel_spec* panel = fb_dev->panel;
+
+ if (!panel) {
+ pr_err("panel doesn't exist.");
+ return -ENXIO;
+ }
+ ret = snprintf(buf, PAGE_SIZE,
+ "current fps: %u\nnew fps: %u\norigin fps: %u\n",
+ panel->fps, attr_info->curr_fps, attr_info->origin_fps);
+
+ return ret;
+}
+
+static ssize_t sysfs_write_fps(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret, fps;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct sprdfb_device *fb_dev = (struct sprdfb_device *)fbi->par;
+ struct attr_info *attr_info = fb_dev->priv1;
+ struct panel_spec* panel = fb_dev->panel;
+
+ if (!panel) {
+ pr_err("panel doesn't exist.");
+ return -ENXIO;
+ }
+ ret = kstrtoint(buf, 10, &fps);
+
+ fps = fps > 0 ? fps : attr_info->origin_fps;
+
+ if (panel->fps == fps) {
+ /* Do nothing */
+ pr_warn("new fps is the same as current fps\n");
+ return count;
+ }
+
+ ret = sprdfb_chg_clk_intf(fb_dev, SPRDFB_DYNAMIC_FPS, (u32)fps);
+ if (ret) {
+ pr_err("%s: failed to change dpi clock. ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+ attr_info->curr_fps = fps;
+
+ return count;
+}
+
+static ssize_t sysfs_rd_current_mipi_clk(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret = 0;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct sprdfb_device *fb_dev = (struct sprdfb_device *)fbi->par;
+ struct attr_info *attr_info = fb_dev->priv1;
+ struct panel_spec* panel = fb_dev->panel;
+
+ if (!panel) {
+ pr_err("panel doesn't exist.");
+ return -ENXIO;
+ }
+ if (panel->type != LCD_MODE_DSI) {
+ pr_err("Current panel is not mipi dsi\n");
+ ret = snprintf(buf, PAGE_SIZE,
+ "Current panel is not mipi dsi\n");
+ return ret;
+ }
+
+ ret = snprintf(buf, PAGE_SIZE,
+ "current mipi d-phy frequency: %u\n"
+ "new mipi d-phy frequency: %u\n"
+ "origin mipi d-phy frequency: %u\n",
+ panel->info.mipi->phy_feq,
+ attr_info->curr_mipi_clk,
+ attr_info->origin_mipi_clk);
+ return ret;
+}
+
+static ssize_t sysfs_write_mipi_clk(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = 0;
+ u32 dphy_freq;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct sprdfb_device *fb_dev = (struct sprdfb_device *)fbi->par;
+ struct attr_info *attr_info = fb_dev->priv1;
+ struct panel_spec* panel = fb_dev->panel;
+
+ if (!panel) {
+ pr_err("panel doesn't exist.");
+ return -ENXIO;
+ }
+ if (panel->type != LCD_MODE_DSI) {
+ pr_err("sys write failure. Current panel is not mipi dsi\n");
+ return count;
+ }
+ ret = kstrtoint(buf, 10, &dphy_freq);
+ if (ret) {
+ pr_err("Invalid input for dphy_freq\n");
+ return -EINVAL;
+ }
+
+ if (dphy_freq > 0) {
+ /*
+ * because of double edge trigger,
+ * the rule is actual freq * 10 / 2,
+ * Eg: Required freq is 500M
+ * Equation: 2500*2*1000/10=500*1000=2500*200=500M
+ */
+ dphy_freq *= 200;
+ } else
+ dphy_freq = attr_info->origin_mipi_clk;
+
+ /* dphy supported freq ranges is 90M-1500M*/
+ pr_debug("input dphy_freq is %d\n", dphy_freq);
+
+ if (dphy_freq == attr_info->curr_mipi_clk) {
+ /* Do nothing */
+ pr_warn("new dphy_freq is the same as current freq\n");
+ return count;
+ }
+
+ if (dphy_freq <= 1500000 && dphy_freq >= 90000) {
+ ret = sprdfb_chg_clk_intf(fb_dev, SPRDFB_DYNAMIC_MIPI_CLK, dphy_freq);
+ if (ret) {
+ pr_err("sprdfb_chg_clk_intf change d-phy freq fail.\n");
+ return count;
+ }
+ attr_info->curr_mipi_clk = dphy_freq;
+ } else {
+ pr_warn("input mipi frequency:%d is out of range.\n",
+ dphy_freq);
+ }
+
+ return count;
+}
+
+static ssize_t sysfs_rd_current_frame_count(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct sprdfb_device *fb_dev = (struct sprdfb_device *)fbi->par;
+
+ if (!fb_dev) {
+ pr_err("fb_dev can't be found\n");
+ return -ENXIO;
+ }
+ ret = snprintf(buf, PAGE_SIZE,
+ "current frame_count: %lld\n", fb_dev->frame_count);
+
+ return ret;
+}
+
+#ifdef CONFIG_FB_ESD_SUPPORT
+static ssize_t sysfs_rd_current_esd(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct sprdfb_device *fb_dev = (struct sprdfb_device *)fbi->par;
+// struct attr_info *attr_info = fb_dev->priv1;
+
+ if (!fb_dev) {
+ pr_err("fb_dev can't be found\n");
+ return -ENXIO;
+ }
+ ret = snprintf(buf, PAGE_SIZE,
+ "current esd: %u\n",fb_dev->ESD_work_start);
+
+ return ret;
+}
+
+static ssize_t sysfs_write_esd(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret, esd;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct sprdfb_device *fb_dev = (struct sprdfb_device *)fbi->par;
+// struct attr_info *attr_info = fb_dev->priv1;
+
+ ret = kstrtoint(buf, 10, &esd);
+
+ esd = (esd == 1) ? 1:0;
+
+ if ((1 == esd) && (fb_dev->enable == 1)) {
+ if (!fb_dev->ESD_work_start) {
+ printk("sprdfb: schedule ESD work queue!\n");
+ schedule_delayed_work(&fb_dev->ESD_work, msecs_to_jiffies(fb_dev->ESD_timeout_val));
+ fb_dev->ESD_work_start = true;
+ }
+ } else {
+ if (fb_dev->ESD_work_start == true) {
+ printk("sprdfb: cancel ESD work queue\n");
+ cancel_delayed_work_sync(&fb_dev->ESD_work);
+ fb_dev->ESD_work_start = false;
+ }
+ }
+ return count;
+}
+#endif
+
+int sprdfb_create_sysfs(struct sprdfb_device *fb_dev)
+{
+ int rc;
+ struct panel_spec* panel = fb_dev->panel;
+ struct attr_info *attr;
+
+ fb_dev->priv1 = kzalloc(sizeof(struct attr_info), GFP_KERNEL);
+ if (!fb_dev->priv1) {
+ pr_err("shortage of memory\n");
+ return -ENOMEM;
+ }
+ attr = fb_dev->priv1;
+
+ rc = sysfs_create_group(&fb_dev->fb->dev->kobj, &sprdfb_attrs_group);
+ if (rc)
+ pr_err("sysfs group creation failed, rc=%d\n", rc);
+
+ attr->origin_pclk = fb_dev->dpi_clock;
+ if (panel) {
+ attr->origin_fps = panel->fps;
+ if (panel->type == LCD_MODE_DSI)
+ attr->origin_mipi_clk = panel->info.mipi->phy_feq;
+ }
+ sema_init(&attr->sem, 1);
+
+ return rc;
+}
+
+void sprdfb_remove_sysfs(struct sprdfb_device *fb_dev)
+{
+ struct attr_info *attr = fb_dev->priv1;
+ sysfs_remove_group(&fb_dev->fb->dev->kobj, &sprdfb_attrs_group);
+
+ if (attr)
+ kfree(attr);
+}
diff --git a/drivers/video/sprdfb/sprdfb_chip_7715.c b/drivers/video/sprdfb/sprdfb_chip_7715.c
new file mode 100755
index 00000000..079095e7
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_chip_7715.c
@@ -0,0 +1,35 @@
+/******************************************************************************
+ ** File Name: sprdfb_chip_7715.c *
+ ** Author: congfu.zhao *
+ ** DATE: 30/04/2013 *
+ ** Copyright: 2013 Spreatrum, Incoporated. All Rights Reserved. *
+ ** Description: *
+ ******************************************************************************/
+/******************************************************************************
+ ** Edit History *
+ **---------------------------------------------------------------------------*
+ ** DATE NAME DESCRIPTION *
+
+ ******************************************************************************/
+
+
+#include "sprdfb_chip_7715.h"
+#include "sprdfb_chip_common.h"
+
+
+void dispc_print_clk(void)
+{
+ uint32_t reg_val0,reg_val1,reg_val2;
+ reg_val0 = dispc_glb_read(SPRD_AONAPB_BASE+0x4);
+ reg_val1 = dispc_glb_read(SPRD_AHB_BASE);
+ reg_val2 = dispc_glb_read(SPRD_APBREG_BASE);
+ printk("sprdfb: 0x402e0004 = 0x%x 0x20d00000 = 0x%x 0x71300000 = 0x%x \n",reg_val0, reg_val1, reg_val2);
+ reg_val0 = dispc_glb_read(SPRD_APBCKG_BASE+0x34);
+ reg_val1 = dispc_glb_read(SPRD_APBCKG_BASE+0x30);
+ reg_val2 = dispc_glb_read(SPRD_APBCKG_BASE+0x2c);
+ printk("sprdfb: 0x71200034 = 0x%x 0x71200030 = 0x%x 0x7120002c = 0x%x \n",reg_val0, reg_val1, reg_val2);
+}
+
+
+
+
diff --git a/drivers/video/sprdfb/sprdfb_chip_7715.h b/drivers/video/sprdfb/sprdfb_chip_7715.h
new file mode 100755
index 00000000..86ecc2ee
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_chip_7715.h
@@ -0,0 +1,116 @@
+/******************************************************************************
+ ** File Name: sprdfb_chip_7715.h *
+ ** Author: congfu.zhao *
+ ** DATE: 30/04/2013 *
+ ** Copyright: 2013 Spreatrum, Incoporated. All Rights Reserved. *
+ ** Description: *
+ ******************************************************************************/
+/******************************************************************************
+ ** Edit History *
+ **---------------------------------------------------------------------------*
+ ** DATE NAME DESCRIPTION *
+
+ ******************************************************************************/
+#ifndef _SC7715_DISPC_GLB_REG_K_H_
+#define _SC7715_DISPC_GLB_REG_K_H_
+
+
+#include <linux/kernel.h>
+
+#include <mach/sci_glb_regs.h>
+
+
+//#define BIT(x) (1<<x)
+//no mipi
+#ifndef CONFIG_OF
+#define DISPC_PLL_CLK ("clk_disc0")
+#define DISPC_DBI_CLK ("clk_disc0_dbi")
+#define DISPC_DPI_CLK ("clk_disc0_dpi")
+#define DISPC_EMC_CLK ("clk_disp_emc")
+#define DISPC_DPI_CLOCK (384*1000000/14)
+
+#define SPRD_DISPC_BASE SPRD_LCDC_BASE
+#define IRQ_DISPC_INT IRQ_DISPC0_INT
+#endif
+
+#define REG_AHB_SOFT_RST (0x4 + SPRD_AHB_BASE)
+#define BIT_DISPC_SOFT_RST BIT_DISPC0_SOFT_RST
+
+#define DISPC_CORE_EN (REG_AP_APB_APB_EB)
+#define BIT_DISPC_CORE_EN (BIT_AP_CKG_EB)
+
+#ifndef CONFIG_OF
+#define DISPC_AHB_EN (REG_AP_AHB_AHB_EB)
+#define BIT_DISPC_AHB_EN (BIT_DISPC0_EB)
+
+#define DISPC_EMC_EN (REG_AON_APB_APB_EB1)
+#define BIT_DISPC_EMC_EN (BIT_DISP_EMC_EB)
+
+#define DISPC_PLL_SEL_CFG REG_AP_CLK_DISPC0_CFG
+#define BITS_DISPC_PLL_SEL_CFG 0
+#define BIT0_DISPC_PLL_SEL_CFG BIT(0)
+#define BIT1_DISPC_PLL_SEL_CFG BIT(1)
+#define BIT_DISPC_PLL_SEL_MSK BIT1_DISPC_PLL_SEL_CFG | BIT0_DISPC_PLL_SEL_CFG
+
+#define DISPC_PLL_DIV_CFG REG_AP_CLK_DISPC0_CFG
+#define BITS_DISPC_PLL_DIV_CFG 8
+#define BIT0_DISPC_PLL_DIV_CFG BIT(8)
+#define BIT1_DISPC_PLL_DIV_CFG BIT(9)
+#define BIT2_DISPC_PLL_DIV_CFG BIT(10)
+#define BIT_DISPC_PLL_DIV_MSK BIT0_DISPC_PLL_DIV_CFG | BIT1_DISPC_PLL_DIV_CFG | BIT2_DISPC_PLL_DIV_CFG
+
+#define DISPC_DBI_SEL_CFG REG_AP_CLK_DISPC0_DBI_CFG
+#define BITS_DISPC_DBI_SEL_CFG 0
+#define BIT0_DISPC_DBI_SEL_CFG BIT(0)
+#define BIT1_DISPC_DBI_SEL_CFG BIT(1)
+#define BIT_DISPC_DBI_SEL_MSK BIT0_DISPC_DBI_SEL_CFG | BIT1_DISPC_DBI_SEL_CFG
+
+#define DISPC_DBI_DIV_CFG REG_AP_CLK_DISPC0_DBI_CFG
+#define BITS_DISPC_DBI_DIV_CFG 8
+#define BIT0_DISPC_DBI_DIV_CFG BIT(8)
+#define BIT1_DISPC_DBI_DIV_CFG BIT(9)
+#define BIT2_DISPC_DBI_DIV_CFG BIT(10)
+#define BIT_DISPC_DBI_DIV_MSK BIT0_DISPC_DBI_DIV_CFG | BIT1_DISPC_DBI_DIV_CFG | BIT2_DISPC_DBI_DIV_CFG
+
+#define DISPC_DPI_SEL_CFG REG_AP_CLK_DISPC0_DPI_CFG
+#define BITS_DISPC_DPI_SEL_CFG 0
+#define BIT0_DISPC_DPI_SEL_CFG BIT(0)
+#define BIT1_DISPC_DPI_SEL_CFG BIT(1)
+#define BIT_DISPC_DPI_SEL_MSK BIT0_DISPC_DPI_SEL_CFG | BIT1_DISPC_DPI_SEL_CFG
+
+#define DISPC_DPI_DIV_CFG REG_AP_CLK_DISPC0_DPI_CFG
+#define BITS_DISPC_DPI_DIV_CFG 8
+#define BIT0_DISPC_DPI_DIV_CFG BIT(8)
+#define BIT1_DISPC_DPI_DIV_CFG BIT(9)
+#define BIT2_DISPC_DPI_DIV_CFG BIT(10)
+#define BIT3_DISPC_DPI_DIV_CFG BIT(11)
+#define BIT4_DISPC_DPI_DIV_CFG BIT(12)
+#define BIT5_DISPC_DPI_DIV_CFG BIT(13)
+#define BIT6_DISPC_DPI_DIV_CFG BIT(14)
+#define BIT7_DISPC_DPI_DIV_CFG BIT(15)
+#define BIT_DISPC_DPI_DIV_MSK BIT0_DISPC_DPI_DIV_CFG | BIT1_DISPC_DPI_DIV_CFG | BIT2_DISPC_DPI_DIV_CFG | BIT3_DISPC_DPI_DIV_CFG \
+ | BIT4_DISPC_DPI_DIV_CFG | BIT5_DISPC_DPI_DIV_CFG | BIT6_DISPC_DPI_DIV_CFG | BIT7_DISPC_DPI_DIV_CFG
+
+
+enum{
+ DISPC_PLL_SEL_153_6M = 0,
+ DISPC_PLL_SEL_192M,
+};
+
+enum{
+ DISPC_DBI_SEL_128M = 0,
+ DISPC_DBI_SEL_153_6M,
+ DISPC_DBI_SEL_192M,
+ DISPC_DBI_SEL_256M
+};
+
+enum{
+ DISPC_DPI_SEL_128M = 0,
+ DISPC_DPI_SEL_153_6M,
+ DISPC_DPI_SEL_192M,
+ DISPC_DPI_SEL_384M,
+};
+#endif
+
+
+#endif
diff --git a/drivers/video/sprdfb/sprdfb_chip_8830.c b/drivers/video/sprdfb/sprdfb_chip_8830.c
new file mode 100644
index 00000000..08cb77b8
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_chip_8830.c
@@ -0,0 +1,80 @@
+/******************************************************************************
+ ** File Name: sprdfb_chip_8830.c *
+ ** Author: congfu.zhao *
+ ** DATE: 30/04/2013 *
+ ** Copyright: 2013 Spreatrum, Incoporated. All Rights Reserved. *
+ ** Description: *
+ ******************************************************************************/
+/******************************************************************************
+ ** Edit History *
+ **---------------------------------------------------------------------------*
+ ** DATE NAME DESCRIPTION *
+
+ ******************************************************************************/
+
+
+#include "sprdfb_chip_8830.h"
+#include "sprdfb_chip_common.h"
+
+
+void dsi_enable(void)
+{
+#ifdef CONFIG_FB_SCX30G
+ sci_glb_clr(REG_AON_APB_PWR_CTRL, BIT_DSI_PHY_PD);
+#endif
+ sci_glb_set(REG_AP_AHB_MISC_CKG_EN, BIT_DPHY_REF_CKG_EN);
+ sci_glb_set(REG_AP_AHB_MISC_CKG_EN, BIT_DPHY_CFG_CKG_EN);
+
+ printk("sprdfb:dsi_enable %08x\n",REG_AP_AHB_MISC_CKG_EN);
+ sci_glb_set(DSI_REG_EB, DSI_BIT_EB);
+}
+
+void dsi_disable(void)
+{
+ sci_glb_clr(REG_AP_AHB_MISC_CKG_EN, BIT_DPHY_REF_CKG_EN);
+ sci_glb_clr(REG_AP_AHB_MISC_CKG_EN, BIT_DPHY_CFG_CKG_EN);
+
+ sci_glb_clr(DSI_REG_EB, DSI_BIT_EB);
+#ifdef CONFIG_FB_SCX30G
+ sci_glb_set(REG_AON_APB_PWR_CTRL, BIT_DSI_PHY_PD);
+#endif
+}
+
+void dsi_print_global_config(void)
+{
+ u32 reg_val0, reg_val1;
+#ifdef CONFIG_FB_SCX30G
+ u32 reg_val2;
+#endif
+ reg_val0 = sci_glb_read(REG_AP_AHB_MISC_CKG_EN, 0xffffffff);
+ reg_val1 = sci_glb_read(DSI_REG_EB, 0xffffffff);
+#ifdef CONFIG_FB_SCX30G
+ reg_val2 = sci_glb_read(REG_AON_APB_PWR_CTRL, 0xffffffff);
+#endif
+
+#ifdef CONFIG_FB_SCX30G
+ printk("sprdfb: dsi: 0x20D00040 = 0x%x, 0x20D00000 = 0x%x, 0x402E0024 = 0x%x\n",
+ reg_val0, reg_val1, reg_val2);
+#else
+ printk("sprdfb: dsi: 0x20D00040 = 0x%x, 0x20D00000 = 0x%x\n",
+ reg_val0, reg_val1);
+#endif
+}
+
+
+void dispc_print_clk(void)
+{
+ uint32_t reg_val0,reg_val1,reg_val2;
+ reg_val0 = dispc_glb_read(SPRD_AONAPB_BASE+0x4);
+ reg_val1 = dispc_glb_read(SPRD_AHB_BASE);
+ reg_val2 = dispc_glb_read(SPRD_APBREG_BASE);
+ printk("sprdfb: 0x402e0004 = 0x%x 0x20d00000 = 0x%x 0x71300000 = 0x%x \n",reg_val0, reg_val1, reg_val2);
+ reg_val0 = dispc_glb_read(SPRD_APBCKG_BASE+0x34);
+ reg_val1 = dispc_glb_read(SPRD_APBCKG_BASE+0x30);
+ reg_val2 = dispc_glb_read(SPRD_APBCKG_BASE+0x2c);
+ printk("sprdfb: 0x71200034 = 0x%x 0x71200030 = 0x%x 0x7120002c = 0x%x \n",reg_val0, reg_val1, reg_val2);
+}
+
+
+
+
diff --git a/drivers/video/sprdfb/sprdfb_chip_8830.h b/drivers/video/sprdfb/sprdfb_chip_8830.h
new file mode 100644
index 00000000..cfe36551
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_chip_8830.h
@@ -0,0 +1,135 @@
+/******************************************************************************
+ ** File Name: sprdfb_chip_8830.h *
+ ** Author: congfu.zhao *
+ ** DATE: 30/04/2013 *
+ ** Copyright: 2013 Spreatrum, Incoporated. All Rights Reserved. *
+ ** Description: *
+ ******************************************************************************/
+/******************************************************************************
+ ** Edit History *
+ **---------------------------------------------------------------------------*
+ ** DATE NAME DESCRIPTION *
+
+ ******************************************************************************/
+#ifndef _SC8830_DISPC_GLB_REG_K_H_
+#define _SC8830_DISPC_GLB_REG_K_H_
+
+#include <linux/kernel.h>
+#include <soc/sprd/sci_glb_regs.h>
+
+#define SPRD_MIPI_DPHY_GEN2
+
+#ifndef CONFIG_OF
+#define DISPC_PLL_CLK ("clk_disc0")
+#define DISPC_DBI_CLK ("clk_disc0_dbi")
+#define DISPC_DPI_CLK ("clk_disc0_dpi")
+#define DISPC_EMC_CLK ("clk_disp_emc")
+#define DISPC_DPI_CLOCK (384*1000000/7)
+
+#define SPRD_DISPC_BASE SPRD_LCDC_BASE
+#define IRQ_DISPC_INT IRQ_DISPC0_INT
+
+#define SPRD_MIPI_DSIC_BASE SPRD_DSI_BASE
+#else
+#define SPRD_MIPI_DSIC_BASE g_dsi_base_addr
+#define SPRD_LCDC_BASE g_dispc_base_addr
+#endif
+
+#define DSI_AHB_SOFT_RST REG_AP_AHB_AHB_RST
+//#define BIT_DSI_SOFT_RST BIT_DSI_SOFT_RST
+//#define BIT_DSI_SOFT_RST ( BIT(0) )
+
+#define DSI_REG_EB REG_AP_AHB_AHB_EB
+#define DSI_BIT_EB BIT_DSI_EB
+
+#ifndef CONFIG_OF
+#define IRQ_DSI_INTN0 IRQ_DSI0_INT
+#define IRQ_DSI_INTN1 IRQ_DSI1_INT
+
+#ifdef CONFIG_ARCH_SCX20
+#define IRQ_DSI_INTN2 IRQ_DSI2_INT
+#endif
+
+#endif
+#define REG_AHB_SOFT_RST (0x4 + SPRD_AHB_BASE)
+#define BIT_DISPC_SOFT_RST BIT_DISPC0_SOFT_RST
+
+#define DISPC_CORE_EN (REG_AP_APB_APB_EB)
+#define BIT_DISPC_CORE_EN (BIT_AP_CKG_EB)
+
+#ifndef CONFIG_OF
+#define DISPC_AHB_EN (REG_AP_AHB_AHB_EB)
+#define BIT_DISPC_AHB_EN (BIT_DISPC0_EB)
+
+#define DISPC_EMC_EN (REG_AON_APB_APB_EB1)
+#define BIT_DISPC_EMC_EN (BIT_DISP_EMC_EB)
+
+#define DISPC_PLL_SEL_CFG REG_AP_CLK_DISPC0_CFG
+#define BITS_DISPC_PLL_SEL_CFG 0
+#define BIT0_DISPC_PLL_SEL_CFG BIT(0)
+#define BIT1_DISPC_PLL_SEL_CFG BIT(1)
+#define BIT_DISPC_PLL_SEL_MSK BIT1_DISPC_PLL_SEL_CFG | BIT0_DISPC_PLL_SEL_CFG
+
+#define DISPC_PLL_DIV_CFG REG_AP_CLK_DISPC0_CFG
+#define BITS_DISPC_PLL_DIV_CFG 8
+#define BIT0_DISPC_PLL_DIV_CFG BIT(8)
+#define BIT1_DISPC_PLL_DIV_CFG BIT(9)
+#define BIT2_DISPC_PLL_DIV_CFG BIT(10)
+#define BIT_DISPC_PLL_DIV_MSK BIT0_DISPC_PLL_DIV_CFG | BIT1_DISPC_PLL_DIV_CFG | BIT2_DISPC_PLL_DIV_CFG
+
+#define DISPC_DBI_SEL_CFG REG_AP_CLK_DISPC0_DBI_CFG
+#define BITS_DISPC_DBI_SEL_CFG 0
+#define BIT0_DISPC_DBI_SEL_CFG BIT(0)
+#define BIT1_DISPC_DBI_SEL_CFG BIT(1)
+#define BIT_DISPC_DBI_SEL_MSK BIT0_DISPC_DBI_SEL_CFG | BIT1_DISPC_DBI_SEL_CFG
+
+#define DISPC_DBI_DIV_CFG REG_AP_CLK_DISPC0_DBI_CFG
+#define BITS_DISPC_DBI_DIV_CFG 8
+#define BIT0_DISPC_DBI_DIV_CFG BIT(8)
+#define BIT1_DISPC_DBI_DIV_CFG BIT(9)
+#define BIT2_DISPC_DBI_DIV_CFG BIT(10)
+#define BIT_DISPC_DBI_DIV_MSK BIT0_DISPC_DBI_DIV_CFG | BIT1_DISPC_DBI_DIV_CFG | BIT2_DISPC_DBI_DIV_CFG
+
+#define DISPC_DPI_SEL_CFG REG_AP_CLK_DISPC0_DPI_CFG
+#define BITS_DISPC_DPI_SEL_CFG 0
+#define BIT0_DISPC_DPI_SEL_CFG BIT(0)
+#define BIT1_DISPC_DPI_SEL_CFG BIT(1)
+#define BIT_DISPC_DPI_SEL_MSK BIT0_DISPC_DPI_SEL_CFG | BIT1_DISPC_DPI_SEL_CFG
+
+#define DISPC_DPI_DIV_CFG REG_AP_CLK_DISPC0_DPI_CFG
+#define BITS_DISPC_DPI_DIV_CFG 8
+#define BIT0_DISPC_DPI_DIV_CFG BIT(8)
+#define BIT1_DISPC_DPI_DIV_CFG BIT(9)
+#define BIT2_DISPC_DPI_DIV_CFG BIT(10)
+#define BIT3_DISPC_DPI_DIV_CFG BIT(11)
+#define BIT4_DISPC_DPI_DIV_CFG BIT(12)
+#define BIT5_DISPC_DPI_DIV_CFG BIT(13)
+#define BIT6_DISPC_DPI_DIV_CFG BIT(14)
+#define BIT7_DISPC_DPI_DIV_CFG BIT(15)
+#define BIT_DISPC_DPI_DIV_MSK BIT0_DISPC_DPI_DIV_CFG | BIT1_DISPC_DPI_DIV_CFG | BIT2_DISPC_DPI_DIV_CFG | BIT3_DISPC_DPI_DIV_CFG \
+ | BIT4_DISPC_DPI_DIV_CFG | BIT5_DISPC_DPI_DIV_CFG | BIT6_DISPC_DPI_DIV_CFG | BIT7_DISPC_DPI_DIV_CFG
+
+
+enum{
+ DISPC_PLL_SEL_96M = 0,
+ DISPC_PLL_SEL_192M,
+ DISPC_PLL_SEL_256M,
+ DISPC_PLL_SEL_312M
+};
+
+enum{
+ DISPC_DBI_SEL_128M = 0,
+ DISPC_DBI_SEL_153_6M,
+ DISPC_DBI_SEL_192M,
+ DISPC_DBI_SEL_256M
+};
+
+enum{
+ DISPC_DPI_SEL_128M = 0,
+ DISPC_DPI_SEL_153_6M,
+ DISPC_DPI_SEL_192M,
+ DISPC_DPI_SEL_384M
+};
+#endif
+
+#endif
diff --git a/drivers/video/sprdfb/sprdfb_chip_9630.c b/drivers/video/sprdfb/sprdfb_chip_9630.c
new file mode 100644
index 00000000..09c9f472
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_chip_9630.c
@@ -0,0 +1,58 @@
+/******************************************************************************
+ ** File Name: sprdfb_chip_9630.c *
+ ** Author: Yang.Haibing Haibing.yang@spreadtrum.com *
+ ** DATE: 2014-05-14 *
+ ** Copyright: 2014 Spreatrum, Incoporated. All Rights Reserved. *
+ ** Description: *
+ ******************************************************************************/
+
+#include "sprdfb_chip_9630.h"
+#include "sprdfb_chip_common.h"
+
+
+void dsi_enable(void)
+{
+ sci_glb_clr(REG_AON_APB_PWR_CTRL, BIT_MIPI_DSI_PS_PD_S);
+ sci_glb_clr(REG_AON_APB_PWR_CTRL, BIT_MIPI_DSI_PS_PD_L);
+ sci_glb_set(REG_AP_AHB_MISC_CKG_EN, BIT_DPHY_REF_CKG_EN);
+ sci_glb_set(REG_AP_AHB_MISC_CKG_EN, BIT_DPHY_CFG_CKG_EN);
+ pr_info("sprdfb: dsi_enable %08x\n", REG_AP_AHB_MISC_CKG_EN);
+ sci_glb_set(DSI_REG_EB, DSI_BIT_EB);
+}
+
+void dsi_disable(void)
+{
+ sci_glb_set(REG_AON_APB_PWR_CTRL, BIT_MIPI_DSI_PS_PD_S);
+ sci_glb_set(REG_AON_APB_PWR_CTRL, BIT_MIPI_DSI_PS_PD_L);
+ sci_glb_clr(REG_AP_AHB_MISC_CKG_EN, BIT_DPHY_REF_CKG_EN);
+ sci_glb_clr(REG_AP_AHB_MISC_CKG_EN, BIT_DPHY_CFG_CKG_EN);
+ sci_glb_clr(DSI_REG_EB, DSI_BIT_EB);
+}
+
+void dsi_print_global_config(void)
+{
+ u32 reg_val0, reg_val1, reg_val2;
+
+ reg_val0 = sci_glb_read(REG_AP_AHB_MISC_CKG_EN, 0xffffffff);
+ reg_val1 = sci_glb_read(DSI_REG_EB, 0xffffffff);
+ reg_val2 = sci_glb_read(REG_AON_APB_PWR_CTRL, 0xffffffff);
+
+ printk("sprdfb: dsi: 0x20E00040 = 0x%x, 0x20E00000 = 0x%x, 0x402E0024 = 0x%x\n",
+ reg_val0, reg_val1, reg_val2);
+}
+
+void dispc_print_clk(void)
+{
+ u32 reg_val0, reg_val1, reg_val2;
+ reg_val0 = dispc_glb_read(SPRD_AONAPB_BASE + 0x4);
+ reg_val1 = dispc_glb_read(SPRD_AHB_BASE);
+ reg_val2 = dispc_glb_read(SPRD_APBREG_BASE);
+ pr_info("sprdfb:0x402e0004 = 0x%x 0x20d00000 = 0x%x 0x71300000 = 0x%x\n",
+ reg_val0, reg_val1, reg_val2);
+
+ reg_val0 = dispc_glb_read(SPRD_APBCKG_BASE + 0x34);
+ reg_val1 = dispc_glb_read(SPRD_APBCKG_BASE + 0x30);
+ reg_val2 = dispc_glb_read(SPRD_APBCKG_BASE + 0x2c);
+ pr_info("sprdfb:0x71200034 = 0x%x 0x71200030 = 0x%x 0x7120002c = 0x%x\n",
+ reg_val0, reg_val1, reg_val2);
+}
diff --git a/drivers/video/sprdfb/sprdfb_chip_9630.h b/drivers/video/sprdfb/sprdfb_chip_9630.h
new file mode 100644
index 00000000..65b07c33
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_chip_9630.h
@@ -0,0 +1,129 @@
+/******************************************************************************
+ ** File Name: sprdfb_chip_9630.h *
+ ** Author: Yang.Haibing Haibing.yang@spreadtrum.com *
+ ** DATE: 2014-05-14 *
+ ** Copyright: 2014 Spreatrum, Incoporated. All Rights Reserved. *
+ ** Description: *
+ ******************************************************************************/
+#ifndef _SC8830_DISPC_GLB_REG_K_H_
+#define _SC8830_DISPC_GLB_REG_K_H_
+
+#include <linux/kernel.h>
+//#include <mach/sci_glb_regs.h>
+#include <soc/sprd/sci_glb_regs.h>
+
+#define SPRD_MIPI_DPHY_GEN2
+
+#ifndef CONFIG_OF
+#define DISPC_PLL_CLK ("clk_disc0")
+#define DISPC_DBI_CLK ("clk_disc0_dbi")
+#define DISPC_DPI_CLK ("clk_disc0_dpi")
+#define DISPC_EMC_CLK ("clk_disp_emc")
+#define DISPC_DPI_CLOCK (384*1000000/7)
+
+#define SPRD_DISPC_BASE SPRD_LCDC_BASE
+#define IRQ_DISPC_INT IRQ_DISPC0_INT
+
+#define SPRD_MIPI_DSIC_BASE SPRD_DSI_BASE
+#else
+#define SPRD_MIPI_DSIC_BASE g_dsi_base_addr
+#define SPRD_LCDC_BASE g_dispc_base_addr
+#endif
+
+#define DSI_AHB_SOFT_RST REG_AP_AHB_AHB_RST
+
+#define DSI_REG_EB REG_AP_AHB_AHB_EB
+#define DSI_BIT_EB BIT_DSI_EB
+
+#ifndef CONFIG_OF
+#define IRQ_DSI_INTN0 IRQ_DSI0_INT
+#define IRQ_DSI_INTN1 IRQ_DSI1_INT
+#define IRQ_DSI_INTN2 IRQ_DSI2_INT
+#endif
+
+#if (!defined CONFIG_ARCH_SCX35L64) && (!defined CONFIG_ARCH_SCX35LT8)
+#define REG_AHB_SOFT_RST (0x4 + SPRD_AHB_BASE)
+#else
+#define REG_AHB_SOFT_RST (0x4 + REGS_AHB_BASE)
+#endif
+
+#define BIT_DISPC_SOFT_RST BIT(1)
+
+#define DISPC_CORE_EN (REG_AP_APB_APB_EB)
+#define BIT_DISPC_CORE_EN (BIT_AP_CKG_EB)
+
+#ifndef CONFIG_OF
+#define DISPC_AHB_EN (REG_AP_AHB_AHB_EB)
+#define BIT_DISPC_AHB_EN (BIT_DISPC0_EB)
+
+#define DISPC_EMC_EN (REG_AON_APB_APB_EB1)
+#define BIT_DISPC_EMC_EN (BIT_DISP_EMC_EB)
+
+#define DISPC_PLL_SEL_CFG REG_AP_CLK_DISPC0_CFG
+#define BITS_DISPC_PLL_SEL_CFG 0
+#define BIT0_DISPC_PLL_SEL_CFG BIT(0)
+#define BIT1_DISPC_PLL_SEL_CFG BIT(1)
+#define BIT_DISPC_PLL_SEL_MSK BIT1_DISPC_PLL_SEL_CFG | BIT0_DISPC_PLL_SEL_CFG
+
+#define DISPC_PLL_DIV_CFG REG_AP_CLK_DISPC0_CFG
+#define BITS_DISPC_PLL_DIV_CFG 8
+#define BIT0_DISPC_PLL_DIV_CFG BIT(8)
+#define BIT1_DISPC_PLL_DIV_CFG BIT(9)
+#define BIT2_DISPC_PLL_DIV_CFG BIT(10)
+#define BIT_DISPC_PLL_DIV_MSK BIT0_DISPC_PLL_DIV_CFG | BIT1_DISPC_PLL_DIV_CFG | BIT2_DISPC_PLL_DIV_CFG
+
+#define DISPC_DBI_SEL_CFG REG_AP_CLK_DISPC0_DBI_CFG
+#define BITS_DISPC_DBI_SEL_CFG 0
+#define BIT0_DISPC_DBI_SEL_CFG BIT(0)
+#define BIT1_DISPC_DBI_SEL_CFG BIT(1)
+#define BIT_DISPC_DBI_SEL_MSK BIT0_DISPC_DBI_SEL_CFG | BIT1_DISPC_DBI_SEL_CFG
+
+#define DISPC_DBI_DIV_CFG REG_AP_CLK_DISPC0_DBI_CFG
+#define BITS_DISPC_DBI_DIV_CFG 8
+#define BIT0_DISPC_DBI_DIV_CFG BIT(8)
+#define BIT1_DISPC_DBI_DIV_CFG BIT(9)
+#define BIT2_DISPC_DBI_DIV_CFG BIT(10)
+#define BIT_DISPC_DBI_DIV_MSK BIT0_DISPC_DBI_DIV_CFG | BIT1_DISPC_DBI_DIV_CFG | BIT2_DISPC_DBI_DIV_CFG
+
+#define DISPC_DPI_SEL_CFG REG_AP_CLK_DISPC0_DPI_CFG
+#define BITS_DISPC_DPI_SEL_CFG 0
+#define BIT0_DISPC_DPI_SEL_CFG BIT(0)
+#define BIT1_DISPC_DPI_SEL_CFG BIT(1)
+#define BIT_DISPC_DPI_SEL_MSK BIT0_DISPC_DPI_SEL_CFG | BIT1_DISPC_DPI_SEL_CFG
+
+#define DISPC_DPI_DIV_CFG REG_AP_CLK_DISPC0_DPI_CFG
+#define BITS_DISPC_DPI_DIV_CFG 8
+#define BIT0_DISPC_DPI_DIV_CFG BIT(8)
+#define BIT1_DISPC_DPI_DIV_CFG BIT(9)
+#define BIT2_DISPC_DPI_DIV_CFG BIT(10)
+#define BIT3_DISPC_DPI_DIV_CFG BIT(11)
+#define BIT4_DISPC_DPI_DIV_CFG BIT(12)
+#define BIT5_DISPC_DPI_DIV_CFG BIT(13)
+#define BIT6_DISPC_DPI_DIV_CFG BIT(14)
+#define BIT7_DISPC_DPI_DIV_CFG BIT(15)
+#define BIT_DISPC_DPI_DIV_MSK BIT0_DISPC_DPI_DIV_CFG | BIT1_DISPC_DPI_DIV_CFG | BIT2_DISPC_DPI_DIV_CFG | BIT3_DISPC_DPI_DIV_CFG \
+ | BIT4_DISPC_DPI_DIV_CFG | BIT5_DISPC_DPI_DIV_CFG | BIT6_DISPC_DPI_DIV_CFG | BIT7_DISPC_DPI_DIV_CFG
+
+enum {
+ DISPC_PLL_SEL_96M = 0,
+ DISPC_PLL_SEL_192M,
+ DISPC_PLL_SEL_256M,
+ DISPC_PLL_SEL_312M
+};
+
+enum {
+ DISPC_DBI_SEL_128M = 0,
+ DISPC_DBI_SEL_153_6M,
+ DISPC_DBI_SEL_192M,
+ DISPC_DBI_SEL_256M
+};
+
+enum {
+ DISPC_DPI_SEL_128M = 0,
+ DISPC_DPI_SEL_153_6M,
+ DISPC_DPI_SEL_192M,
+ DISPC_DPI_SEL_384M
+};
+
+#endif
+#endif
diff --git a/drivers/video/sprdfb/sprdfb_chip_common.c b/drivers/video/sprdfb/sprdfb_chip_common.c
new file mode 100644
index 00000000..46d42f00
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_chip_common.c
@@ -0,0 +1,23 @@
+/******************************************************************************
+ ** File Name: sprdfb_chip_common.c *
+ ** Author: congfu.zhao *
+ ** DATE: 30/04/2013 *
+ ** Copyright: 2013 Spreatrum, Incoporated. All Rights Reserved. *
+ ** Description: *
+ ******************************************************************************/
+/******************************************************************************
+ ** Edit History *
+ **---------------------------------------------------------------------------*
+ ** DATE NAME DESCRIPTION *
+
+ ******************************************************************************/
+
+
+#include <linux/kernel.h>
+#include "sprdfb_chip_common.h"
+
+u32 dispc_glb_read(unsigned long reg)
+{
+ return sci_glb_read(reg, 0xffffffff);
+}
+
diff --git a/drivers/video/sprdfb/sprdfb_chip_common.h b/drivers/video/sprdfb/sprdfb_chip_common.h
new file mode 100644
index 00000000..8ff391c8
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_chip_common.h
@@ -0,0 +1,58 @@
+/******************************************************************************
+ ** File Name: sprdfb_chip_common.h *
+ ** Author: congfu.zhao *
+ ** DATE: 30/04/2013 *
+ ** Copyright: 2013 Spreatrum, Incoporated. All Rights Reserved. *
+ ** Description: *
+ ******************************************************************************/
+/******************************************************************************
+ ** Edit History *
+ **---------------------------------------------------------------------------*
+ ** DATE NAME DESCRIPTION *
+
+ ******************************************************************************/
+#ifndef __DISPC_CHIP_COM_H_
+#define __DISPC_CHIP_COM_H_
+
+#ifdef CONFIG_64BIT
+#include <soc/sprd/sci_glb_regs.h>
+#include <soc/sprd/sci.h>
+#else
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/globalregs.h>
+#include <mach/irqs.h>
+#include <soc/sprd/sci.h>
+#include <soc/sprd/sci_glb_regs.h>
+#endif
+#include <linux/io.h>
+
+#if defined(CONFIG_FB_SCX35L)
+#include "sprdfb_chip_9630.h"
+#define SPRDFB_SUPPORT_LVDS_PANEL
+#elif defined(CONFIG_FB_SCX35) || defined(CONFIG_FB_SCX30G)
+#include "sprdfb_chip_8830.h"
+#elif defined(CONFIG_FB_SCX15)
+#include "sprdfb_chip_7715.h"
+#else
+#error "Unknown architecture specification"
+#endif
+
+
+//void __raw_bits_set_value(unsigned int reg, unsigned int value, unsigned int bit, unsigned int mask);
+
+void dispc_pll_clk_set(unsigned int clk_src, unsigned int clk_div);
+
+void dispc_dbi_clk_set(unsigned int clk_src, unsigned int clk_div);
+
+void dispc_dpi_clk_set(unsigned int clk_src, unsigned int clk_div);
+
+void dsi_enable(void);
+void dsi_disable(void);
+
+u32 dispc_glb_read(unsigned long reg);
+
+void dispc_print_clk(void);
+//void dsi_print_global_config(void);
+
+
+#endif
diff --git a/drivers/video/sprdfb/sprdfb_dispc.c b/drivers/video/sprdfb/sprdfb_dispc.c
new file mode 100644
index 00000000..b50dfd89
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_dispc.c
@@ -0,0 +1,2446 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#define pr_fmt(fmt) "sprdfb: " fmt
+
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#if (defined(CONFIG_SPRD_SCXX30_DMC_FREQ) || defined(CONFIG_SPRD_SCX35_DMC_FREQ))
+#include <linux/devfreq.h>
+#endif
+#include <linux/irqreturn.h>
+#include <linux/interrupt.h>
+#ifdef CONFIG_OF
+#include <linux/of_irq.h>
+#endif
+#include <asm/cacheflush.h>
+#include "sprdfb_dispc_reg.h"
+#include "sprdfb_panel.h"
+#include "sprdfb.h"
+#include "sprdfb_chip_common.h"
+#ifdef CONFIG_CPU_IDLE
+#include <soc/sprd/cpuidle.h>
+#endif
+#include <linux/dma-mapping.h>
+
+//#define SHARK_LAYER_COLOR_SWITCH_FEATURE // bug212892
+
+#ifndef CONFIG_OF
+#ifdef CONFIG_FB_SCX15
+#define DISPC_CLOCK_PARENT ("clk_192m")
+#define DISPC_CLOCK (192*1000000)
+#define DISPC_DBI_CLOCK_PARENT ("clk_256m")
+#define DISPC_DBI_CLOCK (256*1000000)
+#define DISPC_DPI_CLOCK_PARENT ("clk_384m")
+#define SPRDFB_DPI_CLOCK_SRC (384000000)
+#else
+#define DISPC_CLOCK_PARENT ("clk_256m")
+#define DISPC_CLOCK (256*1000000)
+#define DISPC_DBI_CLOCK_PARENT ("clk_256m")
+#define DISPC_DBI_CLOCK (256*1000000)
+#define DISPC_DPI_CLOCK_PARENT ("clk_384m")
+#define SPRDFB_DPI_CLOCK_SRC (384000000)
+#endif
+#define DISPC_EMC_EN_PARENT ("clk_aon_apb")
+#else
+#define DISPC_CLOCK_PARENT ("dispc_clk_parent")
+//#define DISPC_CLOCK (192*1000000)
+#define DISPC_DBI_CLOCK_PARENT ("dispc_dbi_clk_parent")
+//#define DISPC_DBI_CLOCK (256*1000000)
+#define DISPC_DPI_CLOCK_PARENT ("dispc_dpi_clk_parent")
+//#define SPRDFB_DPI_CLOCK_SRC (192000000)
+#define DISPC_EMC_EN_PARENT ("dispc_emc_clk_parent")
+#define DISPC_PLL_CLK ("dispc_clk")
+#define DISPC_DBI_CLK ("dispc_dbi_clk")
+#define DISPC_DPI_CLK ("dispc_dpi_clk")
+#define DISPC_EMC_CLK ("dispc_emc_clk")
+
+#define DISPC_CLOCK_SRC_ID 0
+#define DISPC_DBI_CLOCK_SRC_ID 1
+#define DISPC_DPI_CLOCK_SRC_ID 2
+
+#define DISPC_CLOCK_NUM 3
+#endif
+
+#if (defined CONFIG_FB_SCX35L)
+
+#define SPRDFB_BRIGHTNESS (0x00<<16)//(0x03<<16)// 9-bits
+#define SPRDFB_CONTRAST (0x100<<0) //10-bits
+#define SPRDFB_OFFSET_U (0x81<<16)//8-bits
+#define SPRDFB_SATURATION_U (0x100<<0)//(0x12A<<0)//10-bits
+#define SPRDFB_OFFSET_V (0x82<<16)//8-bits
+#define SPRDFB_SATURATION_V (0x100<<0)//(0x12A<<0)//10-bits
+
+#elif ((defined CONFIG_FB_SCX15) || (defined CONFIG_FB_SCX30G))
+#define SPRDFB_BRIGHTNESS (0x02<<16)//(0x03<<16)// 9-bits
+#define SPRDFB_CONTRAST (0x12A<<0) //10-bits
+#define SPRDFB_OFFSET_U (0x81<<16)//8-bits
+#define SPRDFB_SATURATION_U (0x123<<0)//(0x12A<<0)//10-bits
+#define SPRDFB_OFFSET_V (0x82<<16)//8-bits
+#define SPRDFB_SATURATION_V (0x123<<0)//(0x12A<<0)//10-bits
+#else
+#define SPRDFB_CONTRAST (74)
+#define SPRDFB_SATURATION (73)
+#define SPRDFB_BRIGHTNESS (2)
+#endif
+
+typedef enum
+{
+ SPRDFB_DYNAMIC_CLK_FORCE, //force enable/disable
+ SPRDFB_DYNAMIC_CLK_REFRESH, //enable for refresh/display_overlay
+ SPRDFB_DYNAMIC_CLK_COUNT, //enable disable in pairs
+ SPRDFB_DYNAMIC_CLK_MAX,
+} SPRDFB_DYNAMIC_CLK_SWITCH_E;
+
+struct sprdfb_dispc_context {
+ struct clk *clk_dispc;
+ struct clk *clk_dispc_dpi;
+ struct clk *clk_dispc_dbi;
+ struct clk *clk_dispc_emc;
+ bool is_inited;
+ bool is_first_frame;
+ bool clk_is_open;
+ bool clk_is_refreshing;
+ int clk_open_count;
+ //spinlock_t clk_spinlock;
+ struct semaphore clk_sem;
+ struct sprdfb_device *dev;
+
+ uint32_t vsync_waiter;
+ wait_queue_head_t vsync_queue;
+ uint32_t vsync_done;
+
+#ifdef CONFIG_FB_LCD_OVERLAY_SUPPORT
+ /* overlay */
+ uint32_t overlay_state; /*0-closed, 1-configed, 2-started*/
+// struct semaphore overlay_lock;
+#endif
+
+#ifdef CONFIG_FB_VSYNC_SUPPORT
+ uint32_t waitfor_vsync_waiter;
+ wait_queue_head_t waitfor_vsync_queue;
+ uint32_t waitfor_vsync_done;
+#endif
+#ifdef CONFIG_FB_MMAP_CACHED
+ struct vm_area_struct *vma;
+#endif
+};
+
+static struct sprdfb_dispc_context dispc_ctx = {0};
+#ifdef CONFIG_OF
+unsigned long g_dispc_base_addr = 0;
+EXPORT_SYMBOL(g_dispc_base_addr);
+#endif
+
+extern void sprdfb_panel_suspend(struct sprdfb_device *dev);
+extern void sprdfb_panel_resume(struct sprdfb_device *dev, bool from_deep_sleep);
+extern void sprdfb_panel_before_refresh(struct sprdfb_device *dev);
+extern void sprdfb_panel_after_refresh(struct sprdfb_device *dev);
+extern void sprdfb_panel_invalidate(struct panel_spec *self);
+extern void sprdfb_panel_invalidate_rect(struct panel_spec *self,
+ uint16_t left, uint16_t top,
+ uint16_t right, uint16_t bottom);
+
+#ifdef CONFIG_FB_ESD_SUPPORT
+extern uint32_t sprdfb_panel_ESD_check(struct sprdfb_device *dev);
+#endif
+
+#ifdef CONFIG_FB_LCD_OVERLAY_SUPPORT
+static int overlay_start(struct sprdfb_device *dev, uint32_t layer_index);
+static int overlay_close(struct sprdfb_device *dev);
+#endif
+
+static int sprdfb_dispc_clk_disable(struct sprdfb_dispc_context *dispc_ctx_ptr, SPRDFB_DYNAMIC_CLK_SWITCH_E clock_switch_type);
+static int sprdfb_dispc_clk_enable(struct sprdfb_dispc_context *dispc_ctx_ptr, SPRDFB_DYNAMIC_CLK_SWITCH_E clock_switch_type);
+static int32_t sprdfb_dispc_init(struct sprdfb_device *dev);
+static void dispc_reset(void);
+static void dispc_stop(struct sprdfb_device *dev);
+static void dispc_module_enable(void);
+//#if (defined(CONFIG_FB_DYNAMIC_FREQ_SCALING) || !defined(FB_CHECK_ESD_IN_VFP))
+static void dispc_stop_for_feature(struct sprdfb_device *dev);
+static void dispc_run_for_feature(struct sprdfb_device *dev);
+#if (defined(CONFIG_SPRD_SCXX30_DMC_FREQ) || defined(CONFIG_SPRD_SCX35_DMC_FREQ))
+static unsigned int sprdfb_dispc_change_threshold(struct devfreq_dbs *h, unsigned int state);
+static unsigned int sprdfb_dispc_threshold_check(void);
+#endif
+
+static int dispc_update_clk(struct sprdfb_device *fb_dev,
+ u32 new_val, int howto);
+
+/**
+ * author: Yang.Haibing haibing.yang@spreadtrum.com
+ *
+ * dispc_check_new_clk - check and convert new clock to the value that can be set
+ * @fb_dev: spreadtrum specific fb device
+ * @new_pclk: actual settable clock via calculating new_val and fps
+ * @pclk_src: clock source of dpi clock
+ * @new_val: expected clock
+ * @type: check the type is fps or pclk
+ *
+ * Returns 0 on success, MINUS on error.
+ */
+static int dispc_check_new_clk(struct sprdfb_device *fb_dev,
+ u32 *new_pclk, u32 pclk_src,
+ u32 new_val, int type)
+{
+ int divider;
+ u32 hpixels, vlines, pclk, fps;
+ struct panel_spec* panel = fb_dev->panel;
+ struct info_mipi * mipi;
+ struct info_rgb* rgb;
+
+ pr_debug("%s: enter\n", __func__);
+ if(!panel){
+ pr_err("No panel is specified!\n");
+ return -ENXIO;
+ }
+
+ mipi = panel->info.mipi;
+ rgb = panel->info.rgb;
+
+ if (fb_dev->panel_if_type != SPRDFB_PANEL_IF_DPI) {
+ pr_err("panel interface should be DPI\n");
+ return -EINVAL;
+ }
+ if (new_val <= 0 || !new_pclk) {
+ pr_err("new parameter is invalid\n");
+ return -EINVAL;
+ }
+
+ if (fb_dev->panel->type == LCD_MODE_DSI) {
+ hpixels = panel->width + mipi->timing->hsync +
+ mipi->timing->hbp + mipi->timing->hfp;
+ vlines = panel->height + mipi->timing->vsync +
+ mipi->timing->vbp + mipi->timing->vfp;
+ } else if(fb_dev->panel->type == LCD_MODE_RGB ||
+ fb_dev->panel->type == LCD_MODE_LVDS) {
+ hpixels = panel->width + rgb->timing->hsync +
+ rgb->timing->hbp + rgb->timing->hfp;
+ vlines = panel->height + rgb->timing->vsync +
+ rgb->timing->vbp + rgb->timing->vfp;
+ } else {
+ pr_err("[%s] unexpected panel type (%d)\n",
+ __func__, fb_dev->panel->type);
+ return -EINVAL;
+ }
+
+ switch (type) {
+ /*
+ * FIXME: TODO: SPRDFB_FORCE_FPS will be used for accurate fps someday.
+ * But now it is the same as SPRDFB_DYNAMIC_FPS.
+ */
+ case SPRDFB_FORCE_FPS:
+ case SPRDFB_DYNAMIC_FPS:
+ if (new_val < LCD_MIN_FPS || new_val > LCD_MAX_FPS) {
+ pr_err("Unsupported FPS. fps range should be [%d, %d]\n",
+ LCD_MIN_FPS, LCD_MAX_FPS);
+ return -EINVAL;
+ }
+ pclk = hpixels * vlines * new_val;
+ divider = ROUND(pclk_src, pclk);
+ *new_pclk = pclk_src / divider;
+ /* Save the updated fps */
+ panel->fps = new_val;
+ break;
+
+ case SPRDFB_DYNAMIC_PCLK:
+ divider = ROUND(pclk_src, new_val);
+ pclk = pclk_src / divider;
+ fps = pclk / ( hpixels * vlines);
+ if (fps < LCD_MIN_FPS || fps > LCD_MAX_FPS) {
+ pr_err("Unsupported FPS. fps range should be [%d, %d]\n",
+ LCD_MIN_FPS, LCD_MAX_FPS);
+ return -EINVAL;
+ }
+ *new_pclk = pclk;
+ /* Save the updated fps */
+ panel->fps = fps;
+ break;
+
+ default:
+ pr_err("This checked type is unsupported.\n");
+ *new_pclk = 0;
+ return -EINVAL;
+ }
+ return 0;
+}
+
+void dispc_irq_trick(struct sprdfb_device *dev)
+{
+ if(NULL == dev){
+ return;
+ }
+
+ if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){
+ dispc_set_bits(DISPC_INT_ERR_MASK, DISPC_INT_EN);
+ }
+}
+
+extern void dsi_irq_trick(void);
+
+//static uint32_t underflow_ever_happened = 0;
+static irqreturn_t dispc_isr(int irq, void *data)
+{
+ struct sprdfb_dispc_context *dispc_ctx = (struct sprdfb_dispc_context *)data;
+ uint32_t reg_val;
+ struct sprdfb_device *dev = dispc_ctx->dev;
+ bool done = false;
+#ifdef CONFIG_FB_VSYNC_SUPPORT
+ bool vsync = false;
+#endif
+
+ reg_val = dispc_read(DISPC_INT_STATUS);
+
+ pr_debug("sprdfb: dispc_isr (0x%x)\n",reg_val );
+ //printk("%s%d: underflow_ever_happened:0x%08x \n",__func__,__LINE__,underflow_ever_happened);
+ //dispc_irq_trick_in(reg_val);
+
+ if(reg_val & DISPC_INT_ERR_MASK){
+ printk("sprdfb: Warning: dispc underflow (0x%x)!\n",reg_val);
+ //underflow_ever_happened++;
+ dispc_write(DISPC_INT_ERR_MASK, DISPC_INT_CLR);
+ /*disable err interupt*/
+ dispc_clear_bits(DISPC_INT_ERR_MASK, DISPC_INT_EN);
+ }
+
+ if(NULL == dev){
+ return IRQ_HANDLED;
+ }
+
+ if((reg_val & 0x10) && (SPRDFB_PANEL_IF_DPI == dev->panel_if_type)){/*dispc update done isr*/
+#if 0
+ if(dispc_ctx->is_first_frame){
+ /*dpi register update with SW and VSync*/
+ dispc_clear_bits(BIT(4), DISPC_DPI_CTRL);
+
+ /* start refresh */
+ dispc_set_bits((1 << 4), DISPC_CTRL);
+
+ dispc_ctx->is_first_frame = false;
+ }
+#endif
+ dispc_write(DISPC_INT_UPDATE_DONE_MASK, DISPC_INT_CLR);
+ done = true;
+ }else if ((reg_val & DISPC_INT_DONE_MASK) && (SPRDFB_PANEL_IF_DPI != dev->panel_if_type)){ /* dispc done isr */
+ dispc_write(DISPC_INT_DONE_MASK, DISPC_INT_CLR);
+ dispc_ctx->is_first_frame = false;
+ done = true;
+ }
+#ifdef CONFIG_FB_ESD_SUPPORT
+#ifdef FB_CHECK_ESD_BY_TE_SUPPORT
+ if((reg_val & DISPC_INT_TE_MASK) && (SPRDFB_PANEL_IF_DPI == dev->panel_if_type)){ /*dispc external TE isr*/
+ dispc_write(DISPC_INT_TE_MASK, DISPC_INT_CLR);
+ if(0 != dev->esd_te_waiter){
+ printk("sprdfb: dispc_isr esd_te_done!");
+ dev->esd_te_done =1;
+ wake_up_interruptible_all(&(dev->esd_te_queue));
+ dev->esd_te_waiter = 0;
+ }
+ }
+#endif
+#endif
+
+#ifdef CONFIG_FB_VSYNC_SUPPORT
+ if((reg_val & DISPC_INT_HWVSYNC) && (SPRDFB_PANEL_IF_DPI == dev->panel_if_type)){/*dispc done isr*/
+ dispc_write(DISPC_INT_HWVSYNC, DISPC_INT_CLR);
+ vsync = true;
+ }else if((reg_val & DISPC_INT_TE_MASK) && (SPRDFB_PANEL_IF_EDPI == dev->panel_if_type)){ /*dispc te isr*/
+ dispc_write(DISPC_INT_TE_MASK, DISPC_INT_CLR);
+ vsync = true;
+ }
+ if(vsync){
+ //printk("sprdfb: got vsync!\n");
+ dispc_ctx->waitfor_vsync_done = 1;
+ if(dispc_ctx->waitfor_vsync_waiter){
+ //printk("sprdfb: wake!\n");
+ wake_up_interruptible_all(&(dispc_ctx->waitfor_vsync_queue));
+ }
+ }
+#endif
+
+ if(done){
+ dispc_ctx->vsync_done = 1;
+
+#ifdef CONFIG_FB_DYNAMIC_CLK_SUPPORT
+ if(SPRDFB_PANEL_IF_DPI != dev->panel_if_type){
+ sprdfb_dispc_clk_disable(dispc_ctx,SPRDFB_DYNAMIC_CLK_REFRESH);
+ }
+#endif
+
+ if (dispc_ctx->vsync_waiter) {
+ wake_up_interruptible_all(&(dispc_ctx->vsync_queue));
+ dispc_ctx->vsync_waiter = 0;
+ }
+ sprdfb_panel_after_refresh(dev);
+ pr_debug(KERN_INFO "sprdfb: [%s]: Done INT, reg_val = %d !\n", __FUNCTION__, reg_val);
+ }
+
+ return IRQ_HANDLED;
+}
+
+
+/* dispc soft reset */
+static void dispc_reset(void)
+{
+ sci_glb_set(REG_AHB_SOFT_RST, (BIT_DISPC_SOFT_RST) );
+ udelay(10);
+ sci_glb_clr(REG_AHB_SOFT_RST, (BIT_DISPC_SOFT_RST) );
+}
+
+static inline void dispc_set_bg_color(uint32_t bg_color)
+{
+ dispc_write(bg_color, DISPC_BG_COLOR);
+}
+
+static inline void dispc_set_osd_ck(uint32_t ck_color)
+{
+ dispc_write(ck_color, DISPC_OSD_CK);
+}
+
+static inline void dispc_osd_enable(bool is_enable)
+{
+ uint32_t reg_val;
+
+ reg_val = dispc_read(DISPC_OSD_CTRL);
+ if(is_enable){
+ reg_val = reg_val | (BIT(0));
+ }
+ else{
+ reg_val = reg_val & (~(BIT(0)));
+ }
+ dispc_write(reg_val, DISPC_OSD_CTRL);
+}
+
+static inline void dispc_set_osd_alpha(uint8_t alpha)
+{
+ dispc_write(alpha, DISPC_OSD_ALPHA);
+}
+
+static void dispc_dithering_enable(bool enable)
+{
+ if(enable){
+ dispc_set_bits(BIT(6), DISPC_CTRL);
+ }else{
+ dispc_clear_bits(BIT(6), DISPC_CTRL);
+ }
+}
+
+static void dispc_pwr_enable(bool enable)
+{
+ if(enable){
+ dispc_set_bits(BIT(7), DISPC_CTRL);
+ }else{
+ dispc_clear_bits(BIT(7), DISPC_CTRL);
+ }
+}
+
+static void dispc_set_exp_mode(uint16_t exp_mode)
+{
+ uint32_t reg_val = dispc_read(DISPC_CTRL);
+
+ reg_val &= ~(0x3 << 16);
+ reg_val |= (exp_mode << 16);
+ dispc_write(reg_val, DISPC_CTRL);
+}
+
+/*
+ * thres0: module fetch data when buffer depth <= thres0
+ * thres1: module release busy and close AXI clock
+ * thres2: module open AXI clock and prepare to fetch data
+ */
+static void dispc_set_threshold(uint16_t thres0, uint16_t thres1, uint16_t thres2)
+{
+ dispc_write((thres0)|(thres1<<14)|(thres2<<16), DISPC_BUF_THRES);
+}
+
+static void dispc_module_enable(void)
+{
+ /*dispc module enable */
+ dispc_write((1<<0), DISPC_CTRL);
+
+ /*disable dispc INT*/
+ dispc_write(0x0, DISPC_INT_EN);
+
+ /* clear dispc INT */
+ dispc_write(0x3F, DISPC_INT_CLR);
+}
+
+static inline int32_t dispc_set_disp_size(struct fb_var_screeninfo *var)
+{
+ uint32_t reg_val;
+
+ reg_val = (var->xres & 0xfff) | ((var->yres & 0xfff ) << 16);
+ dispc_write(reg_val, DISPC_SIZE_XY);
+
+ return 0;
+}
+
+static void dispc_layer_init(struct fb_var_screeninfo *var)
+{
+ uint32_t reg_val = 0;
+
+// dispc_clear_bits((1<<0),DISPC_IMG_CTRL);
+ dispc_write(0x0, DISPC_IMG_CTRL);
+ dispc_clear_bits((1<<0),DISPC_OSD_CTRL);
+
+ /******************* OSD layer setting **********************/
+
+ /*enable OSD layer*/
+ reg_val |= (1 << 0);
+
+ /*disable color key */
+
+ /* alpha mode select - block alpha*/
+ reg_val |= (1 << 2);
+
+ /* data format */
+ if (var->bits_per_pixel == 32) {
+ /* ABGR */
+ reg_val |= (3 << 4);
+ /* rb switch */
+ reg_val |= (1 << 15);
+ } else {
+ /* RGB565 */
+ reg_val |= (5 << 4);
+ /* B2B3B0B1 */
+ reg_val |= (2 << 8);
+ }
+
+ dispc_write(reg_val, DISPC_OSD_CTRL);
+
+ /* OSD layer alpha value */
+ dispc_set_osd_alpha(0xff);
+
+ /* OSD layer size */
+ reg_val = ( var->xres & 0xfff) | (( var->yres & 0xfff ) << 16);
+ dispc_write(reg_val, DISPC_OSD_SIZE_XY);
+
+ /* OSD layer start position */
+ dispc_write(0, DISPC_OSD_DISP_XY);
+
+ /* OSD layer pitch */
+ reg_val = ( var->xres & 0xfff) ;
+ dispc_write(reg_val, DISPC_OSD_PITCH);
+
+ /* OSD color_key value */
+ dispc_set_osd_ck(0x0);
+}
+
+static void dispc_layer_update(struct fb_var_screeninfo *var)
+{
+ uint32_t reg_val = 0;
+
+ /******************* OSD layer setting **********************/
+
+ /*enable OSD layer*/
+ reg_val |= (1 << 0);
+
+ /*disable color key */
+
+ /* alpha mode select - block alpha*/
+ reg_val |= (1 << 2);
+
+ /* data format */
+ if (var->bits_per_pixel == 32) {
+ /* ABGR */
+ reg_val |= (3 << 4);
+ /* rb switch */
+ reg_val |= (1 << 15);
+ } else {
+ /* RGB565 */
+ reg_val |= (5 << 4);
+ /* B2B3B0B1 */
+ reg_val |= (2 << 8);
+ }
+
+ dispc_write(reg_val, DISPC_OSD_CTRL);
+}
+
+static int32_t dispc_sync(struct sprdfb_device *dev)
+{
+ int ret;
+
+ if (dev->enable == 0) {
+ printk("sprdfb: dispc_sync fb suspeneded already!!\n");
+ return -1;
+ }
+
+#ifdef CONFIG_SC_FPGA
+ ret = wait_event_interruptible_timeout(dispc_ctx.vsync_queue,
+ dispc_ctx.vsync_done, msecs_to_jiffies(500));
+#else
+ ret = wait_event_interruptible_timeout(dispc_ctx.vsync_queue,
+ dispc_ctx.vsync_done, msecs_to_jiffies(100));
+#endif
+
+ if (!ret) { /* time out */
+ dispc_ctx.vsync_done = 1; /*error recovery */
+ printk(KERN_ERR "sprdfb: dispc_sync time out!!!!!\n");
+ {/*for debug*/
+ int32_t i = 0;
+ for(i=0;i<256;i+=16){
+ printk("sprdfb: %x: 0x%x, 0x%x, 0x%x, 0x%x\n", i, dispc_read(i), dispc_read(i+4), dispc_read(i+8), dispc_read(i+12));
+ }
+ printk("**************************************\n");
+ }
+
+ return -1;
+ }
+ return 0;
+}
+
+
+static void dispc_run(struct sprdfb_device *dev)
+{
+ if(0 == dev->enable){
+ return;
+ }
+
+ if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){
+ if(!dispc_ctx.is_first_frame){
+ dispc_ctx.vsync_done = 0;
+ dispc_ctx.vsync_waiter ++;
+ }
+ /*dpi register update*/
+ dispc_set_bits(BIT(5), DISPC_DPI_CTRL);
+ udelay(30);
+
+ if(dispc_ctx.is_first_frame){
+ /*dpi register update with SW and VSync*/
+ dispc_clear_bits(BIT(4), DISPC_DPI_CTRL);
+
+ /* start refresh */
+ dispc_set_bits((1 << 4), DISPC_CTRL);
+
+ dispc_ctx.is_first_frame = false;
+ } else {
+#ifndef CONFIG_FB_TRIPLE_FRAMEBUFFER
+ dispc_sync(dev);
+#else
+#ifdef CONFIG_FB_LCD_OVERLAY_SUPPORT
+ if(SPRD_OVERLAY_STATUS_STARTED == dispc_ctx.overlay_state){
+ dispc_sync(dev);
+ }
+#endif
+#endif
+ }
+ }else{
+ dispc_ctx.vsync_done = 0;
+ /* start refresh */
+ dispc_set_bits((1 << 4), DISPC_CTRL);
+ }
+ dispc_irq_trick(dev);
+ //dispc_irq_trick_out();
+
+#if !defined(CONFIG_FB_SCX15) && !defined(CONFIG_SC_FPGA)
+ //dsi_irq_trick(0,0);
+ dsi_irq_trick();
+#endif
+}
+
+static void dispc_stop(struct sprdfb_device *dev)
+{
+ if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){
+ /*dpi register update with SW only*/
+ dispc_set_bits(BIT(4), DISPC_DPI_CTRL);
+
+ /* stop refresh */
+ dispc_clear_bits((1 << 4), DISPC_CTRL);
+
+ dispc_ctx.is_first_frame = true;
+ }
+}
+
+static int32_t sprdfb_dispc_uninit(struct sprdfb_device *dev)
+{
+ pr_debug(KERN_INFO "sprdfb: [%s]\n",__FUNCTION__);
+
+ dev->enable = 0;
+ sprdfb_dispc_clk_disable(&dispc_ctx,SPRDFB_DYNAMIC_CLK_FORCE);
+
+ return 0;
+}
+
+static int32_t dispc_clk_init(struct sprdfb_device *dev)
+{
+ int ret = 0;
+ u32 dpi_clk;
+ struct clk *clk_parent1, *clk_parent2, *clk_parent3, *clk_parent4;
+#ifdef CONFIG_OF
+ uint32_t clk_src[DISPC_CLOCK_NUM];
+ uint32_t def_dpi_clk_div = 1;
+#endif
+
+ pr_debug(KERN_INFO "sprdfb: [%s]\n", __FUNCTION__);
+
+ sci_glb_set(DISPC_CORE_EN, BIT_DISPC_CORE_EN);
+// sci_glb_set(DISPC_EMC_EN, BIT_DISPC_EMC_EN);
+
+#ifdef CONFIG_OF
+ ret = of_property_read_u32_array(dev->of_dev->of_node, "clock-src", clk_src, 3);
+ if(0 != ret){
+ printk("sprdfb: read clock-src fail (%d)\n", ret);
+ return -1;
+ }
+
+ ret = of_property_read_u32(dev->of_dev->of_node, "dpi_clk_div", &def_dpi_clk_div);
+ if(0 != ret){
+ printk("sprdfb: read dpi_clk_div fail (%d)\n", ret);
+ return -1;
+ }
+ clk_parent1 = of_clk_get_by_name(dev->of_dev->of_node, DISPC_CLOCK_PARENT);
+ dpi_clk = clk_src[DISPC_DPI_CLOCK_SRC_ID]/def_dpi_clk_div;
+#else
+ dpi_clk = DISPC_DPI_CLOCK;
+ clk_parent1 = clk_get(NULL, DISPC_CLOCK_PARENT);
+#endif
+ if (IS_ERR(clk_parent1)) {
+ printk(KERN_WARNING "sprdfb: get clk_parent1 fail!\n");
+ return -1;
+ } else {
+ pr_debug(KERN_INFO "sprdfb: get clk_parent1 ok!\n");
+ }
+
+#ifdef CONFIG_OF
+ clk_parent2 = of_clk_get_by_name(dev->of_dev->of_node, DISPC_DBI_CLOCK_PARENT);
+#else
+ clk_parent2 = clk_get(NULL, DISPC_DBI_CLOCK_PARENT);
+#endif
+ if (IS_ERR(clk_parent2)) {
+ printk(KERN_WARNING "sprdfb: get clk_parent2 fail!\n");
+ return -1;
+ } else {
+ pr_debug(KERN_INFO "sprdfb: get clk_parent2 ok!\n");
+ }
+
+#ifdef CONFIG_OF
+ clk_parent3 = of_clk_get_by_name(dev->of_dev->of_node, DISPC_DPI_CLOCK_PARENT);
+#else
+ clk_parent3 = clk_get(NULL, DISPC_DPI_CLOCK_PARENT);
+#endif
+ if (IS_ERR(clk_parent3)) {
+ printk(KERN_WARNING "sprdfb: get clk_parent3 fail!\n");
+ return -1;
+ } else {
+ pr_debug(KERN_INFO "sprdfb: get clk_parent3 ok!\n");
+ }
+
+#ifdef CONFIG_OF
+ clk_parent4 = of_clk_get_by_name(dev->of_dev->of_node, DISPC_EMC_EN_PARENT);
+#else
+ clk_parent4 = clk_get(NULL, DISPC_EMC_EN_PARENT);
+#endif
+ if (IS_ERR(clk_parent3)) {
+ printk(KERN_WARNING "sprdfb: get clk_parent4 fail!\n");
+ return -1;
+ } else {
+ pr_debug(KERN_INFO "sprdfb: get clk_parent4 ok!\n");
+ }
+
+#ifdef CONFIG_OF
+ dispc_ctx.clk_dispc = of_clk_get_by_name(dev->of_dev->of_node, DISPC_PLL_CLK);
+#else
+ dispc_ctx.clk_dispc = clk_get(NULL, DISPC_PLL_CLK);
+#endif
+ if (IS_ERR(dispc_ctx.clk_dispc)) {
+ printk(KERN_WARNING "sprdfb: get clk_dispc fail!\n");
+ return -1;
+ } else {
+ pr_debug(KERN_INFO "sprdfb: get clk_dispc ok!\n");
+ }
+
+#ifdef CONFIG_OF
+ dispc_ctx.clk_dispc_dbi = of_clk_get_by_name(dev->of_dev->of_node, DISPC_DBI_CLK);
+#else
+ dispc_ctx.clk_dispc_dbi = clk_get(NULL, DISPC_DBI_CLK);
+#endif
+ if (IS_ERR(dispc_ctx.clk_dispc_dbi)) {
+ printk(KERN_WARNING "sprdfb: get clk_dispc_dbi fail!\n");
+ return -1;
+ } else {
+ pr_debug(KERN_INFO "sprdfb: get clk_dispc_dbi ok!\n");
+ }
+
+#ifdef CONFIG_OF
+ dispc_ctx.clk_dispc_dpi = of_clk_get_by_name(dev->of_dev->of_node, DISPC_DPI_CLK);
+#else
+ dispc_ctx.clk_dispc_dpi = clk_get(NULL, DISPC_DPI_CLK);
+#endif
+ if (IS_ERR(dispc_ctx.clk_dispc_dpi)) {
+ printk(KERN_WARNING "sprdfb: get clk_dispc_dpi fail!\n");
+ return -1;
+ } else {
+ pr_debug(KERN_INFO "sprdfb: get clk_dispc_dpi ok!\n");
+ }
+
+#ifdef CONFIG_OF
+ dispc_ctx.clk_dispc_emc = of_clk_get_by_name(dev->of_dev->of_node, DISPC_EMC_CLK);
+#else
+ dispc_ctx.clk_dispc_emc = clk_get(NULL, DISPC_EMC_CLK);
+#endif
+ if (IS_ERR(dispc_ctx.clk_dispc_emc)) {
+ printk(KERN_WARNING "sprdfb: get clk_dispc_dpi fail!\n");
+ return -1;
+ } else {
+ pr_debug(KERN_INFO "sprdfb: get clk_dispc_emc ok!\n");
+ }
+
+ ret = clk_set_parent(dispc_ctx.clk_dispc, clk_parent1);
+ if(ret){
+ printk(KERN_ERR "sprdfb: dispc set clk parent fail\n");
+ }
+#ifdef CONFIG_OF
+ ret = clk_set_rate(dispc_ctx.clk_dispc, clk_src[DISPC_CLOCK_SRC_ID]);
+#else
+ ret = clk_set_rate(dispc_ctx.clk_dispc, DISPC_CLOCK);
+#endif
+ if(ret){
+ printk(KERN_ERR "sprdfb: dispc set clk parent fail\n");
+ }
+
+ ret = clk_set_parent(dispc_ctx.clk_dispc_dbi, clk_parent2);
+ if(ret){
+ printk(KERN_ERR "sprdfb: dispc set dbi clk parent fail\n");
+ }
+#ifdef CONFIG_OF
+ ret = clk_set_rate(dispc_ctx.clk_dispc_dbi, clk_src[DISPC_DBI_CLOCK_SRC_ID]);
+#else
+ ret = clk_set_rate(dispc_ctx.clk_dispc_dbi, DISPC_DBI_CLOCK);
+#endif
+ if(ret){
+ printk(KERN_ERR "sprdfb: dispc set dbi clk parent fail\n");
+ }
+
+ ret = clk_set_parent(dispc_ctx.clk_dispc_dpi, clk_parent3);
+ if(ret){
+ printk(KERN_ERR "sprdfb: dispc set dpi clk parent fail\n");
+ }
+
+ ret = clk_set_parent(dispc_ctx.clk_dispc_emc, clk_parent4);
+ if(ret){
+ printk(KERN_ERR "sprdfb: dispc set emc clk parent fail\n");
+ }
+
+ if (dev->panel && dev->panel->fps)
+ dispc_update_clk(dev, dev->panel->fps, SPRDFB_FORCE_FPS);
+ else
+ dispc_update_clk(dev, dpi_clk, SPRDFB_FORCE_PCLK);
+
+ ret = clk_prepare_enable(dispc_ctx.clk_dispc_emc);
+ if(ret){
+ printk("sprdfb: enable clk_dispc_emc error!!!\n");
+ }
+
+ ret = sprdfb_dispc_clk_enable(&dispc_ctx,SPRDFB_DYNAMIC_CLK_FORCE);
+ if (ret) {
+ printk(KERN_WARNING "sprdfb: [%s] enable dispc_clk fail!\n",__FUNCTION__);
+ return -1;
+ } else {
+ pr_debug(KERN_INFO "sprdfb: [%s] enable dispc_clk ok!\n",__FUNCTION__);
+ }
+
+ dispc_print_clk();
+
+ return 0;
+}
+
+#if (defined(CONFIG_SPRD_SCXX30_DMC_FREQ) || defined(CONFIG_SPRD_SCX35_DMC_FREQ))
+struct devfreq_dbs sprd_fb_notify = {
+ .level = 0,
+ .data = &dispc_ctx,
+ .devfreq_notifier = sprdfb_dispc_change_threshold,
+};
+#endif
+
+#ifdef CONFIG_CPU_IDLE
+
+static int scxx30_dispc_cpuidle_notify(struct notifier_block *nb, unsigned long event, void *dummy)
+{
+ if (event == SC_CPUIDLE_PREPARE){
+ if(0 == dispc_ctx.vsync_done
+#ifdef CONFIG_FB_VSYNC_SUPPORT
+ || 0 == dispc_ctx.waitfor_vsync_done
+#endif
+)
+ {
+ return NOTIFY_BAD; //work now, can't not sleep
+ }
+ else
+ {
+ return NOTIFY_OK;
+ }
+ }
+ else{
+ printk("sprdfb: error in cpuidle notify type!\n");
+ }
+ return 0;
+
+}
+
+static struct notifier_block scxx30_dispc_cpuidle_notifier = {
+ .notifier_call = scxx30_dispc_cpuidle_notify,
+};
+#endif
+
+static int32_t sprdfb_dispc_module_init(struct sprdfb_device *dev)
+{
+ int ret = 0;
+ int irq_num = 0;
+
+ if(dispc_ctx.is_inited){
+ printk(KERN_WARNING "sprdfb: dispc_module has already initialized! warning!!");
+ return 0;
+ }
+ else{
+ printk(KERN_INFO "sprdfb: dispc_module_init. call only once!");
+ }
+ dispc_ctx.vsync_done = 1;
+ dispc_ctx.vsync_waiter = 0;
+ init_waitqueue_head(&(dispc_ctx.vsync_queue));
+
+#ifdef CONFIG_FB_ESD_SUPPORT
+#ifdef FB_CHECK_ESD_BY_TE_SUPPORT
+ init_waitqueue_head(&(dev->esd_te_queue));
+ dev->esd_te_waiter = 0;
+ dev->esd_te_done = 0;
+#endif
+#endif
+
+#ifdef CONFIG_FB_VSYNC_SUPPORT
+ dispc_ctx.waitfor_vsync_done = 1;
+ dispc_ctx.waitfor_vsync_waiter = 0;
+ init_waitqueue_head(&(dispc_ctx.waitfor_vsync_queue));
+#endif
+ sema_init(&dev->refresh_lock, 1);
+
+#ifdef CONFIG_OF
+ irq_num = irq_of_parse_and_map(dev->of_dev->of_node, 0);
+#else
+ irq_num = IRQ_DISPC_INT;
+#endif
+ printk("sprdfb: dispc irq_num = %d\n", irq_num);
+
+ //ret = request_irq(IRQ_DISPC_INT, dispc_isr, IRQF_DISABLED, "DISPC", &dispc_ctx);
+ ret = request_irq(irq_num, dispc_isr, IRQF_DISABLED, "DISPC", &dispc_ctx);
+ if (ret) {
+ printk(KERN_ERR "sprdfb: dispc failed to request irq!\n");
+ sprdfb_dispc_uninit(dev);
+ return -1;
+ }
+
+ dispc_ctx.is_inited = true;
+
+#if (defined(CONFIG_SPRD_SCXX30_DMC_FREQ) || defined(CONFIG_SPRD_SCX35_DMC_FREQ))
+ ret=sprdfb_dispc_threshold_check();
+ if(ret)
+ devfreq_notifier_register(&sprd_fb_notify);
+#endif
+
+#ifdef CONFIG_CPU_IDLE
+ if(1 == dev->capability.need_light_sleep)
+ {
+ ret = register_sc_cpuidle_notifier(&scxx30_dispc_cpuidle_notifier);
+ if (ret) {
+ printk("sprdfb: Failed to setup light sleep notifier!\n");
+ }
+ }
+#endif
+ return 0;
+
+}
+
+static int32_t sprdfb_dispc_early_init(struct sprdfb_device *dev)
+{
+ int ret = 0;
+
+ if (!dispc_ctx.is_inited) {
+ //spin_lock_init(&dispc_ctx.clk_spinlock);
+ sema_init(&dispc_ctx.clk_sem, 1);
+ }
+
+ ret = dispc_clk_init(dev);
+ if(ret){
+ printk(KERN_WARNING "sprdfb: dispc_clk_init fail!\n");
+ return -1;
+ }
+
+ if(!dispc_ctx.is_inited){
+ //init
+ if(dev->panel_ready){
+ //panel ready
+ printk(KERN_INFO "sprdfb: [%s]: dispc has alread initialized\n", __FUNCTION__);
+ dispc_ctx.is_first_frame = false;
+ }else{
+ //panel not ready
+ printk(KERN_INFO "sprdfb: [%s]: dispc is not initialized\n", __FUNCTION__);
+ dispc_reset();
+ dispc_module_enable();
+ dispc_ctx.is_first_frame = true;
+ }
+ ret = sprdfb_dispc_module_init(dev);
+ }else{
+ //resume
+ printk(KERN_INFO "sprdfb: [%s]: sprdfb_dispc_early_init resume\n", __FUNCTION__);
+ dispc_reset();
+ dispc_module_enable();
+ dispc_ctx.is_first_frame = true;
+ }
+
+ return ret;
+}
+
+
+static int sprdfb_dispc_clk_disable(struct sprdfb_dispc_context *dispc_ctx_ptr, SPRDFB_DYNAMIC_CLK_SWITCH_E clock_switch_type)
+{
+ bool is_need_disable=false;
+// unsigned long irqflags;
+
+ pr_debug(KERN_INFO "sprdfb: [%s]\n",__FUNCTION__);
+ if(!dispc_ctx_ptr){
+ return 0;
+ }
+
+ //spin_lock_irqsave(&dispc_ctx.clk_spinlock, irqflags);
+ down(&dispc_ctx.clk_sem);
+ switch(clock_switch_type){
+ case SPRDFB_DYNAMIC_CLK_FORCE:
+ is_need_disable=true;
+ break;
+ case SPRDFB_DYNAMIC_CLK_REFRESH:
+ dispc_ctx_ptr->clk_is_refreshing=false;
+ if(dispc_ctx_ptr->clk_open_count<=0){
+ is_need_disable=true;
+ }
+ break;
+ case SPRDFB_DYNAMIC_CLK_COUNT:
+ if(dispc_ctx_ptr->clk_open_count>0){
+ dispc_ctx_ptr->clk_open_count--;
+ if(dispc_ctx_ptr->clk_open_count==0){
+ if(!dispc_ctx_ptr->clk_is_refreshing){
+ is_need_disable=true;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if(dispc_ctx_ptr->clk_is_open && is_need_disable){
+ pr_debug(KERN_INFO "sprdfb: sprdfb_dispc_clk_disable real\n");
+ clk_disable_unprepare(dispc_ctx_ptr->clk_dispc);
+ clk_disable_unprepare(dispc_ctx_ptr->clk_dispc_dpi);
+ clk_disable_unprepare(dispc_ctx_ptr->clk_dispc_dbi);
+ dispc_ctx_ptr->clk_is_open=false;
+ dispc_ctx_ptr->clk_is_refreshing=false;
+ dispc_ctx_ptr->clk_open_count=0;
+ }
+
+ //spin_unlock_irqrestore(&dispc_ctx.clk_spinlock,irqflags);
+ up(&dispc_ctx.clk_sem);
+
+ pr_debug(KERN_INFO "sprdfb: sprdfb_dispc_clk_disable type=%d refresh=%d,count=%d\n",clock_switch_type,dispc_ctx_ptr->clk_is_refreshing,dispc_ctx_ptr->clk_open_count);
+ return 0;
+}
+
+static int sprdfb_dispc_clk_enable(struct sprdfb_dispc_context *dispc_ctx_ptr, SPRDFB_DYNAMIC_CLK_SWITCH_E clock_switch_type)
+{
+ int ret = 0;
+ bool is_dispc_enable=false;
+ bool is_dispc_dpi_enable=false;
+ //unsigned long irqflags;
+
+ pr_debug(KERN_INFO "sprdfb: [%s]\n",__FUNCTION__);
+ if(!dispc_ctx_ptr){
+ return -1;
+ }
+
+ //spin_lock_irqsave(&dispc_ctx.clk_spinlock, irqflags);
+ down(&dispc_ctx.clk_sem);
+
+ if(!dispc_ctx_ptr->clk_is_open){
+ pr_debug(KERN_INFO "sprdfb: sprdfb_dispc_clk_enable real\n");
+ ret = clk_prepare_enable(dispc_ctx_ptr->clk_dispc);
+ if(ret){
+ printk("sprdfb: enable clk_dispc error!!!\n");
+ ret=-1;
+ goto ERROR_CLK_ENABLE;
+ }
+ is_dispc_enable=true;
+ ret = clk_prepare_enable(dispc_ctx_ptr->clk_dispc_dpi);
+ if(ret){
+ printk("sprdfb: enable clk_dispc_dpi error!!!\n");
+ ret=-1;
+ goto ERROR_CLK_ENABLE;
+ }
+ is_dispc_dpi_enable=true;
+ ret = clk_prepare_enable(dispc_ctx_ptr->clk_dispc_dbi);
+ if(ret){
+ printk("sprdfb: enable clk_dispc_dbi error!!!\n");
+ ret=-1;
+ goto ERROR_CLK_ENABLE;
+ }
+ dispc_ctx_ptr->clk_is_open=true;
+ }
+
+ switch(clock_switch_type){
+ case SPRDFB_DYNAMIC_CLK_FORCE:
+ break;
+ case SPRDFB_DYNAMIC_CLK_REFRESH:
+ dispc_ctx_ptr->clk_is_refreshing=true;
+ break;
+ case SPRDFB_DYNAMIC_CLK_COUNT:
+ dispc_ctx_ptr->clk_open_count++;
+ break;
+ default:
+ break;
+ }
+
+ //spin_unlock_irqrestore(&dispc_ctx.clk_spinlock,irqflags);
+ up(&dispc_ctx.clk_sem);
+
+ pr_debug(KERN_INFO "sprdfb: sprdfb_dispc_clk_enable type=%d refresh=%d,count=%d,ret=%d\n",clock_switch_type,dispc_ctx_ptr->clk_is_refreshing,dispc_ctx_ptr->clk_open_count,ret);
+ return ret;
+
+ERROR_CLK_ENABLE:
+ if(is_dispc_enable){
+ clk_disable_unprepare(dispc_ctx_ptr->clk_dispc);
+ }
+ if(is_dispc_dpi_enable){
+ clk_disable_unprepare(dispc_ctx_ptr->clk_dispc_dpi);
+ }
+
+ //spin_unlock_irqrestore(&dispc_ctx.clk_spinlock,irqflags);
+ up(&dispc_ctx.clk_sem);
+
+ printk("sprdfb: sprdfb_dispc_clk_enable error!!!!!!\n");
+ return ret;
+}
+
+static int32_t sprdfb_dispc_init(struct sprdfb_device *dev)
+{
+ uint32_t dispc_int_en_reg_val = 0x00;//ONLY for dispc interrupt en reg
+
+ pr_debug(KERN_INFO "sprdfb: [%s]\n",__FUNCTION__);
+
+ if(NULL == dev){
+ printk("sprdfb: [%s] Invalid parameter!\n", __FUNCTION__);
+ return -1;
+ }
+
+ dispc_ctx.dev = dev;
+
+ /*set bg color*/
+ //dispc_set_bg_color(0xFFFFFFFF);
+ dispc_set_bg_color(0x0);
+ /*enable dithering*/
+ dispc_dithering_enable(true);
+ /*use MSBs as img exp mode*/
+ dispc_set_exp_mode(0x0);
+ //enable DISPC Power Control
+ dispc_pwr_enable(true);
+#if defined( CONFIG_FB_SCX30G)
+ //set buf thres
+ dispc_set_threshold(0x960, 0x00, 0x960);//0x1000: 4K
+#elif defined(CONFIG_FB_SCX35L)
+ dispc_set_threshold(0x1388, 0x00, 0x1388);//For sharkl, linebuffer size: 5K
+#endif
+
+ printk("sprdfb: [%s] 00000000000000001!\n", __FUNCTION__);
+
+ if(dispc_ctx.is_first_frame){
+ dispc_layer_init(&(dev->fb->var));
+ }else{
+ dispc_layer_update(&(dev->fb->var));
+ }
+
+ if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){
+ if(dispc_ctx.is_first_frame){
+ /*set dpi register update only with SW*/
+ dispc_set_bits(BIT(4), DISPC_DPI_CTRL);
+ }else{
+ /*set dpi register update with SW & VSYNC*/
+ dispc_clear_bits(BIT(4), DISPC_DPI_CTRL);
+ }
+ /*enable dispc update done INT*/
+ dispc_int_en_reg_val |= DISPC_INT_UPDATE_DONE_MASK;
+ /* enable hw vsync */
+ dispc_int_en_reg_val |= DISPC_INT_HWVSYNC;
+ }else{
+ /* enable dispc DONE INT*/
+ dispc_int_en_reg_val |= DISPC_INT_DONE_MASK;
+ }
+
+ dispc_int_en_reg_val |= DISPC_INT_ERR_MASK;
+ dispc_write(dispc_int_en_reg_val, DISPC_INT_EN);
+ dev->enable = 1;
+
+ return 0;
+}
+
+static void sprdfb_dispc_clean_lcd (struct sprdfb_device *dev)
+{
+ struct fb_info *fb = NULL;
+ uint32_t size = 0;
+
+ pr_debug(KERN_INFO "sprdfb: [%s]\n",__FUNCTION__);
+
+ if((NULL == dev) || (NULL == dev->fb)){
+ printk("sprdfb: [%s] Invalid parameter!\n",__FUNCTION__);
+ return;
+ }
+
+ down(&dev->refresh_lock);
+ if(!dispc_ctx.is_first_frame || NULL== dev){
+ printk("sprdfb: [%s] not first_frame\n",__FUNCTION__);
+ up(&dev->refresh_lock);
+ return;
+ }
+
+ fb = dev->fb;
+ size = (dev->panel->width &0xffff) | ((dev->panel->height)<<16);
+ if(SPRDFB_PANEL_IF_DPI != dev->panel_if_type){
+ sprdfb_panel_invalidate(dev->panel);
+ }
+ printk("sprdfb: [%s] clean lcd!\n",__FUNCTION__);
+
+ dispc_write(size, DISPC_SIZE_XY);
+
+ dispc_set_bg_color(0x00);
+ dispc_write(dev->fb->fix.smem_start, DISPC_OSD_BASE_ADDR);
+ //dispc_osd_enable(false);
+ dispc_set_osd_alpha(0x00);
+ dispc_run(dev);
+ //dispc_osd_enable(true);
+ up(&dev->refresh_lock);
+ if(SPRDFB_PANEL_IF_DPI != dev->panel_if_type){
+ dispc_sync(dev);
+ }
+#ifdef CONFIG_FB_TRIPLE_FRAMEBUFFER
+ else{
+ dispc_sync(dev);
+ }
+#endif
+ mdelay(30);
+}
+
+
+static int32_t sprdfb_dispc_refresh (struct sprdfb_device *dev)
+{
+ uint32_t reg_val = 0;
+ struct fb_info *fb = dev->fb;
+ uint32_t size = 0;
+
+ uint32_t base = fb->fix.smem_start + fb->fix.line_length * fb->var.yoffset;
+
+ pr_debug(KERN_INFO "sprdfb: [%s]\n",__FUNCTION__);
+
+ down(&dev->refresh_lock);
+ if(0 == dev->enable){
+ printk("sprdfb: [%s]: do not refresh in suspend!!!\n", __FUNCTION__);
+ goto ERROR_REFRESH;
+ }
+
+ if(SPRDFB_PANEL_IF_DPI != dev->panel_if_type){
+ dispc_ctx.vsync_waiter ++;
+ dispc_sync(dev);
+// dispc_ctx.vsync_done = 0;
+#ifdef CONFIG_FB_DYNAMIC_CLK_SUPPORT
+ if(sprdfb_dispc_clk_enable(&dispc_ctx,SPRDFB_DYNAMIC_CLK_REFRESH)){
+ printk(KERN_WARNING "sprdfb: enable dispc_clk fail in refresh!\n");
+ goto ERROR_REFRESH;
+ }
+#endif
+ }
+#ifdef CONFIG_FB_TRIPLE_FRAMEBUFFER
+ else{
+ if((dispc_read(DISPC_OSD_BASE_ADDR) != dispc_read(SHDW_OSD_BASE_ADDR))
+ &&dispc_read(SHDW_OSD_BASE_ADDR) != 0){
+ dispc_ctx.vsync_waiter ++;
+ dispc_sync(dev);
+ }
+ }
+#endif
+
+ pr_debug(KERN_INFO "srpdfb: [%s] got sync\n", __FUNCTION__);
+
+#ifdef CONFIG_FB_MMAP_CACHED
+ if(NULL != dispc_ctx.vma){
+ pr_debug("sprdfb: sprdfb_dispc_refresh dispc_ctx.vma=0x%x\n ",dispc_ctx.vma);
+ dma_sync_single_for_device(dev->fb->dev, dev->fb->fix.smem_start, dev->fb->fix.smem_len, DMA_TO_DEVICE);
+ }
+ if(fb->var.reserved[3] == 1){
+ dispc_dithering_enable(false);
+ if(NULL != dev->panel->ops->panel_change_epf){
+ dev->panel->ops->panel_change_epf(dev->panel,false);
+ }
+ }else{
+ dispc_dithering_enable(true);
+ if(NULL != dev->panel->ops->panel_change_epf){
+ dev->panel->ops->panel_change_epf(dev->panel,true);
+ }
+ }
+#endif
+ //dispc_osd_enable(true);
+ dispc_set_osd_alpha(0xff);
+
+// dispc_ctx.dev = dev;
+#ifdef CONFIG_FB_LCD_OVERLAY_SUPPORT
+ if(SPRD_OVERLAY_STATUS_STARTED == dispc_ctx.overlay_state){
+ overlay_close(dev);
+ }
+#endif
+
+ size = (fb->var.xres & 0xffff) | ((fb->var.yres) << 16);
+
+ dispc_write(base, DISPC_OSD_BASE_ADDR);
+ dispc_write(0, DISPC_OSD_DISP_XY);
+ dispc_write(size, DISPC_OSD_SIZE_XY);
+ dispc_write(fb->var.xres, DISPC_OSD_PITCH);
+#ifdef CONFIG_FB_LOW_RES_SIMU
+ size = (dev->panel->width &0xffff) | ((dev->panel->height)<<16);
+#endif
+ dispc_write(size, DISPC_SIZE_XY);
+
+#ifdef BIT_PER_PIXEL_SURPPORT
+ /* data format */
+ if (fb->var.bits_per_pixel == 32) {
+ /* ABGR */
+ reg_val |= (3 << 4);
+ /* rb switch */
+ reg_val |= (1 << 15);
+ dispc_clear_bits(0x30000,DISPC_CTRL);
+ } else {
+ /* RGB565 */
+ reg_val |= (5 << 4);
+ /* B2B3B0B1 */
+ reg_val |= (2 << 8);
+
+ dispc_clear_bits(0x30000,DISPC_CTRL);
+ dispc_set_bits(0x10000,DISPC_CTRL);
+ }
+ reg_val |= (1 << 0);
+
+ /* alpha mode select - block alpha*/
+ reg_val |= (1 << 2);
+
+ dispc_write(reg_val, DISPC_OSD_CTRL);
+#endif
+
+ if(SPRDFB_PANEL_IF_DPI != dev->panel_if_type){
+ sprdfb_panel_invalidate(dev->panel);
+ }
+
+ sprdfb_panel_before_refresh(dev);
+
+#ifdef CONFIG_FB_LCD_OVERLAY_SUPPORT
+ dispc_set_bits(BIT(0), DISPC_OSD_CTRL);
+ if(SPRD_OVERLAY_STATUS_ON == dispc_ctx.overlay_state){
+ overlay_start(dev, (SPRD_LAYER_IMG));
+ }
+#endif
+
+ dev->frame_count += 1;
+ dispc_run(dev);
+
+#ifdef CONFIG_FB_ESD_SUPPORT
+ if(!dev->ESD_work_start){
+ printk("sprdfb: schedule ESD work queue!\n");
+ schedule_delayed_work(&dev->ESD_work, msecs_to_jiffies(dev->ESD_timeout_val));
+ dev->ESD_work_start = true;
+ }
+#endif
+
+ERROR_REFRESH:
+ up(&dev->refresh_lock);
+
+ if(NULL != dev->logo_buffer_addr_v){
+ printk("sprdfb: free logo proc buffer!\n");
+ free_pages((unsigned long)dev->logo_buffer_addr_v, get_order(dev->logo_buffer_size));
+ dev->logo_buffer_addr_v = 0;
+ }
+
+ pr_debug("sprdfb: DISPC_CTRL: 0x%x\n", dispc_read(DISPC_CTRL));
+ pr_debug("sprdfb: DISPC_SIZE_XY: 0x%x\n", dispc_read(DISPC_SIZE_XY));
+
+ pr_debug("sprdfb: DISPC_BG_COLOR: 0x%x\n", dispc_read(DISPC_BG_COLOR));
+
+ pr_debug("sprdfb: DISPC_INT_EN: 0x%x\n", dispc_read(DISPC_INT_EN));
+
+ pr_debug("sprdfb: DISPC_OSD_CTRL: 0x%x\n", dispc_read(DISPC_OSD_CTRL));
+ pr_debug("sprdfb: DISPC_OSD_BASE_ADDR: 0x%x\n", dispc_read(DISPC_OSD_BASE_ADDR));
+ pr_debug("sprdfb: DISPC_OSD_SIZE_XY: 0x%x\n", dispc_read(DISPC_OSD_SIZE_XY));
+ pr_debug("sprdfb: DISPC_OSD_PITCH: 0x%x\n", dispc_read(DISPC_OSD_PITCH));
+ pr_debug("sprdfb: DISPC_OSD_DISP_XY: 0x%x\n", dispc_read(DISPC_OSD_DISP_XY));
+ pr_debug("sprdfb: DISPC_OSD_ALPHA : 0x%x\n", dispc_read(DISPC_OSD_ALPHA));
+
+ return 0;
+}
+
+static int32_t sprdfb_dispc_suspend(struct sprdfb_device *dev)
+{
+ printk(KERN_INFO "sprdfb: [%s], dev->enable = %d\n",__FUNCTION__, dev->enable);
+
+ if (0 != dev->enable){
+ down(&dev->refresh_lock);
+ if(SPRDFB_PANEL_IF_DPI != dev->panel_if_type){
+ /* must wait ,dispc_sync() */
+ dispc_ctx.vsync_waiter ++;
+ dispc_sync(dev);
+#ifdef CONFIG_FB_DYNAMIC_CLK_SUPPORT
+ printk("sprdfb: open clk in suspend\n");
+ if(sprdfb_dispc_clk_enable(&dispc_ctx,SPRDFB_DYNAMIC_CLK_COUNT)){
+ printk(KERN_WARNING "sprdfb: [%s] clk enable fail!!!\n",__FUNCTION__);
+ }
+#endif
+ printk(KERN_INFO "sprdfb: [%s] got sync\n",__FUNCTION__);
+ }
+
+ dev->enable = 0;
+ up(&dev->refresh_lock);
+
+#ifdef CONFIG_FB_ESD_SUPPORT
+ if(dev->ESD_work_start == true){
+ printk("sprdfb: cancel ESD work queue\n");
+ cancel_delayed_work_sync(&dev->ESD_work);
+ dev->ESD_work_start = false;
+ }
+
+#endif
+
+ sprdfb_panel_suspend(dev);
+
+ dispc_stop(dev);
+ dispc_write(0, DISPC_INT_EN);
+
+ msleep(50); /*fps>20*/
+
+ clk_disable_unprepare(dispc_ctx.clk_dispc_emc);
+ sprdfb_dispc_clk_disable(&dispc_ctx,SPRDFB_DYNAMIC_CLK_FORCE);
+// sci_glb_clr(DISPC_EMC_EN, BIT_DISPC_EMC_EN);
+ }else{
+ printk(KERN_ERR "sprdfb: [%s]: Invalid device status %d\n", __FUNCTION__, dev->enable);
+ }
+ return 0;
+}
+
+static int32_t sprdfb_dispc_resume(struct sprdfb_device *dev)
+{
+ printk(KERN_INFO "sprdfb: [%s], dev->enable= %d\n",__FUNCTION__, dev->enable);
+
+ if (dev->enable == 0) {
+ if(sprdfb_dispc_clk_enable(&dispc_ctx,SPRDFB_DYNAMIC_CLK_FORCE)){
+ printk(KERN_WARNING "sprdfb: [%s] clk enable fail!!\n",__FUNCTION__);
+ //return 0;
+ }
+// sci_glb_set(DISPC_EMC_EN, BIT_DISPC_EMC_EN);
+
+ dispc_ctx.vsync_done = 1;
+ if (1){//(dispc_read(DISPC_SIZE_XY) == 0 ) { /* resume from deep sleep */
+ printk(KERN_INFO "sprdfb: [%s] from deep sleep\n",__FUNCTION__);
+ sprdfb_dispc_early_init(dev);
+ sprdfb_panel_resume(dev, true);
+ sprdfb_dispc_init(dev);
+ printk(KERN_INFO "sprdfb: [%s] from deep sleep out\n",__FUNCTION__);
+ }else {
+ printk(KERN_INFO "sprdfb: [%s] not from deep sleep\n",__FUNCTION__);
+
+ sprdfb_panel_resume(dev, true);
+ }
+
+ dev->enable = 1;
+ if(dev->panel->is_clean_lcd){
+ sprdfb_dispc_clean_lcd(dev);
+ }
+
+ }
+ printk(KERN_INFO "sprdfb: [%s], leave dev->enable= %d\n",__FUNCTION__, dev->enable);
+
+ return 0;
+}
+
+
+#ifdef CONFIG_FB_ESD_SUPPORT
+//for video esd check
+static int32_t sprdfb_dispc_check_esd_dpi(struct sprdfb_device *dev)
+{
+ uint32_t ret = 0;
+ unsigned long flags;
+
+#ifdef FB_CHECK_ESD_BY_TE_SUPPORT
+ ret = sprdfb_panel_ESD_check(dev);
+ if(0 !=ret){
+ dispc_run_for_feature(dev);
+ }
+#else
+#ifdef FB_CHECK_ESD_IN_VFP
+ ret = sprdfb_panel_ESD_check(dev);
+#else
+ local_irq_save(flags);
+ dispc_stop_for_feature(dev);
+
+ ret = sprdfb_panel_ESD_check(dev); //make sure there is no log in this function
+
+ dispc_run_for_feature(dev);
+ local_irq_restore(flags);
+#endif
+#endif
+
+ return ret;
+}
+
+//for cmd esd check
+static int32_t sprdfb_dispc_check_esd_edpi(struct sprdfb_device *dev)
+{
+ uint32_t ret = 0;
+
+ dispc_ctx.vsync_waiter ++;
+ dispc_sync(dev);
+#ifdef CONFIG_FB_DYNAMIC_CLK_SUPPORT
+ if(sprdfb_dispc_clk_enable(&dispc_ctx,SPRDFB_DYNAMIC_CLK_COUNT)){
+ printk(KERN_WARNING "sprdfb: [%s] clk enable fail!!!\n",__FUNCTION__);
+ return -1;
+ }
+#endif
+
+ ret = sprdfb_panel_ESD_check(dev);
+
+ if(0 !=ret){
+ dispc_run_for_feature(dev);
+ }
+#ifdef CONFIG_FB_DYNAMIC_CLK_SUPPORT
+ sprdfb_dispc_clk_disable(&dispc_ctx,SPRDFB_DYNAMIC_CLK_COUNT);
+#endif
+
+ return ret;
+}
+
+static int32_t sprdfb_dispc_check_esd(struct sprdfb_device *dev)
+{
+ uint32_t ret = 0;
+ bool is_refresh_lock_down=false;
+
+ pr_debug("sprdfb: [%s] \n", __FUNCTION__);
+
+ if(SPRDFB_PANEL_IF_DBI == dev->panel_if_type){
+ printk("sprdfb: [%s] leave (not support dbi mode now)!\n", __FUNCTION__);
+ ret = -1;
+ goto ERROR_CHECK_ESD;
+ }
+ down(&dev->refresh_lock);
+ is_refresh_lock_down=true;
+ if(0 == dev->enable){
+ printk("sprdfb: [%s] leave (Invalid device status)!\n", __FUNCTION__);
+ ret=-1;
+ goto ERROR_CHECK_ESD;
+ }
+
+ if(0 == (dev->check_esd_time % 30)){
+ printk("sprdfb: [%s] (%d, %d, %d)\n",__FUNCTION__, dev->check_esd_time, dev->panel_reset_time, dev->reset_dsi_time);
+ }else{
+ pr_debug("sprdfb: [%s] (%d, %d, %d)\n",__FUNCTION__, dev->check_esd_time, dev->panel_reset_time, dev->reset_dsi_time);
+ }
+ if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){
+ ret=sprdfb_dispc_check_esd_dpi(dev);
+ }
+ else{
+ ret=sprdfb_dispc_check_esd_edpi(dev);
+ }
+
+ERROR_CHECK_ESD:
+ if(is_refresh_lock_down){
+ up(&dev->refresh_lock);
+ }
+
+ return ret;
+}
+#endif
+
+
+#ifdef CONFIG_FB_LCD_OVERLAY_SUPPORT
+static int overlay_open(void)
+{
+ pr_debug("sprdfb: [%s] : %d\n", __FUNCTION__,dispc_ctx.overlay_state);
+
+/*
+ if(SPRD_OVERLAY_STATUS_OFF != dispc_ctx.overlay_state){
+ printk(KERN_ERR "sprdfb: Overlay open fail (has been opened)");
+ return -1;
+ }
+*/
+
+ dispc_ctx.overlay_state = SPRD_OVERLAY_STATUS_ON;
+ return 0;
+}
+
+static int overlay_start(struct sprdfb_device *dev, uint32_t layer_index)
+{
+ pr_debug("sprdfb: [%s] : %d, %d\n", __FUNCTION__,dispc_ctx.overlay_state, layer_index);
+
+
+ if(SPRD_OVERLAY_STATUS_ON != dispc_ctx.overlay_state){
+ printk(KERN_ERR "sprdfb: overlay start fail. (not opened)");
+ return -1;
+ }
+
+ if((0 == dispc_read(DISPC_IMG_Y_BASE_ADDR)) && (0 == dispc_read(DISPC_OSD_BASE_ADDR))){
+ printk(KERN_ERR "sprdfb: overlay start fail. (not configged)");
+ return -1;
+ }
+
+/*
+ if(0 != dispc_sync(dev)){
+ printk(KERN_ERR "sprdfb: overlay start fail. (wait done fail)");
+ return -1;
+ }
+*/
+ dispc_set_bg_color(0x0);
+ dispc_clear_bits(BIT(2), DISPC_OSD_CTRL); /*use pixel alpha*/
+ dispc_set_osd_alpha(0x80);
+
+ if((layer_index & SPRD_LAYER_IMG) && (0 != dispc_read(DISPC_IMG_Y_BASE_ADDR))){
+ dispc_set_bits(BIT(0), DISPC_IMG_CTRL);/* enable the image layer */
+ }
+ if((layer_index & SPRD_LAYER_OSD) && (0 != dispc_read(DISPC_OSD_BASE_ADDR))){
+ dispc_set_bits(BIT(0), DISPC_OSD_CTRL);/* enable the osd layer */
+ }
+ dispc_ctx.overlay_state = SPRD_OVERLAY_STATUS_STARTED;
+ return 0;
+}
+
+static int overlay_img_configure(struct sprdfb_device *dev, int type, overlay_rect *rect, unsigned char *buffer, int y_endian, int uv_endian, bool rb_switch)
+{
+ uint32_t reg_value;
+
+ pr_debug("sprdfb: [%s] : %d, (%d, %d,%d,%d), 0x%x\n", __FUNCTION__, type, rect->x, rect->y, rect->h, rect->w, (unsigned int)buffer);
+
+
+ if(SPRD_OVERLAY_STATUS_ON != dispc_ctx.overlay_state){
+ printk(KERN_ERR "sprdfb: Overlay config fail (not opened)");
+ return -1;
+ }
+
+ if (type >= SPRD_DATA_TYPE_LIMIT) {
+ printk(KERN_ERR "sprdfb: Overlay config fail (type error)");
+ return -1;
+ }
+
+ if((y_endian >= SPRD_IMG_DATA_ENDIAN_LIMIT) || (uv_endian >= SPRD_IMG_DATA_ENDIAN_LIMIT)){
+ printk(KERN_ERR "sprdfb: Overlay config fail (y, uv endian error)");
+ return -1;
+ }
+
+/* lcdc_write(((type << 3) | (1 << 0)), LCDC_IMG_CTRL); */
+ /*lcdc_write((type << 3) , LCDC_IMG_CTRL);*/
+ reg_value = (y_endian << 8)|(uv_endian<< 10)|(type << 4);
+ if(rb_switch){
+ reg_value |= (1 << 15);
+ }
+ dispc_write(reg_value, DISPC_IMG_CTRL);
+
+ dispc_write((uint32_t)buffer, DISPC_IMG_Y_BASE_ADDR);
+ if (type < SPRD_DATA_TYPE_RGB888) {
+ uint32_t size = rect->w * rect->h;
+ dispc_write((uint32_t)(buffer + size), DISPC_IMG_UV_BASE_ADDR);
+ }
+
+ reg_value = (rect->h << 16) | (rect->w);
+ dispc_write(reg_value, DISPC_IMG_SIZE_XY);
+
+ dispc_write(rect->w, DISPC_IMG_PITCH);
+
+ reg_value = (rect->y << 16) | (rect->x);
+ dispc_write(reg_value, DISPC_IMG_DISP_XY);
+
+ if(type < SPRD_DATA_TYPE_RGB888) {
+ dispc_write(1, DISPC_Y2R_CTRL);
+#ifndef CONFIG_FB_SCX35
+ dispc_write(SPRDFB_BRIGHTNESS|SPRDFB_CONTRAST, DISPC_Y2R_Y_PARAM);
+ dispc_write(SPRDFB_OFFSET_U|SPRDFB_SATURATION_U, DISPC_Y2R_U_PARAM);
+ dispc_write(SPRDFB_OFFSET_V|SPRDFB_SATURATION_V, DISPC_Y2R_V_PARAM);
+#else
+ dispc_write(SPRDFB_CONTRAST, DISPC_Y2R_CONTRAST);
+ dispc_write(SPRDFB_SATURATION, DISPC_Y2R_SATURATION);
+ dispc_write(SPRDFB_BRIGHTNESS, DISPC_Y2R_BRIGHTNESS);
+#endif
+ }
+
+ pr_debug("sprdfb: DISPC_IMG_CTRL: 0x%x\n", dispc_read(DISPC_IMG_CTRL));
+ pr_debug("sprdfb: DISPC_IMG_Y_BASE_ADDR: 0x%x\n", dispc_read(DISPC_IMG_Y_BASE_ADDR));
+ pr_debug("sprdfb: DISPC_IMG_UV_BASE_ADDR: 0x%x\n", dispc_read(DISPC_IMG_UV_BASE_ADDR));
+ pr_debug("sprdfb: DISPC_IMG_SIZE_XY: 0x%x\n", dispc_read(DISPC_IMG_SIZE_XY));
+ pr_debug("sprdfb: DISPC_IMG_PITCH: 0x%x\n", dispc_read(DISPC_IMG_PITCH));
+ pr_debug("sprdfb: DISPC_IMG_DISP_XY: 0x%x\n", dispc_read(DISPC_IMG_DISP_XY));
+ pr_debug("sprdfb: DISPC_Y2R_CTRL: 0x%x\n", dispc_read(DISPC_Y2R_CTRL));
+#ifndef CONFIG_FB_SCX35
+ pr_debug("sprdfb: DISPC_Y2R_Y_PARAM: 0x%x\n", dispc_read(DISPC_Y2R_Y_PARAM));
+ pr_debug("sprdfb: DISPC_Y2R_U_PARAM: 0x%x\n", dispc_read(DISPC_Y2R_U_PARAM));
+ pr_debug("sprdfb: DISPC_Y2R_V_PARAM: 0x%x\n", dispc_read(DISPC_Y2R_V_PARAM));
+#else
+ pr_debug("sprdfb: DISPC_Y2R_CONTRAST: 0x%x\n", dispc_read(DISPC_Y2R_CONTRAST));
+ pr_debug("sprdfb: DISPC_Y2R_SATURATION: 0x%x\n", dispc_read(DISPC_Y2R_SATURATION));
+ pr_debug("sprdfb: DISPC_Y2R_BRIGHTNESS: 0x%x\n", dispc_read(DISPC_Y2R_BRIGHTNESS));
+#endif
+ return 0;
+}
+
+static int overlay_osd_configure(struct sprdfb_device *dev, int type, overlay_rect *rect, unsigned char *buffer, int y_endian, int uv_endian, bool rb_switch)
+{
+ uint32_t reg_value;
+
+ pr_debug("sprdfb: [%s] : %d, (%d, %d,%d,%d), 0x%x\n", __FUNCTION__, type, rect->x, rect->y, rect->h, rect->w, (unsigned int)buffer);
+
+
+ if(SPRD_OVERLAY_STATUS_ON != dispc_ctx.overlay_state){
+ printk(KERN_ERR "sprdfb: Overlay config fail (not opened)");
+ return -1;
+ }
+
+ if ((type >= SPRD_DATA_TYPE_LIMIT) || (type <= SPRD_DATA_TYPE_YUV400)) {
+ printk(KERN_ERR "sprdfb: Overlay config fail (type error)");
+ return -1;
+ }
+
+ if(y_endian >= SPRD_IMG_DATA_ENDIAN_LIMIT ){
+ printk(KERN_ERR "sprdfb: Overlay config fail (rgb endian error)");
+ return -1;
+ }
+
+/* lcdc_write(((type << 3) | (1 << 0)), LCDC_IMG_CTRL); */
+ /*lcdc_write((type << 3) , LCDC_IMG_CTRL);*/
+
+ /*use premultiply pixel alpha*/
+ reg_value = (y_endian<<8)|(type << 4|(1<<2))|(2<<16);
+ if(rb_switch){
+ reg_value |= (1 << 15);
+ }
+ dispc_write(reg_value, DISPC_OSD_CTRL);
+
+ dispc_write((uint32_t)buffer, DISPC_OSD_BASE_ADDR);
+
+ reg_value = (rect->h << 16) | (rect->w);
+ dispc_write(reg_value, DISPC_OSD_SIZE_XY);
+
+ dispc_write(rect->w, DISPC_OSD_PITCH);
+
+ reg_value = (rect->y << 16) | (rect->x);
+ dispc_write(reg_value, DISPC_OSD_DISP_XY);
+
+
+ pr_debug("sprdfb: DISPC_OSD_CTRL: 0x%x\n", dispc_read(DISPC_OSD_CTRL));
+ pr_debug("sprdfb: DISPC_OSD_BASE_ADDR: 0x%x\n", dispc_read(DISPC_OSD_BASE_ADDR));
+ pr_debug("sprdfb: DISPC_OSD_SIZE_XY: 0x%x\n", dispc_read(DISPC_OSD_SIZE_XY));
+ pr_debug("sprdfb: DISPC_OSD_PITCH: 0x%x\n", dispc_read(DISPC_OSD_PITCH));
+ pr_debug("sprdfb: DISPC_OSD_DISP_XY: 0x%x\n", dispc_read(DISPC_OSD_DISP_XY));
+
+ return 0;
+}
+
+static int overlay_close(struct sprdfb_device *dev)
+{
+ if(SPRD_OVERLAY_STATUS_OFF == dispc_ctx.overlay_state){
+ printk(KERN_ERR "sprdfb: overlay close fail. (has been closed)");
+ return 0;
+ }
+
+/*
+ if (0 != sprd_lcdc_sync(dev)) {
+ printk(KERN_ERR "sprdfb: overlay close fail. (wait done fail)\n");
+ return -1;
+ }
+*/
+ //dispc_set_bg_color(0xFFFFFFFF);
+ dispc_set_bg_color(0x0);
+ dispc_set_bits(BIT(2), DISPC_OSD_CTRL);/*use block alpha*/
+ dispc_set_osd_alpha(0xff);
+ dispc_clear_bits(BIT(0), DISPC_IMG_CTRL); /* disable the image layer */
+ dispc_write(0, DISPC_IMG_Y_BASE_ADDR);
+ dispc_write(0, DISPC_OSD_BASE_ADDR);
+ dispc_layer_init(&(dev->fb->var));
+ dispc_ctx.overlay_state = SPRD_OVERLAY_STATUS_OFF;
+
+ return 0;
+}
+
+/*TO DO: need mutext with suspend, resume*/
+static int32_t sprdfb_dispc_enable_overlay(struct sprdfb_device *dev, struct overlay_info* info, int enable)
+{
+ int result = -1;
+ bool is_refresh_lock_down=false;
+#ifdef CONFIG_FB_DYNAMIC_CLK_SUPPORT
+ bool is_clk_enable=false;
+#endif
+
+ pr_debug("sprdfb: [%s]: %d, %d\n", __FUNCTION__, enable, dev->enable);
+
+ if(enable){ /*enable*/
+ if(NULL == info){
+ printk(KERN_ERR "sprdfb: sprdfb_dispc_enable_overlay fail (Invalid parameter)\n");
+ goto ERROR_ENABLE_OVERLAY;
+ }
+
+ down(&dev->refresh_lock);
+ is_refresh_lock_down=true;
+
+ if(0 == dev->enable){
+ printk(KERN_ERR "sprdfb: sprdfb_dispc_enable_overlay fail. (dev not enable)\n");
+ goto ERROR_ENABLE_OVERLAY;
+ }
+
+ if(0 != dispc_sync(dev)){
+ printk(KERN_ERR "sprdfb: sprdfb_dispc_enable_overlay fail. (wait done fail)\n");
+ goto ERROR_ENABLE_OVERLAY;
+ }
+
+#ifdef CONFIG_FB_DYNAMIC_CLK_SUPPORT
+ if(SPRDFB_PANEL_IF_DPI != dev->panel_if_type){
+ if(sprdfb_dispc_clk_enable(&dispc_ctx,SPRDFB_DYNAMIC_CLK_COUNT)){
+ printk(KERN_WARNING "sprdfb: [%s] clk enable fail!!!\n",__FUNCTION__);
+ goto ERROR_ENABLE_OVERLAY;
+ }
+ is_clk_enable=true;
+ }
+#endif
+#ifdef CONFIG_FB_LCD_OVERLAY_SUPPORT
+ if(SPRD_OVERLAY_STATUS_STARTED == dispc_ctx.overlay_state){
+ overlay_close(dev);
+ }
+#endif
+ result = overlay_open();
+ if(0 != result){
+ result=-1;
+ goto ERROR_ENABLE_OVERLAY;
+ }
+
+ if(SPRD_LAYER_IMG == info->layer_index){
+ result = overlay_img_configure(dev, info->data_type, &(info->rect), info->buffer, info->y_endian, info->uv_endian, info->rb_switch);
+ }else if(SPRD_LAYER_OSD == info->layer_index){
+ result = overlay_osd_configure(dev, info->data_type, &(info->rect), info->buffer, info->y_endian, info->uv_endian, info->rb_switch);
+ }else{
+ printk(KERN_ERR "sprdfb: sprdfb_dispc_enable_overlay fail. (invalid layer index)\n");
+ }
+ if(0 != result){
+ result=-1;
+ goto ERROR_ENABLE_OVERLAY;
+ }
+ /*result = overlay_start(dev);*/
+ }else{ /*disable*/
+ /*result = overlay_close(dev);*/
+ }
+ERROR_ENABLE_OVERLAY:
+#ifdef CONFIG_FB_DYNAMIC_CLK_SUPPORT
+ if(is_clk_enable){
+ sprdfb_dispc_clk_disable(&dispc_ctx,SPRDFB_DYNAMIC_CLK_COUNT);
+ }
+#endif
+ if(is_refresh_lock_down){
+ up(&dev->refresh_lock);
+ }
+
+ pr_debug("sprdfb: [%s] return %d\n", __FUNCTION__, result);
+ return result;
+}
+
+
+static int32_t sprdfb_dispc_display_overlay(struct sprdfb_device *dev, struct overlay_display* setting)
+{
+#ifndef CONFIG_FB_LOW_RES_SIMU
+ struct overlay_rect* rect = &(setting->rect);
+ uint32_t size =( (rect->h << 16) | (rect->w & 0xffff));
+#else
+ uint32_t size = (dev->panel->width &0xffff) | ((dev->panel->height)<<16);
+#endif
+ dispc_ctx.dev = dev;
+
+ pr_debug("sprdfb: sprdfb_dispc_display_overlay: layer:%d, (%d, %d,%d,%d)\n",
+ setting->layer_index, setting->rect.x, setting->rect.y, setting->rect.h, setting->rect.w);
+
+ down(&dev->refresh_lock);
+ if(0 == dev->enable){
+ printk("sprdfb: [%s] leave (Invalid device status)!\n", __FUNCTION__);
+ goto ERROR_DISPLAY_OVERLAY;
+ }
+ if(SPRDFB_PANEL_IF_DPI != dev->panel_if_type){
+ dispc_ctx.vsync_waiter ++;
+ dispc_sync(dev);
+ //dispc_ctx.vsync_done = 0;
+#ifdef CONFIG_FB_DYNAMIC_CLK_SUPPORT
+ if(sprdfb_dispc_clk_enable(&dispc_ctx,SPRDFB_DYNAMIC_CLK_REFRESH)){
+ printk(KERN_WARNING "sprdfb: [%s] clk enable fail!!!\n",__FUNCTION__);
+ goto ERROR_DISPLAY_OVERLAY;
+ }
+#endif
+
+ }
+#ifdef CONFIG_FB_MMAP_CACHED
+ dispc_dithering_enable(true);
+ if(NULL != dev->panel->ops->panel_change_epf){
+ dev->panel->ops->panel_change_epf(dev->panel,true);
+ }
+
+#endif
+ pr_debug(KERN_INFO "srpdfb: [%s] got sync\n", __FUNCTION__);
+
+ dispc_ctx.dev = dev;
+
+ dispc_write(size, DISPC_SIZE_XY);
+
+ if(SPRDFB_PANEL_IF_DPI != dev->panel_if_type){
+ sprdfb_panel_invalidate(dev->panel);
+ }
+
+ sprdfb_panel_before_refresh(dev);
+
+ dispc_clear_bits(BIT(0), DISPC_OSD_CTRL);
+ if(SPRD_OVERLAY_STATUS_ON == dispc_ctx.overlay_state){
+ if(overlay_start(dev, setting->layer_index) != 0){
+ printk("sprdfb: %s[%d] overlay_start() err, return without run dispc!\n",__func__,__LINE__);
+ goto ERROR_DISPLAY_OVERLAY;
+ }
+ }
+
+ dev->frame_count += 1;
+ dispc_run(dev);
+
+ if((SPRD_OVERLAY_DISPLAY_SYNC == setting->display_mode) && (SPRDFB_PANEL_IF_DPI != dev->panel_if_type)){
+ dispc_ctx.vsync_waiter ++;
+ if (dispc_sync(dev) != 0) {/* time out??? disable ?? */
+ printk("sprdfb: sprdfb do sprd_lcdc_display_overlay time out!\n");
+ }
+ //dispc_ctx.vsync_done = 0;
+ }
+
+ERROR_DISPLAY_OVERLAY:
+ up(&dev->refresh_lock);
+
+ pr_debug("sprdfb: DISPC_CTRL: 0x%x\n", dispc_read(DISPC_CTRL));
+ pr_debug("sprdfb: DISPC_SIZE_XY: 0x%x\n", dispc_read(DISPC_SIZE_XY));
+
+ pr_debug("sprdfb: DISPC_BG_COLOR: 0x%x\n", dispc_read(DISPC_BG_COLOR));
+
+ pr_debug("sprdfb: DISPC_INT_EN: 0x%x\n", dispc_read(DISPC_INT_EN));
+
+ pr_debug("sprdfb: DISPC_OSD_CTRL: 0x%x\n", dispc_read(DISPC_OSD_CTRL));
+ pr_debug("sprdfb: DISPC_OSD_BASE_ADDR: 0x%x\n", dispc_read(DISPC_OSD_BASE_ADDR));
+ pr_debug("sprdfb: DISPC_OSD_SIZE_XY: 0x%x\n", dispc_read(DISPC_OSD_SIZE_XY));
+ pr_debug("sprdfb: DISPC_OSD_PITCH: 0x%x\n", dispc_read(DISPC_OSD_PITCH));
+ pr_debug("sprdfb: DISPC_OSD_DISP_XY: 0x%x\n", dispc_read(DISPC_OSD_DISP_XY));
+ pr_debug("sprdfb: DISPC_OSD_ALPHA : 0x%x\n", dispc_read(DISPC_OSD_ALPHA));
+ return 0;
+}
+
+#endif
+
+#ifdef CONFIG_FB_VSYNC_SUPPORT
+static int32_t spdfb_dispc_wait_for_vsync(struct sprdfb_device *dev)
+{
+ int ret = 0;
+ uint32_t reg_val0,reg_val1;
+
+ pr_debug("sprdfb: [%s]\n", __FUNCTION__);
+
+ if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){
+ if(!dispc_ctx.is_first_frame){
+ dispc_ctx.waitfor_vsync_done = 0;
+ //dispc_set_bits(BIT(0), DISPC_INT_EN);
+ dispc_ctx.waitfor_vsync_waiter++;
+#ifndef CONFIG_SC_FPGA
+ ret = wait_event_interruptible_timeout(dispc_ctx.waitfor_vsync_queue,
+ dispc_ctx.waitfor_vsync_done, msecs_to_jiffies(100));
+#else /* fpga dpi clock is 6-7MHz, timeout should be longer than reference phone */
+ ret = wait_event_interruptible_timeout(dispc_ctx.waitfor_vsync_queue,
+ dispc_ctx.waitfor_vsync_done, msecs_to_jiffies(900));
+#endif
+ if (!ret) { /* time out */
+ dispc_ctx.waitfor_vsync_done = 1;
+ reg_val0 = dispc_read(DISPC_INT_RAW);
+ reg_val1 = dispc_read(DISPC_DPI_STS1);
+ printk(KERN_ERR "sprdfb: vsync time out!!!!!(0x%x, 0x%x)\n",
+ reg_val0, reg_val1);
+ {/*for debug*/
+ int32_t i = 0;
+ for(i=0;i<256;i+=16){
+ printk("sprdfb: %x: 0x%x, 0x%x, 0x%x, 0x%x\n", i,
+ dispc_read(i), dispc_read(i+4), dispc_read(i+8), dispc_read(i+12));
+ }
+ printk("**************************************\n");
+ }
+ }
+ dispc_ctx.waitfor_vsync_waiter = 0;
+ }else{
+ msleep(16);
+ }
+
+ }else{
+ dispc_ctx.waitfor_vsync_done = 0;
+ dispc_set_bits(BIT(1), DISPC_INT_EN);
+ dispc_ctx.waitfor_vsync_waiter++;
+ ret = wait_event_interruptible_timeout(dispc_ctx.waitfor_vsync_queue,
+ dispc_ctx.waitfor_vsync_done, msecs_to_jiffies(100));
+
+ if (!ret) { /* time out */
+ dispc_ctx.waitfor_vsync_done = 1;
+ printk(KERN_ERR "sprdfb: vsync time out!!!!!\n");
+ {/*for debug*/
+ int32_t i = 0;
+ for(i=0;i<256;i+=16){
+ printk("sprdfb: %x: 0x%x, 0x%x, 0x%x, 0x%x\n", i,
+ dispc_read(i), dispc_read(i+4), dispc_read(i+8), dispc_read(i+12));
+ }
+ printk("**************************************\n");
+ }
+ }
+ dispc_ctx.waitfor_vsync_waiter = 0;
+ }
+ pr_debug("sprdfb: [%s] (%d)\n", __FUNCTION__, ret);
+ return 0;
+}
+#endif
+
+//#if (defined(CONFIG_FB_DYNAMIC_FREQ_SCALING) || !defined(FB_CHECK_ESD_IN_VFP))
+static void dispc_stop_for_feature(struct sprdfb_device *dev)
+{
+ int wait_count = 0;
+
+ if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){
+ dispc_stop(dev);
+ while((dispc_read(DISPC_DPI_STS1) & BIT(16)) && (wait_count < 100)){
+ udelay(1000);
+ wait_count++;
+ }
+ if(wait_count >= 100){
+ printk("sprdfb:[%s] can't wait till dispc stop!!!\n", __func__);
+ }
+ udelay(25);
+ }
+}
+
+static void dispc_run_for_feature(struct sprdfb_device *dev)
+{
+#ifdef CONFIG_FB_LCD_OVERLAY_SUPPORT
+ if(SPRD_OVERLAY_STATUS_ON != dispc_ctx.overlay_state)
+#endif
+ {
+ dispc_run(dev);
+ }
+}
+//#endif
+
+#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING
+/**
+ * author: Yang.Haibing haibing.yang@spreadtrum.com
+ *
+ * sprdfb_dispc_chg_clk - interface for sysfs to change dpi or dphy clock
+ * @fb_dev: spreadtrum specific fb device
+ * @type: check the type is fps or pclk or mipi dphy freq
+ * @new_val: fps or new dpi clock
+ *
+ * Returns 0 on success, MINUS on parsing error.
+ */
+int sprdfb_dispc_chg_clk(struct sprdfb_device *fb_dev,
+ int type, u32 new_val)
+{
+ int ret = 0;
+ unsigned long flags = 0;
+ struct panel_spec* panel = fb_dev->panel;
+
+ pr_debug("%s --enter--", __func__);
+ /* check if new value is valid */
+ if (new_val <= 0) {
+ pr_err("new value is invalid\n");
+ return -EINVAL;
+ }
+
+ down(&fb_dev->refresh_lock);
+ /* Now let's do update dpi clock */
+ switch (type) {
+ case SPRDFB_DYNAMIC_PCLK:
+ if (fb_dev->panel_if_type != SPRDFB_PANEL_IF_DPI) {
+ pr_err("current dispc interface isn't DPI\n");
+ ret=-EINVAL;
+ goto exit;
+ }
+ /* Note: local interrupt will be disabled */
+ local_irq_save(flags);
+ dispc_stop_for_feature(fb_dev);
+ ret = dispc_update_clk(fb_dev, new_val,
+ SPRDFB_DYNAMIC_PCLK);
+ break;
+
+ case SPRDFB_DYNAMIC_FPS:
+ if (fb_dev->panel_if_type != SPRDFB_PANEL_IF_DPI) {
+ dispc_ctx.vsync_waiter ++;
+ dispc_sync(fb_dev);
+ sprdfb_panel_change_fps(fb_dev, new_val);
+ ret=0;
+ goto exit;
+ }
+ /* Note: local interrupt will be disabled */
+ local_irq_save(flags);
+ dispc_stop_for_feature(fb_dev);
+ ret = dispc_update_clk(fb_dev, new_val, SPRDFB_DYNAMIC_FPS);
+ break;
+
+ case SPRDFB_DYNAMIC_MIPI_CLK:
+ /* Note: local interrupt will be disabled */
+ local_irq_save(flags);
+ dispc_stop_for_feature(fb_dev);
+ ret = dispc_update_clk(fb_dev, new_val, SPRDFB_DYNAMIC_MIPI_CLK);
+ break;
+
+ default:
+ pr_err("invalid CMD type\n");
+ ret=-EINVAL;
+ goto exit;
+ }
+
+ if (ret) {
+ pr_err("Failed to set pixel clock, fps or dphy freq.\n");
+ goto DONE;
+ }
+ if (type != SPRDFB_DYNAMIC_MIPI_CLK &&
+ panel->type == LCD_MODE_DSI &&
+ panel->info.mipi->work_mode ==
+ SPRDFB_MIPI_MODE_VIDEO &&
+ fb_dev->enable == true) {
+ ret = dsi_dpi_init(fb_dev);
+ if (ret)
+ pr_err("%s: dsi_dpi_init fail\n", __func__);
+ }
+
+DONE:
+ dispc_run_for_feature(fb_dev);
+ local_irq_restore(flags);
+ up(&fb_dev->refresh_lock);
+
+ pr_debug("%s --leave--", __func__);
+ return ret;
+
+exit:
+ up(&fb_dev->refresh_lock);
+ return ret;
+
+}
+#endif
+
+static int dispc_update_clk_intf(struct sprdfb_device *fb_dev)
+{
+ return dispc_update_clk(fb_dev, fb_dev->panel->fps, SPRDFB_FORCE_FPS);
+}
+
+/**
+ * author: Yang.Haibing haibing.yang@spreadtrum.com
+ *
+ * dispc_update_clk - update dpi clock via @howto and @new_val
+ * @fb_dev: spreadtrum specific fb device
+ * @new_val: fps or new dpi clock
+ * @howto: check the type is fps or pclk or mipi dphy freq
+ *
+ * Returns 0 on success, MINUS on error.
+ */
+static int dispc_update_clk(struct sprdfb_device *fb_dev,
+ u32 new_val, int howto)
+{
+ int ret;
+ u32 new_pclk;
+ u32 old_val;
+ u32 dpi_clk_src;
+ struct panel_spec* panel = fb_dev->panel;
+
+#ifdef CONFIG_OF
+ uint32_t clk_src[DISPC_CLOCK_NUM];
+
+ ret = of_property_read_u32_array(fb_dev->of_dev->of_node,
+ "clock-src", clk_src, DISPC_CLOCK_NUM);
+ if (ret) {
+ pr_err("[%s] read clock-src fail (%d)\n", __func__, ret);
+ return -EINVAL;
+ }
+ dpi_clk_src = clk_src[DISPC_DPI_CLOCK_SRC_ID];
+#else
+ dpi_clk_src = SPRDFB_DPI_CLOCK_SRC;
+#endif
+
+ switch (howto) {
+ case SPRDFB_FORCE_FPS:
+ ret = dispc_check_new_clk(fb_dev, &new_pclk,
+ dpi_clk_src, new_val,
+ SPRDFB_FORCE_FPS);
+ if (ret) {
+ pr_err("%s: new forced fps is invalid.", __func__);
+ return -EINVAL;
+ }
+ break;
+
+ case SPRDFB_DYNAMIC_FPS: /* Calc dpi clock via fps */
+ ret = dispc_check_new_clk(fb_dev, &new_pclk,
+ dpi_clk_src, new_val,
+ SPRDFB_DYNAMIC_FPS);
+ if (ret) {
+ pr_err("%s: new dynamic fps is invalid.", __func__);
+ return -EINVAL;
+ }
+ break;
+
+ case SPRDFB_FORCE_PCLK:
+ new_pclk = new_val;
+ break;
+
+ case SPRDFB_DYNAMIC_PCLK: /* Given dpi clock */
+ ret = dispc_check_new_clk(fb_dev, &new_pclk,
+ dpi_clk_src, new_val,
+ SPRDFB_DYNAMIC_PCLK);
+ if (ret) {
+ pr_err("%s: new dpi clock is invalid.", __func__);
+ return -EINVAL;
+ }
+ break;
+
+ case SPRDFB_DYNAMIC_MIPI_CLK: /* Given mipi clock */
+ if(!panel){
+ pr_err("%s: there is no panel!", __func__);
+ return -ENXIO;
+ }
+ if (panel->type != LCD_MODE_DSI) {
+ pr_err("%s: panel type isn't dsi mode", __func__);
+ return -ENXIO;
+ }
+ old_val = panel->info.mipi->phy_feq;
+ ret = sprdfb_dsi_chg_dphy_freq(fb_dev, new_val);
+ if (ret) {
+ pr_err("%s: new dphy freq is invalid.", __func__);
+ return -EINVAL;
+ }
+ pr_info("dphy frequency is switched from %dHz to %dHz\n",
+ old_val * 1000,
+ new_val * 1000);
+ return ret;
+
+ default:
+ pr_err("%s: Unsupported clock type.\n", __func__);
+ return -EINVAL;
+ }
+
+ if (howto != SPRDFB_FORCE_PCLK &&
+ howto != SPRDFB_FORCE_FPS &&
+ !fb_dev->enable) {
+ pr_warn("After fb_dev is resumed, dpi or mipi clk will be updated\n");
+ return ret;
+ }
+
+ /* Now let's do update dpi clock */
+ ret = clk_set_rate(dispc_ctx.clk_dispc_dpi, new_pclk);
+ if (ret) {
+ pr_err("Failed to set pixel clock.\n");
+ return ret;
+ }
+
+ pr_info("dpi clock is switched from %dHz to %dHz\n",
+ fb_dev->dpi_clock, new_pclk);
+ /* Save the updated clock */
+ fb_dev->dpi_clock = new_pclk;
+ return ret;
+}
+
+#if (defined(CONFIG_SPRD_SCXX30_DMC_FREQ) || defined(CONFIG_SPRD_SCX35_DMC_FREQ))
+
+static unsigned int sprdfb_dispc_threshold_check()
+{
+#if defined CONFIG_FB_SCX30G || defined CONFIG_FB_SCX35L
+ //For Tshark and SharkL, not need to change threshlod
+ return 0;
+#endif
+ return 1;
+}
+
+/*return value:
+0 -- Allow DMC change frequency
+1 -- Don't allow DMC change frequency*/
+static unsigned int sprdfb_dispc_change_threshold(struct devfreq_dbs *h, unsigned int state)
+{
+ struct sprdfb_dispc_context *dispc_ctx = (struct sprdfb_dispc_context *)h->data;
+ struct sprdfb_device *dev = dispc_ctx->dev;
+ if(NULL == dev || 0 == dev->enable){
+ //printk(KERN_ERR "sprdfb: sprdfb_dispc_change_threshold fail.(dev not enable)\n");
+ return 0;
+ }
+ printk(KERN_ERR "sprdfb: DMC change freq(%u)\n", state);
+ mdelay(10);
+ if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){
+ if(state == DEVFREQ_PRE_CHANGE){
+ dispc_set_threshold(0x960, 0x00, 0x960);
+ }else{
+ dispc_set_threshold(0x500, 0x00, 0x500);
+ }
+ }
+ return 0;
+}
+#endif
+
+//begin bug210112
+extern unsigned long lcd_base_from_uboot;
+
+static int32_t sprdfb_dispc_refresh_logo (struct sprdfb_device *dev)
+{
+ uint32_t i = 0;
+ pr_debug("%s:[%d] panel_if_type:%d\n",__func__,__LINE__,dev->panel_if_type);
+
+ if(SPRDFB_PANEL_IF_DPI != dev->panel_if_type){
+ printk(KERN_ERR "sprdfb: sprdfb_dispc_refresh_logo if type error\n!");
+ return 0;
+ }
+ dispc_clear_bits(0x1f, DISPC_INT_EN);//disable all interrupt
+ dispc_set_bits(0x1f, DISPC_INT_CLR);// clear all interruption
+ dispc_set_bits(BIT(5), DISPC_DPI_CTRL);//update
+
+
+//wait for update- done interruption
+ for(i=0; i<500; i++) {
+ if(!(dispc_read(DISPC_INT_RAW) & (0x10))){
+ udelay(1000);
+ } else {
+ break;
+ }
+ }
+ if(i >= 500) {
+ printk("sprdfb: [%s] wait dispc done int time out!! (0x%x)\n", __func__, dispc_read(DISPC_INT_RAW));
+ }
+ dispc_set_bits((1<<5), DISPC_INT_CLR);
+ return 0;
+}
+
+void sprdfb_dispc_logo_proc(struct sprdfb_device *dev)
+{
+ //inline size_t roundUpToPageSize(size_t x) { return (x + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);}
+ unsigned long logo_dst_p = 0;
+ void *logo_src_v = NULL;
+ void *logo_dst_v = NULL; //use the second frame buffer ,virtual
+ uint32_t logo_size = 0;// should be rgb565
+
+ pr_debug("sprdfb: %s[%d] enter.\n",__func__,__LINE__);
+
+ if(dev == NULL) {
+ printk("sprdfb: %s[%d]: dev == NULL, return without process logo!!\n",__func__,__LINE__);
+ return;
+ }
+
+ if(lcd_base_from_uboot == 0L) {
+ printk("sprdfb: %s[%d]: lcd_base_from_uboot == 0, return without process logo!!\n",__func__,__LINE__);
+ return;
+ }
+ if(SPRDFB_PANEL_IF_DPI != dev->panel_if_type)
+ return;
+
+//#define USE_OVERLAY_BUFF
+#ifdef CONFIG_FB_LOW_RES_SIMU
+ if((0 != dev->display_width) && (0 != dev->display_height)){
+ logo_size = dev->display_width * dev->display_height * 2;// should be rgb565
+ }else
+#endif
+ logo_size = dev->panel->width * dev->panel->height * 2;// should be rgb565
+#if 0
+#ifndef USE_OVERLAY_BUFF
+ kernel_fb_size = dev->panel->width * dev->panel->height * (dev->bpp / 8);
+ kernel_fb_size = 0;
+ logo_dst_v = dev->fb->screen_base + kernel_fb_size;//use the second frame buffer
+ logo_dst_p = dev->fb->fix.smem_start + kernel_fb_size;//use the second frame buffer
+#else
+ logo_dst_p = SPRD_ION_OVERLAY_BASE-logo_size;//use overlay frame buffer
+ logo_dst_v = (uint32_t)ioremap(logo_dst_p, logo_size);
+#endif
+#else
+ dev->logo_buffer_size = logo_size;
+ dev->logo_buffer_addr_v = (void*)__get_free_pages(GFP_ATOMIC | __GFP_ZERO , get_order(logo_size));
+ if (!dev->logo_buffer_addr_v) {
+ printk(KERN_ERR "sprdfb: %s Failed to allocate logo proc buffer\n", __FUNCTION__);
+ return;
+ }
+ printk(KERN_INFO "sprdfb: got %d bytes logo proc buffer at 0x%p\n", logo_size,
+ dev->logo_buffer_addr_v);
+
+ logo_dst_v = dev->logo_buffer_addr_v;
+ logo_dst_p = __pa(dev->logo_buffer_addr_v);
+
+#endif
+ logo_src_v = ioremap(lcd_base_from_uboot, logo_size);
+ if (!logo_src_v || !logo_dst_v) {
+ printk(KERN_ERR "sprdfb: %s[%d]: Unable to map boot logo memory: src-0x%p, dst-0x%p\n", __func__,
+ __LINE__,logo_src_v, logo_dst_v);
+ return;
+ }
+
+ printk("sprdfb: %s[%d]: lcd_base_from_uboot: 0x%lx, logo_src_v:0x%p\n",__func__,__LINE__,lcd_base_from_uboot,logo_src_v);
+ printk("sprdfb: %s[%d]: logo_dst_p:0x%lx,logo_dst_v:0x%p\n",__func__,__LINE__,logo_dst_p,logo_dst_v);
+ memcpy(logo_dst_v, logo_src_v, logo_size);
+ dma_sync_single_for_device(dev->fb->dev, logo_dst_p, logo_size, DMA_TO_DEVICE);
+
+ iounmap(logo_src_v);
+
+#if 0
+#ifdef USE_OVERLAY_BUFF
+ iounmap(logo_dst_v);
+#endif
+#endif
+ //dispc_print_osd_config(__func__,__LINE__);
+ dispc_write(logo_dst_p, DISPC_OSD_BASE_ADDR);
+ sprdfb_dispc_refresh_logo(dev);
+ //dispc_print_osd_config(__func__,__LINE__);
+}
+
+//end bug210112
+#ifdef CONFIG_FB_MMAP_CACHED
+void sprdfb_set_vma(struct vm_area_struct *vma)
+{
+ if(NULL != vma){
+ dispc_ctx.vma = vma;
+ }
+}
+#endif
+
+int32_t sprdfb_is_refresh_done(struct sprdfb_device *dev)
+{
+ printk("sprdfb: sprdfb_is_refresh_done vsync_done=%d",dispc_ctx.vsync_done);
+ return (int32_t)dispc_ctx.vsync_done;
+}
+
+struct display_ctrl sprdfb_dispc_ctrl = {
+ .name = "dispc",
+ .early_init = sprdfb_dispc_early_init,
+ .init = sprdfb_dispc_init,
+ .uninit = sprdfb_dispc_uninit,
+ .refresh = sprdfb_dispc_refresh,
+ .logo_proc = sprdfb_dispc_logo_proc,
+ .suspend = sprdfb_dispc_suspend,
+ .resume = sprdfb_dispc_resume,
+ .update_clk = dispc_update_clk_intf,
+#ifdef CONFIG_FB_ESD_SUPPORT
+ .ESD_check = sprdfb_dispc_check_esd,
+#endif
+#ifdef CONFIG_FB_LCD_OVERLAY_SUPPORT
+ .enable_overlay = sprdfb_dispc_enable_overlay,
+ .display_overlay = sprdfb_dispc_display_overlay,
+#endif
+#ifdef CONFIG_FB_VSYNC_SUPPORT
+ .wait_for_vsync = spdfb_dispc_wait_for_vsync,
+#endif
+#ifdef CONFIG_FB_MMAP_CACHED
+ .set_vma = sprdfb_set_vma,
+#endif
+ .is_refresh_done = sprdfb_is_refresh_done,
+
+};
+
+
diff --git a/drivers/video/sprdfb/sprdfb_dispc_reg.h b/drivers/video/sprdfb/sprdfb_dispc_reg.h
new file mode 100644
index 00000000..70ef8711
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_dispc_reg.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DISPC_REG_H_
+#define _DISPC_REG_H_
+
+#include <asm/io.h>
+
+#include "sprdfb_chip_common.h"
+
+/* DISPC regs offset */
+#define DISPC_CTRL (0x0000)
+#define DISPC_SIZE_XY (0x0004)
+#define DISPC_RSTN (0x0008)
+#define DISPC_BUF_THRES (0x000C)
+
+#define DISPC_STS (0x0010)
+
+#define DISPC_LVDS_CTRL (0x0018)
+
+#define DISPC_IMG_CTRL (0x0020)
+#define DISPC_IMG_Y_BASE_ADDR (0x0024)
+#define DISPC_IMG_UV_BASE_ADDR (0x0028)
+#define DISPC_IMG_V_BASE_ADDR (0x002c)
+#define DISPC_IMG_SIZE_XY (0x0030)
+#define DISPC_IMG_PITCH (0x0034)
+#define DISPC_IMG_DISP_XY (0x0038)
+#define DISPC_BG_COLOR (0x003c)
+
+#define DISPC_OSD_CTRL (0x0040)
+#define DISPC_OSD_BASE_ADDR (0x0044)
+#define DISPC_OSD_SIZE_XY (0x0048)
+#define DISPC_OSD_PITCH (0x004c)
+#define DISPC_OSD_DISP_XY (0x0050)
+#define DISPC_OSD_ALPHA (0x0054)
+#define DISPC_OSD_CK (0x0058)
+
+#define DISPC_Y2R_CTRL (0x0060)
+#ifndef CONFIG_FB_SCX35
+#define DISPC_Y2R_Y_PARAM (0x0064)
+#define DISPC_Y2R_U_PARAM (0x0068)
+#define DISPC_Y2R_V_PARAM (0x006c)
+#else
+#define DISPC_Y2R_CONTRAST (0x0064)
+#define DISPC_Y2R_SATURATION (0x0068)
+#define DISPC_Y2R_BRIGHTNESS (0x006c)
+#endif
+
+#define DISPC_INT_EN (0x0070)
+#define DISPC_INT_CLR (0x0074)
+#define DISPC_INT_STATUS (0x0078)
+#define DISPC_INT_RAW (0x007c)
+
+#define DISPC_DPI_CTRL (0x0080)
+#define DISPC_DPI_H_TIMING (0x0084)
+#define DISPC_DPI_V_TIMING (0x0088)
+#define DISPC_DPI_STS0 (0x008c)
+#define DISPC_DPI_STS1 (0x0090)
+
+#define DISPC_DBI_CTRL (0x00a0)
+#define DISPC_DBI_TIMING0 (0x00a4)
+#define DISPC_DBI_TIMING1 (0x00a8)
+#define DISPC_DBI_RDATA (0x00ac)
+#define DISPC_DBI_CMD (0x00b0)
+#define DISPC_DBI_DATA (0x00b4)
+#define DISPC_DBI_QUEUE (0x00b8)
+#define DISPC_TE_SYNC_DELAY (0x00bc)
+
+
+//shadow register , read only
+#define SHDW_IMG_CTRL (0x00E0)
+#define SHDW_IMG_Y_BASE_ADDR (0x00E4)
+#define SHDW_IMG_UV_BASE_ADDR (0x00E8)
+#define SHDW_IMG_V_BASE_ADDR (0x00EC)
+#define SHDW_IMG_SIZE_XY (0x00F0)
+#define SHDW_IMG_PITCH (0x00F4)
+#define SHDW_IMG_DISP_XY (0x00F8)
+#define SHDW_BG_COLOR (0x00FC)
+#define SHDW_OSD_CTRL (0x0100)
+#define SHDW_OSD_BASE_ADDR (0x0104)
+#define SHDW_OSD_SIZE_XY (0x0108)
+#define SHDW_OSD_PITCH (0x010C)
+#define SHDW_OSD_DISP_XY (0x0110)
+#define SHDW_OSD_ALPHA (0x0114)
+#define SHDW_OSD_CK (0x0118)
+#define SHDW_Y2R_CTRL (0x0120)
+#define SHDW_Y2R_CONTRAST (0x0124)
+#define SHDW_Y2R_SATURATION (0x0128)
+#define SHDW_Y2R_BRIGHTNESS (0x012C)
+#define SHDW_DPI_H_TIMING (0x0130)
+#define SHDW_DPI_V_TIMING (0x0134)
+
+
+#define AHB_MATRIX_CLOCK (0x0208)
+#define REG_AHB_MATRIX_CLOCK (AHB_MATRIX_CLOCK + SPRD_AHB_BASE)
+
+#define DISPC_INT_DONE_MASK BIT(0)
+#define DISPC_INT_TE_MASK BIT(1)
+#define DISPC_INT_ERR_MASK BIT(2)
+#define DISPC_INT_EDPI_TE_MASK BIT(3)
+#define DISPC_INT_UPDATE_DONE_MASK BIT(4)
+#define DISPC_INT_DPI_VSYNC_MASK BIT(5)
+
+#if (defined(CONFIG_FB_SCX30G) || defined(CONFIG_FB_SCX35L))
+#define DISPC_INT_HWVSYNC DISPC_INT_DPI_VSYNC_MASK
+#else
+#define DISPC_INT_HWVSYNC DISPC_INT_DONE_MASK
+#endif
+
+typedef enum _DispC_Int_Type_
+{
+ DISPC_INT_DONE,
+ DISPC_INT_TE,
+ DISPC_INT_ERR,// underflow err
+ DISPC_INT_EDPI_TE,
+ DISPC_INT_UPDATE_DONE,
+ DISPC_INT_MAX,
+}DispC_Int_Type;
+
+#define DISPC_INTERRUPT_SET(bit,val)\
+{\
+ uint32_t reg_val = dispc_read(DISPC_INT_EN);\
+ reg_val = (val == 1)?(reg_val | (1UL<<bit)):(reg_val & (~(1UL<<bit)));\
+ dispc_write(reg_val, DISPC_INT_EN);\
+}
+
+#ifdef CONFIG_OF
+extern unsigned long g_dispc_base_addr;
+#endif
+
+static inline uint32_t dispc_read(uint32_t reg)
+{
+#ifdef CONFIG_OF
+ return __raw_readl(g_dispc_base_addr+ reg);
+#else
+ return __raw_readl(SPRD_DISPC_BASE + reg);
+#endif
+}
+
+static inline void dispc_write(uint32_t value, uint32_t reg)
+{
+#ifdef CONFIG_OF
+ __raw_writel(value, (g_dispc_base_addr + reg));
+#else
+ __raw_writel(value, (SPRD_DISPC_BASE + reg));
+#endif
+}
+
+static inline void dispc_set_bits(uint32_t bits, uint32_t reg)
+{
+ dispc_write(dispc_read(reg) | bits, reg);
+}
+
+static inline void dispc_clear_bits(uint32_t bits, uint32_t reg)
+{
+ dispc_write(dispc_read(reg) & ~bits, reg);
+}
+
+#endif
diff --git a/drivers/video/sprdfb/sprdfb_dsi.c b/drivers/video/sprdfb/sprdfb_dsi.c
new file mode 100644
index 00000000..7f0e8b81
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_dsi.c
@@ -0,0 +1,1010 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kgdb.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/irqreturn.h>
+#include <linux/interrupt.h>
+#ifdef CONFIG_OF
+#include <linux/fb.h>
+
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#endif
+
+#include "sprdfb_chip_common.h"
+#include "sprdfb.h"
+#include "sprdfb_panel.h"
+
+#if (defined(CONFIG_FB_SCX30G) || defined(CONFIG_FB_SCX35L))
+#define FB_DSIH_VERSION_1P21A
+#endif
+
+#ifdef FB_DSIH_VERSION_1P21A
+#include "dsi_1_21a/mipi_dsih_local.h"
+#include "dsi_1_21a/mipi_dsih_dphy.h"
+#include "dsi_1_21a/mipi_dsih_hal.h"
+#include "dsi_1_21a/mipi_dsih_api.h"
+#else
+#include "dsi_1_10a/mipi_dsih_local.h"
+#include "dsi_1_10a/mipi_dsih_dphy.h"
+#include "dsi_1_10a/mipi_dsih_hal.h"
+#include "dsi_1_10a/mipi_dsih_api.h"
+#endif
+
+#define DSI_PHY_REF_CLOCK (26*1000)
+
+#define DSI_EDPI_CFG (0x6c)
+
+struct sprdfb_dsi_context {
+ struct clk *clk_dsi;
+ bool is_inited;
+ uint32_t status;/*0- normal, 1- uninit, 2-abnormal*/
+ struct sprdfb_device *dev;
+
+ dsih_ctrl_t dsi_inst;
+};
+
+static struct sprdfb_dsi_context dsi_ctx;
+#ifdef CONFIG_OF
+unsigned long g_dsi_base_addr = 0;
+EXPORT_SYMBOL(g_dsi_base_addr);
+#endif
+
+
+static int32_t sprdfb_dsi_set_lp_mode(void);
+static int32_t sprdfb_dsi_set_ulps_mode(void);
+
+static uint32_t dsi_core_read_function(unsigned long addr, uint32_t offset)
+{
+ return __raw_readl(addr + offset);
+}
+
+static void dsi_core_write_function(unsigned long addr, uint32_t offset, uint32_t data)
+{
+// __raw_writel(data, addr + offset);
+ __raw_writel(data, (addr + offset));
+}
+
+void dsi_core_or_function(unsigned long addr,unsigned int data)
+{
+ __raw_writel((__raw_readl(addr) | data), addr);
+}
+void dsi_core_and_function(unsigned long addr,unsigned int data)
+{
+ __raw_writel((__raw_readl(addr) & data), addr);
+}
+
+void dsi_irq_trick(void)
+{
+ /*enable ack_with_err_0 interrupt*/
+ DSI_INT_MASK0_SET(0, 0);
+}
+
+//static uint32_t sot_ever_happened = 0;
+static irqreturn_t dsi_isr0(int irq, void *data)
+{
+#ifdef FB_DSIH_VERSION_1P21A
+ uint32_t reg_val = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_ST0);
+#else
+ uint32_t reg_val = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_ST0);
+#endif
+
+ printk(KERN_ERR "sprdfb: [%s](0x%x)!\n", __FUNCTION__, reg_val);
+ /*
+ printk("Warning: sot_ever_happened:(0x%x)!\n",sot_ever_happened);
+ */
+ if(reg_val & 0x1) {
+/*
+ //sot_ever_happened = 1;
+ mask = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK0);
+ mask |= 0x1;
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK0, mask);
+*/
+ DSI_INT_MASK0_SET(0, 1);
+ }
+
+ //dsi_irq_trick(0,reg_val);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t dsi_isr1(int irq, void *data)
+{
+#ifdef FB_DSIH_VERSION_1P21A
+ uint32_t reg_val = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_ST1);
+#else
+ uint32_t reg_val = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_ST1);
+#endif
+ uint32_t i = 0;
+ struct sprdfb_dsi_context *dsi_ctx = (struct sprdfb_dsi_context *)data;
+ struct sprdfb_device *dev = dsi_ctx->dev;
+ dsih_ctrl_t* dsi_instance = &(dsi_ctx->dsi_inst);
+ dphy_t *phy = &(dsi_instance->phy_instance);
+ struct panel_spec* panel = dev->panel;
+ struct info_mipi * mipi = panel->info.mipi;
+
+ printk(KERN_ERR "sprdfb: [%s](0x%x)!\n", __FUNCTION__, reg_val);
+
+ if(BIT(7) == (reg_val & BIT(7))){
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PWR_UP, 0);
+ /*need delay 1us*/
+ printk("sprdfb: reset dsi host!\n");
+ printk("sprdfb: mipi->lan_number:%d ,mipi->phy_feq:%d \n",mipi->lan_number,mipi->phy_feq);
+ if(NULL == phy){
+ printk("sprdfb: the phy is null \n");
+ //dsi_irq_trick(1,reg_val);
+ return IRQ_NONE;
+ }
+
+ mipi_dsih_dphy_configure(phy, mipi->lan_number, mipi->phy_feq);
+
+ {/*for debug*/
+ for(i=0;i<256;i+=16){
+ printk("sprdfb: %x: 0x%x, 0x%x, 0x%x, 0x%x\n", i, dsi_core_read_function(SPRD_MIPI_DSIC_BASE, i),
+ dsi_core_read_function(SPRD_MIPI_DSIC_BASE, i+4),
+ dsi_core_read_function(SPRD_MIPI_DSIC_BASE, i+8),
+ dsi_core_read_function(SPRD_MIPI_DSIC_BASE, i+12));
+ }
+ printk("**************************\n");
+ }
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PWR_UP, 1);
+ }
+ //dsi_irq_trick(1,reg_val);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t dsi_isr2(int irq, void *data)
+{
+ uint32_t reg_val = 0;
+ struct sprdfb_dsi_context *dsi_ctx = (struct sprdfb_dsi_context *)data;
+ struct sprdfb_device *dev = dsi_ctx->dev;
+
+ printk(KERN_ERR "sprdfb: [%s](0x%x)!\n", __FUNCTION__, reg_val);
+
+ if(MIPI_PLL_TYPE_1 == dev->capability.mipi_pll_type) /* for PikeL / Pike */
+ {
+ reg_val = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_MIPI_PLL_INT_STS);
+ if(BIT(0) == (reg_val & BIT(0)))
+ {
+ dsi_core_or_function(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_MIPI_PLL_INT_CLR, BIT(0));
+ printk("sprdfb: [%s], mipi pll interrupt!\n",__FUNCTION__);
+ dsi_core_and_function(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_MIPI_PLL_INT_MSK, 0xFFFFFFFE);
+ }
+ }
+ else if(MIPI_PLL_TYPE_2 == dev->capability.mipi_pll_type) /* for Sharkl64 / SharklT8*/
+ {
+ dsi_core_or_function(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_MIPI_PLL_INT_CLR, BIT(0));
+ printk("sprdfb: [%s], mipi pll interrupt!\n",__FUNCTION__);
+ dsi_core_or_function(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_MIPI_PLL_INT_EN, BIT(0));
+ }
+ return IRQ_HANDLED;
+}
+
+static void dsi_reset(void)
+{
+ sci_glb_set(DSI_AHB_SOFT_RST, BIT_DSI_SOFT_RST);
+ udelay(10);
+ sci_glb_clr(DSI_AHB_SOFT_RST, BIT_DSI_SOFT_RST);
+}
+
+static int32_t dsi_edpi_setbuswidth(struct info_mipi * mipi)
+{
+ dsih_color_coding_t color_coding = 0;
+
+ switch(mipi->video_bus_width){
+ case 16:
+ color_coding = COLOR_CODE_16BIT_CONFIG1;
+ break;
+ case 18:
+ color_coding = COLOR_CODE_18BIT_CONFIG1;
+ break;
+ case 24:
+ color_coding = COLOR_CODE_24BIT;
+ break;
+ default:
+ printk(KERN_ERR "sprdfb: [%s] fail, invalid video_bus_width\n", __FUNCTION__);
+ return 0;
+ }
+
+#ifdef FB_DSIH_VERSION_1P21A
+ dsi_core_and_function((SPRD_MIPI_DSIC_BASE+R_DSI_HOST_DPI_COLOR_CODE),0xfffffff0);
+ dsi_core_or_function((SPRD_MIPI_DSIC_BASE+R_DSI_HOST_DPI_COLOR_CODE),color_coding);
+#else
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_DPI_CFG, ((uint32_t)color_coding<<2));
+#endif
+ return 0;
+}
+
+
+static int32_t dsi_edpi_init(void)
+{
+#ifdef FB_DSIH_VERSION_1P21A
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_EDPI_CMD_SIZE, 0x500);
+#else
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, DSI_EDPI_CFG, 0x10500);
+#endif
+ return 0;
+}
+
+int32_t dsi_dpi_init(struct sprdfb_device *dev)
+{
+ dsih_dpi_video_t dpi_param = {0};
+ dsih_error_t result;
+ struct panel_spec* panel = dev->panel;
+ struct info_mipi * mipi = panel->info.mipi;
+
+ dpi_param.no_of_lanes = mipi->lan_number;
+ dpi_param.byte_clock = mipi->phy_feq / 8;
+#ifndef CONFIG_SC_FPGA
+ dpi_param.pixel_clock = dev->dpi_clock/1000;
+#else
+ dpi_param.pixel_clock = 6500;
+#endif
+#ifdef FB_DSIH_VERSION_1P21A
+ dpi_param.max_hs_to_lp_cycles = 4;//110;
+ dpi_param.max_lp_to_hs_cycles = 15;//10;
+ dpi_param.max_clk_hs_to_lp_cycles = 4;//110;
+ dpi_param.max_clk_lp_to_hs_cycles = 15;//10;
+#endif
+
+ switch(mipi->video_bus_width){
+ case 16:
+ dpi_param.color_coding = COLOR_CODE_16BIT_CONFIG1;
+ break;
+ case 18:
+ dpi_param.color_coding = COLOR_CODE_18BIT_CONFIG1;
+ break;
+ case 24:
+ dpi_param.color_coding = COLOR_CODE_24BIT;
+ break;
+ default:
+ printk(KERN_ERR "sprdfb: [%s] fail, invalid video_bus_width\n", __FUNCTION__);
+ break;
+ }
+
+ if(SPRDFB_POLARITY_POS == mipi ->h_sync_pol){
+ dpi_param.h_polarity = 1;
+ }
+
+ if(SPRDFB_POLARITY_POS == mipi ->v_sync_pol){
+ dpi_param.v_polarity = 1;
+ }
+
+ if(SPRDFB_POLARITY_POS == mipi ->de_pol){
+ dpi_param.data_en_polarity = 1;
+ }
+
+ dpi_param.h_active_pixels = panel->width;
+ dpi_param.h_sync_pixels = mipi->timing->hsync;
+ dpi_param.h_back_porch_pixels = mipi->timing->hbp;
+ dpi_param.h_total_pixels = panel->width + mipi->timing->hsync + mipi->timing->hbp + mipi->timing->hfp;
+
+ dpi_param.v_active_lines = panel->height;
+ dpi_param.v_sync_lines = mipi->timing->vsync;
+ dpi_param.v_back_porch_lines = mipi->timing->vbp;
+ dpi_param.v_total_lines = panel->height + mipi->timing->vsync + mipi->timing->vbp + mipi->timing->vfp;
+
+ dpi_param.receive_ack_packets = 0;
+ dpi_param.video_mode = VIDEO_BURST_WITH_SYNC_PULSES;
+ dpi_param.virtual_channel = 0;
+#ifndef CONFIG_FB_LCD_ILI9486S1_MIPI
+ dpi_param.is_18_loosely = 0;
+#else
+ dpi_param.is_18_loosely = 1;
+#endif
+
+ result = mipi_dsih_dpi_video(&(dsi_ctx.dsi_inst), &dpi_param);
+ if(result != OK){
+ printk(KERN_ERR "sprdfb: [%s] mipi_dsih_dpi_video fail (%d)!\n", __FUNCTION__, result);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void dsi_log_error(const char * string)
+{
+ printk(string);
+}
+
+static int32_t dsi_module_init(struct sprdfb_device *dev)
+{
+ int ret = 0;
+ dsih_ctrl_t* dsi_instance = &(dsi_ctx.dsi_inst);
+ dphy_t *phy = &(dsi_instance->phy_instance);
+
+ struct info_mipi * mipi = dev->panel->info.mipi;
+
+ int irq_num_1, irq_num_2, irq_num_3;
+
+ pr_debug(KERN_INFO "sprdfb: [%s]\n", __FUNCTION__);
+
+ if(dsi_ctx.is_inited){
+ printk(KERN_INFO "sprdfb: dsi_module_init. is_inited==true!");
+ return 0;
+ }
+ else{
+ printk(KERN_INFO "sprdfb: dsi_module_init. call only once!");
+ }
+
+ phy->address = SPRD_MIPI_DSIC_BASE;
+ phy->core_read_function = dsi_core_read_function;
+ phy->core_write_function = dsi_core_write_function;
+ phy->log_error = dsi_log_error;
+ phy->log_info = NULL;
+ phy->reference_freq = DSI_PHY_REF_CLOCK;
+
+ dsi_instance->address = SPRD_MIPI_DSIC_BASE;
+ //dsi_instance->color_mode_polarity =mipi->color_mode_pol;
+ //dsi_instance->shut_down_polarity = mipi->shut_down_pol;
+ dsi_instance->core_read_function = dsi_core_read_function;
+ dsi_instance->core_write_function = dsi_core_write_function;
+ dsi_instance->log_error = dsi_log_error;
+ dsi_instance->log_info = NULL;
+ /*in our rtl implementation, this is max rd time, not bta time and use 15bits*/
+ dsi_instance->max_bta_cycles = 0x6000;//10;
+#ifndef FB_DSIH_VERSION_1P21A
+ dsi_instance->max_hs_to_lp_cycles = 4;//110;
+ dsi_instance->max_lp_to_hs_cycles = 15;//10;
+#endif
+ //dsi_instance->max_lanes = mipi->lan_number;
+#ifdef CONFIG_OF
+ irq_num_1 = irq_of_parse_and_map(dev->of_dev->of_node, 1);
+#else
+ irq_num_1 = IRQ_DSI_INTN0;
+#endif
+ printk("sprdfb: dsi irq_num_1 = %d\n", irq_num_1);
+
+// ret = request_irq(IRQ_DSI_INTN0, dsi_isr0, IRQF_DISABLED, "DSI_INT0", &dsi_ctx);
+ ret = request_irq(irq_num_1, dsi_isr0, IRQF_DISABLED, "DSI_INT0", &dsi_ctx);
+ if (ret) {
+ printk(KERN_ERR "sprdfb: dsi failed to request irq int0!\n");
+// clk_disable(dsi_ctx.clk_dsi);
+ }else{
+ printk(KERN_ERR "sprdfb: dsi request irq int0 OK!\n");
+ }
+
+#ifdef CONFIG_OF
+ irq_num_2 = irq_of_parse_and_map(dev->of_dev->of_node, 2);
+#else
+ irq_num_2 = IRQ_DSI_INTN1;
+#endif
+ printk("sprdfb: dsi irq_num_2 = %d\n", irq_num_2);
+
+// ret = request_irq(IRQ_DSI_INTN1, dsi_isr1, IRQF_DISABLED, "DSI_INT1", &dsi_ctx);
+ ret = request_irq(irq_num_2, dsi_isr1, IRQF_DISABLED, "DSI_INT1", &dsi_ctx);
+ if (ret) {
+ printk(KERN_ERR "sprdfb: dsi failed to request irq int1!\n");
+// clk_disable(dsi_ctx.clk_dsi);
+ }else{
+ printk(KERN_ERR "sprdfb: dsi request irq int1 OK!\n");
+ }
+
+ if((dev->capability.mipi_pll_type > MIPI_PLL_TYPE_NONE)
+ && (dev->capability.mipi_pll_type < MIPI_PLL_TYPE_LIMIT))
+ {
+#ifdef CONFIG_OF
+ irq_num_3 = irq_of_parse_and_map(dev->of_dev->of_node, 3);
+#else
+ irq_num_3 = IRQ_DSI_INTN2;
+#endif
+ printk("sprdfb: dsi irq_num_3 = %d\n", irq_num_3);
+
+ ret = request_irq(irq_num_3, dsi_isr2, IRQF_DISABLED, "DSI_INT2", &dsi_ctx);
+ if (ret) {
+ printk(KERN_ERR "sprdfb: dsi failed to request irq int2!\n");
+ }else{
+ printk(KERN_ERR "sprdfb: dsi request irq int2 OK!\n");
+ }
+
+ if(MIPI_PLL_TYPE_1 == dev->capability.mipi_pll_type) {
+ dsi_core_and_function(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_MIPI_PLL_INT_MSK, 0xFFFFFFFE);
+ } else if (MIPI_PLL_TYPE_2 == dev->capability.mipi_pll_type) {
+ dsi_core_and_function(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_MIPI_PLL_INT_MSK, 0xFFFFFFFE);
+ dsi_core_or_function(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_MIPI_PLL_INT_EN, BIT(0));
+ }
+ }
+
+ dsi_ctx.is_inited = true;
+
+ return 0;
+}
+
+#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING
+int sprdfb_dsi_chg_dphy_freq(struct sprdfb_device *fb_dev,
+ u32 dphy_freq)
+{
+ dsih_error_t result = OK;
+ dsih_ctrl_t *ctrl = &(dsi_ctx.dsi_inst);
+ struct info_mipi *mipi = fb_dev->panel->info.mipi;
+
+ if (ctrl->status == INITIALIZED) {
+ pr_info("Let's do update D-PHY frequency(%u)\n", dphy_freq);
+ ctrl->phy_instance.phy_keep_work = true;
+ result = mipi_dsih_dphy_configure(&ctrl->phy_instance,
+ mipi->lan_number, dphy_freq);
+ if (result != OK) {
+ pr_err("[%s]: mipi_dsih_dphy_configure fail (%d)\n",
+ __func__, result);
+ ctrl->phy_instance.phy_keep_work = false;
+ return -1;
+ }
+ ctrl->phy_instance.phy_keep_work = false;
+ }
+ mipi->phy_feq = dphy_freq;
+ return 0;
+}
+#else
+int sprdfb_dsi_chg_dphy_freq(struct sprdfb_device *fb_dev,
+ u32 dphy_freq)
+{
+ return -EINVAL;
+}
+#endif
+
+int32_t sprdfb_dsih_init(struct sprdfb_device *dev)
+{
+ dsih_error_t result = OK;
+ dsih_ctrl_t* dsi_instance = &(dsi_ctx.dsi_inst);
+ dphy_t *phy = &(dsi_instance->phy_instance);
+ struct info_mipi * mipi = dev->panel->info.mipi;
+ int wait_count = 0;
+#ifdef FB_DSIH_VERSION_1P21A
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_MSK0, 0x1fffff);
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_MSK1, 0x3ffff);
+#else
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK0, 0x1fffff);
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK1, 0x3ffff);
+#endif
+
+ if(SPRDFB_MIPI_MODE_CMD == mipi->work_mode){
+ dsi_edpi_init();
+ }/*else{
+ dsi_dpi_init(dev->panel);
+ }*/
+
+/*
+ result = mipi_dsih_unregister_all_events(dsi_instance);
+ if(OK != result){
+ printk(KERN_ERR "sprdfb: [%s]: mipi_dsih_unregister_all_events fail (%d)!\n", __FUNCTION__, result);
+ return -1;
+ }
+*/
+// dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK0, 0x1fffff);
+// dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK1, 0x3ffff);
+
+ dsi_instance->phy_feq = dev->panel->info.mipi->phy_feq;
+ dsi_instance->max_lanes = dev->panel->info.mipi->lan_number;
+ dsi_instance->color_mode_polarity =dev->panel->info.mipi->color_mode_pol;
+ dsi_instance->shut_down_polarity = dev->panel->info.mipi->shut_down_pol;
+
+ result = mipi_dsih_open(dsi_instance);
+ if(OK != result){
+ printk(KERN_ERR "sprdfb: [%s]: mipi_dsih_open fail (%d)!\n", __FUNCTION__, result);
+ dsi_ctx.status = 1;
+ return -1;
+ }
+
+ result = mipi_dsih_dphy_configure(phy, mipi->lan_number, mipi->phy_feq);
+ if(OK != result){
+ printk(KERN_ERR "sprdfb: [%s]: mipi_dsih_dphy_configure fail (%d)!\n", __FUNCTION__, result);
+ dsi_ctx.status = 1;
+ return -1;
+ }
+
+ while(5 != (dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PHY_STATUS) & 5) &&
+ (wait_count < 100000)){
+ udelay(3);
+ if(0x0 == ++wait_count%1000){
+ printk("sprdfb: [%s] warning: busy waiting!\n", __FUNCTION__);
+ }
+ }
+ if(wait_count >= 100000){
+ printk("sprdfb: [%s] Errior: dsi phy can't be locked!!!\n", __FUNCTION__);
+ }
+ if(wait_count >= 100000){
+ printk("sprdfb: [%s] Errior: dsi phy can't be locked!!!\n", __FUNCTION__);
+ }
+
+ if(SPRDFB_MIPI_MODE_CMD == mipi->work_mode){
+ dsi_edpi_setbuswidth(mipi);
+ }
+
+ result = mipi_dsih_enable_rx(dsi_instance, 1);
+ if(OK != result){
+ printk(KERN_ERR "sprdfb: [%s]: mipi_dsih_enable_rx fail (%d)!\n", __FUNCTION__, result);
+ dsi_ctx.status = 1;
+ return -1;
+ }
+
+ result = mipi_dsih_ecc_rx(dsi_instance, 1);
+ if(OK != result){
+ printk(KERN_ERR "sprdfb: [%s]: mipi_dsih_ecc_rx fail (%d)!\n", __FUNCTION__, result);
+ dsi_ctx.status = 1;
+ return -1;
+ }
+
+ result = mipi_dsih_eotp_rx(dsi_instance, 1);
+ if(OK != result){
+ printk(KERN_ERR "sprdfb: [%s]: mipi_dsih_eotp_rx fail (%d)!\n", __FUNCTION__, result);
+ dsi_ctx.status = 1;
+ return -1;
+ }
+
+ result = mipi_dsih_eotp_tx(dsi_instance, 1);
+ if(OK != result){
+ printk(KERN_ERR "sprdfb: [%s]: mipi_dsih_eotp_tx fail (%d)!\n", __FUNCTION__, result);
+ dsi_ctx.status = 1;
+ return -1;
+ }
+
+ if(SPRDFB_MIPI_MODE_VIDEO == mipi->work_mode){
+ dsi_dpi_init(dev);
+ }
+
+#ifdef FB_DSIH_VERSION_1P21A
+ mipi_dsih_dphy_enable_nc_clk(&(dsi_instance->phy_instance), false);
+#endif
+ dsi_ctx.status = 0;
+
+ return 0;
+}
+
+int32_t sprdfb_dsi_init(struct sprdfb_device *dev)
+{
+ dsih_error_t result = OK;
+ dsih_ctrl_t* dsi_instance = &(dsi_ctx.dsi_inst);
+#ifdef CONFIG_OF
+ struct resource r;
+#endif
+
+ dsi_ctx.dev = dev;
+
+#ifdef CONFIG_OF
+ if(0 == g_dsi_base_addr){
+ if(0 != of_address_to_resource(dev->of_dev->of_node, 1, &r)){
+ printk(KERN_ERR "sprdfb: sprdfb_dsi_init fail. (can't get register base address)\n");
+ return -1;
+ }
+ g_dsi_base_addr = (unsigned long)ioremap_nocache(r.start, resource_size(&r));
+ }
+ if (0 == g_dsi_base_addr){
+ printk("sprdfb: g_dsi_base_addr = 0!(0x%ul)\n", r.start);
+ return -ENOMEM;
+ }
+ printk("sprdfb: set g_dsi_base_addr = 0x%lx\n", g_dsi_base_addr);
+#endif
+
+
+ if(!dsi_ctx.is_inited){
+ //init
+ if(dev->panel_ready){
+ //panel ready
+ printk(KERN_INFO "sprdfb: [%s]: dsi has alread initialized\n", __FUNCTION__);
+ dsi_instance->status = INITIALIZED;
+ dsi_instance->phy_instance.status = INITIALIZED;
+ dsi_module_init(dev);
+#ifdef FB_DSIH_VERSION_1P21A
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_MSK0, 0x0);
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_MSK1, 0x800);
+#else
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK0, 0x0);
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK1, 0x800);
+#endif
+ }else{
+ //panel not ready
+ printk(KERN_INFO "sprdfb: [%s]: dsi is not initialized\n", __FUNCTION__);
+ dsi_enable();
+ dsi_reset();
+ dsi_module_init(dev);
+ result=sprdfb_dsih_init(dev);
+ }
+ }else{
+ //resume
+ printk(KERN_INFO "sprdfb: [%s]: resume\n", __FUNCTION__);
+ dsi_enable();
+ dsi_reset();
+ result=sprdfb_dsih_init(dev);
+ }
+
+ return result;
+}
+
+int32_t sprdfb_dsi_uninit(struct sprdfb_device *dev)
+{
+ dsih_error_t result;
+ dsih_ctrl_t* dsi_instance = &(dsi_ctx.dsi_inst);
+ printk(KERN_INFO "sprdfb: [%s], dev_id = %d\n",__FUNCTION__, dev->dev_id);
+#ifdef FB_DSIH_VERSION_1P21A
+ mipi_dsih_dphy_enable_hs_clk(&(dsi_instance->phy_instance), false);
+#else
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PHY_IF_CTRL, 0);
+#endif
+ result = mipi_dsih_close(&(dsi_ctx.dsi_inst));
+ dsi_instance->status = NOT_INITIALIZED;
+
+ dsi_ctx.status = 1;
+
+ if(OK != result){
+ printk(KERN_ERR "sprdfb: [%s]: sprdfb_dsi_uninit fail (%d)!\n", __FUNCTION__, result);
+ return -1;
+ }
+
+ msleep(10);
+ dsi_disable();
+ return 0;
+}
+
+int32_t sprdfb_dsi_suspend(struct sprdfb_device *dev)
+{
+ dsih_ctrl_t* dsi_instance = &(dsi_ctx.dsi_inst);
+ printk(KERN_INFO "sprdfb: [%s], dev_id = %d\n",__FUNCTION__, dev->dev_id);
+// sprdfb_dsi_uninit(dev);
+// mipi_dsih_dphy_close(&(dsi_instance->phy_instance));
+// mipi_dsih_dphy_shutdown(&(dsi_instance->phy_instance), 0);
+ mipi_dsih_hal_power(dsi_instance, 0);
+
+ return 0;
+}
+
+int32_t sprdfb_dsi_resume(struct sprdfb_device *dev)
+{
+ dsih_ctrl_t* dsi_instance = &(dsi_ctx.dsi_inst);
+#if 0
+ dsih_error_t result = OK;
+ dphy_t *phy = &(dsi_instance->phy_instance);
+ struct info_mipi * mipi = dev->panel->info.mipi;
+#endif
+ printk(KERN_INFO "sprdfb: [%s], dev_id = %d\n",__FUNCTION__, dev->dev_id);
+
+#if 0
+ result = mipi_dsih_dphy_open(&(dsi_instance->phy_instance));
+ if(0 != result){
+ printk("Jessica: mipi_dsih_dphy_open fail!(%d)\n",result);
+ }
+ udelay(100);
+#endif
+// mipi_dsih_dphy_shutdown(&(dsi_instance->phy_instance), 1);
+ mipi_dsih_hal_power(dsi_instance, 1);
+
+#if 0
+ result = mipi_dsih_dphy_configure(phy, mipi->lan_number, mipi->phy_feq);
+ if(OK != result){
+ printk(KERN_ERR "sprdfb: [%s]: mipi_dsih_dphy_configure fail (%d)!\n", __FUNCTION__, result);
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+int32_t sprdfb_dsi_ready(struct sprdfb_device *dev)
+{
+ struct info_mipi * mipi = dev->panel->info.mipi;
+
+ if(SPRDFB_MIPI_MODE_CMD == mipi->work_mode){
+ mipi_dsih_cmd_mode(&(dsi_ctx.dsi_inst), 1);
+#ifdef FB_DSIH_VERSION_1P21A
+ mipi_dsih_dphy_enable_hs_clk(&(dsi_ctx.dsi_inst.phy_instance), true);
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_CMD_MODE_CFG, 0x0);
+#else
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_CMD_MODE_CFG, 0x1);
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PHY_IF_CTRL, 0x1);
+#endif
+ }else{
+#ifdef FB_DSIH_VERSION_1P21A
+ mipi_dsih_dphy_enable_hs_clk(&(dsi_ctx.dsi_inst.phy_instance), true);
+#else
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PHY_IF_CTRL, 0x1);
+#endif
+ mipi_dsih_video_mode(&(dsi_ctx.dsi_inst), 1);
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PWR_UP, 0);
+ udelay(100);
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PWR_UP, 1);
+ usleep_range(3000, 3500);
+#ifdef FB_DSIH_VERSION_1P21A
+ dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_ST0);
+ dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_ST1);
+#else
+ dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_ST0);
+ dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_ST1);
+#endif
+ }
+
+#ifdef FB_DSIH_VERSION_1P21A
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_MSK0, 0x0);
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_MSK1, 0x800);
+#else
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK0, 0x0);
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK1, 0x800);
+#endif
+ return 0;
+}
+
+int32_t sprdfb_dsi_before_panel_reset(struct sprdfb_device *dev)
+{
+ sprdfb_dsi_set_lp_mode();
+ return 0;
+}
+
+int32_t sprdfb_dsi_enter_ulps(struct sprdfb_device *dev)
+{
+ sprdfb_dsi_set_ulps_mode();
+ return 0;
+}
+
+uint32_t sprdfb_dsi_get_status(struct sprdfb_device *dev)
+{
+ return dsi_ctx.status;
+}
+
+static int32_t sprdfb_dsi_set_cmd_mode(void)
+{
+ mipi_dsih_cmd_mode(&(dsi_ctx.dsi_inst), 1);
+ return 0;
+}
+
+static int32_t sprdfb_dsi_set_video_mode(void)
+{
+ mipi_dsih_video_mode(&(dsi_ctx.dsi_inst), 1);
+ return 0;
+}
+
+static int32_t sprdfb_dsi_set_lp_mode(void)
+{
+#ifndef FB_DSIH_VERSION_1P21A
+ uint32_t reg_val;
+#endif
+ pr_debug(KERN_INFO "sprdfb: [%s]\n",__FUNCTION__);
+
+ mipi_dsih_cmd_mode(&(dsi_ctx.dsi_inst), 1);
+#ifdef FB_DSIH_VERSION_1P21A
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_CMD_MODE_CFG, 0x01ffff00);
+ mipi_dsih_dphy_enable_hs_clk(&(dsi_ctx.dsi_inst.phy_instance), false);
+#else
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_CMD_MODE_CFG, 0x1fff);
+ reg_val = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PHY_IF_CTRL);
+ reg_val = reg_val & (~(BIT(0)));
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PHY_IF_CTRL, reg_val);
+#endif
+ return 0;
+}
+
+static int32_t sprdfb_dsi_set_hs_mode(void)
+{
+ pr_debug(KERN_INFO "sprdfb: [%s]\n",__FUNCTION__);
+
+ mipi_dsih_cmd_mode(&(dsi_ctx.dsi_inst), 1);
+#ifdef FB_DSIH_VERSION_1P21A
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_CMD_MODE_CFG, 0x0);
+ mipi_dsih_dphy_enable_hs_clk(&(dsi_ctx.dsi_inst.phy_instance), true);
+#else
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_CMD_MODE_CFG, 0x1);
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PHY_IF_CTRL, 0x1);
+#endif
+ return 0;
+}
+
+static int32_t sprdfb_dsi_set_ulps_mode(void)
+{
+ mipi_dsih_ulps_mode(&(dsi_ctx.dsi_inst), 1);
+ return 0;
+}
+
+static int32_t sprdfb_dsi_set_data_lp_mode(void)
+{
+// pr_debug(KERN_INFO "sprdfb: [%s]\n",__FUNCTION__);
+
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_CMD_MODE_CFG, 0x1fff);
+
+ return 0;
+}
+
+static int32_t sprdfb_dsi_set_data_hs_mode(void)
+{
+ int active_mode = mipi_dsih_active_mode(&(dsi_ctx.dsi_inst));
+// pr_debug(KERN_INFO "sprdfb: [%s]\n",__FUNCTION__);
+
+// printk("aoke sprdfb: set data hs mode active_mode=%d\n",active_mode);
+ if(1==active_mode){
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_CMD_MODE_CFG, 0x1);
+ }else{
+ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_CMD_MODE_CFG, 0x0);
+ }
+ return 0;
+}
+
+static int32_t sprdfb_dsi_gen_write(uint8_t *param, uint16_t param_length)
+{
+ dsih_error_t result;
+
+ result = mipi_dsih_gen_wr_cmd(&(dsi_ctx.dsi_inst), 0, param, param_length);
+ if(OK != result){
+ printk(KERN_ERR "sprdfb: [%s] error (%d)\n", __FUNCTION__, result);
+ return -1;
+ }
+ return 0;
+}
+
+#define LCM_SEND(len) ((1 << 24)| len)
+#define LCM_TAG_MASK ((1 << 24) -1)
+
+static unsigned char set_bl_seq[] = {
+#ifndef CONFIG_MACH_TSHARK2TABE
+ 0x51, 0xFF
+#else
+ 0xF5, 0x8B
+#endif
+};
+
+void backlight_control(int brigtness)
+{
+ set_bl_seq[1] = brigtness;
+ sprdfb_dsi_gen_write(set_bl_seq, LCM_SEND(2) & LCM_TAG_MASK);
+}
+EXPORT_SYMBOL(backlight_control);
+
+
+static int32_t sprdfb_dsi_gen_read(uint8_t *param, uint16_t param_length, uint8_t bytes_to_read, uint8_t *read_buffer)
+{
+ uint16_t result;
+ uint32_t reg_val, reg_val_1, reg_val_2;
+ result = mipi_dsih_gen_rd_cmd(&(dsi_ctx.dsi_inst), 0, param, param_length, bytes_to_read, read_buffer);
+
+ reg_val = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_PHY_STATUS);
+#ifdef FB_DSIH_VERSION_1P21A
+ reg_val_1 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_INT_ST0);
+ reg_val_2 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_INT_ST1);
+#else
+ reg_val_1 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_ERROR_ST0);
+ reg_val_2 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_ERROR_ST1);
+#endif
+ if(0 != (reg_val & 0x2)){
+ printk("sprdfb: [%s] mipi read hang (0x%x)!\n", __FUNCTION__, reg_val);
+ dsi_ctx.status = 2;
+ result = 0;
+ }
+
+ if(0 != (reg_val_1 & 0x701)){
+ printk("sprdfb: [%s] mipi read status error!(0x%x, 0x%x)\n", __FUNCTION__, reg_val_1, reg_val_2);
+ result = 0;
+ }
+
+ if(0 == result){
+ printk(KERN_ERR "sprdfb: [%s] return error (%d)\n", __FUNCTION__, result);
+ return -1;
+ }
+ return 0;
+}
+
+static int32_t sprdfb_dsi_dcs_write(uint8_t *param, uint16_t param_length)
+{
+ dsih_error_t result;
+ result = mipi_dsih_dcs_wr_cmd(&(dsi_ctx.dsi_inst), 0, param, param_length);
+ if(OK != result){
+ printk(KERN_ERR "sprdfb: [%s] error (%d)\n", __FUNCTION__, result);
+ return -1;
+ }
+ return 0;
+}
+
+static int32_t sprdfb_dsi_dcs_read(uint8_t command, uint8_t bytes_to_read, uint8_t *read_buffer)
+{
+ uint16_t result;
+ uint32_t reg_val, reg_val_1, reg_val_2;
+
+ result = mipi_dsih_dcs_rd_cmd(&(dsi_ctx.dsi_inst), 0, command, bytes_to_read, read_buffer);
+ reg_val = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_PHY_STATUS);
+#ifdef FB_DSIH_VERSION_1P21A
+ reg_val_1 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_INT_ST0);
+ reg_val_2 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_INT_ST1);
+#else
+ reg_val_1 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_ERROR_ST0);
+ reg_val_2 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_ERROR_ST1);
+#endif
+ if(0 != (reg_val & 0x2)){
+ printk("sprdfb: [%s] mipi read hang (0x%x)!\n", __FUNCTION__, reg_val);
+ dsi_ctx.status = 2;
+ result = 0;
+ }
+
+ if(0 != (reg_val_1 & 0x701)){
+ printk("sprdfb: [%s] mipi read status error!(0x%x, 0x%x)\n", __FUNCTION__, reg_val_1, reg_val_2);
+ result = 0;
+ }
+
+ if(0 == result){
+ printk(KERN_ERR "sprdfb: [%s] return error (%d)\n", __FUNCTION__, result);
+ return -1;
+ }
+ return 0;
+}
+
+static int32_t sprd_dsi_force_write(uint8_t data_type, uint8_t *p_params, uint16_t param_length)
+{
+ int32_t iRtn = 0;
+
+ iRtn = mipi_dsih_gen_wr_packet(&(dsi_ctx.dsi_inst), 0, data_type, p_params, param_length);
+
+ return iRtn;
+}
+
+static int32_t sprd_dsi_force_read(uint8_t command, uint8_t bytes_to_read, uint8_t * read_buffer)
+{
+ int32_t iRtn = 0;
+ uint32_t reg_val, reg_val_1, reg_val_2;
+
+ iRtn = mipi_dsih_gen_rd_packet(&(dsi_ctx.dsi_inst), 0, 6, 0, command, bytes_to_read, read_buffer);
+
+ reg_val = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_PHY_STATUS);
+#ifdef FB_DSIH_VERSION_1P21A
+ reg_val_1 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_INT_ST0);
+ reg_val_2 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_INT_ST1);
+#else
+ reg_val_1 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_ERROR_ST0);
+ reg_val_2 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_ERROR_ST1);
+#endif
+ if(0 != (reg_val & 0x2)){
+ printk("sprdfb: [%s] mipi read hang (0x%x)!\n", __FUNCTION__, reg_val);
+ dsi_ctx.status = 2;
+ iRtn = 0;
+ }
+
+ if(0 != (reg_val_1 & 0x701)){
+ printk("sprdfb: [%s] mipi read status error!(0x%x, 0x%x)\n", __FUNCTION__, reg_val_1, reg_val_2);
+ iRtn = 0;
+ }
+
+
+ if(0 == iRtn){
+ printk(KERN_ERR "sprdfb: [%s] return error (%d)\n", __FUNCTION__, iRtn);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int32_t sprd_dsi_eotp_set(uint8_t rx_en, uint8_t tx_en)
+{
+ dsih_ctrl_t *curInstancePtr = &(dsi_ctx.dsi_inst);
+ if(0 == rx_en)
+ mipi_dsih_eotp_rx(curInstancePtr, 0);
+ else if(1 == rx_en)
+ mipi_dsih_eotp_rx(curInstancePtr, 1);
+ if(0 == tx_en)
+ mipi_dsih_eotp_tx(curInstancePtr, 0);
+ else if(1 == tx_en)
+ mipi_dsih_eotp_tx(curInstancePtr, 1);
+ return 0;
+}
+
+struct ops_mipi sprdfb_mipi_ops = {
+ .mipi_set_cmd_mode = sprdfb_dsi_set_cmd_mode,
+ .mipi_set_video_mode = sprdfb_dsi_set_video_mode,
+ .mipi_set_lp_mode = sprdfb_dsi_set_lp_mode,
+ .mipi_set_hs_mode = sprdfb_dsi_set_hs_mode,
+ .mipi_set_data_lp_mode = sprdfb_dsi_set_data_lp_mode,
+ .mipi_set_data_hs_mode = sprdfb_dsi_set_data_hs_mode,
+ .mipi_gen_write = sprdfb_dsi_gen_write,
+ .mipi_gen_read = sprdfb_dsi_gen_read,
+ .mipi_dcs_write = sprdfb_dsi_dcs_write,
+ .mipi_dcs_read = sprdfb_dsi_dcs_read,
+ .mipi_force_write = sprd_dsi_force_write,
+ .mipi_force_read = sprd_dsi_force_read,
+ .mipi_eotp_set = sprd_dsi_eotp_set,
+};
+
+
+
diff --git a/drivers/video/sprdfb/sprdfb_gpio2spi.c b/drivers/video/sprdfb/sprdfb_gpio2spi.c
new file mode 100644
index 00000000..892be6d5
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_gpio2spi.c
@@ -0,0 +1,199 @@
+/*
+ * drivers/video/sprdfb/lcd/lcd_ili6150_lvds.c
+ *
+ * Copyright (C) 2014 Spreadtrum Communications Inc.
+ *
+ * Author: Haibing.Yang <haibing.yang@spreadtrum.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <asm/io.h>
+#include "sprdfb.h"
+
+#define GPIO_BASE_ADDR 0x40280000
+#define GPIO_LVDSCHIP_OFFSET 0x480
+
+#ifndef BIT
+#define BIT(x) (1<<x)
+#endif
+
+#define GPIO_SCK_BIT BIT(6)
+#define GPIO_CS_BIT BIT(7)
+#define GPIO_SDI_BIT BIT(8)
+
+#define GPIO_SPI_SCK_PIN 6
+#define GPIO_SPI_CS_PIN 7
+#define GPIO_SPI_SDI_PIN 8
+
+#define DELAY_CNT 10
+
+static unsigned long gpio_base_addr;
+
+struct gpio_ctrl_reg {
+ volatile u32 data; /* bits data */
+ volatile u32 msk; /* bits data mask */
+ volatile u32 dir; /* bits data direction */
+ volatile u32 is; /* bits interrupt sense */
+ volatile u32 ibe; /* bits both edges interrupt */
+ volatile u32 iev; /* bits interrupt event */
+ volatile u32 ie; /* bits interrupt enable */
+ volatile u32 ris; /* bits raw interrupt status */
+ volatile u32 mis; /* bits masked interrupt status */
+ volatile u32 inen; /* input enable */
+};
+
+static int gpio_spi_write(u32 index, u8 len_i, u32 data, u8 len_d)
+{
+ u32 i, reg_val;
+ volatile struct gpio_ctrl_reg *regs =
+ (volatile struct gpio_ctrl_reg *)
+ (gpio_base_addr + GPIO_LVDSCHIP_OFFSET);
+
+ regs->inen = 0;
+ regs->msk = GPIO_SCK_BIT | GPIO_CS_BIT | GPIO_SDI_BIT;
+ regs->dir = GPIO_SCK_BIT | GPIO_CS_BIT | GPIO_SDI_BIT;
+ regs->data = GPIO_SCK_BIT | GPIO_CS_BIT;
+
+ /* Bit[7] output 1, CS Enable */
+ reg_val = GPIO_CS_BIT;
+ regs->data = reg_val;
+ udelay(DELAY_CNT);
+
+ /* all output 0 */
+ reg_val = 0;
+ regs->data = reg_val;
+ /* Write data */
+ for (i = 0; i < len_d; ++i) {
+ reg_val = 0;
+ /* Get a bit value */
+ reg_val = ((data >> (len_d - i -1)) << GPIO_SPI_SDI_PIN) & GPIO_SDI_BIT;
+ regs->data = reg_val;
+ udelay(DELAY_CNT);
+ /* High clock to set bit */
+ regs->data |= GPIO_SCK_BIT;
+ udelay(DELAY_CNT);
+ }
+
+ /* Write index */
+ for (i = 0; i < len_i; ++i) {
+ reg_val = 0;
+ /* Get a bit value */
+ reg_val = ((index >> (len_i - i -1)) << GPIO_SPI_SDI_PIN) & GPIO_SDI_BIT;
+ regs->data = reg_val;
+ udelay(DELAY_CNT);
+ /* High clock to set bit */
+ regs->data |= GPIO_SCK_BIT;
+ udelay(DELAY_CNT);
+ }
+
+ regs->data = 0;
+ udelay(DELAY_CNT);
+ regs->data |= GPIO_CS_BIT;
+ udelay(DELAY_CNT);
+ regs->data |= GPIO_SCK_BIT;
+ udelay(DELAY_CNT * 20);
+
+ return 0;
+}
+
+static int gpio_spi_read(u32 index, u8 len_i, u32 data, u8 len_d)
+{
+ u32 i, reg_val = 0, rd_val = 0;
+ u32 rd_reg[16] = { 0 };
+ u32 rd_reg1[16] = { 0 };
+ u32 rd_reg2[16] = { 0 };
+ volatile struct gpio_ctrl_reg *regs =
+ (volatile struct gpio_ctrl_reg *)
+ (gpio_base_addr + GPIO_LVDSCHIP_OFFSET);
+
+ regs->inen = 0;
+ regs->msk = GPIO_SCK_BIT | GPIO_CS_BIT | GPIO_SDI_BIT;
+ regs->dir = GPIO_SCK_BIT | GPIO_CS_BIT | GPIO_SDI_BIT;
+ regs->data = GPIO_SCK_BIT | GPIO_CS_BIT;
+
+ /* Bit[7] output 1 */
+ reg_val = GPIO_CS_BIT;
+ regs->data = reg_val;
+ udelay(DELAY_CNT);
+
+ /* all output 0 */
+ reg_val = 0;
+ regs->data = reg_val;
+
+ for (i = 0; i < len_d; ++i) {
+ reg_val = 0;
+ reg_val = ((data >> (len_d - i -1)) << GPIO_SPI_SDI_PIN) & GPIO_SDI_BIT;
+ regs->data = reg_val;
+ udelay(DELAY_CNT);
+
+ regs->data |= GPIO_SCK_BIT;
+ udelay(DELAY_CNT);
+ }
+
+ for (i = 0; i < len_i; ++i) {
+ reg_val = 0;
+ reg_val = ((index >> (len_i - i -1)) << GPIO_SPI_SDI_PIN) & GPIO_SDI_BIT;
+ regs->data = reg_val;
+ udelay(DELAY_CNT);
+
+ regs->data |= GPIO_SCK_BIT;
+ udelay(DELAY_CNT);
+ }
+
+ regs->data = 0;
+ udelay(DELAY_CNT);
+ regs->data |= GPIO_CS_BIT;
+ udelay(DELAY_CNT);
+ regs->inen |= GPIO_SDI_BIT;
+ regs->dir &= ~GPIO_SDI_BIT;
+ regs->data |= GPIO_SCK_BIT;
+ udelay(DELAY_CNT);
+ regs->data &= ~GPIO_SCK_BIT;
+
+ for (i = 0; i < 16; ++i) {
+ udelay(DELAY_CNT);
+ regs->data |= GPIO_SCK_BIT;
+ rd_reg[i] = regs->data & GPIO_SDI_BIT;
+ rd_reg1[i] = rd_reg[i] >> 10;
+ rd_reg2[i] = rd_reg1[i] << (15 - i);
+ rd_val |= rd_reg2[i];
+ udelay(DELAY_CNT);
+ regs->data &= ~GPIO_SCK_BIT;
+ }
+
+ udelay(DELAY_CNT);
+ regs->data |= GPIO_CS_BIT;
+ udelay(DELAY_CNT);
+ regs->data |= GPIO_SCK_BIT;
+ regs->data |= GPIO_SDI_BIT;
+ udelay(DELAY_CNT * 50);
+
+ return rd_val;
+}
+
+int sprdchip_lvds_init(void)
+{
+ u32 i, rd_val1, rd_val2;
+ gpio_base_addr = ioremap(GPIO_BASE_ADDR, 0x1000);
+ for (i = 0; i < 50; ++i) {
+ gpio_spi_write(27, 18, 0, 16);
+ rd_val1 = gpio_spi_read(63, 18, 27, 16);
+ }
+
+ for (i = 0; i < 50; ++i) {
+ gpio_spi_write(28, 18, 10240, 16);
+ gpio_spi_write(27, 18, 16, 16);
+ rd_val1 = gpio_spi_read(63, 18, 27, 16);
+ rd_val2 = gpio_spi_read(63, 18, 28, 16);
+ }
+ return 0;
+}
diff --git a/drivers/video/sprdfb/sprdfb_i2c.c b/drivers/video/sprdfb/sprdfb_i2c.c
new file mode 100644
index 00000000..00c4d339
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_i2c.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+
+#include "sprdfb.h"
+#include "sprdfb_panel.h"
+
+
+#define SPRDFB_I2C_NAME "sprdfb_i2c"
+#define SPRDFB_I2C_TRY_NUM (4)
+
+static struct i2c_client *this_client = NULL;
+static struct panel_spec *i2c_panel_info = NULL;
+
+static struct i2c_device_id panel_i2c_id[] = {
+ {SPRDFB_I2C_NAME, 0},
+ {}
+};
+
+static unsigned short panel_i2c_default_addr_list[] =
+ { I2C_CLIENT_END, I2C_CLIENT_END };
+
+
+static int sprdfb_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int res = 0;
+// struct sprdfb_device *dev = (struct sprdfb_device *)id->driver_data;;
+
+ printk(KERN_INFO "sprdfb: [%s], addr = %d\n", __FUNCTION__, client->addr);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ printk(KERN_INFO "sprdfb: [%s]: functionality check failed\n",
+ __FUNCTION__);
+ res = -ENODEV;
+ goto out;
+ }
+
+ this_client = client;
+
+ if (i2c_panel_info->info.rgb->bus_info.i2c->i2c_addr != (this_client->addr & (~0xFF))) {
+ this_client->addr =
+ (this_client->addr & (~0xFF)) |
+ (i2c_panel_info->info.rgb->bus_info.i2c->i2c_addr & 0xFF);
+ }
+ printk(KERN_INFO "sordfb: [%s]:this_client->addr =0x%x\n", __FUNCTION__,
+ this_client->addr);
+ msleep(20);
+ return 0;
+out:
+ return res;
+}
+
+static int sprdfb_i2c_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+static int sprdfb_i2c_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+ printk("SENSOR_DRV: detect!");
+ strcpy(info->type, client->name);
+ return 0;
+}
+
+static struct i2c_driver sprdfb_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ },
+ .probe = sprdfb_i2c_probe,
+ .remove = sprdfb_i2c_remove,
+ .detect = sprdfb_i2c_detect,
+};
+
+
+
+bool sprdfb_i2c_init(struct sprdfb_device *dev)
+{
+/* panel_i2c_id[0].driver_data = dev;*/
+ i2c_panel_info = dev->panel;
+ panel_i2c_default_addr_list[0] = dev->panel->info.rgb->bus_info.i2c->i2c_addr;
+
+ sprdfb_i2c_driver.driver.name = SPRDFB_I2C_NAME;
+ sprdfb_i2c_driver.id_table = panel_i2c_id;
+ sprdfb_i2c_driver.address_list = &panel_i2c_default_addr_list[0];
+
+ if (i2c_add_driver(&sprdfb_i2c_driver)) {
+ printk("sprdfb: [%s] i2c_add_driver fail\n", __FUNCTION__);
+ return false;
+ }else{
+ printk("sprdfb: [%s] i2c_add_driver ok\n", __FUNCTION__);
+ }
+
+ return true;
+}
+
+bool sprdfb_i2c_uninit(struct sprdfb_device *dev)
+{
+/* panel_i2c_id[0].driver_data = dev;*/
+ panel_i2c_default_addr_list[0] = dev->panel->info.rgb->bus_info.i2c->i2c_addr;
+
+ sprdfb_i2c_driver.driver.name = SPRDFB_I2C_NAME;
+ sprdfb_i2c_driver.id_table = panel_i2c_id;
+ sprdfb_i2c_driver.address_list = &panel_i2c_default_addr_list[0];
+
+ i2c_panel_info = NULL;
+
+ i2c_del_driver(&sprdfb_i2c_driver);
+
+ return true;
+}
+
+/*write i2c, reg is 8 bit, val is 8 bit*/
+static int32_t sprdfb_i2c_write_8bits(uint8_t reg, uint8_t val)
+{
+ uint8_t buf_w[2];
+ uint32_t i = 0;
+ int32_t ret = -1;
+ struct i2c_msg msg_w;
+
+ if (0xFF == reg) {
+ mdelay(val);
+ printk("sprdfb: [%s], sleep %d\n", __FUNCTION__, val);
+ return 0;
+ }
+
+ buf_w[0] = (uint8_t) reg;
+ buf_w[1] = val;
+ msg_w.addr = this_client->addr;
+ msg_w.flags = 0;
+ msg_w.buf = buf_w;
+ msg_w.len = 2;
+ for (i = 0; i < SPRDFB_I2C_TRY_NUM; i++) {
+ ret = i2c_transfer(this_client->adapter, &msg_w, 1);
+ if (ret != 1) {
+ printk("sprdfb: [%s] write panel reg fai, ret : %d, I2C w addr: 0x%x, \n",
+ __FUNCTION__, ret, this_client->addr);
+ ret = -1;
+ msleep(20);
+ }else{
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+/*read i2c, reg is 8 bit, val is 8 bit*/
+static int32_t sprdfb_i2c_read_8bits(uint8_t reg, uint8_t *val)
+{
+ uint8_t buf_w[1];
+ uint8_t buf_r;
+ uint32_t i = 0;
+ int32_t ret = -1;
+ struct i2c_msg msg_r[2];
+
+ buf_w[0] = reg;
+ msg_r[0].addr = this_client->addr;
+ msg_r[0].flags = 0;
+ msg_r[0].buf = buf_w;
+ msg_r[0].len = 1;
+ msg_r[1].addr = this_client->addr;
+ msg_r[1].flags = I2C_M_RD;
+ msg_r[1].buf = &buf_r;
+ msg_r[1].len = 1;
+ for (i = 0; i < SPRDFB_I2C_TRY_NUM; i++) {
+ ret = i2c_transfer(this_client->adapter, msg_r, 2);
+ if (ret != 2) {
+ printk("sprdfb: [%s]: read i2c reg fail, ret: %d, I2C r addr: 0x%x \n",
+ __FUNCTION__, ret, this_client->addr);
+ *val = 0xff;
+ ret = -1;
+ msleep(20);
+ }else{
+ *val = buf_r;
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+
+/*write i2c, reg is 8 or 16 bit, val is 8 or 16bit*/
+static int32_t sprdfb_i2c_write_16bits(uint16_t reg, bool reg_is_8bit, uint16_t val, bool val_is_8bit)
+{
+ uint8_t cmd[4] = { 0 };
+ uint32_t i = 0;
+ uint32_t cmd_num = 0;
+ struct i2c_msg msg_w;
+ int32_t ret = -1;
+
+ if ((reg_is_8bit && (0xff == reg))||(!reg_is_8bit &&(0xffff == reg))) {
+ mdelay(val);
+ printk("sprdfb: [%s], sleep %d\n", __FUNCTION__, val);
+ return 0;
+ }
+
+ if (!reg_is_8bit) {
+ cmd[cmd_num++] = (uint8_t) ((reg >> 8) & 0xff);
+ cmd[cmd_num++] = (uint8_t) (reg & 0xff);
+ } else {
+ cmd[cmd_num++] = (uint8_t) reg;
+ }
+
+ if (!val_is_8bit) {
+ cmd[cmd_num++] = (uint8_t) ((val >> 8) & 0xff);
+ cmd[cmd_num++] = (uint8_t) (val & 0xff);
+ } else {
+ cmd[cmd_num++] = (uint8_t) val;
+ }
+
+ msg_w.addr = this_client->addr;
+ msg_w.flags = 0;
+ msg_w.buf = cmd;
+ msg_w.len = cmd_num;
+
+ for (i = 0; i < SPRDFB_I2C_TRY_NUM; i++) {
+ ret = i2c_transfer(this_client->adapter, &msg_w, 1);
+ if (ret != 1) {
+ printk("srpdfb [%s]: write sensor reg fai, ret : %d, I2C w addr: 0x%x, \n",
+ __FUNCTION__, ret, this_client->addr);
+ ret = -1;
+ msleep(20);
+ } else {
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+/*read i2c, reg is 8 or 16 bit, val is 8 or 16bit*/
+static int32_t sprdfb_i2c_read_16bits(uint16_t reg, bool reg_is_8bit, uint16_t *val, bool val_is_8bit)
+{
+ uint32_t i = 0;
+ uint8_t cmd[2] = { 0 };
+ uint16_t w_cmd_num = 0;
+ uint16_t r_cmd_num = 0;
+ uint8_t buf_r[2] = { 0 };
+ int32_t ret = -1;
+ struct i2c_msg msg_r[2];
+
+ if (!reg_is_8bit) {
+ cmd[w_cmd_num++] = (uint8_t) ((reg >> 8) & 0xff);
+ cmd[w_cmd_num++] = (uint8_t) (reg & 0xff);
+ } else {
+ cmd[w_cmd_num++] = (uint8_t) reg;
+ }
+
+ if (!val_is_8bit) {
+ r_cmd_num = 2;
+ } else {
+ r_cmd_num = 1;
+ }
+
+ msg_r[0].addr = this_client->addr;
+ msg_r[0].flags = 0;
+ msg_r[0].buf = cmd;
+ msg_r[0].len = w_cmd_num;
+ msg_r[1].addr = this_client->addr;
+ msg_r[1].flags = I2C_M_RD;
+ msg_r[1].buf = buf_r;
+ msg_r[1].len = r_cmd_num;
+
+ for (i = 0; i < SPRDFB_I2C_TRY_NUM; i++) {
+ ret = i2c_transfer(this_client->adapter, msg_r, 2);
+ if (ret != 2) {
+ printk("srpdfb [%s]: read panel reg fai, ret : %d, I2C w addr: 0x%x, \n",
+ __FUNCTION__,ret, this_client->addr);
+ *val = 0xffff;
+ ret = -1;
+ msleep(20);
+ } else {
+ *val = (r_cmd_num == 1) ? (uint16_t) buf_r[0]
+ : (uint16_t) ((buf_r[0] << 8) + buf_r[1]);
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+
+/*write i2c with burst mode*/
+static int32_t sprdfb_i2c_write_burst(uint8_t* buf, int num)
+{
+ uint32_t i = 0;
+ struct i2c_msg msg_w;
+ int32_t ret = -1;
+
+ for (i = 0; i < SPRDFB_I2C_TRY_NUM; i++) {
+ msg_w.addr = this_client->addr;
+ msg_w.flags = 0;
+ msg_w.buf = buf;
+ msg_w.len = num;
+ ret = i2c_transfer(this_client->adapter, &msg_w, 1);
+ if (ret != 1) {
+ printk("srpdfb [%s]: write i2c reg fai, ret : %d, I2C w addr: 0x%x, \n",
+ __FUNCTION__, ret, this_client->addr);
+ ret = -1;
+ msleep(20);
+ } else {
+ ret = 0;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+struct ops_i2c sprdfb_i2c_ops = {
+ .i2c_write_8bits = sprdfb_i2c_write_8bits,
+ .i2c_read_8bits = sprdfb_i2c_read_8bits,
+ .i2c_write_16bits = sprdfb_i2c_write_16bits,
+ .i2c_read_16bits = sprdfb_i2c_read_16bits,
+ .i2c_write_burst = sprdfb_i2c_write_burst,
+};
+
diff --git a/drivers/video/sprdfb/sprdfb_main.c b/drivers/video/sprdfb/sprdfb_main.c
new file mode 100644
index 00000000..176715a9
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_main.c
@@ -0,0 +1,888 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "sprdfb: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include <linux/dma-mapping.h>
+#include <linux/uaccess.h>
+#include <asm/uaccess.h>
+#include <linux/compat.h>
+
+#ifdef CONFIG_OF
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_address.h>
+#endif
+
+#include <soc/sprd/arch_misc.h>
+#include "sprdfb_chip_common.h"
+#include "sprdfb.h"
+#include "sprdfb_panel.h"
+
+#include <linux/proc_fs.h>
+
+#ifdef CONFIG_FB_MMAP_CACHED
+#include <asm/pgtable.h>
+#include <linux/mm.h>
+#endif
+
+enum{
+ SPRD_IN_DATA_TYPE_ABGR888 = 0,
+ SPRD_IN_DATA_TYPE_BGR565,
+/*
+ SPRD_IN_DATA_TYPE_RGB666,
+ SPRD_IN_DATA_TYPE_RGB555,
+ SPRD_IN_DATA_TYPE_PACKET,
+*/ /*not support*/
+ SPRD_IN_DATA_TYPE_LIMIT
+};
+
+#define SPRDFB_IN_DATA_TYPE SPRD_IN_DATA_TYPE_ABGR888
+
+#ifdef CONFIG_FB_TRIPLE_FRAMEBUFFER
+#define FRAMEBUFFER_NR (3)
+#else
+#define FRAMEBUFFER_NR (2)
+#endif
+
+#define SPRDFB_FRAMES_TO_SKIP (1)
+
+#define SPRDFB_DEFAULT_FPS (60)
+
+#define SPRDFB_ESD_TIME_OUT_CMD (2000)
+
+#define SPRDFB_ESD_TIME_OUT_VIDEO (1000)
+
+extern bool sprdfb_panel_get(struct sprdfb_device *dev);
+extern int sprdfb_panel_probe(struct sprdfb_device *dev);
+extern void sprdfb_panel_remove(struct sprdfb_device *dev);
+
+extern struct display_ctrl sprdfb_dispc_ctrl ;
+
+#ifdef CONFIG_OF
+extern unsigned long g_dispc_base_addr;
+#endif
+
+static unsigned PP[16];
+static int frame_count = 0;
+
+static int sprdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb);
+static int sprdfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb);
+static int sprdfb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg);
+#ifdef CONFIG_COMPAT
+static long sprdfb_compat_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg);
+#endif
+#ifdef CONFIG_FB_MMAP_CACHED
+static int sprdfb_mmap(struct fb_info *info, struct vm_area_struct *vma);
+#endif
+
+static struct fb_ops sprdfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = sprdfb_check_var,
+ .fb_pan_display = sprdfb_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_ioctl = sprdfb_ioctl,
+#ifdef CONFIG_COMPAT
+ .fb_compat_ioctl = sprdfb_compat_ioctl,
+#endif
+#ifdef CONFIG_FB_MMAP_CACHED
+ .fb_mmap = sprdfb_mmap,
+#endif
+};
+
+#ifdef CONFIG_FB_MMAP_CACHED
+static int sprdfb_mmap(struct fb_info *info,struct vm_area_struct *vma)
+{
+ struct sprdfb_device *dev = NULL;
+ if(NULL == info){
+ printk(KERN_ERR "sprdfb: sprdfb_ioctl error. (Invalid Parameter)");
+ return -1;
+ }
+
+ dev = info->par;
+ printk("sprdfb: sprdfb_mmap,vma=0x%x\n",vma);
+ vma->vm_page_prot = pgprot_cached(vma->vm_page_prot);
+ dev->ctrl->set_vma(vma);
+
+ return vm_iomap_memory(vma, info->fix.smem_start, info->fix.smem_len);
+}
+#endif
+
+extern uint32_t lcd_id_from_uboot;
+
+static struct proc_dir_entry *lcd_user = NULL;
+
+ssize_t DrvLcdNameRead(struct file *pFile, char __user *pBuffer, size_t nCount, loff_t *pPos)
+{
+ u32 nLength;
+
+ if (*pPos != 0)
+ {
+ return 0;
+ }
+
+ nLength = sprintf(pBuffer, "%x\n", lcd_id_from_uboot);
+
+ *pPos += nLength;
+
+ return nLength;
+}
+
+ssize_t DrvLcdNameWrite(struct file *pFile, const char __user *pBuffer, size_t nCount, loff_t *pPos)
+{
+ return nCount;
+}
+
+static const struct file_operations _gProclcdName = {
+ .read = DrvLcdNameRead,
+ .write = DrvLcdNameWrite,
+};
+
+
+
+static int setup_fb_mem(struct sprdfb_device *dev, struct platform_device *pdev)
+{
+ uint32_t len;
+ void *addr;
+ bool use_reserve_mem;
+ uint32_t reserve_mem[2];
+ int ret;
+
+#ifdef CONFIG_FB_LOW_RES_SIMU
+ if ((0!= dev->display_width) && (0 != dev->display_height))
+ len = dev->display_width * dev->display_height * (dev->bpp / 8) * FRAMEBUFFER_NR;
+ else
+#endif
+ len = dev->panel->width * dev->panel->height * (dev->bpp / 8) * FRAMEBUFFER_NR;
+
+#ifdef CONFIG_OF
+ use_reserve_mem = of_property_read_bool(pdev->dev.of_node, "sprd,fb_use_reservemem");
+ if(use_reserve_mem) {
+ ret = of_property_read_u32_array(pdev->dev.of_node, "sprd,fb_mem",
+ reserve_mem, 2);
+ if(0 != ret)
+ printk(KERN_ERR "sprdfb: Failed to got framebuffer memory from dt file\n");
+ }
+#else
+#ifdef CONFIG_FB_LCD_RESERVE_MEM
+ use_reserve_mem = true;
+ reserve_mem[0] = SPRD_FB_MEM_BASE;
+ reserve_mem[1] = SPRD_FB_MEM_SIZE;
+#else
+ use_reserve_mem = false;
+#endif
+#endif
+
+ if(!use_reserve_mem) {
+ addr = (void*)__get_free_pages(GFP_ATOMIC | __GFP_ZERO, get_order(len));
+ if (NULL == addr) {
+ printk(KERN_ERR "sprdfb: Failed to allocate framebuffer memory\n");
+ return -ENOMEM;
+ }
+ printk(KERN_INFO "sprdfb: got %d bytes mem at 0x%p\n", len, addr);
+
+ dev->fb->fix.smem_start = __pa(addr);
+ dev->fb->fix.smem_len = len;
+ dev->fb->screen_base = (char*)addr;
+ }else{
+ dev->fb->fix.smem_start = reserve_mem[0];
+ printk("sprdfb: setup_fb_mem--smem_start:%lx,len:%d,reserved len:%d\n",
+ dev->fb->fix.smem_start, len, reserve_mem[1]);
+ addr = ioremap(dev->fb->fix.smem_start, len);
+ if (NULL == addr) {
+ printk(KERN_ERR "sprdfb: Unable to map framebuffer base: 0x%p\n", addr);
+ return -ENOMEM;
+ }
+ dev->fb->fix.smem_len = len;
+ dev->fb->screen_base = (char*)addr;
+ }
+ return 0;
+}
+
+static void setup_fb_info(struct sprdfb_device *dev)
+{
+ struct fb_info *fb = dev->fb;
+ struct panel_spec *panel = dev->panel;
+ int r;
+
+ fb->fbops = &sprdfb_ops;
+ fb->flags = FBINFO_DEFAULT;
+
+ /* finish setting up the fb_info struct */
+ strncpy(fb->fix.id, "sprdfb", 16);
+ fb->fix.ypanstep = 1;
+ fb->fix.type = FB_TYPE_PACKED_PIXELS;
+ fb->fix.visual = FB_VISUAL_TRUECOLOR;
+#ifdef CONFIG_FB_LOW_RES_SIMU
+ if((0 != dev->display_width) && (0 != dev->display_height)){
+ fb->fix.line_length = dev->display_width * dev->bpp / 8;
+
+ fb->var.xres = dev->display_width;
+ fb->var.yres = dev->display_height;
+ fb->var.width = dev->display_width;
+ fb->var.height = dev->display_height;
+
+ fb->var.xres_virtual = dev->display_width;
+ fb->var.yres_virtual = dev->display_height * FRAMEBUFFER_NR;
+ }else
+#endif
+ {
+ fb->fix.line_length = panel->width * dev->bpp / 8;
+
+ fb->var.xres = panel->width;
+ fb->var.yres = panel->height;
+ fb->var.width = panel->width;
+ fb->var.height = panel->height;
+
+ fb->var.xres_virtual = panel->width;
+ fb->var.yres_virtual = panel->height * FRAMEBUFFER_NR;
+ }
+ fb->var.bits_per_pixel = dev->bpp;
+#ifdef CONFIG_FB_LOW_RES_SIMU
+ if((0 != dev->display_width) && (0 != dev->display_height)){
+ if(0 != dev->panel->fps){
+ fb->var.pixclock = ((1000000000 /dev->display_width) * 1000) / (dev->panel->fps * dev->display_height);
+ }else{
+ fb->var.pixclock = ((1000000000 /dev->display_width) * 1000) / (SPRDFB_DEFAULT_FPS * dev->display_height);
+ }
+ }else
+#endif
+ {
+ if(0 != dev->panel->fps){
+ fb->var.pixclock = ((1000000000 /panel->width) * 1000) / (dev->panel->fps * panel->height);
+ }else{
+ fb->var.pixclock = ((1000000000 /panel->width) * 1000) / (SPRDFB_DEFAULT_FPS * panel->height);
+ }
+ }
+
+ fb->var.accel_flags = 0;
+ fb->var.yoffset = 0;
+
+ /* only support two pixel format */
+ if (dev->bpp == 32) { /* ABGR */
+ fb->var.red.offset = 16;
+ fb->var.red.length = 8;
+ fb->var.red.msb_right = 0;
+ fb->var.green.offset = 8;
+ fb->var.green.length = 8;
+ fb->var.green.msb_right = 0;
+ fb->var.blue.offset = 0;
+ fb->var.blue.length = 8;
+ fb->var.blue.msb_right = 0;
+ } else { /*BGR*/
+ fb->var.red.offset = 11;
+ fb->var.red.length = 5;
+ fb->var.red.msb_right = 0;
+ fb->var.green.offset = 5;
+ fb->var.green.length = 6;
+ fb->var.green.msb_right = 0;
+ fb->var.blue.offset = 0;
+ fb->var.blue.length = 5;
+ fb->var.blue.msb_right = 0;
+ }
+ r = fb_alloc_cmap(&fb->cmap, 16, 0);
+ fb->pseudo_palette = PP;
+
+ PP[0] = 0;
+ for (r = 1; r < 16; r++){
+ PP[r] = 0xffffffff;
+ }
+}
+
+static void fb_free_resources(struct sprdfb_device *dev)
+{
+ if (dev == NULL)
+ return;
+
+ if (&dev->fb->cmap != NULL) {
+ fb_dealloc_cmap(&dev->fb->cmap);
+ }
+ if (dev->fb->screen_base) {
+ free_pages((unsigned long)dev->fb->screen_base,
+ get_order(dev->fb->fix.smem_len));
+ }
+ unregister_framebuffer(dev->fb);
+ framebuffer_release(dev->fb);
+}
+
+static int sprdfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb)
+{
+ int32_t ret;
+ struct sprdfb_device *dev = fb->par;
+
+ pr_debug("sprdfb: [%s]\n", __FUNCTION__);
+
+ if(frame_count < SPRDFB_FRAMES_TO_SKIP) {
+ frame_count++;
+ return 0;
+ }
+
+ if(0 == dev->enable){
+ printk(KERN_ERR "sprdfb: [%s]: Invalid Device status %d", __FUNCTION__, dev->enable);
+ return -1;
+ }
+
+ ret = dev->ctrl->refresh(dev);
+ if (ret) {
+ printk(KERN_ERR "sprdfb: failed to refresh !!!!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+#include <video/sprd_fb.h>
+static int sprdfb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ int result = -1;
+ struct sprdfb_device *dev = NULL;
+#ifdef CONFIG_FB_LCD_OVERLAY_SUPPORT
+ overlay_info local_overlay_info;
+ overlay_display local_overlay_display;
+#endif
+ int power_mode;
+ void __user *argp = (void __user *)arg;
+
+ if(NULL == info){
+ printk(KERN_ERR "sprdfb: sprdfb_ioctl error. (Invalid Parameter)");
+ return -1;
+ }
+
+ dev = info->par;
+
+ switch(cmd){
+#ifdef CONFIG_FB_LCD_OVERLAY_SUPPORT
+ case SPRD_FB_SET_OVERLAY:
+ pr_debug(KERN_INFO "sprdfb: [%s]: SPRD_FB_SET_OVERLAY\n", __FUNCTION__);
+ memset(&local_overlay_info,0,sizeof(local_overlay_info));
+ if (copy_from_user(&local_overlay_info, argp, sizeof(local_overlay_info))){
+ printk("sprdfb: SET_OVERLAY copy failed!\n");
+ return -EFAULT;
+ }
+ if(NULL != dev->ctrl->enable_overlay){
+ result = dev->ctrl->enable_overlay(dev, &local_overlay_info, 1);
+ }
+ break;
+ case SPRD_FB_DISPLAY_OVERLAY:
+ pr_debug(KERN_INFO "sprdfb: [%s]: SPRD_FB_DISPLAY_OVERLAY\n", __FUNCTION__);
+ memset(&local_overlay_display,0,sizeof(local_overlay_display));
+ if (copy_from_user(&local_overlay_display, argp, sizeof(local_overlay_display))){
+ printk("sprdfb: DISPLAY_OVERLAY copy failed!\n");
+ return -EFAULT;
+ }
+ if(NULL != dev->ctrl->display_overlay){
+ result = dev->ctrl->display_overlay(dev, &local_overlay_display);
+ }
+ break;
+#endif
+#ifdef CONFIG_FB_VSYNC_SUPPORT
+ case FBIO_WAITFORVSYNC:
+ pr_debug(KERN_INFO "sprdfb: [%s]: FBIO_WAITFORVSYNC\n", __FUNCTION__);
+ if(NULL != dev->ctrl->wait_for_vsync){
+ result = dev->ctrl->wait_for_vsync(dev);
+ }
+ break;
+#endif
+
+#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING
+ case SPRD_FB_CHANGE_FPS:
+ {
+ int fps;
+ result = copy_from_user(&fps, argp, sizeof(fps));
+ if (result) {
+ pr_err("%s: copy_from_user failed", __func__);
+ return result;
+ }
+ pr_info("%s: fps will be changed to %d via ioctl\n",
+ __func__, fps);
+ result = sprdfb_chg_clk_intf(dev,
+ SPRDFB_DYNAMIC_FPS, fps);
+ if (result) {
+ pr_err("%s: fps is set fail. fps=%d, ret=%d\n",
+ __func__, fps, result);
+ return result;
+ }
+ break;
+ }
+#endif
+
+ case SPRD_FB_IS_REFRESH_DONE:
+ pr_debug(KERN_INFO "sprdfb: [%s]: SPRD_FB_IS_REFRESH_DONE\n", __FUNCTION__);
+ if(NULL != dev->ctrl->is_refresh_done){
+ result = dev->ctrl->is_refresh_done(dev);
+ }
+ break;
+
+ case SPRD_FB_SET_POWER_MODE:
+ result = copy_from_user(&power_mode, argp, sizeof(power_mode));
+ printk("sprdfb: [%s] : SPRD_FB_SET_POWER_MODE (%d)\n", __FUNCTION__, power_mode);
+ break;
+
+ default:
+ printk(KERN_INFO "sprdfb: [%s]: unknown cmd(%d)\n", __FUNCTION__, cmd);
+ break;
+ }
+
+ pr_debug(KERN_INFO "sprdfb: [%s]: return %d\n",__FUNCTION__, result);
+ return result;
+}
+
+
+#ifdef CONFIG_COMPAT
+#ifdef CONFIG_FB_LCD_OVERLAY_SUPPORT
+
+static int sprdfb_set_overlayinfo(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ overlay_info __user *local_overlay_info;
+ overlay_info32 __user *local_overlay_info32;
+ __u32 buffer;
+ int err;
+
+ local_overlay_info = compat_alloc_user_space(sizeof(overlay_info));
+ local_overlay_info32 = compat_ptr(arg);
+
+ if (copy_in_user(&(local_overlay_info->layer_index), &(local_overlay_info32->layer_index),
+ 4*sizeof(int)))
+ return -EFAULT;
+
+ if (copy_in_user(&(local_overlay_info->rb_switch), &(local_overlay_info32->rb_switch),
+ sizeof(bool)))
+ return -EFAULT;
+
+ if (copy_in_user(&(local_overlay_info->rect), &(local_overlay_info32->rect),
+ sizeof(overlay_rect)))
+ return -EFAULT;
+
+ if (get_user(buffer, &local_overlay_info32->buffer)||
+ put_user(compat_ptr(buffer), &local_overlay_info->buffer))
+ return -EFAULT;
+
+ err = sprdfb_ioctl(info, cmd, (unsigned long) local_overlay_info);
+
+ return err;
+}
+#endif
+static long sprdfb_compat_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ int result = -1;
+
+ pr_debug(KERN_INFO "sprdfb: [%s]: ++\n", __FUNCTION__);
+
+ if(NULL == info){
+ printk(KERN_ERR "sprdfb: sprdfb_ioctl error. (Invalid Parameter)");
+ return -1;
+ }
+
+ switch(cmd){
+#ifdef CONFIG_FB_LCD_OVERLAY_SUPPORT
+ case SPRD_FB_SET_OVERLAY:
+ pr_debug(KERN_INFO "sprdfb: [%s]: SPRD_FB_SET_OVERLAY\n", __FUNCTION__);
+ result = sprdfb_set_overlayinfo(info, cmd, arg);
+ break;
+ case SPRD_FB_DISPLAY_OVERLAY:
+ pr_debug(KERN_INFO "sprdfb: [%s]: SPRD_FB_DISPLAY_OVERLAY\n", __FUNCTION__);
+ arg = (unsigned long) compat_ptr(arg);
+ result = sprdfb_ioctl(info, cmd, arg);
+ break;
+#endif
+#ifdef CONFIG_FB_VSYNC_SUPPORT
+ case FBIO_WAITFORVSYNC:
+ pr_debug(KERN_INFO "sprdfb: [%s]: FBIO_WAITFORVSYNC\n", __FUNCTION__);
+ result = sprdfb_ioctl(info, cmd, arg);
+ break;
+#endif
+#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING
+ case SPRD_FB_CHANGE_FPS:
+#endif
+ case SPRD_FB_SET_POWER_MODE:
+ pr_debug(KERN_INFO "sprdfb: [%s]: (%d)\n", __FUNCTION__,cmd);
+ arg = (unsigned long) compat_ptr(arg);
+ result = sprdfb_ioctl(info, cmd, arg);
+ break;
+ case SPRD_FB_IS_REFRESH_DONE:
+ default:
+ pr_debug(KERN_INFO "sprdfb: [%s]: (%d)\n", __FUNCTION__,cmd);
+ result = sprdfb_ioctl(info, cmd, arg);
+ break;
+ }
+ pr_debug(KERN_INFO "sprdfb: [%s]: return %d\n",__FUNCTION__, result);
+ return result;
+}
+#endif
+
+static int sprdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb)
+{
+ if ((var->xres != fb->var.xres) ||
+ (var->yres != fb->var.yres) ||
+ (var->xres_virtual != fb->var.xres_virtual) ||
+ (var->yres_virtual != fb->var.yres_virtual) ||
+ (var->xoffset != fb->var.xoffset) ||
+#ifndef BIT_PER_PIXEL_SURPPORT
+ (var->bits_per_pixel != fb->var.bits_per_pixel) ||
+#endif
+ (var->grayscale != fb->var.grayscale))
+ return -EINVAL;
+ return 0;
+}
+
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void sprdfb_early_suspend (struct early_suspend* es)
+{
+ struct sprdfb_device *dev = container_of(es, struct sprdfb_device, early_suspend);
+ struct fb_info *fb = dev->fb;
+ printk("sprdfb: [%s]\n",__FUNCTION__);
+
+ fb_set_suspend(fb, FBINFO_STATE_SUSPENDED);
+
+ if (!lock_fb_info(fb)) {
+ return ;
+ }
+ dev->ctrl->suspend(dev);
+ unlock_fb_info(fb);
+}
+
+static void sprdfb_late_resume (struct early_suspend* es)
+{
+ struct sprdfb_device *dev = container_of(es, struct sprdfb_device, early_suspend);
+ struct fb_info *fb = dev->fb;
+ pr_debug("sprdfb: [%s]\n",__FUNCTION__);
+
+ if (!lock_fb_info(fb)) {
+ return ;
+ }
+ dev->ctrl->resume(dev);
+ unlock_fb_info(fb);
+
+ fb_set_suspend(fb, FBINFO_STATE_RUNNING);
+}
+
+#else
+
+static int sprdfb_suspend(struct platform_device *pdev,pm_message_t state)
+{
+ struct sprdfb_device *dev = platform_get_drvdata(pdev);
+ printk("sprdfb: [%s]\n",__FUNCTION__);
+
+ dev->ctrl->suspend(dev);
+
+ return 0;
+}
+
+static int sprdfb_resume(struct platform_device *pdev)
+{
+ struct sprdfb_device *dev = platform_get_drvdata(pdev);
+ printk("sprdfb: [%s]\n",__FUNCTION__);
+
+ dev->ctrl->resume(dev);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_FB_ESD_SUPPORT
+static void ESD_work_func(struct work_struct *work)
+{
+ struct sprdfb_device *dev = container_of(work, struct sprdfb_device, ESD_work.work);
+
+ pr_debug("sprdfb: [%s] enter!\n", __FUNCTION__);
+
+ //do real ESD check
+ //mdelay(1000);
+ if(NULL != dev->ctrl->ESD_check){
+ dev->ctrl->ESD_check(dev);
+ }
+
+ if(0 != dev->enable){
+ pr_debug("sprdfb: reschedule ESD workqueue!\n");
+ schedule_delayed_work(&dev->ESD_work, msecs_to_jiffies(dev->ESD_timeout_val));
+ dev->ESD_work_start = true;
+ }else{
+ printk("sprdfb: DON't reschedule ESD workqueue since device not avialbe!!\n");
+ }
+
+ pr_debug("sprdfb: [%s] leave!\n", __FUNCTION__);
+}
+#endif
+
+uint32_t sprdfb_get_chip_id(void)
+{
+ uint32_t adie_chip_id = sci_get_chip_id();
+ if((adie_chip_id & 0xffff0000) < 0x50000000) {
+ printk("sprdfb: [%s], chip id 0x%08x is invalidate, try to get it by reading reg directly!\n", __FUNCTION__, adie_chip_id);
+
+ adie_chip_id = dispc_glb_read(SPRD_AONAPB_BASE+0xFC);
+ if((adie_chip_id & 0xffff0000) < 0x50000000) {
+ printk("sprdfb: [%s], chip id 0x%08x from reg is invalidate too!\n", __FUNCTION__, adie_chip_id);
+ }
+ }
+
+ printk("sprdfb: return chip id 0x%08x \n", adie_chip_id);
+ return adie_chip_id;
+}
+
+static fb_capability sprdfb_config_capability(void)
+{
+ uint32_t adie_chip_id = 0;
+ static fb_capability s_fb_capability = {0};
+
+ memset((void*)&s_fb_capability, 0, sizeof(s_fb_capability));
+
+ adie_chip_id = sprdfb_get_chip_id();
+ adie_chip_id &= 0xffff0000;
+ switch(adie_chip_id) {
+ case 0x88600000: /*Pike*/
+ case 0x98200000: /*PikeL*/
+ s_fb_capability.need_light_sleep = 0;
+ s_fb_capability.mipi_pll_type = 1;
+ break;
+
+ case 0x96310000: /*Sharkl64*/
+ s_fb_capability.need_light_sleep = 1;
+ s_fb_capability.mipi_pll_type = 2;
+ break;
+
+ default:
+ s_fb_capability.need_light_sleep = 1;
+ s_fb_capability.mipi_pll_type = 0;
+ break;
+ }
+ return s_fb_capability;
+}
+
+static int sprdfb_probe(struct platform_device *pdev)
+{
+ struct fb_info *fb = NULL;
+ struct sprdfb_device *dev = NULL;
+ int ret = 0;
+#ifdef CONFIG_OF
+ struct resource r;
+
+#ifdef CONFIG_FB_LOW_RES_SIMU
+ uint32_t display_size_array[2];
+#endif
+
+ lcd_user = proc_mkdir("lcd_user", NULL);
+
+ if (NULL == proc_create("lcd_name", 0777, lcd_user, &_gProclcdName))
+ {
+ printk("Failed to create _gProclcdName!\n");
+ }
+ else
+ {
+ printk("create _gProclcdName OK!\n");
+ }
+
+ pr_debug(KERN_INFO "sprdfb: [%s]\n", __FUNCTION__);
+#else
+ pr_debug(KERN_INFO "sprdfb: [%s], id = %d\n", __FUNCTION__, pdev->id);
+#endif
+
+ fb = framebuffer_alloc(sizeof(struct sprdfb_device), &pdev->dev);
+ if (!fb) {
+ printk(KERN_ERR "sprdfb: sprdfb_probe allocate buffer fail.\n");
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ dev = fb->par;
+ dev->fb = fb;
+#ifdef CONFIG_OF
+ dev->of_dev = &(pdev->dev);
+
+ dev->dev_id = of_alias_get_id(pdev->dev.of_node, "lcd");
+ printk("sprdfb: [%s] id = %d\n", __FUNCTION__, dev->dev_id);
+#else
+ dev->dev_id = pdev->id;
+#endif
+ if((SPRDFB_MAINLCD_ID != dev->dev_id) &&(SPRDFB_SUBLCD_ID != dev->dev_id)){
+ printk(KERN_ERR "sprdfb: sprdfb_probe fail. (unsupported device id)\n");
+ goto err0;
+ }
+
+ switch(SPRDFB_IN_DATA_TYPE){
+ case SPRD_IN_DATA_TYPE_ABGR888:
+ dev->bpp = 32;
+ break;
+ case SPRD_IN_DATA_TYPE_BGR565:
+ dev->bpp = 16;
+ break;
+ default:
+ dev->bpp = 32;
+ break;
+ }
+
+ if(SPRDFB_MAINLCD_ID == dev->dev_id){
+ dev->ctrl = &sprdfb_dispc_ctrl;
+#ifdef CONFIG_OF
+ if(0 != of_address_to_resource(pdev->dev.of_node, 0, &r)){
+ printk(KERN_ERR "sprdfb: sprdfb_probe fail. (can't get register base address)\n");
+ goto err0;
+ }
+ g_dispc_base_addr = (unsigned long)ioremap_nocache(r.start,
+ resource_size(&r));
+ if(!g_dispc_base_addr)
+ BUG();
+ printk("sprdfb: set g_dispc_base_addr = %ld\n", g_dispc_base_addr);
+#endif
+ }
+
+ dev->frame_count = 0;
+ dev->logo_buffer_addr_v = 0;
+ dev->capability = sprdfb_config_capability();
+
+ if(sprdfb_panel_get(dev)){
+ dev->panel_ready = true;
+
+#ifdef CONFIG_OF
+#ifdef CONFIG_FB_LOW_RES_SIMU
+ ret = of_property_read_u32_array(pdev->dev.of_node, "sprd,fb_display_size", display_size_array, 2);
+ if (0 != ret) {
+ printk("sprdfb: read display_size from dts fail (%d)\n", ret);
+ dev->display_width = dev->panel->width;
+ dev->display_height = dev->panel->height;
+ } else {
+ dev->display_width = display_size_array[0];
+ dev->display_height = display_size_array[1];
+ }
+#endif
+#endif
+
+ dev->ctrl->logo_proc(dev);
+ }else{
+ dev->panel_ready = false;
+ }
+
+ dev->ctrl->early_init(dev);
+
+ if(!dev->panel_ready){
+ if (!sprdfb_panel_probe(dev)) {
+ ret = -EIO;
+ goto cleanup;
+ }
+ }
+
+ ret = setup_fb_mem(dev, pdev);
+ if (ret) {
+ goto cleanup;
+ }
+
+ setup_fb_info(dev);
+ /* register framebuffer device */
+ ret = register_framebuffer(fb);
+ if (ret) {
+ printk(KERN_ERR "sprdfb: sprdfb_probe register framebuffer fail.\n");
+ goto cleanup;
+ }
+ platform_set_drvdata(pdev, dev);
+ sprdfb_create_sysfs(dev);
+ dev->ctrl->init(dev);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ dev->early_suspend.suspend = sprdfb_early_suspend;
+ dev->early_suspend.resume = sprdfb_late_resume;
+ dev->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+ register_early_suspend(&dev->early_suspend);
+#endif
+
+#ifdef CONFIG_FB_ESD_SUPPORT
+ pr_debug("sprdfb: Init ESD work queue!\n");
+ INIT_DELAYED_WORK(&dev->ESD_work, ESD_work_func);
+// sema_init(&dev->ESD_lock, 1);
+
+ if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){
+ dev->ESD_timeout_val = SPRDFB_ESD_TIME_OUT_VIDEO;
+ }else{
+ dev->ESD_timeout_val = SPRDFB_ESD_TIME_OUT_CMD;
+ }
+
+ dev->ESD_work_start = false;
+ dev->check_esd_time = 0;
+ dev->reset_dsi_time = 0;
+ dev->panel_reset_time = 0;
+#endif
+
+ return 0;
+
+cleanup:
+ sprdfb_panel_remove(dev);
+ dev->ctrl->uninit(dev);
+ fb_free_resources(dev);
+err0:
+ dev_err(&pdev->dev, "failed to probe sprdfb\n");
+ return ret;
+}
+
+static int sprdfb_remove(struct platform_device *pdev)
+{
+ struct sprdfb_device *dev = platform_get_drvdata(pdev);
+
+ printk("sprdfb: [%s]\n",__FUNCTION__);
+ sprdfb_remove_sysfs(dev);
+ sprdfb_panel_remove(dev);
+ dev->ctrl->uninit(dev);
+ fb_free_resources(dev);
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id sprdfb_dt_ids[] = {
+ { .compatible = "sprd,sprdfb", },
+ {}
+};
+#endif
+
+static struct platform_driver sprdfb_driver = {
+ .probe = sprdfb_probe,
+
+#ifndef CONFIG_HAS_EARLYSUSPEND
+ .suspend = sprdfb_suspend,
+ .resume = sprdfb_resume,
+#endif
+ .remove = sprdfb_remove,
+ .driver = {
+ .name = "sprd_fb",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = of_match_ptr(sprdfb_dt_ids),
+#endif
+ },
+};
+
+
+static int __init sprdfb_init(void)
+{
+ return platform_driver_register(&sprdfb_driver);
+}
+
+static void __exit sprdfb_exit(void)
+{
+ return platform_driver_unregister(&sprdfb_driver);
+}
+
+module_init(sprdfb_init);
+module_exit(sprdfb_exit);
diff --git a/drivers/video/sprdfb/sprdfb_mcu.c b/drivers/video/sprdfb/sprdfb_mcu.c
new file mode 100644
index 00000000..ff4f91fc
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_mcu.c
@@ -0,0 +1,563 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#ifdef CONFIG_OF
+#include <linux/fb.h>
+#endif
+
+#include "sprdfb.h"
+#include "sprdfb_panel.h"
+#include "sprdfb_dispc_reg.h"
+
+//#define CONFIG_FB_NO_FMARK /*Jessica for FPGA test*/
+
+static int32_t dispc_mcu_send_cmd(uint32_t cmd)
+{
+ int wait_count = 0;
+ /* busy wait for ahb fifo full sign's disappearance */
+ while((dispc_read(DISPC_DBI_QUEUE) & BIT(5)) && (wait_count < 20000)){
+ udelay(5);
+ wait_count++;
+ }
+ if(wait_count >= 20000){
+ printk("sprdfb: [%s] send cmd not finish!!!\n", __FUNCTION__);
+ return -1;
+ }
+
+ dispc_write(cmd, DISPC_DBI_CMD);
+
+ return 0;
+}
+
+static int32_t dispc_mcu_send_cmd_data(uint32_t cmd, uint32_t data)
+{
+ int wait_count = 0;
+ /* busy wait for ahb fifo full sign's disappearance */
+ while((dispc_read(DISPC_DBI_QUEUE) & BIT(5)) && (wait_count < 20000)){
+ udelay(5);
+ wait_count++;
+ }
+ if(wait_count >= 20000){
+ printk("sprdfb: [%s] send cmd data not finish 1!!!\n", __FUNCTION__);
+ return -1;
+ }
+
+ dispc_write(cmd, DISPC_DBI_CMD);
+
+ wait_count = 0;
+ /* busy wait for ahb fifo full sign's disappearance */
+ while((dispc_read(DISPC_DBI_QUEUE) & BIT(5)) && (wait_count < 20000)){
+ udelay(5);
+ wait_count++;
+ }
+ if(wait_count >= 20000){
+ printk("sprdfb: [%s] send cmd data not finish 2!!!\n", __FUNCTION__);
+ return -1;
+ }
+
+ dispc_write(data, DISPC_DBI_DATA);
+
+ return 0;
+}
+
+static int32_t dispc_mcu_send_data(uint32_t data)
+{
+ int wait_count = 0;
+ /* busy wait for ahb fifo full sign's disappearance */
+ while((dispc_read(DISPC_DBI_QUEUE) & BIT(5)) && (wait_count < 20000)){
+ udelay(5);
+ wait_count++;
+ }
+ if(wait_count >= 20000){
+ printk("sprdfb: [%s] send data not finish!!!\n", __FUNCTION__);
+ return -1;
+ }
+
+ dispc_write(data, DISPC_DBI_DATA);
+
+ return 0;
+}
+
+static uint32_t dispc_mcu_read_data(void)
+{
+ int wait_count = 0;
+ /* busy wait for ahb fifo full sign's disappearance */
+ while((dispc_read(DISPC_DBI_QUEUE) & BIT(5)) && (wait_count < 20000)){
+ udelay(5);
+ wait_count++;
+ }
+ if(wait_count >= 20000){
+ printk("sprdfb: [%s] read data not finish!!!\n", __FUNCTION__);
+ return -1;
+ }
+ dispc_write(1 << 24, DISPC_DBI_DATA);
+ udelay(50);
+ return dispc_read(DISPC_DBI_RDATA);
+}
+
+static struct ops_mcu dispc_mcu_ops = {
+ .send_cmd = dispc_mcu_send_cmd,
+ .send_cmd_data = dispc_mcu_send_cmd_data,
+ .send_data = dispc_mcu_send_data,
+ .read_data = dispc_mcu_read_data,
+};
+
+#ifdef CONFIG_OF
+static uint32_t mcu_calc_timing(struct timing_mcu *timing, struct sprdfb_device *dev)
+#else
+static uint32_t mcu_calc_timing(struct timing_mcu *timing, uint16_t dev_id)
+#endif
+{
+ uint32_t clk_rate;
+ uint32_t rcss, rlpw, rhpw, wcss, wlpw, whpw;
+ struct clk * clk = NULL;
+
+ if(NULL == timing){
+ printk(KERN_ERR "sprdfb: [%s]: Invalid Param\n", __FUNCTION__);
+ return 0;
+ }
+
+#ifdef CONFIG_OF
+ if(SPRDFB_MAINLCD_ID == dev->dev_id){
+ clk = of_clk_get_by_name(dev->of_dev->of_node,"dispc_dbi_clk");
+#else
+ if(SPRDFB_MAINLCD_ID == dev_id){
+ clk = clk_get(NULL,"clk_dispc_dbi");
+#endif
+ if (IS_ERR(clk)) {
+ printk(KERN_WARNING "sprdfb: get clk_dispc_dbi fail!\n");
+ } else {
+ pr_debug(KERN_INFO "sprdfb: get clk_dispc_dbi ok!\n");
+ }
+ }
+// clk_rate = clk_get_rate(clk) / 1000000;
+ clk_rate = 250; // dummy 250M Hz
+
+#ifdef CONFIG_OF
+ pr_debug(KERN_INFO "sprdfb: [%s] clk_rate: 0x%x, dev_id = %d\n", __FUNCTION__, clk_rate, dev->dev_id);
+#else
+ pr_debug(KERN_INFO "sprdfb: [%s] clk_rate: 0x%x, dev_id = %d\n", __FUNCTION__, clk_rate, dev_id);
+#endif
+ /********************************************************
+ * we assume : t = ? ns, dispc_dbi = ? MHz so
+ * 1ns need cycle : dispc_dbi /1000
+ * tns need cycles : t * dispc_dbi / 1000
+ *
+ ********************************************************/
+#define MAX_DBI_RWCSS_TIMING_VALUE 15
+#define MAX_DBI_RWLPW_TIMING_VALUE 63
+#define MAX_DBI_RWHPW_TIMING_VALUE 63
+#define DBI_CYCLES(ns) (( (ns) * clk_rate + 1000 - 1)/ 1000)
+
+ /* ceiling*/
+ rcss = DBI_CYCLES(timing->rcss);
+ if (rcss > MAX_DBI_RWCSS_TIMING_VALUE) {
+ rcss = MAX_DBI_RWCSS_TIMING_VALUE ;
+ }
+
+ rlpw = DBI_CYCLES(timing->rlpw);
+ if (rlpw > MAX_DBI_RWLPW_TIMING_VALUE) {
+ rlpw = MAX_DBI_RWLPW_TIMING_VALUE ;
+ }
+
+ rhpw = DBI_CYCLES (timing->rhpw);
+ if (rhpw > MAX_DBI_RWHPW_TIMING_VALUE) {
+ rhpw = MAX_DBI_RWHPW_TIMING_VALUE ;
+ }
+
+ wcss = DBI_CYCLES(timing->wcss);
+ if (wcss > MAX_DBI_RWCSS_TIMING_VALUE) {
+ wcss = MAX_DBI_RWCSS_TIMING_VALUE ;
+ }
+
+ wlpw = DBI_CYCLES(timing->wlpw);
+ if (wlpw > MAX_DBI_RWLPW_TIMING_VALUE) {
+ wlpw = MAX_DBI_RWLPW_TIMING_VALUE ;
+ }
+
+#ifndef CONFIG_LCD_CS_ALWAYS_LOW
+ /* dispc/lcdc will waste one cycle because CS pulse will use one cycle*/
+ whpw = DBI_CYCLES (timing->whpw) - 1;
+#else
+ whpw = DBI_CYCLES (timing->whpw) ;
+#endif
+ if (whpw > MAX_DBI_RWHPW_TIMING_VALUE) {
+ whpw = MAX_DBI_RWHPW_TIMING_VALUE ;
+ }
+
+ return (whpw | (wlpw << 6) | (wcss << 12)
+ | (rhpw << 16) |(rlpw << 22) | (rcss << 28));
+}
+
+static uint32_t mcu_readid(struct panel_spec *self)
+{
+ uint32_t id = 0;
+
+ /* default id reg is 0 */
+ self->info.mcu->ops->send_cmd(0x0);
+
+ if(self->info.mcu->bus_width == 8) {
+ id = (self->info.mcu->ops->read_data()) & 0xff;
+ id <<= 8;
+ id |= (self->info.mcu->ops->read_data()) & 0xff;
+ } else {
+ id = self->info.mcu->ops->read_data();
+ }
+
+ return id;
+}
+
+#ifdef CONFIG_FB_LCD_CS1
+/*cs1*/
+void mcu_dispc_init_config(struct panel_spec *panel)
+{
+ uint32_t reg_val = 0;
+
+ pr_debug("sprdfb: [%s] for cs1\n", __FUNCTION__);
+
+ if(NULL == panel){
+ printk(KERN_ERR "sprdfb: [%s] fail.(Invalid Param)\n", __FUNCTION__);
+ return;
+ }
+
+ if(SPRDFB_PANEL_TYPE_MCU != panel->type){
+ printk(KERN_ERR "sprdfb: [%s] fail.(not mcu panel)\n", __FUNCTION__);
+ return;
+ }
+
+ /*use dbi as interface*/
+ dispc_set_bits((2<<1), DISPC_CTRL);
+
+ /* CS1 bus mode [BIT8]: 8080/6800 */
+ switch (panel->info.mcu->bus_mode) {
+ case LCD_BUS_8080:
+ break;
+ case LCD_BUS_6800:
+ reg_val |= (1<<8);
+ break;
+ default:
+ break;
+ }
+ /* CS1 bus width [BIT11:9] */
+ switch (panel->info.mcu->bus_width) {
+ case 8:
+ break;
+ case 9:
+ reg_val |= (1 << 9);
+ break;
+ case 16:
+ reg_val |= (2 << 9);
+ break;
+ case 18:
+ reg_val |= (3 << 9) ;
+ break;
+ case 24:
+ reg_val |= (4 << 9);
+ break;
+ default:
+ break;
+ }
+
+ /*CS1 pixel bits [BIT13:12]*/
+ switch (panel->info.mcu->bpp) {
+ case 16:
+ break;
+ case 18:
+ reg_val |= (1 << 12) ;
+ break;
+ case 24:
+ reg_val |= (2 << 12);
+ break;
+ default:
+ break;
+ }
+
+#ifndef CONFIG_FB_NO_FMARK
+ /*TE enable*/
+ reg_val |= (1 << 16);
+ if(SPRDFB_POLARITY_NEG == panel->info.mcu->te_pol){
+ reg_val |= (1<< 17);
+ }
+ dispc_write(panel->info.mcu->te_sync_delay, DISPC_TE_SYNC_DELAY);
+#endif
+
+#ifdef CONFIG_LCD_CS_ALWAYS_LOW
+ /*CS alway low mode*/
+ reg_val |= (1<<21);
+#else
+ /*CS not alway low mode*/
+#endif
+
+ /*CS1 selected*/
+ reg_val |= (1 << 20);
+
+ dispc_write(reg_val, DISPC_DBI_CTRL);
+
+ pr_debug("sprdfb: [%s] DISPC_DBI_CTRL = %d\n", __FUNCTION__, dispc_read(DISPC_DBI_CTRL));
+}
+
+void mcu_dispc_set_timing(struct sprdfb_device *dev, uint32_t type)
+{
+ pr_debug("sprdfb: [%s] for cs1, type = %d\n", __FUNCTION__, type);
+
+ switch (type)
+ {
+ case MCU_LCD_REGISTER_TIMING:
+ dispc_write(dev->panel_timing.mcu_timing[MCU_LCD_REGISTER_TIMING],DISPC_DBI_TIMING1);
+ break;
+
+ case MCU_LCD_GRAM_TIMING:
+ dispc_write(dev->panel_timing.mcu_timing[MCU_LCD_GRAM_TIMING],DISPC_DBI_TIMING1);
+ break;
+ default:
+ break;
+ }
+}
+
+#else
+/*cs0*/
+void mcu_dispc_init_config(struct panel_spec *panel)
+{
+ uint32_t reg_val = 0;
+
+ pr_debug("sprdfb: [%s] for cs0\n", __FUNCTION__);
+
+ if(NULL == panel){
+ printk(KERN_ERR "sprdfb: [%s] fail.(Invalid Param)\n", __FUNCTION__);
+ return;
+ }
+
+ if(SPRDFB_PANEL_TYPE_MCU != panel->type){
+ printk(KERN_ERR "sprdfb: [%s] fail.(not mcu panel)\n", __FUNCTION__);
+ return;
+ }
+
+ /*use dbi as interface*/
+ dispc_set_bits((2<<1), DISPC_CTRL);
+
+ /* CS0 bus mode [BIT0]: 8080/6800 */
+ switch (panel->info.mcu->bus_mode) {
+ case LCD_BUS_8080:
+ break;
+ case LCD_BUS_6800:
+ reg_val |= 1;
+ break;
+ default:
+ break;
+ }
+ /* CS0 bus width [BIT3:1] */
+ switch (panel->info.mcu->bus_width) {
+ case 8:
+ break;
+ case 9:
+ reg_val |= (1 << 1);
+ break;
+ case 16:
+ reg_val |= (2 << 1);
+ break;
+ case 18:
+ reg_val |= (3 << 1) ;
+ break;
+ case 24:
+ reg_val |= (4 << 1);
+ break;
+ default:
+ break;
+ }
+
+ /*CS0 pixel bits [BIT5:4]*/
+ switch (panel->info.mcu->bpp) {
+ case 16:
+ break;
+ case 18:
+ reg_val |= (1 << 4) ;
+ break;
+ case 24:
+ reg_val |= (2 << 4);
+ break;
+ default:
+ break;
+ }
+
+#ifndef CONFIG_FB_NO_FMARK
+ /*TE enable*/
+ reg_val |= (1 << 16);
+ if(SPRDFB_POLARITY_NEG == panel->info.mcu->te_pol){
+ reg_val |= (1<< 17);
+ }
+ dispc_write(panel->info.mcu->te_sync_delay, DISPC_TE_SYNC_DELAY);
+#endif
+
+#ifdef CONFIG_LCD_CS_ALWAYS_LOW
+ /*CS alway low mode*/
+ reg_val |= (1<<21);
+#else
+ /*CS not alway low mode*/
+#endif
+
+ /*CS0 selected*/
+
+ dispc_write(reg_val, DISPC_DBI_CTRL);
+
+ pr_debug("sprdfb: [%s] DISPC_DBI_CTRL = %d\n", __FUNCTION__, dispc_read(DISPC_DBI_CTRL));
+}
+
+void mcu_dispc_set_timing(struct sprdfb_device *dev, uint32_t type)
+{
+ pr_debug("sprdfb: [%s] for cs0, type = %d\n", __FUNCTION__, type);
+
+ switch (type)
+ {
+ case MCU_LCD_REGISTER_TIMING:
+ dispc_write(dev->panel_timing.mcu_timing[MCU_LCD_REGISTER_TIMING],DISPC_DBI_TIMING0);
+ break;
+
+ case MCU_LCD_GRAM_TIMING:
+ dispc_write(dev->panel_timing.mcu_timing[MCU_LCD_GRAM_TIMING],DISPC_DBI_TIMING0);
+ break;
+ default:
+ break;
+ }
+}
+
+#endif
+
+static int32_t sprdfb_mcu_panel_check(struct panel_spec *panel)
+{
+ struct info_mcu* mcu_info = NULL;
+ bool rval = true;
+
+ if(NULL == panel){
+ printk("sprdfb: [%s] fail. (Invalid param)\n", __FUNCTION__);
+ return false;
+ }
+
+ if(SPRDFB_PANEL_TYPE_MCU != panel->type){
+ printk("sprdfb: [%s] fail. (not mcu param)\n", __FUNCTION__);
+ return false;
+ }
+
+ mcu_info = panel->info.mcu;
+
+ pr_debug("sprdfb: [%s]: bus width= %d, bpp = %d\n",__FUNCTION__, mcu_info->bus_width, mcu_info->bpp);
+
+ switch(mcu_info->bus_width){
+ case 8:
+ if((16 != mcu_info->bpp) && (24 != mcu_info->bpp)){
+ rval = false;
+ }
+ break;
+ case 9:
+ if(18 != mcu_info->bpp) {
+ rval = false;
+ }
+ break;
+ case 16:
+ if((16 != mcu_info->bpp) && (18 != mcu_info->bpp) &&
+ (24 != mcu_info->bpp)){
+ rval = false;
+ }
+ break;
+ case 18:
+ if(18 != mcu_info->bpp){
+ rval = false;
+ }
+ break;
+ case 24:
+ if(24 != mcu_info->bpp){
+ rval = false;
+ }
+ break;
+ default:
+ rval = false;
+ break;
+ }
+
+ if(!rval){
+ printk(KERN_ERR "sprdfb: mcu_panel_check return false!\n");
+ }
+
+ return rval;
+}
+
+static void sprdfb_mcu_panel_mount(struct sprdfb_device *dev)
+{
+ struct timing_mcu* timing = NULL;
+
+ if((NULL == dev) || (NULL == dev->panel)){
+ printk(KERN_ERR "sprdfb: [%s]: Invalid Param\n", __FUNCTION__);
+ return;
+ }
+
+ pr_debug(KERN_INFO "sprdfb: [%s], dev_id = %d\n",__FUNCTION__, dev->dev_id);
+
+ dev->panel_if_type = SPRDFB_PANEL_IF_DBI;
+
+ if(SPRDFB_MAINLCD_ID == dev->dev_id){
+ dev->panel->info.mcu->ops = &dispc_mcu_ops;
+ }
+
+ if(NULL == dev->panel->ops->panel_readid){
+ dev->panel->ops->panel_readid = mcu_readid;
+ }
+
+ timing = dev->panel->info.mcu->timing;
+#ifdef CONFIG_OF
+ dev->panel_timing.mcu_timing[MCU_LCD_REGISTER_TIMING] = mcu_calc_timing(timing, dev);
+#else
+ dev->panel_timing.mcu_timing[MCU_LCD_REGISTER_TIMING] = mcu_calc_timing(timing, dev->dev_id);
+#endif
+ timing++;
+#ifdef CONFIG_OF
+ dev->panel_timing.mcu_timing[MCU_LCD_GRAM_TIMING] = mcu_calc_timing(timing, dev);
+#else
+ dev->panel_timing.mcu_timing[MCU_LCD_GRAM_TIMING] = mcu_calc_timing(timing, dev->dev_id);
+#endif
+}
+
+static bool sprdfb_mcu_panel_init(struct sprdfb_device *dev)
+{
+ if(SPRDFB_MAINLCD_ID == dev->dev_id){
+ mcu_dispc_init_config(dev->panel);
+ mcu_dispc_set_timing(dev, MCU_LCD_REGISTER_TIMING);
+ }
+ return true;
+}
+
+static void sprdfb_mcu_panel_before_refresh(struct sprdfb_device *dev)
+{
+ if(SPRDFB_MAINLCD_ID == dev->dev_id){
+ mcu_dispc_set_timing(dev, MCU_LCD_GRAM_TIMING);
+ }
+}
+
+static void sprdfb_mcu_panel_after_refresh(struct sprdfb_device *dev)
+{
+ if(SPRDFB_MAINLCD_ID == dev->dev_id){
+ mcu_dispc_set_timing(dev, MCU_LCD_REGISTER_TIMING);
+ }
+}
+
+struct panel_if_ctrl sprdfb_mcu_ctrl = {
+ .if_name = "mcu",
+ .panel_if_check = sprdfb_mcu_panel_check,
+ .panel_if_mount = sprdfb_mcu_panel_mount,
+ .panel_if_init = sprdfb_mcu_panel_init,
+ .panel_if_before_refresh = sprdfb_mcu_panel_before_refresh,
+ .panel_if_after_refresh = sprdfb_mcu_panel_after_refresh,
+};
+
diff --git a/drivers/video/sprdfb/sprdfb_mipi.c b/drivers/video/sprdfb/sprdfb_mipi.c
new file mode 100644
index 00000000..e2cc1179
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_mipi.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+
+#include "sprdfb.h"
+#include "sprdfb_panel.h"
+#include "sprdfb_dispc_reg.h"
+
+extern struct ops_mipi sprdfb_mipi_ops;
+
+extern int32_t sprdfb_dsi_init(struct sprdfb_device *dev);
+extern int32_t sprdfb_dsi_uninit(struct sprdfb_device *dev);
+extern int32_t sprdfb_dsi_ready(struct sprdfb_device *dev);
+extern int32_t sprdfb_dsi_suspend(struct sprdfb_device *dev);
+extern int32_t sprdfb_dsi_resume(struct sprdfb_device *dev);
+extern int32_t sprdfb_dsi_before_panel_reset(struct sprdfb_device *dev);
+extern uint32_t sprdfb_dsi_get_status(struct sprdfb_device *dev);
+extern int32_t sprdfb_dsi_enter_ulps(struct sprdfb_device *dev);
+extern uint32_t rgb_calc_h_timing(struct timing_rgb *timing);
+extern uint32_t rgb_calc_v_timing(struct timing_rgb *timing);
+
+
+static uint32_t mipi_readid(struct panel_spec *self)
+{
+ uint32_t id = 0;
+ return id;
+}
+
+
+static void mipi_dispc_init_config(struct panel_spec *panel)
+{
+ uint32_t reg_val = dispc_read(DISPC_DPI_CTRL);
+
+ pr_debug("sprdfb: [%s]\n", __FUNCTION__);
+
+ if(NULL == panel){
+ printk(KERN_ERR "sprdfb: [%s] fail.(Invalid Param)\n", __FUNCTION__);
+ return;
+ }
+
+ if(SPRDFB_PANEL_TYPE_MIPI != panel->type){
+ printk(KERN_ERR "sprdfb: [%s] fail.(not mcu panel)\n", __FUNCTION__);
+ return;
+ }
+
+ if(SPRDFB_MIPI_MODE_CMD == panel->info.mipi->work_mode){
+ /*use edpi as interface*/
+ dispc_set_bits((1<<1), DISPC_CTRL);
+ }else{
+ /*use dpi as interface*/
+ dispc_clear_bits((3<<1), DISPC_CTRL);
+ }
+
+ /*h sync pol*/
+ if(SPRDFB_POLARITY_NEG == panel->info.mipi->h_sync_pol){
+ reg_val |= (1<<0);
+ }
+
+ /*v sync pol*/
+ if(SPRDFB_POLARITY_NEG == panel->info.mipi->v_sync_pol){
+ reg_val |= (1<<1);
+ }
+
+ /*de sync pol*/
+ if(SPRDFB_POLARITY_NEG == panel->info.mipi->de_pol){
+ reg_val |= (1<<2);
+ }
+
+ if(SPRDFB_MIPI_MODE_VIDEO == panel->info.mipi->work_mode){
+#ifdef CONFIG_DPI_SINGLE_RUN
+ /*single run mode*/
+ reg_val |= (1<<3);
+#endif
+ }else{
+ if(!(panel->cap & PANEL_CAP_NOT_TEAR_SYNC)){
+ printk("sprdfb: mipi_dispc_init_config not support TE\n");
+ /*enable te*/
+ reg_val |= (1<<8);
+ }
+ /*te pol*/
+ if(SPRDFB_POLARITY_NEG == panel->info.mipi->te_pol){
+ reg_val |= (1<<9);
+ }
+ /*use external te*/
+ reg_val |= (1<<10);
+ }
+
+ /*dpi bits*/
+ switch(panel->info.rgb->video_bus_width){
+ case 16:
+ break;
+ case 18:
+ reg_val |= (1 << 6);
+ break;
+ case 24:
+ reg_val |= (2 << 6);
+ break;
+ default:
+ break;
+ }
+
+ dispc_write(reg_val, DISPC_DPI_CTRL);
+
+ pr_debug("sprdfb: [%s] DISPC_DPI_CTRL = %d\n", __FUNCTION__, dispc_read(DISPC_DPI_CTRL));
+}
+
+static void mipi_dispc_set_timing(struct sprdfb_device *dev)
+{
+ pr_debug("sprdfb: [%s]\n", __FUNCTION__);
+
+ dispc_write(dev->panel_timing.rgb_timing[RGB_LCD_H_TIMING], DISPC_DPI_H_TIMING);
+ dispc_write(dev->panel_timing.rgb_timing[RGB_LCD_V_TIMING], DISPC_DPI_V_TIMING);
+}
+
+static int32_t sprdfb_mipi_panel_check(struct panel_spec *panel)
+{
+ if(NULL == panel){
+ printk("sprdfb: [%s] fail. (Invalid param)\n", __FUNCTION__);
+ return false;
+ }
+
+ if(SPRDFB_PANEL_TYPE_MIPI != panel->type){
+ printk("sprdfb: [%s] fail. (not mipi param)\n", __FUNCTION__);
+ return false;
+ }
+
+ pr_debug("sprdfb: [%s]\n",__FUNCTION__);
+
+ return true;
+}
+
+static void sprdfb_mipi_panel_mount(struct sprdfb_device *dev)
+{
+ if((NULL == dev) || (NULL == dev->panel)){
+ printk(KERN_ERR "sprdfb: [%s]: Invalid Param\n", __FUNCTION__);
+ return;
+ }
+
+ pr_debug(KERN_INFO "sprdfb: [%s], dev_id = %d\n",__FUNCTION__, dev->dev_id);
+
+ if(SPRDFB_MIPI_MODE_CMD == dev->panel->info.mipi->work_mode){
+ dev->panel_if_type = SPRDFB_PANEL_IF_EDPI;
+ }else{
+ dev->panel_if_type = SPRDFB_PANEL_IF_DPI;
+ }
+
+ dev->panel->info.mipi->ops = &sprdfb_mipi_ops;
+
+ if(NULL == dev->panel->ops->panel_readid){
+ dev->panel->ops->panel_readid = mipi_readid;
+ }
+
+ dev->panel_timing.rgb_timing[RGB_LCD_H_TIMING] = rgb_calc_h_timing(dev->panel->info.mipi->timing);
+ dev->panel_timing.rgb_timing[RGB_LCD_V_TIMING] = rgb_calc_v_timing(dev->panel->info.mipi->timing);
+}
+
+static bool sprdfb_mipi_panel_init(struct sprdfb_device *dev)
+{
+ sprdfb_dsi_init(dev);
+
+ mipi_dispc_init_config(dev->panel);
+ mipi_dispc_set_timing(dev);
+ return true;
+}
+
+static void sprdfb_mipi_panel_uninit(struct sprdfb_device *dev)
+{
+ sprdfb_dsi_uninit(dev);
+}
+
+static void sprdfb_mipi_panel_ready(struct sprdfb_device *dev)
+{
+ sprdfb_dsi_ready(dev);
+}
+
+static void sprdfb_mipi_panel_before_reset(struct sprdfb_device *dev)
+{
+ sprdfb_dsi_before_panel_reset(dev);
+}
+
+static void sprdfb_mipi_panel_enter_ulps(struct sprdfb_device *dev)
+{
+ sprdfb_dsi_enter_ulps(dev);
+}
+
+static void sprdfb_mipi_panel_suspend(struct sprdfb_device *dev)
+{
+ printk(KERN_INFO "sprdfb: [%s], dev_id = %d\n",__FUNCTION__, dev->dev_id);
+ sprdfb_dsi_uninit(dev);
+ //sprdfb_dsi_suspend(dev);
+}
+
+static void sprdfb_mipi_panel_resume(struct sprdfb_device *dev)
+{
+ printk(KERN_INFO "sprdfb: [%s], dev_id = %d\n",__FUNCTION__, dev->dev_id);
+ sprdfb_dsi_init(dev);
+ //sprdfb_dsi_resume(dev);
+}
+
+static uint32_t sprdfb_mipi_get_status(struct sprdfb_device *dev)
+{
+ return sprdfb_dsi_get_status(dev);
+}
+
+struct panel_if_ctrl sprdfb_mipi_ctrl = {
+ .if_name = "mipi",
+ .panel_if_check = sprdfb_mipi_panel_check,
+ .panel_if_mount = sprdfb_mipi_panel_mount,
+ .panel_if_init = sprdfb_mipi_panel_init,
+ .panel_if_uninit = sprdfb_mipi_panel_uninit,
+ .panel_if_ready =sprdfb_mipi_panel_ready,
+ .panel_if_before_refresh = NULL,
+ .panel_if_after_refresh = NULL,
+ .panel_if_before_panel_reset = sprdfb_mipi_panel_before_reset,
+ .panel_if_enter_ulps = sprdfb_mipi_panel_enter_ulps,
+ .panel_if_suspend = sprdfb_mipi_panel_suspend,
+ .panel_if_resume = sprdfb_mipi_panel_resume,
+ .panel_if_get_status = sprdfb_mipi_get_status,
+};
+
diff --git a/drivers/video/sprdfb/sprdfb_panel.c b/drivers/video/sprdfb/sprdfb_panel.c
new file mode 100644
index 00000000..1d53bbe8
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_panel.c
@@ -0,0 +1,683 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+
+#include "sprdfb.h"
+#include "sprdfb_panel.h"
+#include "sprdfb_dispc_reg.h"
+
+static LIST_HEAD(panel_list_main);/* for main_lcd*/
+static LIST_HEAD(panel_list_sub);/* for sub_lcd */
+static DEFINE_MUTEX(panel_mutex);
+
+uint32_t lcd_id_from_uboot = 0;
+unsigned long lcd_base_from_uboot = 0;
+
+extern struct panel_if_ctrl sprdfb_mcu_ctrl;
+extern struct panel_if_ctrl sprdfb_rgb_ctrl;
+#ifndef CONFIG_FB_SCX15
+extern struct panel_if_ctrl sprdfb_mipi_ctrl;
+#endif
+extern void sprdfb_panel_remove(struct sprdfb_device *dev);
+
+static int __init lcd_id_get(char *str)
+{
+ if ((str != NULL) && (str[0] == 'I') && (str[1] == 'D')) {
+ sscanf(&str[2], "%x", &lcd_id_from_uboot);
+ }
+
+ printk(KERN_INFO "sprdfb: [%s]LCD Panel ID from uboot: 0x%x\n", __FUNCTION__, lcd_id_from_uboot);
+
+ return 1;
+}
+__setup("lcd_id=", lcd_id_get);
+static int __init lcd_base_get(char *str)
+{
+ if (str != NULL) {
+ sscanf(&str[0], "%lx", &lcd_base_from_uboot);
+ }
+ printk(KERN_INFO "sprdfb: [%s]LCD Panel Base from uboot: 0x%lx\n", __FUNCTION__, lcd_base_from_uboot);
+ return 1;
+}
+__setup("lcd_base=", lcd_base_get);
+
+static int32_t panel_reset_dispc(struct panel_spec *self)
+{
+ uint16_t timing1, timing2, timing3;
+
+ if((NULL != self) && (0 != self->reset_timing.time1) &&
+ (0 != self->reset_timing.time2) && (0 != self->reset_timing.time3)) {
+ timing1 = self->reset_timing.time1;
+ timing2 = self->reset_timing.time2;
+ timing3 = self->reset_timing.time3;
+ }else {
+ timing1 = 20;
+ timing2 = 20;
+ timing3 = 120;
+ }
+
+ dispc_write(1, DISPC_RSTN);
+ usleep_range(timing1*1000, timing1*1000+500);
+ dispc_write(0, DISPC_RSTN);
+ usleep_range(timing2*1000, timing2*1000+500);
+ dispc_write(1, DISPC_RSTN);
+
+ /* wait 10ms util the lcd is stable */
+ usleep_range(timing3*1000, timing3*1000+500);
+
+ return 0;
+}
+
+static int32_t panel_set_resetpin_dispc( uint32_t status)
+{
+ if(0 == status){
+ dispc_write(0, DISPC_RSTN);
+ }else{
+ dispc_write(1, DISPC_RSTN);
+ }
+ return 0;
+}
+
+static int panel_reset(struct sprdfb_device *dev)
+{
+ if((NULL == dev) || (NULL == dev->panel)){
+ printk(KERN_ERR "sprdfb: [%s]: Invalid param\n", __FUNCTION__);
+ return -1;
+ }
+
+ pr_debug("sprdfb: [%s], enter\n",__FUNCTION__);
+
+ //clk/data lane enter LP
+ if(NULL != dev->panel->if_ctrl->panel_if_before_panel_reset){
+ dev->panel->if_ctrl->panel_if_before_panel_reset(dev);
+ }
+ usleep_range(5000, 5500);
+
+ //reset panel
+ dev->panel->ops->panel_reset(dev->panel);
+
+ return 0;
+}
+
+static int panel_sleep(struct sprdfb_device *dev)
+{
+ if((NULL == dev) || (NULL == dev->panel)){
+ printk(KERN_ERR "sprdfb: [%s]: Invalid param\n", __FUNCTION__);
+ return -1;
+ }
+
+ pr_debug("sprdfb: [%s], enter\n",__FUNCTION__);
+
+ //send sleep cmd to lcd
+ if (dev->panel->ops->panel_enter_sleep != NULL) {
+ dev->panel->ops->panel_enter_sleep(dev->panel,1);
+ }
+ msleep(100);
+ //clk/data lane enter LP
+ if((NULL != dev->panel->if_ctrl->panel_if_before_panel_reset)
+ &&(SPRDFB_PANEL_TYPE_MIPI == dev->panel->type))
+ {
+ dev->panel->if_ctrl->panel_if_before_panel_reset(dev);
+ }
+ return 0;
+}
+
+static void panel_set_resetpin(uint16_t dev_id, uint32_t status, struct panel_spec *panel )
+{
+ pr_debug("sprdfb: [%s].\n",__FUNCTION__);
+
+ /*panel set reset pin status*/
+ if(SPRDFB_MAINLCD_ID == dev_id){
+ panel_set_resetpin_dispc(status);
+ }
+}
+
+
+static int32_t panel_before_resume(struct sprdfb_device *dev)
+{
+ /*restore the reset pin to high*/
+ panel_set_resetpin(dev->dev_id, 1, dev->panel);
+ return 0;
+}
+
+static int32_t panel_after_suspend(struct sprdfb_device *dev)
+{
+ /*set the reset pin to low*/
+ panel_set_resetpin(dev->dev_id, 0, dev->panel);
+ return 0;
+}
+
+static bool panel_check(struct panel_cfg *cfg)
+{
+ bool rval = true;
+
+ if(NULL == cfg || NULL == cfg->panel){
+ printk(KERN_ERR "sprdfb: [%s] :Invalid Param!\n", __FUNCTION__);
+ return false;
+ }
+
+ pr_debug("sprdfb: [%s], dev_id = %d, lcd_id = 0x%x, type = %d\n",__FUNCTION__, cfg->dev_id, cfg->lcd_id, cfg->panel->type);
+
+ switch(cfg->panel->type){
+ case SPRDFB_PANEL_TYPE_MCU:
+ cfg->panel->if_ctrl = &sprdfb_mcu_ctrl;
+ break;
+ case SPRDFB_PANEL_TYPE_RGB:
+ case SPRDFB_PANEL_TYPE_LVDS:
+ cfg->panel->if_ctrl = &sprdfb_rgb_ctrl;
+ break;
+#ifndef CONFIG_FB_SCX15
+ case SPRDFB_PANEL_TYPE_MIPI:
+ cfg->panel->if_ctrl = &sprdfb_mipi_ctrl;
+ break;
+#endif
+ default:
+ printk("sprdfb: [%s]: erro panel type.(%d,%d, %d)",__FUNCTION__, cfg->dev_id, cfg->lcd_id, cfg->panel->type);
+ cfg->panel->if_ctrl = NULL;
+ break;
+ };
+
+ if(cfg->panel->if_ctrl->panel_if_check){
+ rval = cfg->panel->if_ctrl->panel_if_check(cfg->panel);
+ }
+ return rval;
+}
+
+static int panel_mount(struct sprdfb_device *dev, struct panel_spec *panel)
+{
+ printk("sprdfb: [%s], dev_id = %d\n",__FUNCTION__, dev->dev_id);
+
+ /* TODO: check whether the mode/res are supported */
+ dev->panel = panel;
+
+ if(NULL == dev->panel->ops->panel_reset){
+ if(SPRDFB_MAINLCD_ID == dev->dev_id){
+ dev->panel->ops->panel_reset = panel_reset_dispc;
+ }
+ }
+
+ panel->if_ctrl->panel_if_mount(dev);
+
+ return 0;
+}
+
+
+int panel_init(struct sprdfb_device *dev)
+{
+ if((NULL == dev) || (NULL == dev->panel)){
+ printk(KERN_ERR "sprdfb: [%s]: Invalid param\n", __FUNCTION__);
+ return -1;
+ }
+
+ pr_debug("sprdfb: [%s], dev_id= %d, type = %d\n",__FUNCTION__, dev->dev_id, dev->panel->type);
+
+ if(!dev->panel->if_ctrl->panel_if_init(dev)){
+ printk(KERN_ERR "sprdfb: [%s]: panel_if_init fail!\n", __FUNCTION__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int panel_ready(struct sprdfb_device *dev)
+{
+ if((NULL == dev) || (NULL == dev->panel)){
+ printk(KERN_ERR "sprdfb: [%s]: Invalid param\n", __FUNCTION__);
+ return -1;
+ }
+
+ pr_debug("sprdfb: [%s], dev_id= %d, type = %d\n",__FUNCTION__, dev->dev_id, dev->panel->type);
+
+ if(NULL != dev->panel->if_ctrl->panel_if_ready){
+ dev->panel->if_ctrl->panel_if_ready(dev);
+ }
+
+ return 0;
+}
+
+
+static struct panel_spec *adapt_panel_from_uboot(uint16_t dev_id)
+{
+ struct panel_cfg *cfg;
+ struct list_head *panel_list;
+
+ pr_debug("sprdfb: [%s], dev_id = %d\n",__FUNCTION__, dev_id);
+
+ if (lcd_id_from_uboot == 0) {
+ printk("sprdfb: [%s]: Not got lcd id from uboot\n", __FUNCTION__);
+ return NULL;
+ }
+
+ if(SPRDFB_MAINLCD_ID == dev_id){
+ panel_list = &panel_list_main;
+ }else{
+ panel_list = &panel_list_sub;
+ }
+
+ list_for_each_entry(cfg, panel_list, list) {
+ if(lcd_id_from_uboot == cfg->lcd_id) {
+ printk(KERN_INFO "sprdfb: [%s]: LCD Panel 0x%x is attached!\n", __FUNCTION__,cfg->lcd_id);
+
+ return cfg->panel;
+ }
+ }
+ printk(KERN_ERR "sprdfb: [%s]: Failed to match LCD Panel from uboot!\n", __FUNCTION__);
+
+ return NULL;
+}
+
+static struct panel_spec *adapt_panel_from_readid(struct sprdfb_device *dev)
+{
+ struct panel_cfg *cfg;
+ struct panel_cfg *dummy_cfg = NULL;
+ struct list_head *panel_list;
+ uint32_t id;
+
+ printk("sprdfb: [%s], dev_id = %d\n",__FUNCTION__, dev->dev_id);
+
+ if(SPRDFB_MAINLCD_ID == dev->dev_id){
+ panel_list = &panel_list_main;
+ }else{
+ panel_list = &panel_list_sub;
+ }
+
+ list_for_each_entry(cfg, panel_list, list) {
+ if(0xFFFFFFFF == cfg->lcd_id){
+ dummy_cfg = cfg;
+ continue;
+ }
+ printk("sprdfb: [%s]: try panel 0x%x\n", __FUNCTION__, cfg->lcd_id);
+ panel_mount(dev, cfg->panel);
+#ifndef CONFIG_SC_FPGA
+ dev->ctrl->update_clk(dev);
+#endif
+ panel_init(dev);
+ panel_reset(dev);
+ id = dev->panel->ops->panel_readid(dev->panel);
+ if(id == cfg->lcd_id) {
+ pr_debug(KERN_INFO "sprdfb: [%s]: LCD Panel 0x%x is attached!\n", __FUNCTION__, cfg->lcd_id);
+ dev->panel->ops->panel_init(dev->panel);
+ panel_ready(dev);
+ return cfg->panel;
+ }
+ sprdfb_panel_remove(dev);
+ }
+ if(dummy_cfg != NULL){
+ printk("sprdfb: [%s]: Can't find read panel, Use dummy panel!\n", __FUNCTION__);
+ panel_mount(dev, dummy_cfg->panel);
+#ifndef CONFIG_SC_FPGA
+ dev->ctrl->update_clk(dev);
+#endif
+ panel_init(dev);
+ panel_reset(dev);
+ id = dev->panel->ops->panel_readid(dev->panel);
+ if(id == dummy_cfg->lcd_id) {
+ pr_debug(KERN_INFO "sprdfb: [%s]: LCD Panel 0x%x is attached!\n", __FUNCTION__, dummy_cfg->lcd_id);
+ dev->panel->ops->panel_init(dev->panel);
+ panel_ready(dev);
+ return dummy_cfg->panel;
+ }
+ sprdfb_panel_remove(dev);
+ }
+ printk(KERN_ERR "sprdfb: [%s]: failed to attach LCD Panel!\n", __FUNCTION__);
+ return NULL;
+}
+
+
+bool sprdfb_panel_get(struct sprdfb_device *dev)
+{
+ struct panel_spec *panel = NULL;
+
+ if(NULL == dev){
+ printk("sprdfb: [%s]: Invalid param\n", __FUNCTION__);
+ return false;
+ }
+
+ printk("sprdfb: [%s], dev_id = %d\n",__FUNCTION__, dev->dev_id);
+
+ panel = adapt_panel_from_uboot(dev->dev_id);
+ if (panel) {
+ dev->panel_ready = true;
+ panel_mount(dev, panel);
+ panel_init(dev);
+ printk("sprdfb: [%s] got panel\n", __FUNCTION__);
+ return true;
+ }
+
+ printk("sprdfb: [%s] can not got panel\n", __FUNCTION__);
+
+ return false;
+}
+
+
+bool sprdfb_panel_probe(struct sprdfb_device *dev)
+{
+ struct panel_spec *panel;
+
+ if(NULL == dev){
+ printk("sprdfb: [%s]: Invalid param\n", __FUNCTION__);
+ return false;
+ }
+
+ printk("sprdfb: [%s], dev_id = %d\n",__FUNCTION__, dev->dev_id);
+
+ /* can not be here in normal; we should get correct device id from uboot */
+ panel = adapt_panel_from_readid(dev);
+
+ if (panel) {
+ printk("sprdfb: [%s] got panel\n", __FUNCTION__);
+ return true;
+ }
+
+ printk("sprdfb: [%s] can not got panel\n", __FUNCTION__);
+
+ return false;
+}
+
+void sprdfb_panel_invalidate_rect(struct panel_spec *self,
+ uint16_t left, uint16_t top,
+ uint16_t right, uint16_t bottom)
+{
+ /*Jessica TODO: */
+ if(NULL != self->ops->panel_invalidate_rect){
+ self->ops->panel_invalidate_rect(self, left, top, right, bottom);
+ }
+ /*Jessica TODO: Need set timing to GRAM timing*/
+}
+
+void sprdfb_panel_invalidate(struct panel_spec *self)
+{
+ /*Jessica TODO:*/
+ if(NULL != self->ops->panel_invalidate){
+ self->ops->panel_invalidate(self);
+ }
+ /*Jessica TODO: Need set timing to GRAM timing*/
+}
+
+void sprdfb_panel_before_refresh(struct sprdfb_device *dev)
+{
+ if(NULL != dev->panel->if_ctrl->panel_if_before_refresh){
+ dev->panel->if_ctrl->panel_if_before_refresh(dev);
+ }
+}
+
+void sprdfb_panel_after_refresh(struct sprdfb_device *dev)
+{
+ if(NULL != dev->panel->if_ctrl->panel_if_after_refresh){
+ dev->panel->if_ctrl->panel_if_after_refresh(dev);
+ }
+}
+
+#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING
+void sprdfb_panel_change_fps(struct sprdfb_device *dev, int fps_level)
+{
+ if (dev->panel->ops->panel_change_fps!= NULL) {
+ printk("sprdfb: [%s] fps_level= %d\n", __FUNCTION__,fps_level);
+ dev->panel->ops->panel_change_fps(dev->panel,fps_level);
+ }
+}
+#endif
+
+#ifdef CONFIG_FB_ESD_SUPPORT
+/*return value: 0--panel OK.1-panel has been reset*/
+uint32_t sprdfb_panel_ESD_check(struct sprdfb_device *dev)
+{
+ int32_t result = 0;
+ uint32_t if_status = 0;
+
+// printk("sprdfb: [%s] (%d, %d, %d)\n",__FUNCTION__, dev->check_esd_time, dev->panel_reset_time, dev->reset_dsi_time);
+
+ dev->check_esd_time++;
+
+ if(SPRDFB_PANEL_IF_EDPI == dev->panel_if_type){
+ if (dev->panel->ops->panel_esd_check != NULL) {
+ result = dev->panel->ops->panel_esd_check(dev->panel);
+ pr_debug("sprdfb: [%s] panel check return %d\n", __FUNCTION__, result);
+ }
+ }else if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){
+#ifdef FB_CHECK_ESD_BY_TE_SUPPORT
+ dev->esd_te_waiter++;
+ dev->esd_te_done = 0;
+ dispc_set_bits(BIT(1), DISPC_INT_EN);
+ result = wait_event_interruptible_timeout(dev->esd_te_queue,
+ dev->esd_te_done, msecs_to_jiffies(600));
+ pr_debug("sprdfb: after wait (%d)\n", result);
+ dispc_clear_bits(BIT(1), DISPC_INT_EN);
+ if(!result){ /*time out*/
+ printk("sprdfb: [%s] esd check not got te signal!!!!\n", __FUNCTION__);
+ dev->esd_te_waiter = 0;
+ result = 0;
+ }else{
+ pr_debug("sprdfb: [%s] esd check got te signal!\n", __FUNCTION__);
+ result = 1;
+ }
+#else
+ if (dev->panel->ops->panel_esd_check != NULL) {
+ result = dev->panel->ops->panel_esd_check(dev->panel);
+// pr_debug("sprdfb: [%s] panel check return %d\n", __FUNCTION__, result);
+ }
+
+#endif
+ }
+
+
+ if(0 == dev->enable){
+ printk("sprdfb: [%s] leave (Invalid device status)!\n", __FUNCTION__);
+ return 0;
+ }
+
+ if(result == 0){
+ dev->panel_reset_time++;
+
+ if(SPRDFB_PANEL_IF_EDPI == dev->panel_if_type){
+ if(NULL != dev->panel->if_ctrl->panel_if_get_status){
+ if_status = dev->panel->if_ctrl->panel_if_get_status(dev);
+ }
+ }else if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){
+ if_status = 2; /*need reset dsi as default for dpi mode*/
+ }
+
+ if(0 == if_status){
+ printk("sprdfb: [%s] fail! Need reset panel.(%d,%d,%d)\n", __FUNCTION__,
+ dev->check_esd_time, dev->panel_reset_time, dev->reset_dsi_time);
+ panel_reset(dev);
+
+ if(0 == dev->enable){
+ printk("sprdfb: [%s] leave (Invalid device status)!\n", __FUNCTION__);
+ return 0;
+ }
+
+ dev->panel->ops->panel_init(dev->panel);
+ panel_ready(dev);
+ }else{
+ printk("sprdfb: [%s] fail! Need reset panel and panel if!!!!(%d,%d,%d)\n",__FUNCTION__,
+ dev->check_esd_time, dev->panel_reset_time, dev->reset_dsi_time);
+ dev->reset_dsi_time++;
+ if(NULL != dev->panel->if_ctrl->panel_if_suspend){
+ dev->panel->if_ctrl->panel_if_suspend(dev);
+ }
+
+ mdelay(10);
+
+ if(0 == dev->enable){
+ printk("sprdfb: [%s] leave (Invalid device status)!\n", __FUNCTION__);
+ return 0;
+ }
+
+ panel_init(dev);
+ panel_reset(dev);
+
+ if(0 == dev->enable){
+ printk("sprdfb: [%s] leave (Invalid device status)!\n", __FUNCTION__);
+ return 0;
+ }
+
+ dev->panel->ops->panel_init(dev->panel);
+ panel_ready(dev);
+ }
+ pr_debug("sprdfb: [%s]return 1\n",__FUNCTION__);
+ return 1;
+ }
+// pr_debug("sprdfb: [%s]return 0\n",__FUNCTION__);
+ return 0;
+}
+#endif
+
+void sprdfb_panel_suspend(struct sprdfb_device *dev)
+{
+ if(NULL == dev->panel){
+ return;
+ }
+
+ printk("sprdfb: [%s], dev_id = %d\n",__FUNCTION__, dev->dev_id);
+#if 0
+ //step1-1 clk/data lane enter LP
+ if(NULL != dev->panel->if_ctrl->panel_if_before_panel_reset){
+ dev->panel->if_ctrl->panel_if_before_panel_reset(dev);
+ }
+
+ //step1-2 enter sleep (another way : reset panel)
+ /*Jessica TODO: Need do some I2c, SPI, mipi sleep here*/
+ /* let lcdc sleep in */
+
+ if (dev->panel->ops->panel_enter_sleep != NULL) {
+ dev->panel->ops->panel_enter_sleep(dev->panel,1);
+ }
+ msleep(100);
+#else
+ //step1 send lcd sleep cmd or reset panel directly
+ if(dev->panel->suspend_mode == SEND_SLEEP_CMD){
+ panel_sleep(dev);
+ }else{
+ panel_reset(dev);
+ }
+#endif
+
+ //step2 clk/data lane enter ulps
+ if(NULL != dev->panel->if_ctrl->panel_if_enter_ulps){
+ dev->panel->if_ctrl->panel_if_enter_ulps(dev);
+ }
+
+ //step3 turn off mipi
+ if(NULL != dev->panel->if_ctrl->panel_if_suspend){
+ dev->panel->if_ctrl->panel_if_suspend(dev);
+ }
+
+ //step4 reset pin to low
+ if (dev->panel->ops->panel_after_suspend != NULL) {
+ //himax mipi lcd may define empty function
+ dev->panel->ops->panel_after_suspend(dev->panel);
+ }
+ else{
+ panel_after_suspend(dev);
+ }
+}
+
+void sprdfb_panel_resume(struct sprdfb_device *dev, bool from_deep_sleep)
+{
+ if(NULL == dev->panel){
+ return;
+ }
+
+ printk(KERN_INFO "sprdfb: [%s], dev->enable= %d, from_deep_sleep = %d\n",__FUNCTION__, dev->enable, from_deep_sleep);
+#if 0
+ /*Jessica TODO: resume i2c, spi, mipi*/
+ if(NULL != dev->panel->if_ctrl->panel_if_resume){
+ dev->panel->if_ctrl->panel_if_resume(dev);
+ }
+ panel_ready(dev);
+#endif
+ //step1 reset pin to high
+ if (dev->panel->ops->panel_before_resume != NULL) {
+ //himax mipi lcd may define empty function
+ dev->panel->ops->panel_before_resume(dev->panel);
+ }
+ else{
+ panel_before_resume(dev);
+ }
+
+ if(from_deep_sleep){
+ //step2 turn on mipi
+ panel_init(dev);
+
+ //step3 reset panel
+ panel_reset(dev);
+
+ //step4 panel init
+ dev->panel->ops->panel_init(dev->panel);
+
+ //step5 clk/data lane enter HS
+ panel_ready(dev);
+ }else{
+ //step2 turn on mipi
+ /*Jessica TODO: resume i2c, spi, mipi*/
+ if(NULL != dev->panel->if_ctrl->panel_if_resume){
+ dev->panel->if_ctrl->panel_if_resume(dev);
+ }
+
+ //step3 sleep out
+ if(NULL != dev->panel->ops->panel_enter_sleep){
+ dev->panel->ops->panel_enter_sleep(dev->panel,0);
+ }
+
+ //step4 clk/data lane enter HS
+ panel_ready(dev);
+ }
+
+}
+
+void sprdfb_panel_remove(struct sprdfb_device *dev)
+{
+ if(NULL == dev->panel){
+ return;
+ }
+
+ /*Jessica TODO:close panel, i2c, spi, mipi*/
+ if(NULL != dev->panel->if_ctrl->panel_if_uninit){
+ dev->panel->if_ctrl->panel_if_uninit(dev);
+ }
+ dev->panel = NULL;
+}
+
+
+int sprdfb_panel_register(struct panel_cfg *cfg)
+{
+ pr_debug("sprdfb: [%s], panel id = %d\n",__FUNCTION__, cfg->dev_id);
+
+ if(!panel_check(cfg)){
+ printk("sprdfb: [%s]: panel check fail!id = %d\n",__FUNCTION__, cfg->dev_id);
+ return -1;
+ }
+
+ mutex_lock(&panel_mutex);
+
+ if (cfg->dev_id == SPRDFB_MAINLCD_ID) {
+ list_add_tail(&cfg->list, &panel_list_main);
+ } else if (cfg->dev_id == SPRDFB_SUBLCD_ID) {
+ list_add_tail(&cfg->list, &panel_list_sub);
+ } else {
+ list_add_tail(&cfg->list, &panel_list_main);
+ list_add_tail(&cfg->list, &panel_list_sub);
+ }
+
+ mutex_unlock(&panel_mutex);
+
+ return 0;
+}
+
+
diff --git a/drivers/video/sprdfb/sprdfb_panel.h b/drivers/video/sprdfb/sprdfb_panel.h
new file mode 100644
index 00000000..026935e1
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_panel.h
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SPRDFB_PANEL_H_
+#define _SPRDFB_PANEL_H_
+
+#include "sprdfb.h"
+
+#define SPRDFB_MAINLCD_ID 0
+#define SPRDFB_SUBLCD_ID 1
+#define SPRDFB_UNDEFINELCD_ID -1
+
+#define SPRDFB_I2C_WRITE_DELAY 0xffff
+
+
+/* LCD mode */
+#define LCD_MODE_MCU 0
+#define LCD_MODE_RGB 1
+#define LCD_MODE_DSI 2
+#define LCD_MODE_LVDS 3
+
+/* LCD supported FPS */
+#define LCD_MAX_FPS 70
+#define LCD_MIN_FPS 30
+
+/* LCD suspend mode */
+
+/* SEND_SLEEP_CMD refer to send enter sleep cmd to panel before reset panel,
+ssd panel need hs clk before enter sleep or reset panel */
+#define SEND_SLEEP_CMD 1
+
+
+/* bus mode */
+#define LCD_BUS_8080 0
+#define LCD_BUS_6800 1
+#define LCD_BUS_SPI 2
+
+/* lcd directions */
+#define LCD_DIRECT_NORMAL 0
+#define LCD_DIRECT_ROT_90 1
+#define LCD_DIRECT_ROT_180 2
+#define LCD_DIRECT_ROT_270 3
+#define LCD_DIRECT_MIR_H 4
+#define LCD_DIRECT_MIR_V 5
+#define LCD_DIRECT_MIR_HV 6
+
+/* panel property */
+/* lcdc refresh, TE on, double timing, partial update*/
+#define PANEL_CAP_NORMAL 0x0
+
+/* only not support partial update*/
+#define PANEL_CAP_NOT_PARTIAL_UPDATE 0x1
+
+/* write register, grame have the same timing */
+#define PANEL_CAP_UNIQUE_TIMING 0x2
+
+/* lcd not support TE */
+#define PANEL_CAP_NOT_TEAR_SYNC 0x4
+
+/* only do command/data register, such as some mono oled display device */
+#define PANEL_CAP_MANUAL_REFRESH 0x8
+
+
+#define LCD_DelayMS msleep
+
+enum{
+ SPRDFB_PANEL_TYPE_MCU = 0,
+ SPRDFB_PANEL_TYPE_RGB,
+ SPRDFB_PANEL_TYPE_MIPI,
+ SPRDFB_PANEL_TYPE_LVDS,
+ SPRDFB_PANEL_TYPE_LIMIT
+};
+
+enum{
+ SPRDFB_POLARITY_POS = 0,
+ SPRDFB_POLARITY_NEG,
+ SPRDFB_POLARITY_LIMIT
+};
+
+enum{
+ SPRDFB_RGB_BUS_TYPE_I2C = 0,
+ SPRDFB_RGB_BUS_TYPE_SPI,
+ SPRDFB_RGB_BUS_TYPE_LVDS,
+ SPRDFB_RGB_BUG_TYPE_LIMIT
+};
+
+enum{
+ SPRDFB_MIPI_MODE_CMD = 0,
+ SPRDFB_MIPI_MODE_VIDEO,
+ SPRDFB_MIPI_MODE_LIMIT
+};
+
+struct panel_spec;
+
+typedef int32_t (*send_cmd_t)(uint32_t data);
+typedef int32_t (*send_data_t)(uint32_t data);
+typedef int32_t (*send_cmd_data_t)(uint32_t cmd, uint32_t data);
+typedef uint32_t (*read_data_t)(void);
+
+
+typedef int32_t (*mipi_set_cmd_mode_t)(void);
+typedef int32_t (*mipi_set_video_mode_t)(void);
+typedef int32_t (*mipi_set_lp_mode_t)(void);
+typedef int32_t (*mipi_set_hs_mode_t)(void);
+typedef int32_t (*mipi_gen_write_t)(uint8_t *param, uint16_t param_length);
+typedef int32_t (*mipi_gen_read_t)(uint8_t *param, uint16_t param_length, uint8_t bytes_to_read, uint8_t *read_buffer);
+typedef int32_t (*mipi_dcs_write_t)(uint8_t *param, uint16_t param_length);
+typedef int32_t (*mipi_dcs_read_t)(uint8_t command, uint8_t bytes_to_read, uint8_t *read_buffer);
+typedef int32_t (*mipi_force_write_t)(uint8_t data_type, uint8_t *param, uint16_t param_length); //add for LCD adapter
+typedef int32_t (*mipi_force_read_t)(uint8_t command, uint8_t bytes_to_read, uint8_t *read_buffer);
+typedef int32_t (*mipi_eotp_set_t)(uint8_t rx_en, uint8_t tx_en);
+
+typedef int32_t (*i2c_write_8bits_t)(uint8_t reg, uint8_t val);
+typedef int32_t (*i2c_read_8bits_t)(uint8_t reg, uint8_t *val);
+typedef int32_t (*i2c_write_16bits_t)(uint16_t reg, bool reg_is_8bit, uint16_t val, bool val_is_8bit);
+typedef int32_t (*i2c_read_16bits_t)(uint16_t reg, bool reg_is_8bit, uint16_t *val, bool val_is_8bit);
+typedef int32_t (*i2c_write_burst_t)(uint8_t* buf, int num);
+
+typedef void (*spi_send_cmd_t)(uint32_t cmd);
+typedef void (*spi_send_data_t)(uint32_t data);
+typedef void (*spi_read_t)(uint32_t *data);
+
+/* LCD operations */
+struct panel_operations {
+ int32_t (*panel_init)(struct panel_spec *self);
+ int32_t (*panel_close)(struct panel_spec *self);
+ int32_t (*panel_reset)(struct panel_spec *self);
+ int32_t (*panel_enter_sleep)(struct panel_spec *self, uint8_t is_sleep);
+ int32_t (*panel_after_suspend)(struct panel_spec *self);
+ int32_t (*panel_before_resume)(struct panel_spec *self);
+ int32_t (*panel_set_contrast)(struct panel_spec *self, uint16_t contrast);
+ int32_t (*panel_set_brightness)(struct panel_spec *self,
+ uint16_t brightness);
+ int32_t (*panel_set_window)(struct panel_spec *self,
+ uint16_t left, uint16_t top,
+ uint16_t right, uint16_t bottom);
+ int32_t (*panel_invalidate)(struct panel_spec *self);
+ int32_t (*panel_invalidate_rect)(struct panel_spec *self,
+ uint16_t left, uint16_t top,
+ uint16_t right, uint16_t bottom);
+ int32_t (*panel_rotate_invalidate_rect)(struct panel_spec *self,
+ uint16_t left, uint16_t top,
+ uint16_t right, uint16_t bottom,
+ uint16_t angle);
+ int32_t (*panel_set_direction)(struct panel_spec *self, uint16_t direction);
+ uint32_t (*panel_readid)(struct panel_spec *self);
+ int32_t (*panel_esd_check)(struct panel_spec *self);
+ int32_t (*panel_change_fps)(struct panel_spec *self, int fps_level);
+ int32_t (*panel_change_epf)(struct panel_spec *self, bool is_default);
+};
+
+/* MCU LCD specific properties */
+struct timing_mcu {
+ uint16_t rcss; /*unit: ns*/
+ uint16_t rlpw;
+ uint16_t rhpw;
+ uint16_t wcss;
+ uint16_t wlpw;
+ uint16_t whpw;
+};
+
+/* RGB LCD specific properties */
+struct timing_rgb {
+ uint16_t hfp;/*unit: pixel*/
+ uint16_t hbp;
+ uint16_t hsync;
+ uint16_t vfp; /*unit: line*/
+ uint16_t vbp;
+ uint16_t vsync;
+};
+
+struct ops_mcu {
+ int32_t (*send_cmd)(uint32_t cmd);
+ int32_t (*send_cmd_data)(uint32_t cmd, uint32_t data);
+ int32_t (*send_data)(uint32_t data);
+ uint32_t (*read_data)(void);
+};
+
+struct ops_i2c {
+ int32_t (*i2c_write_8bits)(uint8_t reg, uint8_t val);
+ int32_t (*i2c_read_8bits)(uint8_t reg, uint8_t *val);
+ int32_t (*i2c_write_16bits)(uint16_t reg, bool reg_is_8bit, uint16_t val, bool val_is_8bit);
+ int32_t (*i2c_read_16bits)(uint16_t reg, bool reg_is_8bit, uint16_t *val, bool val_is_8bit);
+ int32_t (*i2c_write_burst)(uint8_t* buf, int num);
+};
+
+struct ops_spi{
+ void (*spi_send_cmd)(uint32_t cmd);
+ void (*spi_send_data)(uint32_t data);
+ void (*spi_read)(uint32_t *data);
+};
+
+struct ops_mipi{
+ int32_t (*mipi_set_cmd_mode)(void);
+ int32_t (*mipi_set_video_mode)(void);
+ int32_t (*mipi_set_lp_mode)(void);
+ int32_t (*mipi_set_hs_mode)(void);
+ int32_t (*mipi_set_data_lp_mode)(void);
+ int32_t (*mipi_set_data_hs_mode)(void);
+ int32_t (*mipi_gen_write)(uint8_t *param, uint16_t param_length);
+ int32_t (*mipi_gen_read)(uint8_t *param, uint16_t param_length, uint8_t bytes_to_read, uint8_t *read_buffer);
+ int32_t (*mipi_dcs_write)(uint8_t *param, uint16_t param_length);
+ int32_t (*mipi_dcs_read)(uint8_t command, uint8_t bytes_to_read, uint8_t *read_buffer);
+ int32_t (*mipi_force_write)(uint8_t data_type, uint8_t *param, uint16_t param_length); //add for LCD adapter
+ int32_t (*mipi_force_read)(uint8_t command, uint8_t bytes_to_read, uint8_t *read_buffer);
+ int32_t (*mipi_eotp_set)(uint8_t rx_en, uint8_t tx_en);
+};
+
+struct i2c_info{
+ uint32_t i2c_addr;
+ struct ops_i2c *ops;
+};
+
+struct spi_info{
+ struct ops_spi *ops;
+};
+
+
+struct info_mipi {
+ uint16_t work_mode; /*command_mode, video_mode*/
+ uint16_t video_bus_width;
+ uint32_t lan_number;
+ uint32_t phy_feq; /*unit:Hz*/
+ uint16_t h_sync_pol;
+ uint16_t v_sync_pol;
+ uint16_t de_pol;
+ uint16_t te_pol; /*only for command_mode*/
+ uint16_t color_mode_pol;
+ uint16_t shut_down_pol;
+ struct timing_rgb *timing;
+ struct ops_mipi *ops;
+};
+
+struct info_rgb {
+ uint16_t cmd_bus_mode; /*spi, i2c*/
+ uint16_t video_bus_width;
+ uint16_t h_sync_pol;
+ uint16_t v_sync_pol;
+ uint16_t de_pol;
+ struct timing_rgb *timing;
+ union{
+ struct i2c_info *i2c;
+ struct spi_info *spi;
+ }bus_info;
+};
+
+struct info_mcu {
+ uint16_t bus_mode; /*8080, 6800*/
+ uint16_t bus_width;
+ uint16_t bpp;
+ uint16_t te_pol;
+ uint32_t te_sync_delay;
+ struct timing_mcu *timing;
+ struct ops_mcu *ops;
+};
+
+struct panel_if_ctrl{
+ const char *if_name;
+
+ int32_t (*panel_if_check)(struct panel_spec *self);
+ void (*panel_if_mount)(struct sprdfb_device *dev);
+ bool (*panel_if_init)(struct sprdfb_device *dev);
+ void (*panel_if_ready)(struct sprdfb_device *dev);
+ void (*panel_if_uninit)(struct sprdfb_device *dev);
+ void (*panel_if_before_refresh)(struct sprdfb_device *dev);
+ void (*panel_if_after_refresh)(struct sprdfb_device *dev);
+ void (*panel_if_before_panel_reset)(struct sprdfb_device *dev);
+ void (*panel_if_enter_ulps)(struct sprdfb_device *dev);
+ void (*panel_if_suspend)(struct sprdfb_device *dev);
+ void (*panel_if_resume)(struct sprdfb_device *dev);
+ uint32_t (*panel_if_get_status)(struct sprdfb_device *dev);
+
+};
+
+struct reset_timing_s {
+ uint16_t time1;//high //ms
+ uint16_t time2;//low //ms
+ uint16_t time3;//high //ms
+};
+
+/* LCD abstraction */
+struct panel_spec {
+ uint32_t cap;
+ uint16_t width;
+ uint16_t height;
+
+ struct reset_timing_s reset_timing;
+ uint32_t fps;
+ uint16_t suspend_mode;
+ uint16_t type; /*mcu, rgb, mipi*/
+ uint16_t direction;
+ bool is_clean_lcd;
+ union {
+ struct info_mcu *mcu;
+ struct info_rgb *rgb;
+ struct info_mipi * mipi;
+ } info;
+ struct panel_if_ctrl *if_ctrl;
+ struct panel_operations *ops;
+};
+
+struct panel_cfg {
+ struct list_head list;
+ uint32_t dev_id; /*main_lcd, sub_lcd, undefined*/
+ uint32_t lcd_id;
+ const char *lcd_name;
+ struct panel_spec *panel;
+};
+
+int sprdfb_panel_register(struct panel_cfg *cfg);
+
+void sprdfb_panel_change_fps(struct sprdfb_device *dev, int fps_level);
+
+#endif
diff --git a/drivers/video/sprdfb/sprdfb_rgb.c b/drivers/video/sprdfb/sprdfb_rgb.c
new file mode 100755
index 00000000..d444bdae
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_rgb.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#include "sprdfb.h"
+#include "sprdfb_panel.h"
+#include "sprdfb_dispc_reg.h"
+
+extern struct ops_i2c sprdfb_i2c_ops;
+extern struct ops_spi sprdfb_spi_ops;
+
+extern bool sprdfb_i2c_init(struct sprdfb_device *dev);
+extern bool sprdfb_i2c_uninit(struct sprdfb_device *dev);
+
+extern bool sprdfb_spi_init(struct sprdfb_device *dev);
+extern bool sprdfb_spi_uninit(struct sprdfb_device *dev);
+
+static uint32_t rgb_readid(struct panel_spec *self)
+{
+ uint32_t id = 0;
+ struct info_rgb *rgb = self->info.rgb;
+ /* default id reg is 0 */
+#ifdef CONFIG_I2C
+ if(SPRDFB_RGB_BUS_TYPE_I2C == rgb->cmd_bus_mode){
+ rgb->bus_info.i2c->ops->i2c_read_16bits(0x0, false, (uint16_t*)&id, false);
+ } else
+#endif
+ {
+ rgb->bus_info.spi->ops->spi_send_cmd(0x0);
+ rgb->bus_info.spi->ops->spi_read(&id);
+ }
+ return id;
+}
+
+static void rgb_dispc_init_config(struct panel_spec *panel)
+{
+ uint32_t reg_val = dispc_read(DISPC_DPI_CTRL);
+
+ pr_debug("sprdfb: [%s]\n", __FUNCTION__);
+
+ if(NULL == panel){
+ printk(KERN_ERR "sprdfb: [%s] fail.(Invalid Param)\n", __FUNCTION__);
+ return;
+ }
+
+ if (SPRDFB_PANEL_TYPE_RGB != panel->type &&
+ SPRDFB_PANEL_TYPE_LVDS != panel->type) {
+ printk(KERN_ERR "sprdfb: [%s] fail.(not mcu panel)\n", __FUNCTION__);
+ return;
+ }
+
+ /*use dpi as interface*/
+ dispc_clear_bits((3<<1), DISPC_CTRL);
+
+ /*h sync pol*/
+ if(SPRDFB_POLARITY_NEG == panel->info.rgb->h_sync_pol){
+ reg_val |= (1<<0);
+ }
+
+ /*v sync pol*/
+ if(SPRDFB_POLARITY_NEG == panel->info.rgb->v_sync_pol){
+ reg_val |= (1<<1);
+ }
+
+ /*de sync pol*/
+ if(SPRDFB_POLARITY_NEG == panel->info.rgb->de_pol){
+ reg_val |= (1<<2);
+ }
+
+#ifdef CONFIG_DPI_SINGLE_RUN
+ /*single run mode*/
+ reg_val |= (1<<3);
+#endif
+
+ /*dpi bits*/
+ switch(panel->info.rgb->video_bus_width){
+ case 16:
+ break;
+ case 18:
+ reg_val |= (1 << 6);
+ break;
+ case 24:
+ reg_val |= (2 << 6);
+ break;
+ default:
+ break;
+ }
+
+ dispc_write(reg_val, DISPC_DPI_CTRL);
+
+ pr_debug("sprdfb: [%s] DISPC_DPI_CTRL = %d\n", __FUNCTION__, dispc_read(DISPC_DPI_CTRL));
+}
+
+static void rgb_dispc_set_timing(struct sprdfb_device *dev)
+{
+ pr_debug("sprdfb: [%s]\n", __FUNCTION__);
+
+ dispc_write(dev->panel_timing.rgb_timing[RGB_LCD_H_TIMING], DISPC_DPI_H_TIMING);
+ dispc_write(dev->panel_timing.rgb_timing[RGB_LCD_V_TIMING], DISPC_DPI_V_TIMING);
+}
+
+uint32_t rgb_calc_h_timing(struct timing_rgb *timing)
+{
+#if 0
+ uint32_t clk_rate;
+ uint32_t hsync, hbp, hfp;
+ struct clk * clk = NULL;
+
+ if(NULL == timing){
+ printk(KERN_ERR "sprdfb: [%s]: Invalid Param\n", __FUNCTION__);
+ return 0;
+ }
+
+ clk_get(NULL,"clk_dispc_dpi");
+ clk_rate = clk_get_rate(clk) / 1000000;
+
+ pr_debug(KERN_INFO "sprdfb: [%s] clk_rate: 0x%x\n", __FUNCTION__, clk_rate);
+
+/********************************************************
+ * we assume : t = ? ns, dispc_dpi = ? MHz so
+ * 1ns need cycle : dispc_dpi /1000
+ * tns need cycles : t * dispc_dpi / 1000
+ *
+ ********************************************************/
+#define MAX_DPI_HSYNC_TIMING_VALUE 255
+#define MAX_DPI_HBP_TIMING_VALUE 4095
+#define MAX_DPI_HFP_TIMING_VALUE 4095
+#define DPI_CYCLES(ns) (( (ns) * clk_rate + 1000 - 1)/ 1000)
+
+ /* ceiling*/
+ hsync = DPI_CYCLES(timing->hsync);
+ if (hsync > MAX_DPI_HSYNC_TIMING_VALUE) {
+ hsync = MAX_DPI_HSYNC_TIMING_VALUE ;
+ }
+
+ hbp = DPI_CYCLES(timing->hbp);
+ if (hbp > MAX_DPI_HSYNC_TIMING_VALUE) {
+ hbp = MAX_DPI_HSYNC_TIMING_VALUE ;
+ }
+
+ hfp = DPI_CYCLES (timing->hfp);
+ if (hfp > MAX_DPI_HFP_TIMING_VALUE) {
+ hfp = MAX_DPI_HFP_TIMING_VALUE ;
+ }
+
+ return (hsync | (hbp << 8) | (hfp << 20));
+#else
+ return (timing->hsync | (timing->hbp << 8) | (timing->hfp << 20));
+#endif
+}
+
+
+uint32_t rgb_calc_v_timing(struct timing_rgb *timing)
+{
+ return (timing->vsync| (timing->vbp << 8) | (timing->vfp << 20));
+}
+
+static int32_t sprdfb_rgb_panel_check(struct panel_spec *panel)
+{
+ if(NULL == panel){
+ printk("sprdfb: [%s] fail. (Invalid param)\n", __FUNCTION__);
+ return false;
+ }
+
+ if(SPRDFB_PANEL_TYPE_RGB != panel->type &&
+ SPRDFB_PANEL_TYPE_LVDS != panel->type) {
+ printk("sprdfb: [%s] fail. (not rgb or lvds param)\n", __FUNCTION__);
+ return false;
+ }
+
+ pr_debug("sprdfb: [%s]\n",__FUNCTION__);
+
+ return true;
+}
+
+static void sprdfb_rgb_panel_mount(struct sprdfb_device *dev)
+{
+ if((NULL == dev) || (NULL == dev->panel)){
+ printk(KERN_ERR "sprdfb: [%s]: Invalid Param\n", __FUNCTION__);
+ return;
+ }
+
+ pr_debug(KERN_INFO "sprdfb: [%s], dev_id = %d\n",__FUNCTION__, dev->dev_id);
+
+ dev->panel_if_type = SPRDFB_PANEL_IF_DPI;
+ if(SPRDFB_RGB_BUS_TYPE_I2C == dev->panel->info.rgb->cmd_bus_mode){
+ dev->panel->info.rgb->bus_info.i2c->ops = &sprdfb_i2c_ops;
+ } else {
+ if (dev->panel->info.rgb->bus_info.spi)
+ dev->panel->info.rgb->bus_info.spi->ops = &sprdfb_spi_ops;
+ }
+
+ if(NULL == dev->panel->ops->panel_readid){
+ dev->panel->ops->panel_readid = rgb_readid;
+ }
+
+ dev->panel_timing.rgb_timing[RGB_LCD_H_TIMING] = rgb_calc_h_timing(dev->panel->info.rgb->timing);
+ dev->panel_timing.rgb_timing[RGB_LCD_V_TIMING] = rgb_calc_v_timing(dev->panel->info.rgb->timing);
+}
+
+static bool sprdfb_rgb_panel_init(struct sprdfb_device *dev)
+{
+ bool ret = false;
+
+ if(SPRDFB_RGB_BUS_TYPE_I2C == dev->panel->info.rgb->cmd_bus_mode){
+ ret = sprdfb_i2c_init(dev);
+ }else if (SPRDFB_RGB_BUS_TYPE_SPI == dev->panel->info.rgb->cmd_bus_mode) {
+ ret = sprdfb_spi_init(dev);
+ }
+ if (dev->panel->info.rgb->cmd_bus_mode == SPRDFB_RGB_BUS_TYPE_LVDS) {
+ ret = true;
+ }
+
+ if(!ret) {
+ printk(KERN_ERR "sprdfb: [%s]: bus init fail!\n", __FUNCTION__);
+ return false;
+ }
+
+ rgb_dispc_init_config(dev->panel);
+ rgb_dispc_set_timing(dev);
+
+ if(! dev->panel_ready){
+ /*Nt35516 need vsync before panel init*/
+ dispc_set_bits(BIT(4), DISPC_CTRL);
+ udelay(100);
+ dispc_clear_bits(BIT(4), DISPC_CTRL);
+ }
+
+#ifdef SPRDFB_SUPPORT_LVDS_PANEL
+ if (dev->panel->type == SPRDFB_PANEL_TYPE_LVDS) {
+ pr_info("sprdfb: [%s]: Now initialize LVDS mode\n", __FUNCTION__);
+ /* bit[16] clk from LVDS TX (need set when in LVDS mode) */
+ __raw_writel(BIT(16), REG_AP_CLK_DISPC0_DPI_CFG);
+ /* a4, bit[0]: LVDS AP select */
+ /* 60, bit[0]: LVDS TX power down (active '1') */
+ __raw_writel(BIT(0), REG_PMU_APB_LVDSDIS_PLL_REL_CFG);
+ __raw_writel(BIT(0), REG_AON_APB_LVDS_CFG);
+ /* '0': R/G/B[1:0] sent by lan3; '1': RGB[7:6] sent by lan3 */
+ dispc_set_bits(BIT(21), DISPC_CTRL + 0x18);
+ }
+#endif
+
+ return true;
+}
+
+static void sprdfb_rgb_panel_uninit(struct sprdfb_device *dev)
+{
+ if (SPRDFB_RGB_BUS_TYPE_I2C == dev->panel->info.rgb->cmd_bus_mode) {
+ sprdfb_i2c_uninit(dev);
+ } else if (SPRDFB_RGB_BUS_TYPE_SPI == dev->panel->info.rgb->cmd_bus_mode) {
+ sprdfb_spi_uninit(dev);
+ }
+}
+
+struct panel_if_ctrl sprdfb_rgb_ctrl = {
+ .if_name = "rgb",
+ .panel_if_check = sprdfb_rgb_panel_check,
+ .panel_if_mount = sprdfb_rgb_panel_mount,
+ .panel_if_init = sprdfb_rgb_panel_init,
+ .panel_if_uninit = sprdfb_rgb_panel_uninit,
+ .panel_if_before_refresh = NULL,
+ .panel_if_after_refresh = NULL,
+};
+
diff --git a/drivers/video/sprdfb/sprdfb_spi.c b/drivers/video/sprdfb/sprdfb_spi.c
new file mode 100644
index 00000000..fb11bb8a
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_spi.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#ifdef CONFIG_OF
+#include <linux/fb.h>
+#endif
+#include <soc/sprd/sci.h>
+#include "spi/spi_simple_drv.h"
+#include "sprdfb.h"
+#include "sprdfb_panel.h"
+
+ SPI_INIT_PARM spi_int_parm[] =
+ { // clk_div
+ {
+ TX_POS_EDGE,
+ RX_NEG_EDGE,
+ TX_RX_MSB,
+ RX_TX_MODE,
+ NO_SWITCH,
+ MASTER_MODE,
+ 0x0,
+ 0x0,
+ 0xc0, //clk_div:(n+1)*2
+ 0x0, //data_width.0-32bits per word; n-nbits per word
+ 0x0,
+ SPI_TX_FIFO_DEPTH - 1,
+ 0x0,
+ SPI_RX_FIFO_DEPTH - 1
+ }, //for spi_lcm test
+ //{TX_POS_EDGE,RX_NEG_EDGE,TX_RX_LSB,RX_TX_MODE,NO_SWITCH,SLAVE_MODE,0x0,0x0,0xF0,0x0,0x0,SPI_TX_FIFO_DEPTH - 1,0x0,SPI_RX_FIFO_DEPTH - 1},
+ };
+
+
+ /**---------------------------------------------------------------------------*
+ ** SPI Interface for LCM test case depend on spi_drv.c *
+ **---------------------------------------------------------------------------*/
+//CASE1:
+// --------------------------------------------------------------------------- //
+// Description: configure the start byte
+// Global resource dependence:
+// Author: lichd
+// Note : LCM test code
+// --------------------------------------------------------------------------- //
+
+static void DISPC_SpiWriteCmd(uint32_t cmd)
+{
+ SPI_SetDatawidth(8);
+ SPI_SetCsLow(0, true);
+ SPI_SetCd( 0 );
+
+ // Write a data identical with buswidth
+ SPI_WriteData( cmd, 1, 0);
+
+ SPI_SetCsLow(0, false);
+}
+
+static void DISPC_SpiWriteData(uint32_t data)
+{
+ SPI_SetDatawidth(8);
+
+ SPI_SetCsLow(0, true);
+ SPI_SetCd( 1 );
+
+ // Write a data identical with buswidth
+ SPI_WriteData( data, 1, 0);
+
+ SPI_SetCsLow(0, false);
+}
+
+static void SPI_Read( uint32_t* data)
+{
+ uint32_t lcm_id=0;
+
+ SPI_SetCsLow(0, false);
+ {
+ uint32_t i=0;
+ for(i=0; i<1000; i++);
+ }
+
+ SPI_SetCsLow(0, true);
+ SPI_SetCd( 1 );
+ SPI_SetDatawidth(8);
+
+ //Read data 16bits
+ lcm_id = SPI_ReadData(2, 0); //unit of buswidth
+
+ *data = lcm_id;
+}
+
+void SPI_PinCfg( void )
+{
+ /*enable access the spi reg*/
+
+// sci_glb_set((SPRD_GREG_BASE+0x8), 0x2);
+// sci_glb_set((SPRD_GREG_BASE+0xc0), 0x1);
+
+/*
+ //select spi0_2
+ CHIP_REG_SET (PIN_LCD_D6_REG, (PIN_FPD_EN | PIN_FUNC_1 | PIN_O_EN)); //SPI0_2_CD
+ CHIP_REG_SET (PIN_LCD_RDN_REG, (PIN_FPD_EN | PIN_FUNC_1 | PIN_I_EN)); //SPI0_2_DI
+ CHIP_REG_SET (PIN_LCD_WRN_REG, (PIN_FPD_EN | PIN_FUNC_1 | PIN_O_EN)); //SPI0_2_DO
+ CHIP_REG_SET (PIN_LCD_CD_REG, (PIN_FPD_EN | PIN_FUNC_1 | PIN_O_EN)); //SPI0_2_CLK
+ CHIP_REG_SET (PIN_LCD_CSN0_REG, (PIN_FPD_EN | PIN_FUNC_1 | PIN_O_EN)); //SPI0_2_CS0
+*/
+#if 0
+ TB_REG_OR(GEN0, (1 << 13));
+
+ //select spi0_1
+ TB_REG_SET (PIN_LCD_D0_REG, (PIN_DS_2 | PIN_FUNC_1 )); //SPI0_1_DI
+ TB_REG_SET (PIN_LCD_D1_REG, (PIN_DS_2 | PIN_FUNC_1 )); //SPI0_1_DO
+ TB_REG_SET (PIN_LCD_D2_REG, (PIN_DS_2 | PIN_FUNC_1 )); //SPI0_1_CLK
+ TB_REG_SET (PIN_LCD_D3_REG, (PIN_DS_2 | PIN_FUNC_1 )); //SPI0_1_CS0
+ TB_REG_SET (PIN_LCD_D4_REG, (PIN_DS_2 | PIN_FUNC_1 )); //SPI0_1_CS1
+ TB_REG_SET (PIN_LCD_D5_REG, (PIN_DS_2 | PIN_FUNC_1 )); //SPI0_1_CD
+
+ //
+ TB_REG_AND(PIN_CTL_REG, ~(BIT_29|BIT_30));
+ TB_REG_OR(PIN_CTL_REG, (1<<29));
+#endif
+}
+
+bool sprdfb_spi_init(struct sprdfb_device *dev)
+{
+#ifdef CONFIG_OF
+ SPI_Init(dev->of_dev, SPI_USED_ID, spi_int_parm );
+#else
+ SPI_Init( SPI_USED_ID, spi_int_parm );
+#endif
+ return true;
+}
+
+bool sprdfb_spi_uninit(struct sprdfb_device *dev)
+{
+ return true;
+}
+
+struct ops_spi sprdfb_spi_ops = {
+ .spi_send_cmd = DISPC_SpiWriteCmd,
+ .spi_send_data = DISPC_SpiWriteData,
+ .spi_read = SPI_Read,
+};
+