board-m6skt-panel.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. /*
  2. * arch/arm/mach-meson3/board-m6skt-panel.c
  3. *
  4. * Copyright (C) 2011-2012 Amlogic, Inc.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  14. * more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. #include <linux/kernel.h>
  21. #include <linux/init.h>
  22. #include <linux/platform_device.h>
  23. #include <linux/clk.h>
  24. #include <asm/mach-types.h>
  25. #include <asm/mach/arch.h>
  26. #include <plat/platform.h>
  27. #include <plat/plat_dev.h>
  28. #include <plat/lm.h>
  29. #include <mach/clock.h>
  30. #include <mach/map.h>
  31. #include <mach/gpio.h>
  32. #include <mach/gpio_data.h>
  33. #include <linux/delay.h>
  34. #include <plat/regops.h>
  35. #include <mach/reg_addr.h>
  36. #include <linux/vout/lcdoutc.h>
  37. #include <linux/aml_bl.h>
  38. #include <mach/lcd_aml.h>
  39. #include "board-m6skt.h"
  40. #ifdef CONFIG_AW_AXP
  41. extern int axp_gpio_set_io(int gpio, int io_state);
  42. extern int axp_gpio_get_io(int gpio, int *io_state);
  43. extern int axp_gpio_set_value(int gpio, int value);
  44. extern int axp_gpio_get_value(int gpio, int *value);
  45. #endif
  46. extern Lcd_Config_t m6skt_lcd_config;
  47. // Define backlight control method
  48. #define BL_CTL_GPIO 0
  49. #define BL_CTL_PWM 1
  50. #define BL_CTL BL_CTL_GPIO
  51. #if(BL_CTL==BL_CTL_PWM)
  52. #define PWM_MAX 60000 //PWM_MAX <= 65535
  53. #define PWM_PRE_DIV 0 //pwm_freq = 24M / (pre_div + 1) / PWM_MAX
  54. #endif
  55. #define BL_MAX_LEVEL 255
  56. #define BL_MIN_LEVEL 0
  57. static unsigned m6skt_bl_level = 0;
  58. static void m6skt_lvds_ports_ctrl(Bool_t status)
  59. {
  60. printk(KERN_INFO "%s: %s\n", __FUNCTION__, (status ? "ON" : "OFF"));
  61. if (status) {
  62. aml_write_reg32(P_LVDS_GEN_CNTL, aml_read_reg32(P_LVDS_GEN_CNTL) | (1 << 3)); // enable fifo
  63. aml_write_reg32(P_LVDS_PHY_CNTL4, aml_read_reg32(P_LVDS_PHY_CNTL4) | (0x2f<<0)); //enable LVDS phy port
  64. }else {
  65. aml_write_reg32(P_LVDS_PHY_CNTL4, aml_read_reg32(P_LVDS_PHY_CNTL4) & ~(0x7f<<0)); //disable LVDS phy port
  66. aml_write_reg32(P_LVDS_GEN_CNTL, aml_read_reg32(P_LVDS_GEN_CNTL) & ~(1 << 3)); // disable fifo
  67. }
  68. }
  69. // Refer to H/W schematics
  70. static void m6skt_backlight_power_ctrl(Bool_t status)
  71. {
  72. printk(KERN_INFO "%s() Power %s\n", __FUNCTION__, (status ? "ON" : "OFF"));
  73. if( status == ON ){
  74. m6skt_lvds_ports_ctrl(ON);
  75. aml_set_reg32_bits(P_LED_PWM_REG0, 1, 12, 2);
  76. msleep(300); // wait for PWM charge
  77. //BL_EN -> GPIOD_1: 1
  78. #if (BL_CTL==BL_CTL_GPIO)
  79. // gpio_out(PAD_GPIOD_1, gpio_status_out);
  80. // gpio_out_high(PAD_GPIOD_1);
  81. gpio_out(PAD_GPIOD_1, 1);
  82. #elif (BL_CTL==BL_CTL_PWM)
  83. aml_set_reg32_bits(P_PWM_PWM_D, 0, 0, 16); //pwm low
  84. aml_set_reg32_bits(P_PWM_PWM_D, PWM_MAX, 16, 16); //pwm high
  85. aml_write_reg32(P_PWM_MISC_REG_CD, (aml_read_reg32(P_PWM_MISC_REG_CD) & ~(0x7f<<16)) | ((1 << 23) | (PWM_PRE_DIV<<16) | (1<<1))); //enable pwm clk & pwm output
  86. aml_write_reg32(P_PERIPHS_PIN_MUX_2, aml_read_reg32(P_PERIPHS_PIN_MUX_2) | (1<<3)); //enable pwm pinmux
  87. #endif
  88. }
  89. else{
  90. //BL_EN -> GPIOD_1: 0
  91. aml_write_reg32(P_PWM_MISC_REG_CD, aml_read_reg32(P_PWM_MISC_REG_CD) & ~((1 << 23) | (1<<1))); //disable pwm clk & pwm output
  92. // gpio_out(PAD_GPIOD_1, gpio_status_out);
  93. // gpio_out_low(PAD_GPIOD_1);
  94. gpio_out(PAD_GPIOD_1, 0);
  95. msleep(30);
  96. m6skt_lvds_ports_ctrl(OFF);
  97. }
  98. }
  99. static void m6skt_set_backlight_level(unsigned level)
  100. {
  101. m6skt_bl_level = level;
  102. printk(KERN_DEBUG "%s: %d\n", __FUNCTION__, m6skt_bl_level);
  103. level = (level > BL_MAX_LEVEL ? BL_MAX_LEVEL : (level < BL_MIN_LEVEL ? BL_MIN_LEVEL : level));
  104. #if (BL_CTL==BL_CTL_GPIO)
  105. level = level * 15 / BL_MAX_LEVEL;
  106. level = 15 - level;
  107. aml_set_reg32_bits(P_LED_PWM_REG0, level, 0, 4);
  108. #elif (BL_CTL==BL_CTL_PWM)
  109. level = level * PWM_MAX / BL_MAX_LEVEL ;
  110. aml_set_reg32_bits(P_PWM_PWM_D, (PWM_MAX - level), 0, 16); //pwm low
  111. aml_set_reg32_bits(P_PWM_PWM_D, level, 16, 16); //pwm high
  112. #endif
  113. }
  114. static unsigned m6skt_get_backlight_level(void)
  115. {
  116. printk(KERN_DEBUG "%s: %d\n", __FUNCTION__, m6skt_bl_level);
  117. return m6skt_bl_level;
  118. }
  119. static void m6skt_lcd_power_ctrl(Bool_t status)
  120. {
  121. printk(KERN_INFO "%s() Power %s\n", __FUNCTION__, (status ? "ON" : "OFF"));
  122. if (status) {
  123. //GPIOA27 -> LCD_PWR_EN#: 0 lcd 3.3v
  124. //aml_set_reg32_bits(P_PREG_PAD_GPIO0_EN_N, 0, 27, 1);
  125. //aml_set_reg32_bits(P_PREG_PAD_GPIO0_O, 0, 27, 1);
  126. gpio_out(PAD_GPIOA_27, 0);
  127. msleep(20);
  128. //GPIOC2 -> VCCx3_EN: 0
  129. //gpio_out(PAD_GPIOC_2, 0);
  130. #ifdef CONFIG_AW_AXP
  131. axp_gpio_set_io(3,1);
  132. axp_gpio_set_value(3, 0);
  133. #endif
  134. }
  135. else {
  136. //GPIOC2 -> VCCx3_EN: 1
  137. //gpio_out(PAD_GPIOC_2, 1);
  138. #ifdef CONFIG_AW_AXP
  139. axp_gpio_set_io(3,0);
  140. #endif
  141. msleep(20);
  142. //GPIOA27 -> LCD_PWR_EN#: 1 lcd 3.3v
  143. //aml_set_reg32_bits(P_PREG_PAD_GPIO0_EN_N, 0, 27, 1);
  144. //aml_set_reg32_bits(P_PREG_PAD_GPIO0_O, 1, 27, 1);
  145. gpio_out(PAD_GPIOA_27, 1);
  146. }
  147. }
  148. static int m6skt_lcd_suspend(void *args)
  149. {
  150. args = args;
  151. printk(KERN_INFO "LCD suspending...\n");
  152. return 0;
  153. }
  154. static int m6skt_lcd_resume(void *args)
  155. {
  156. args = args;
  157. printk(KERN_INFO "LCD resuming...\n");
  158. return 0;
  159. }
  160. #define H_ACTIVE 800
  161. #define V_ACTIVE 1280
  162. #define H_PERIOD 960
  163. #define V_PERIOD 1320
  164. #define VIDEO_ON_PIXEL 80
  165. #define VIDEO_ON_LINE 32
  166. // Define LVDS physical PREM SWING VCM REF
  167. static Lvds_Phy_Control_t lcd_lvds_phy_control =
  168. {
  169. .lvds_prem_ctl = 0x0,
  170. .lvds_swing_ctl = 0x4,
  171. .lvds_vcm_ctl = 0x0,
  172. .lvds_ref_ctl = 0x15,
  173. };
  174. //Define LVDS data mapping, pn swap.
  175. static Lvds_Config_t lcd_lvds_config=
  176. {
  177. .lvds_repack=0, //data mapping //0:JEDIA mode, 1:VESA mode
  178. .pn_swap=0, //0:normal, 1:swap
  179. };
  180. Lcd_Config_t m6skt_lcd_config = {
  181. // Refer to LCD Spec
  182. .lcd_basic = {
  183. .h_active = H_ACTIVE,
  184. .v_active = V_ACTIVE,
  185. .h_period = H_PERIOD,
  186. .v_period = V_PERIOD,
  187. .screen_ratio_width = 5,
  188. .screen_ratio_height = 8,
  189. .lcd_type = LCD_DIGITAL_LVDS, //LCD_DIGITAL_TTL //LCD_DIGITAL_LVDS //LCD_DIGITAL_MINILVDS
  190. .lcd_bits = 8, //8 //6
  191. },
  192. .lcd_timing = {
  193. .pll_ctrl = 0x10225, //clk=63.4MHz, 50.1Hz
  194. .div_ctrl = 0x18803,
  195. .clk_ctrl = 0x1111, //[19:16]ss_ctrl, [12]pll_sel, [8]div_sel, [4]vclk_sel, [3:0]xd
  196. //.sync_duration_num = 501,
  197. //.sync_duration_den = 10,
  198. .video_on_pixel = VIDEO_ON_PIXEL,
  199. .video_on_line = VIDEO_ON_LINE,
  200. .sth1_hs_addr = 10,
  201. .sth1_he_addr = 20,
  202. .sth1_vs_addr = 0,
  203. .sth1_ve_addr = V_PERIOD - 1,
  204. .stv1_hs_addr = 10,
  205. .stv1_he_addr = 20,
  206. .stv1_vs_addr = 2,
  207. .stv1_ve_addr = 4,
  208. .pol_cntl_addr = (0x0 << LCD_CPH1_POL) |(0x1 << LCD_HS_POL) | (0x1 << LCD_VS_POL),
  209. .inv_cnt_addr = (0<<LCD_INV_EN) | (0<<LCD_INV_CNT),
  210. .tcon_misc_sel_addr = (1<<LCD_STV1_SEL) | (1<<LCD_STV2_SEL),
  211. .dual_port_cntl_addr = (1<<LCD_TTL_SEL) | (1<<LCD_ANALOG_SEL_CPH3) | (1<<LCD_ANALOG_3PHI_CLK_SEL) | (0<<LCD_RGB_SWP) | (0<<LCD_BIT_SWP),
  212. },
  213. .lcd_effect = {
  214. .gamma_cntl_port = (1 << LCD_GAMMA_EN) | (0 << LCD_GAMMA_RVS_OUT) | (1 << LCD_GAMMA_VCOM_POL),
  215. .gamma_vcom_hswitch_addr = 0,
  216. .rgb_base_addr = 0xf0,
  217. .rgb_coeff_addr = 0x74a,
  218. },
  219. .lvds_mlvds_config = {
  220. .lvds_config = &lcd_lvds_config,
  221. .lvds_phy_control = &lcd_lvds_phy_control,
  222. },
  223. .lcd_power_ctrl = {
  224. .cur_bl_level = 0,
  225. .power_ctrl = m6skt_lcd_power_ctrl,
  226. .backlight_ctrl = m6skt_backlight_power_ctrl,
  227. .get_bl_level = m6skt_get_backlight_level,
  228. .set_bl_level = m6skt_set_backlight_level,
  229. .lcd_suspend = m6skt_lcd_suspend,
  230. .lcd_resume = m6skt_lcd_resume,
  231. },
  232. };
  233. static void lcd_setup_gamma_table(Lcd_Config_t *pConf)
  234. {
  235. int i;
  236. const unsigned short gamma_adjust[256] = {
  237. 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
  238. 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
  239. 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,
  240. 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
  241. 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
  242. 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
  243. 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
  244. 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
  245. };
  246. for (i=0; i<256; i++) {
  247. pConf->lcd_effect.GammaTableR[i] = gamma_adjust[i] << 2;
  248. pConf->lcd_effect.GammaTableG[i] = gamma_adjust[i] << 2;
  249. pConf->lcd_effect.GammaTableB[i] = gamma_adjust[i] << 2;
  250. }
  251. }
  252. static void lcd_video_adjust(Lcd_Config_t *pConf)
  253. {
  254. int i;
  255. const signed short video_adjust[33] = { -999, -937, -875, -812, -750, -687, -625, -562, -500, -437, -375, -312, -250, -187, -125, -62, 0, 62, 125, 187, 250, 312, 375, 437, 500, 562, 625, 687, 750, 812, 875, 937, 1000};
  256. for (i=0; i<33; i++)
  257. {
  258. pConf->lcd_effect.brightness[i] = video_adjust[i];
  259. pConf->lcd_effect.contrast[i] = video_adjust[i];
  260. pConf->lcd_effect.saturation[i] = video_adjust[i];
  261. pConf->lcd_effect.hue[i] = video_adjust[i];
  262. }
  263. }
  264. static void lcd_sync_duration(Lcd_Config_t *pConf)
  265. {
  266. unsigned m, n, od, div, xd;
  267. unsigned pre_div;
  268. unsigned sync_duration;
  269. m = ((pConf->lcd_timing.pll_ctrl) >> 0) & 0x1ff;
  270. n = ((pConf->lcd_timing.pll_ctrl) >> 9) & 0x1f;
  271. od = ((pConf->lcd_timing.pll_ctrl) >> 16) & 0x3;
  272. div = ((pConf->lcd_timing.div_ctrl) >> 4) & 0x7;
  273. xd = ((pConf->lcd_timing.clk_ctrl) >> 0) & 0xf;
  274. od = (od == 0) ? 1:((od == 1) ? 2:4);
  275. switch(pConf->lcd_basic.lcd_type)
  276. {
  277. case LCD_DIGITAL_TTL:
  278. pre_div = 1;
  279. break;
  280. case LCD_DIGITAL_LVDS:
  281. pre_div = 7;
  282. break;
  283. default:
  284. pre_div = 1;
  285. break;
  286. }
  287. sync_duration = m*24*100/(n*od*(div+1)*xd*pre_div);
  288. sync_duration = ((sync_duration * 100000 / H_PERIOD) * 10) / V_PERIOD;
  289. sync_duration = (sync_duration + 5) / 10;
  290. pConf->lcd_timing.sync_duration_num = sync_duration;
  291. pConf->lcd_timing.sync_duration_den = 10;
  292. }
  293. static struct aml_bl_platform_data m6skt_backlight_data =
  294. {
  295. //.power_on_bl = power_on_backlight,
  296. //.power_off_bl = power_off_backlight,
  297. .get_bl_level = m6skt_get_backlight_level,
  298. .set_bl_level = m6skt_set_backlight_level,
  299. .max_brightness = 255,
  300. .dft_brightness = 200,
  301. };
  302. static struct platform_device m6skt_backlight_device = {
  303. .name = "aml-bl",
  304. .id = -1,
  305. .num_resources = 0,
  306. .resource = NULL,
  307. .dev = {
  308. .platform_data = &m6skt_backlight_data,
  309. },
  310. };
  311. static struct aml_lcd_platform __initdata m6skt_lcd_data = {
  312. .lcd_conf = &m6skt_lcd_config,
  313. };
  314. static struct platform_device __initdata * m6skt_lcd_devices[] = {
  315. &meson_device_lcd,
  316. // &meson_device_vout,
  317. &m6skt_backlight_device,
  318. };
  319. int m6skt_lcd_init(void)
  320. {
  321. int err;
  322. lcd_sync_duration(&m6skt_lcd_config);
  323. lcd_setup_gamma_table(&m6skt_lcd_config);
  324. lcd_video_adjust(&m6skt_lcd_config);
  325. meson_lcd_set_platdata(&m6skt_lcd_data, sizeof(struct aml_lcd_platform));
  326. err = platform_add_devices(m6skt_lcd_devices, ARRAY_SIZE(m6skt_lcd_devices));
  327. return err;
  328. }