board-m6ref-panel.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. /*
  2. * arch/arm/mach-meson3/board-m6ref-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-m6ref.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 m6ref_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 m6ref_bl_level = 0;
  58. static void m6ref_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_PHY_CNTL3, 0x0ee1);
  63. aml_write_reg32(P_LVDS_GEN_CNTL, aml_read_reg32(P_LVDS_GEN_CNTL) | (1 << 3)); // enable fifo
  64. aml_write_reg32(P_LVDS_PHY_CNTL4, aml_read_reg32(P_LVDS_PHY_CNTL4) | (0x2f<<0)); //enable LVDS phy port
  65. }else {
  66. aml_write_reg32(P_LVDS_PHY_CNTL4, aml_read_reg32(P_LVDS_PHY_CNTL4) & ~(0x7f<<0)); //disable LVDS phy port
  67. aml_write_reg32(P_LVDS_GEN_CNTL, aml_read_reg32(P_LVDS_GEN_CNTL) & ~(1 << 3)); // disable fifo
  68. }
  69. }
  70. // Refer to H/W schematics
  71. static void m6ref_backlight_power_ctrl(Bool_t status)
  72. {
  73. printk(KERN_INFO "%s() Power %s\n", __FUNCTION__, (status ? "ON" : "OFF"));
  74. if( status == ON ){
  75. msleep(30);
  76. m6ref_lvds_ports_ctrl(ON);
  77. aml_set_reg32_bits(P_LED_PWM_REG0, 1, 12, 2);
  78. msleep(300); // wait for PWM charge
  79. //BL_EN -> GPIOD_1: 1
  80. #if (BL_CTL==BL_CTL_GPIO)
  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, 0);
  93. msleep(30);
  94. m6ref_lvds_ports_ctrl(OFF);
  95. msleep(30);
  96. }
  97. }
  98. static void m6ref_set_backlight_level(unsigned level)
  99. {
  100. m6ref_bl_level = level;
  101. printk(KERN_DEBUG "%s: %d\n", __FUNCTION__, m6ref_bl_level);
  102. level = (level > BL_MAX_LEVEL ? BL_MAX_LEVEL : (level < BL_MIN_LEVEL ? BL_MIN_LEVEL : level));
  103. #if (BL_CTL==BL_CTL_GPIO)
  104. level = level * 15 / BL_MAX_LEVEL;
  105. level = 15 - level;
  106. aml_set_reg32_bits(P_LED_PWM_REG0, level, 0, 4);
  107. #elif (BL_CTL==BL_CTL_PWM)
  108. level = level * PWM_MAX / BL_MAX_LEVEL ;
  109. aml_set_reg32_bits(P_PWM_PWM_D, (PWM_MAX - level), 0, 16); //pwm low
  110. aml_set_reg32_bits(P_PWM_PWM_D, level, 16, 16); //pwm high
  111. #endif
  112. }
  113. static unsigned m6ref_get_backlight_level(void)
  114. {
  115. printk(KERN_DEBUG "%s: %d\n", __FUNCTION__, m6ref_bl_level);
  116. return m6ref_bl_level;
  117. }
  118. static void m6ref_lcd_power_ctrl(Bool_t status)
  119. {
  120. printk(KERN_INFO "%s() Power %s\n", __FUNCTION__, (status ? "ON" : "OFF"));
  121. if (status) {
  122. //GPIOA27 -> LCD_PWR_EN#: 0 lcd 3.3v
  123. //aml_set_reg32_bits(P_PREG_PAD_GPIO0_EN_N, 0, 27, 1);
  124. //aml_set_reg32_bits(P_PREG_PAD_GPIO0_O, 0, 27, 1);
  125. gpio_out(PAD_GPIOA_27, 0);
  126. msleep(20);
  127. //GPIOC2 -> VCCx3_EN: 1
  128. //gpio_out(PAD_GPIOC_2, 1);
  129. #ifdef CONFIG_AW_AXP
  130. axp_gpio_set_io(3,1);
  131. axp_gpio_set_value(3, 0);
  132. #endif
  133. }
  134. else {
  135. //GPIOC2 -> VCCx3_EN: 0
  136. //gpio_out(PAD_GPIOC_2, 0);
  137. #ifdef CONFIG_AW_AXP
  138. axp_gpio_set_io(3,0);
  139. #endif
  140. msleep(20);
  141. //GPIOA27 -> LCD_PWR_EN#: 1 lcd 3.3v
  142. //aml_set_reg32_bits(P_PREG_PAD_GPIO0_EN_N, 0, 27, 1);
  143. //aml_set_reg32_bits(P_PREG_PAD_GPIO0_O, 1, 27, 1);
  144. gpio_out(PAD_GPIOA_27, 1);
  145. }
  146. }
  147. static int m6ref_lcd_suspend(void *args)
  148. {
  149. args = args;
  150. printk(KERN_INFO "LCD suspending...\n");
  151. return 0;
  152. }
  153. static int m6ref_lcd_resume(void *args)
  154. {
  155. args = args;
  156. printk(KERN_INFO "LCD resuming...\n");
  157. return 0;
  158. }
  159. #define H_ACTIVE 800
  160. #define V_ACTIVE 1280
  161. #define H_PERIOD 960
  162. #define V_PERIOD 1320
  163. #define VIDEO_ON_PIXEL 80
  164. #define VIDEO_ON_LINE 32
  165. // Define LVDS physical PREM SWING VCM REF
  166. static Lvds_Phy_Control_t lcd_lvds_phy_control =
  167. {
  168. .lvds_prem_ctl = 0x0,
  169. .lvds_swing_ctl = 0x4,
  170. .lvds_vcm_ctl = 0x0,
  171. .lvds_ref_ctl = 0x15,
  172. };
  173. //Define LVDS data mapping, pn swap.
  174. static Lvds_Config_t lcd_lvds_config=
  175. {
  176. .lvds_repack=0, //data mapping //0:JEDIA mode, 1:VESA mode
  177. .pn_swap=0, //0:normal, 1:swap
  178. };
  179. Lcd_Config_t m6ref_lcd_config = {
  180. // Refer to LCD Spec
  181. .lcd_basic = {
  182. .h_active = H_ACTIVE,
  183. .v_active = V_ACTIVE,
  184. .h_period = H_PERIOD,
  185. .v_period = V_PERIOD,
  186. .screen_ratio_width = 5,
  187. .screen_ratio_height = 8,
  188. .lcd_type = LCD_DIGITAL_LVDS, //LCD_DIGITAL_TTL //LCD_DIGITAL_LVDS //LCD_DIGITAL_MINILVDS
  189. .lcd_bits = 8, //8 //6
  190. },
  191. .lcd_timing = {
  192. .pll_ctrl = 0x10225, //clk=63.4MHz, 50.1Hz
  193. .div_ctrl = 0x18803,
  194. .clk_ctrl = 0x1111, //[19:16]ss_ctrl, [12]pll_sel, [8]div_sel, [4]vclk_sel, [3:0]xd
  195. //.sync_duration_num = 501,
  196. //.sync_duration_den = 10,
  197. .video_on_pixel = VIDEO_ON_PIXEL,
  198. .video_on_line = VIDEO_ON_LINE,
  199. .sth1_hs_addr = 10,
  200. .sth1_he_addr = 20,
  201. .sth1_vs_addr = 0,
  202. .sth1_ve_addr = V_PERIOD - 1,
  203. .stv1_hs_addr = 10,
  204. .stv1_he_addr = 20,
  205. .stv1_vs_addr = 2,
  206. .stv1_ve_addr = 4,
  207. .pol_cntl_addr = (0x0 << LCD_CPH1_POL) |(0x1 << LCD_HS_POL) | (0x1 << LCD_VS_POL),
  208. .inv_cnt_addr = (0<<LCD_INV_EN) | (0<<LCD_INV_CNT),
  209. .tcon_misc_sel_addr = (1<<LCD_STV1_SEL) | (1<<LCD_STV2_SEL),
  210. .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),
  211. },
  212. .lcd_effect = {
  213. .gamma_cntl_port = (1 << LCD_GAMMA_EN) | (0 << LCD_GAMMA_RVS_OUT) | (1 << LCD_GAMMA_VCOM_POL),
  214. .gamma_vcom_hswitch_addr = 0,
  215. .rgb_base_addr = 0xf0,
  216. .rgb_coeff_addr = 0x74a,
  217. },
  218. .lvds_mlvds_config = {
  219. .lvds_config = &lcd_lvds_config,
  220. .lvds_phy_control = &lcd_lvds_phy_control,
  221. },
  222. .lcd_power_ctrl = {
  223. .cur_bl_level = 0,
  224. .power_ctrl = m6ref_lcd_power_ctrl,
  225. .backlight_ctrl = m6ref_backlight_power_ctrl,
  226. .get_bl_level = m6ref_get_backlight_level,
  227. .set_bl_level = m6ref_set_backlight_level,
  228. .lcd_suspend = m6ref_lcd_suspend,
  229. .lcd_resume = m6ref_lcd_resume,
  230. },
  231. };
  232. static void lcd_setup_gamma_table(Lcd_Config_t *pConf)
  233. {
  234. int i;
  235. const unsigned short gamma_adjust[256] = {
  236. 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,
  237. 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,
  238. 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,
  239. 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,
  240. 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,
  241. 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,
  242. 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,
  243. 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
  244. };
  245. for (i=0; i<256; i++) {
  246. pConf->lcd_effect.GammaTableR[i] = gamma_adjust[i] << 2;
  247. pConf->lcd_effect.GammaTableG[i] = gamma_adjust[i] << 2;
  248. pConf->lcd_effect.GammaTableB[i] = gamma_adjust[i] << 2;
  249. }
  250. }
  251. static void lcd_video_adjust(Lcd_Config_t *pConf)
  252. {
  253. int i;
  254. 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};
  255. for (i=0; i<33; i++)
  256. {
  257. pConf->lcd_effect.brightness[i] = video_adjust[i];
  258. pConf->lcd_effect.contrast[i] = video_adjust[i];
  259. pConf->lcd_effect.saturation[i] = video_adjust[i];
  260. pConf->lcd_effect.hue[i] = video_adjust[i];
  261. }
  262. }
  263. static void lcd_sync_duration(Lcd_Config_t *pConf)
  264. {
  265. unsigned m, n, od, div, xd;
  266. unsigned pre_div;
  267. unsigned sync_duration;
  268. m = ((pConf->lcd_timing.pll_ctrl) >> 0) & 0x1ff;
  269. n = ((pConf->lcd_timing.pll_ctrl) >> 9) & 0x1f;
  270. od = ((pConf->lcd_timing.pll_ctrl) >> 16) & 0x3;
  271. div = ((pConf->lcd_timing.div_ctrl) >> 4) & 0x7;
  272. xd = ((pConf->lcd_timing.clk_ctrl) >> 0) & 0xf;
  273. od = (od == 0) ? 1:((od == 1) ? 2:4);
  274. switch(pConf->lcd_basic.lcd_type)
  275. {
  276. case LCD_DIGITAL_TTL:
  277. pre_div = 1;
  278. break;
  279. case LCD_DIGITAL_LVDS:
  280. pre_div = 7;
  281. break;
  282. default:
  283. pre_div = 1;
  284. break;
  285. }
  286. sync_duration = m*24*100/(n*od*(div+1)*xd*pre_div);
  287. sync_duration = ((sync_duration * 100000 / H_PERIOD) * 10) / V_PERIOD;
  288. sync_duration = (sync_duration + 5) / 10;
  289. pConf->lcd_timing.sync_duration_num = sync_duration;
  290. pConf->lcd_timing.sync_duration_den = 10;
  291. }
  292. static struct aml_bl_platform_data m6ref_backlight_data =
  293. {
  294. //.power_on_bl = power_on_backlight,
  295. //.power_off_bl = power_off_backlight,
  296. .get_bl_level = m6ref_get_backlight_level,
  297. .set_bl_level = m6ref_set_backlight_level,
  298. .max_brightness = 255,
  299. .dft_brightness = 200,
  300. };
  301. static struct platform_device m6ref_backlight_device = {
  302. .name = "aml-bl",
  303. .id = -1,
  304. .num_resources = 0,
  305. .resource = NULL,
  306. .dev = {
  307. .platform_data = &m6ref_backlight_data,
  308. },
  309. };
  310. static struct aml_lcd_platform __initdata m6ref_lcd_data = {
  311. .lcd_conf = &m6ref_lcd_config,
  312. };
  313. static struct platform_device __initdata * m6ref_lcd_devices[] = {
  314. &meson_device_lcd,
  315. // &meson_device_vout,
  316. &m6ref_backlight_device,
  317. };
  318. int m6ref_lcd_init(void)
  319. {
  320. int err;
  321. lcd_sync_duration(&m6ref_lcd_config);
  322. lcd_setup_gamma_table(&m6ref_lcd_config);
  323. lcd_video_adjust(&m6ref_lcd_config);
  324. meson_lcd_set_platdata(&m6ref_lcd_data, sizeof(struct aml_lcd_platform));
  325. err = platform_add_devices(m6ref_lcd_devices, ARRAY_SIZE(m6ref_lcd_devices));
  326. return err;
  327. }