From 8e4bff4cab0ddac6060645b0715210484d02ff40 Mon Sep 17 00:00:00 2001 From: Yuval Adam <_@yuv.al> Date: Wed, 30 Aug 2017 08:25:59 +0000 Subject: Initial file dump from open source release --- drivers/video/sprdfb/Kconfig | 363 +++ drivers/video/sprdfb/Makefile | 35 + drivers/video/sprdfb/dsi_1_10a/Makefile | 2 + drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.c | 1216 ++++++++++ drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.h | 113 + drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.c | 1031 +++++++++ drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.h | 55 + drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.c | 529 +++++ drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.h | 242 ++ drivers/video/sprdfb/dsi_1_10a/mipi_dsih_local.h | 227 ++ drivers/video/sprdfb/dsi_1_21a/Makefile | 12 + drivers/video/sprdfb/dsi_1_21a/mipi_dsih_api.c | 1750 ++++++++++++++ drivers/video/sprdfb/dsi_1_21a/mipi_dsih_api.h | 134 ++ drivers/video/sprdfb/dsi_1_21a/mipi_dsih_dphy.c | 1080 +++++++++ drivers/video/sprdfb/dsi_1_21a/mipi_dsih_dphy.h | 61 + .../sprdfb/dsi_1_21a/mipi_dsih_dphy_megacores.c | 1166 ++++++++++ drivers/video/sprdfb/dsi_1_21a/mipi_dsih_hal.c | 1114 +++++++++ drivers/video/sprdfb/dsi_1_21a/mipi_dsih_hal.h | 1807 +++++++++++++++ drivers/video/sprdfb/dsi_1_21a/mipi_dsih_local.h | 361 +++ drivers/video/sprdfb/lcd/Makefile | 50 + drivers/video/sprdfb/lcd/lcd_dummy.c | 104 + drivers/video/sprdfb/lcd/lcd_fl10802_mipi.c | 364 +++ drivers/video/sprdfb/lcd/lcd_hx8363_mcu.c | 406 ++++ drivers/video/sprdfb/lcd/lcd_hx8363_rgb_spi.c | 445 ++++ drivers/video/sprdfb/lcd/lcd_hx8363_rgb_spi_viva.c | 442 ++++ drivers/video/sprdfb/lcd/lcd_hx8369.c | 391 ++++ .../video/sprdfb/lcd/lcd_hx8369b_grandneo_mipi.c | 338 +++ drivers/video/sprdfb/lcd/lcd_hx8369b_mipi.c | 348 +++ .../sprdfb/lcd/lcd_hx8369b_mipi_coreprimelite.c | 348 +++ .../lcd/lcd_hx8369b_mipi_coreprimelite_marlin.c | 348 +++ .../video/sprdfb/lcd/lcd_hx8369b_mipi_kiran3g.c | 384 +++ .../sprdfb/lcd/lcd_hx8369b_mipi_sharkls_z3lte.c | 348 +++ .../video/sprdfb/lcd/lcd_hx8369b_mipi_vivaltoVE.c | 283 +++ .../video/sprdfb/lcd/lcd_hx8369b_tshark2_j3_mipi.c | 290 +++ drivers/video/sprdfb/lcd/lcd_hx8379a_mipi.c | 312 +++ drivers/video/sprdfb/lcd/lcd_hx8389c_mipi.c | 318 +++ drivers/video/sprdfb/lcd/lcd_hx8394a_mipi.c | 295 +++ drivers/video/sprdfb/lcd/lcd_hx8394d_mipi.c | 430 ++++ drivers/video/sprdfb/lcd/lcd_ili6150_lvds.c | 81 + drivers/video/sprdfb/lcd/lcd_ili9341.c | 428 ++++ drivers/video/sprdfb/lcd/lcd_ili9486.c | 434 ++++ drivers/video/sprdfb/lcd/lcd_ili9486_rgb_spi.c | 397 ++++ drivers/video/sprdfb/lcd/lcd_ili9486s1_mipi.c | 268 +++ drivers/video/sprdfb/lcd/lcd_ili9806e_2_mipi.c | 487 ++++ drivers/video/sprdfb/lcd/lcd_ili9806e_mipi.c | 632 +++++ drivers/video/sprdfb/lcd/lcd_jd9161_mipi.c | 380 +++ drivers/video/sprdfb/lcd/lcd_nt35502_mipi.c | 300 +++ drivers/video/sprdfb/lcd/lcd_nt35510_mipi.c | 291 +++ drivers/video/sprdfb/lcd/lcd_nt35512_mipi.c | 183 ++ drivers/video/sprdfb/lcd/lcd_nt35516_mcu.c | 585 +++++ drivers/video/sprdfb/lcd/lcd_nt35516_mipi.c | 441 ++++ drivers/video/sprdfb/lcd/lcd_nt35516_rgb_i2c.c | 623 +++++ drivers/video/sprdfb/lcd/lcd_nt35516_rgb_spi.c | 624 +++++ drivers/video/sprdfb/lcd/lcd_nt35596h_mipi.c | 841 +++++++ drivers/video/sprdfb/lcd/lcd_nt51017_goyal_mipi.c | 296 +++ drivers/video/sprdfb/lcd/lcd_nt51017_mipi_lvds.c | 589 +++++ drivers/video/sprdfb/lcd/lcd_otm1283a_mipi.c | 560 +++++ drivers/video/sprdfb/lcd/lcd_otm8019a_mipi.c | 516 +++++ drivers/video/sprdfb/lcd/lcd_otm_8018b_mipi.c | 296 +++ drivers/video/sprdfb/lcd/lcd_rm68180_mipi.c | 383 +++ drivers/video/sprdfb/lcd/lcd_s6d0139.c | 244 ++ drivers/video/sprdfb/lcd/lcd_s6d77a1_pikeA_mipi.c | 330 +++ drivers/video/sprdfb/lcd/lcd_s6d7aa0x62_t8_mipi.c | 350 +++ drivers/video/sprdfb/lcd/lcd_sc7798_rgb_spi.c | 561 +++++ drivers/video/sprdfb/lcd/lcd_sd7798d_mipi.c | 261 +++ .../sprdfb/lcd/lcd_sd7798d_mipi_sharkls_z3lte.c | 261 +++ drivers/video/sprdfb/lcd/lcd_ssd2075_mipi.c | 375 +++ drivers/video/sprdfb/lcd/lcd_st7789v_mcu.c | 336 +++ drivers/video/sprdfb/lcd/lcd_t8861_mipi.c | 485 ++++ drivers/video/sprdfb/lcd/lcd_vx5b3d_mipi.c | 965 ++++++++ drivers/video/sprdfb/spi/Makefile | 7 + drivers/video/sprdfb/spi/spi_simple_drv.c | 358 +++ drivers/video/sprdfb/spi/spi_simple_drv.h | 178 ++ drivers/video/sprdfb/sprdfb.h | 289 +++ drivers/video/sprdfb/sprdfb_attr.c | 429 ++++ drivers/video/sprdfb/sprdfb_chip_7715.c | 35 + drivers/video/sprdfb/sprdfb_chip_7715.h | 116 + drivers/video/sprdfb/sprdfb_chip_8830.c | 80 + drivers/video/sprdfb/sprdfb_chip_8830.h | 135 ++ drivers/video/sprdfb/sprdfb_chip_9630.c | 58 + drivers/video/sprdfb/sprdfb_chip_9630.h | 129 ++ drivers/video/sprdfb/sprdfb_chip_common.c | 23 + drivers/video/sprdfb/sprdfb_chip_common.h | 58 + drivers/video/sprdfb/sprdfb_dispc.c | 2446 ++++++++++++++++++++ drivers/video/sprdfb/sprdfb_dispc_reg.h | 169 ++ drivers/video/sprdfb/sprdfb_dsi.c | 1010 ++++++++ drivers/video/sprdfb/sprdfb_gpio2spi.c | 199 ++ drivers/video/sprdfb/sprdfb_i2c.c | 333 +++ drivers/video/sprdfb/sprdfb_main.c | 888 +++++++ drivers/video/sprdfb/sprdfb_mcu.c | 563 +++++ drivers/video/sprdfb/sprdfb_mipi.c | 231 ++ drivers/video/sprdfb/sprdfb_panel.c | 683 ++++++ drivers/video/sprdfb/sprdfb_panel.h | 324 +++ drivers/video/sprdfb/sprdfb_rgb.c | 277 +++ drivers/video/sprdfb/sprdfb_spi.c | 153 ++ 95 files changed, 40516 insertions(+) create mode 100644 drivers/video/sprdfb/Kconfig create mode 100644 drivers/video/sprdfb/Makefile create mode 100644 drivers/video/sprdfb/dsi_1_10a/Makefile create mode 100644 drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.c create mode 100644 drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.h create mode 100644 drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.c create mode 100644 drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.h create mode 100644 drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.c create mode 100644 drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.h create mode 100644 drivers/video/sprdfb/dsi_1_10a/mipi_dsih_local.h create mode 100644 drivers/video/sprdfb/dsi_1_21a/Makefile create mode 100644 drivers/video/sprdfb/dsi_1_21a/mipi_dsih_api.c create mode 100644 drivers/video/sprdfb/dsi_1_21a/mipi_dsih_api.h create mode 100644 drivers/video/sprdfb/dsi_1_21a/mipi_dsih_dphy.c create mode 100644 drivers/video/sprdfb/dsi_1_21a/mipi_dsih_dphy.h create mode 100644 drivers/video/sprdfb/dsi_1_21a/mipi_dsih_dphy_megacores.c create mode 100644 drivers/video/sprdfb/dsi_1_21a/mipi_dsih_hal.c create mode 100644 drivers/video/sprdfb/dsi_1_21a/mipi_dsih_hal.h create mode 100644 drivers/video/sprdfb/dsi_1_21a/mipi_dsih_local.h create mode 100644 drivers/video/sprdfb/lcd/Makefile create mode 100644 drivers/video/sprdfb/lcd/lcd_dummy.c create mode 100644 drivers/video/sprdfb/lcd/lcd_fl10802_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_hx8363_mcu.c create mode 100644 drivers/video/sprdfb/lcd/lcd_hx8363_rgb_spi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_hx8363_rgb_spi_viva.c create mode 100644 drivers/video/sprdfb/lcd/lcd_hx8369.c create mode 100755 drivers/video/sprdfb/lcd/lcd_hx8369b_grandneo_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_hx8369b_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_coreprimelite.c create mode 100644 drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_coreprimelite_marlin.c create mode 100644 drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_kiran3g.c create mode 100644 drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_sharkls_z3lte.c create mode 100644 drivers/video/sprdfb/lcd/lcd_hx8369b_mipi_vivaltoVE.c create mode 100755 drivers/video/sprdfb/lcd/lcd_hx8369b_tshark2_j3_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_hx8379a_mipi.c create mode 100755 drivers/video/sprdfb/lcd/lcd_hx8389c_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_hx8394a_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_hx8394d_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_ili6150_lvds.c create mode 100644 drivers/video/sprdfb/lcd/lcd_ili9341.c create mode 100644 drivers/video/sprdfb/lcd/lcd_ili9486.c create mode 100644 drivers/video/sprdfb/lcd/lcd_ili9486_rgb_spi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_ili9486s1_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_ili9806e_2_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_ili9806e_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_jd9161_mipi.c create mode 100755 drivers/video/sprdfb/lcd/lcd_nt35502_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_nt35510_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_nt35512_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_nt35516_mcu.c create mode 100644 drivers/video/sprdfb/lcd/lcd_nt35516_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_nt35516_rgb_i2c.c create mode 100755 drivers/video/sprdfb/lcd/lcd_nt35516_rgb_spi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_nt35596h_mipi.c create mode 100755 drivers/video/sprdfb/lcd/lcd_nt51017_goyal_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_nt51017_mipi_lvds.c create mode 100644 drivers/video/sprdfb/lcd/lcd_otm1283a_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_otm8019a_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_otm_8018b_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_rm68180_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_s6d0139.c create mode 100644 drivers/video/sprdfb/lcd/lcd_s6d77a1_pikeA_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_s6d7aa0x62_t8_mipi.c create mode 100755 drivers/video/sprdfb/lcd/lcd_sc7798_rgb_spi.c create mode 100755 drivers/video/sprdfb/lcd/lcd_sd7798d_mipi.c create mode 100755 drivers/video/sprdfb/lcd/lcd_sd7798d_mipi_sharkls_z3lte.c create mode 100644 drivers/video/sprdfb/lcd/lcd_ssd2075_mipi.c create mode 100644 drivers/video/sprdfb/lcd/lcd_st7789v_mcu.c create mode 100644 drivers/video/sprdfb/lcd/lcd_t8861_mipi.c create mode 100755 drivers/video/sprdfb/lcd/lcd_vx5b3d_mipi.c create mode 100644 drivers/video/sprdfb/spi/Makefile create mode 100644 drivers/video/sprdfb/spi/spi_simple_drv.c create mode 100644 drivers/video/sprdfb/spi/spi_simple_drv.h create mode 100644 drivers/video/sprdfb/sprdfb.h create mode 100644 drivers/video/sprdfb/sprdfb_attr.c create mode 100755 drivers/video/sprdfb/sprdfb_chip_7715.c create mode 100755 drivers/video/sprdfb/sprdfb_chip_7715.h create mode 100644 drivers/video/sprdfb/sprdfb_chip_8830.c create mode 100644 drivers/video/sprdfb/sprdfb_chip_8830.h create mode 100644 drivers/video/sprdfb/sprdfb_chip_9630.c create mode 100644 drivers/video/sprdfb/sprdfb_chip_9630.h create mode 100644 drivers/video/sprdfb/sprdfb_chip_common.c create mode 100644 drivers/video/sprdfb/sprdfb_chip_common.h create mode 100644 drivers/video/sprdfb/sprdfb_dispc.c create mode 100644 drivers/video/sprdfb/sprdfb_dispc_reg.h create mode 100644 drivers/video/sprdfb/sprdfb_dsi.c create mode 100644 drivers/video/sprdfb/sprdfb_gpio2spi.c create mode 100644 drivers/video/sprdfb/sprdfb_i2c.c create mode 100644 drivers/video/sprdfb/sprdfb_main.c create mode 100644 drivers/video/sprdfb/sprdfb_mcu.c create mode 100644 drivers/video/sprdfb/sprdfb_mipi.c create mode 100644 drivers/video/sprdfb/sprdfb_panel.c create mode 100644 drivers/video/sprdfb/sprdfb_panel.h create mode 100755 drivers/video/sprdfb/sprdfb_rgb.c create mode 100644 drivers/video/sprdfb/sprdfb_spi.c (limited to 'drivers/video/sprdfb') 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 + +/* 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< +#include +#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 + +/* 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 + * + * + * 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 +#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 *)®s, '\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 *)®s; + + 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< 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 +#include +#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 +#include +#include +#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 +#include +#include +#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 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 +#include +#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 +#include +#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 +#include +#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 +#include +#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 +#include +#include +#include "../sprdfb_panel.h" +#include + +#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 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 +#include +#include +#include "../sprdfb_panel.h" +#include + +#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 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 +#include +#include +#include "../sprdfb_panel.h" +#include + +#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 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 +#include +#include +#include "../sprdfb_panel.h" +#include + +#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 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 +#include +#include +#include "../sprdfb_panel.h" +#include + +#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 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 +#include +#include +#include "../sprdfb_panel.h" +#include + +#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 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 +#include +#include +#include "../sprdfb_panel.h" +#include + +#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 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 +#include +#include +#include "../sprdfb_panel.h" +#include + +#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 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 +#include +#include +#include "../sprdfb_panel.h" +#include + +#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 +#include +#include +#include "../sprdfb_panel.h" +#include + +#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 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 +#include +#include +#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 + * + * 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 +#include +#include +#include + +#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 + * + * 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 +#include +#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 +#include +#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 +#include +#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 +#include +#include +#include "../sprdfb_panel.h" +#include + +#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 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 +#include +#include +#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 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 +#include +#include +#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 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 +#include +#include +#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 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 +#include +#include +#include "../sprdfb_panel.h" +#include + +#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 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 +#include +#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 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 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 +#include +#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 +#include +#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 +#include +#include +#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 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 +#include +#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 +#include +#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 +#include +#include +#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 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 +#include +#include +#include "../sprdfb_panel.h" +#include + +#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 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 +//#include +#include +//#include +#include +//#include +#include +//#include +//#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; iname, 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; iname, 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 = ® + 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 +#include +#include +#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 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 +#include +#include +#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 +#include +#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 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 +#include +#include +#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 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 +#include +#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 +#include +#include +#include "../sprdfb_panel.h" +#include + +#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 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 +#include +#include +#include "../sprdfb_panel.h" +#include + +#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 +#include +#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 +#include +#include +#include "../sprdfb_panel.h" +#include + +#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 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 +#include +#include +#include "../sprdfb_panel.h" +#include + +#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 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 +#include +#include +#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 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 +#include +#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 +#include +#include +#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 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 +#include +#include "../sprdfb_panel.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#include +#include +#ifdef CONFIG_OF +#include +#endif + +#include +#include +#include + +#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<ctl0 |= ((1<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<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 + +#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< +#endif +#include +#include +#include +#include +#ifdef CONFIG_FB_MMAP_CACHED +#include +#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 + * + * 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 +#include +#include +#include +#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, ÷r); + + 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 + +#include + + +//#define BIT(x) (1< +#include + +#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 +//#include +#include + +#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 +#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 +#include +#else +#include +#include +#include +#include +#include +#endif +#include + +#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 +#include +#include +#include +#include +#include +#if (defined(CONFIG_SPRD_SCXX30_DMC_FREQ) || defined(CONFIG_SPRD_SCX35_DMC_FREQ)) +#include +#endif +#include +#include +#ifdef CONFIG_OF +#include +#endif +#include +#include "sprdfb_dispc_reg.h" +#include "sprdfb_panel.h" +#include "sprdfb.h" +#include "sprdfb_chip_common.h" +#ifdef CONFIG_CPU_IDLE +#include +#endif +#include + +//#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 + +#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< +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_OF +#include + +#include +#include +#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 + * + * 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 +#include +#include "sprdfb.h" + +#define GPIO_BASE_ADDR 0x40280000 +#define GPIO_LVDSCHIP_OFFSET 0x480 + +#ifndef BIT +#define BIT(x) (1<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 +#include +#include +#include + +#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 +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_OF +#include +#include +#include +#endif + +#include +#include "sprdfb_chip_common.h" +#include "sprdfb.h" +#include "sprdfb_panel.h" + +#include + +#ifdef CONFIG_FB_MMAP_CACHED +#include +#include +#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