mdfld_device.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. /**************************************************************************
  2. * Copyright (c) 2011, Intel Corporation.
  3. * All Rights Reserved.
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms and conditions of the GNU General Public License,
  7. * version 2, as published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12. * more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along with
  15. * this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  17. *
  18. **************************************************************************/
  19. #include "psb_drv.h"
  20. #include "mid_bios.h"
  21. #include "mdfld_output.h"
  22. #include "mdfld_dsi_output.h"
  23. #include "tc35876x-dsi-lvds.h"
  24. #include <asm/intel_scu_ipc.h>
  25. #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
  26. #define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF
  27. #define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */
  28. #define BLC_PWM_FREQ_CALC_CONSTANT 32
  29. #define MHz 1000000
  30. #define BRIGHTNESS_MIN_LEVEL 1
  31. #define BRIGHTNESS_MAX_LEVEL 100
  32. #define BRIGHTNESS_MASK 0xFF
  33. #define BLC_POLARITY_NORMAL 0
  34. #define BLC_POLARITY_INVERSE 1
  35. #define BLC_ADJUSTMENT_MAX 100
  36. #define MDFLD_BLC_PWM_PRECISION_FACTOR 10
  37. #define MDFLD_BLC_MAX_PWM_REG_FREQ 0xFFFE
  38. #define MDFLD_BLC_MIN_PWM_REG_FREQ 0x2
  39. #define MDFLD_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
  40. #define MDFLD_BACKLIGHT_PWM_CTL_SHIFT (16)
  41. static struct backlight_device *mdfld_backlight_device;
  42. int mdfld_set_brightness(struct backlight_device *bd)
  43. {
  44. struct drm_device *dev =
  45. (struct drm_device *)bl_get_data(mdfld_backlight_device);
  46. struct drm_psb_private *dev_priv = dev->dev_private;
  47. int level = bd->props.brightness;
  48. DRM_DEBUG_DRIVER("backlight level set to %d\n", level);
  49. /* Perform value bounds checking */
  50. if (level < BRIGHTNESS_MIN_LEVEL)
  51. level = BRIGHTNESS_MIN_LEVEL;
  52. if (gma_power_begin(dev, false)) {
  53. u32 adjusted_level = 0;
  54. /*
  55. * Adjust the backlight level with the percent in
  56. * dev_priv->blc_adj2
  57. */
  58. adjusted_level = level * dev_priv->blc_adj2;
  59. adjusted_level = adjusted_level / BLC_ADJUSTMENT_MAX;
  60. dev_priv->brightness_adjusted = adjusted_level;
  61. if (mdfld_get_panel_type(dev, 0) == TC35876X) {
  62. if (dev_priv->dpi_panel_on[0] ||
  63. dev_priv->dpi_panel_on[2])
  64. tc35876x_brightness_control(dev,
  65. dev_priv->brightness_adjusted);
  66. } else {
  67. if (dev_priv->dpi_panel_on[0])
  68. mdfld_dsi_brightness_control(dev, 0,
  69. dev_priv->brightness_adjusted);
  70. }
  71. if (dev_priv->dpi_panel_on[2])
  72. mdfld_dsi_brightness_control(dev, 2,
  73. dev_priv->brightness_adjusted);
  74. gma_power_end(dev);
  75. }
  76. /* cache the brightness for later use */
  77. dev_priv->brightness = level;
  78. return 0;
  79. }
  80. static int mdfld_get_brightness(struct backlight_device *bd)
  81. {
  82. struct drm_device *dev =
  83. (struct drm_device *)bl_get_data(mdfld_backlight_device);
  84. struct drm_psb_private *dev_priv = dev->dev_private;
  85. DRM_DEBUG_DRIVER("brightness = 0x%x \n", dev_priv->brightness);
  86. /* return locally cached var instead of HW read (due to DPST etc.) */
  87. return dev_priv->brightness;
  88. }
  89. static const struct backlight_ops mdfld_ops = {
  90. .get_brightness = mdfld_get_brightness,
  91. .update_status = mdfld_set_brightness,
  92. };
  93. static int device_backlight_init(struct drm_device *dev)
  94. {
  95. struct drm_psb_private *dev_priv = (struct drm_psb_private *)
  96. dev->dev_private;
  97. dev_priv->blc_adj1 = BLC_ADJUSTMENT_MAX;
  98. dev_priv->blc_adj2 = BLC_ADJUSTMENT_MAX;
  99. return 0;
  100. }
  101. static int mdfld_backlight_init(struct drm_device *dev)
  102. {
  103. struct backlight_properties props;
  104. int ret = 0;
  105. memset(&props, 0, sizeof(struct backlight_properties));
  106. props.max_brightness = BRIGHTNESS_MAX_LEVEL;
  107. props.type = BACKLIGHT_PLATFORM;
  108. mdfld_backlight_device = backlight_device_register("mdfld-bl",
  109. NULL, (void *)dev, &mdfld_ops, &props);
  110. if (IS_ERR(mdfld_backlight_device))
  111. return PTR_ERR(mdfld_backlight_device);
  112. ret = device_backlight_init(dev);
  113. if (ret)
  114. return ret;
  115. mdfld_backlight_device->props.brightness = BRIGHTNESS_MAX_LEVEL;
  116. mdfld_backlight_device->props.max_brightness = BRIGHTNESS_MAX_LEVEL;
  117. backlight_update_status(mdfld_backlight_device);
  118. return 0;
  119. }
  120. #endif
  121. struct backlight_device *mdfld_get_backlight_device(void)
  122. {
  123. #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
  124. return mdfld_backlight_device;
  125. #else
  126. return NULL;
  127. #endif
  128. }
  129. /*
  130. * mdfld_save_display_registers
  131. *
  132. * Description: We are going to suspend so save current display
  133. * register state.
  134. *
  135. * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
  136. */
  137. static int mdfld_save_display_registers(struct drm_device *dev, int pipenum)
  138. {
  139. struct drm_psb_private *dev_priv = dev->dev_private;
  140. struct medfield_state *regs = &dev_priv->regs.mdfld;
  141. struct psb_pipe *pipe = &dev_priv->regs.pipe[pipenum];
  142. const struct psb_offset *map = &dev_priv->regmap[pipenum];
  143. int i;
  144. u32 *mipi_val;
  145. /* register */
  146. u32 mipi_reg = MIPI;
  147. switch (pipenum) {
  148. case 0:
  149. mipi_val = &regs->saveMIPI;
  150. break;
  151. case 1:
  152. mipi_val = &regs->saveMIPI;
  153. break;
  154. case 2:
  155. /* register */
  156. mipi_reg = MIPI_C;
  157. /* pointer to values */
  158. mipi_val = &regs->saveMIPI_C;
  159. break;
  160. default:
  161. DRM_ERROR("%s, invalid pipe number.\n", __func__);
  162. return -EINVAL;
  163. }
  164. /* Pipe & plane A info */
  165. pipe->dpll = PSB_RVDC32(map->dpll);
  166. pipe->fp0 = PSB_RVDC32(map->fp0);
  167. pipe->conf = PSB_RVDC32(map->conf);
  168. pipe->htotal = PSB_RVDC32(map->htotal);
  169. pipe->hblank = PSB_RVDC32(map->hblank);
  170. pipe->hsync = PSB_RVDC32(map->hsync);
  171. pipe->vtotal = PSB_RVDC32(map->vtotal);
  172. pipe->vblank = PSB_RVDC32(map->vblank);
  173. pipe->vsync = PSB_RVDC32(map->vsync);
  174. pipe->src = PSB_RVDC32(map->src);
  175. pipe->stride = PSB_RVDC32(map->stride);
  176. pipe->linoff = PSB_RVDC32(map->linoff);
  177. pipe->tileoff = PSB_RVDC32(map->tileoff);
  178. pipe->size = PSB_RVDC32(map->size);
  179. pipe->pos = PSB_RVDC32(map->pos);
  180. pipe->surf = PSB_RVDC32(map->surf);
  181. pipe->cntr = PSB_RVDC32(map->cntr);
  182. pipe->status = PSB_RVDC32(map->status);
  183. /*save palette (gamma) */
  184. for (i = 0; i < 256; i++)
  185. pipe->palette[i] = PSB_RVDC32(map->palette + (i << 2));
  186. if (pipenum == 1) {
  187. regs->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL);
  188. regs->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS);
  189. regs->saveHDMIPHYMISCCTL = PSB_RVDC32(HDMIPHYMISCCTL);
  190. regs->saveHDMIB_CONTROL = PSB_RVDC32(HDMIB_CONTROL);
  191. return 0;
  192. }
  193. *mipi_val = PSB_RVDC32(mipi_reg);
  194. return 0;
  195. }
  196. /*
  197. * mdfld_restore_display_registers
  198. *
  199. * Description: We are going to resume so restore display register state.
  200. *
  201. * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
  202. */
  203. static int mdfld_restore_display_registers(struct drm_device *dev, int pipenum)
  204. {
  205. /* To get panel out of ULPS mode. */
  206. u32 temp = 0;
  207. u32 device_ready_reg = DEVICE_READY_REG;
  208. struct drm_psb_private *dev_priv = dev->dev_private;
  209. struct mdfld_dsi_config *dsi_config = NULL;
  210. struct medfield_state *regs = &dev_priv->regs.mdfld;
  211. struct psb_pipe *pipe = &dev_priv->regs.pipe[pipenum];
  212. const struct psb_offset *map = &dev_priv->regmap[pipenum];
  213. u32 i;
  214. u32 dpll;
  215. u32 timeout = 0;
  216. /* register */
  217. u32 mipi_reg = MIPI;
  218. /* values */
  219. u32 dpll_val = pipe->dpll;
  220. u32 mipi_val = regs->saveMIPI;
  221. switch (pipenum) {
  222. case 0:
  223. dpll_val &= ~DPLL_VCO_ENABLE;
  224. dsi_config = dev_priv->dsi_configs[0];
  225. break;
  226. case 1:
  227. dpll_val &= ~DPLL_VCO_ENABLE;
  228. break;
  229. case 2:
  230. mipi_reg = MIPI_C;
  231. mipi_val = regs->saveMIPI_C;
  232. dsi_config = dev_priv->dsi_configs[1];
  233. break;
  234. default:
  235. DRM_ERROR("%s, invalid pipe number.\n", __func__);
  236. return -EINVAL;
  237. }
  238. /*make sure VGA plane is off. it initializes to on after reset!*/
  239. PSB_WVDC32(0x80000000, VGACNTRL);
  240. if (pipenum == 1) {
  241. PSB_WVDC32(dpll_val & ~DPLL_VCO_ENABLE, map->dpll);
  242. PSB_RVDC32(map->dpll);
  243. PSB_WVDC32(pipe->fp0, map->fp0);
  244. } else {
  245. dpll = PSB_RVDC32(map->dpll);
  246. if (!(dpll & DPLL_VCO_ENABLE)) {
  247. /* When ungating power of DPLL, needs to wait 0.5us
  248. before enable the VCO */
  249. if (dpll & MDFLD_PWR_GATE_EN) {
  250. dpll &= ~MDFLD_PWR_GATE_EN;
  251. PSB_WVDC32(dpll, map->dpll);
  252. /* FIXME_MDFLD PO - change 500 to 1 after PO */
  253. udelay(500);
  254. }
  255. PSB_WVDC32(pipe->fp0, map->fp0);
  256. PSB_WVDC32(dpll_val, map->dpll);
  257. /* FIXME_MDFLD PO - change 500 to 1 after PO */
  258. udelay(500);
  259. dpll_val |= DPLL_VCO_ENABLE;
  260. PSB_WVDC32(dpll_val, map->dpll);
  261. PSB_RVDC32(map->dpll);
  262. /* wait for DSI PLL to lock */
  263. while (timeout < 20000 &&
  264. !(PSB_RVDC32(map->conf) & PIPECONF_DSIPLL_LOCK)) {
  265. udelay(150);
  266. timeout++;
  267. }
  268. if (timeout == 20000) {
  269. DRM_ERROR("%s, can't lock DSIPLL.\n",
  270. __func__);
  271. return -EINVAL;
  272. }
  273. }
  274. }
  275. /* Restore mode */
  276. PSB_WVDC32(pipe->htotal, map->htotal);
  277. PSB_WVDC32(pipe->hblank, map->hblank);
  278. PSB_WVDC32(pipe->hsync, map->hsync);
  279. PSB_WVDC32(pipe->vtotal, map->vtotal);
  280. PSB_WVDC32(pipe->vblank, map->vblank);
  281. PSB_WVDC32(pipe->vsync, map->vsync);
  282. PSB_WVDC32(pipe->src, map->src);
  283. PSB_WVDC32(pipe->status, map->status);
  284. /*set up the plane*/
  285. PSB_WVDC32(pipe->stride, map->stride);
  286. PSB_WVDC32(pipe->linoff, map->linoff);
  287. PSB_WVDC32(pipe->tileoff, map->tileoff);
  288. PSB_WVDC32(pipe->size, map->size);
  289. PSB_WVDC32(pipe->pos, map->pos);
  290. PSB_WVDC32(pipe->surf, map->surf);
  291. if (pipenum == 1) {
  292. /* restore palette (gamma) */
  293. /*DRM_UDELAY(50000); */
  294. for (i = 0; i < 256; i++)
  295. PSB_WVDC32(pipe->palette[i], map->palette + (i << 2));
  296. PSB_WVDC32(regs->savePFIT_CONTROL, PFIT_CONTROL);
  297. PSB_WVDC32(regs->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS);
  298. /*TODO: resume HDMI port */
  299. /*TODO: resume pipe*/
  300. /*enable the plane*/
  301. PSB_WVDC32(pipe->cntr & ~DISPLAY_PLANE_ENABLE, map->cntr);
  302. return 0;
  303. }
  304. /*set up pipe related registers*/
  305. PSB_WVDC32(mipi_val, mipi_reg);
  306. /*setup MIPI adapter + MIPI IP registers*/
  307. if (dsi_config)
  308. mdfld_dsi_controller_init(dsi_config, pipenum);
  309. if (in_atomic() || in_interrupt())
  310. mdelay(20);
  311. else
  312. msleep(20);
  313. /*enable the plane*/
  314. PSB_WVDC32(pipe->cntr, map->cntr);
  315. if (in_atomic() || in_interrupt())
  316. mdelay(20);
  317. else
  318. msleep(20);
  319. /* LP Hold Release */
  320. temp = REG_READ(mipi_reg);
  321. temp |= LP_OUTPUT_HOLD_RELEASE;
  322. REG_WRITE(mipi_reg, temp);
  323. mdelay(1);
  324. /* Set DSI host to exit from Utra Low Power State */
  325. temp = REG_READ(device_ready_reg);
  326. temp &= ~ULPS_MASK;
  327. temp |= 0x3;
  328. temp |= EXIT_ULPS_DEV_READY;
  329. REG_WRITE(device_ready_reg, temp);
  330. mdelay(1);
  331. temp = REG_READ(device_ready_reg);
  332. temp &= ~ULPS_MASK;
  333. temp |= EXITING_ULPS;
  334. REG_WRITE(device_ready_reg, temp);
  335. mdelay(1);
  336. /*enable the pipe*/
  337. PSB_WVDC32(pipe->conf, map->conf);
  338. /* restore palette (gamma) */
  339. /*DRM_UDELAY(50000); */
  340. for (i = 0; i < 256; i++)
  341. PSB_WVDC32(pipe->palette[i], map->palette + (i << 2));
  342. return 0;
  343. }
  344. static int mdfld_save_registers(struct drm_device *dev)
  345. {
  346. /* mdfld_save_cursor_overlay_registers(dev); */
  347. mdfld_save_display_registers(dev, 0);
  348. mdfld_save_display_registers(dev, 2);
  349. mdfld_disable_crtc(dev, 0);
  350. mdfld_disable_crtc(dev, 2);
  351. return 0;
  352. }
  353. static int mdfld_restore_registers(struct drm_device *dev)
  354. {
  355. mdfld_restore_display_registers(dev, 2);
  356. mdfld_restore_display_registers(dev, 0);
  357. /* mdfld_restore_cursor_overlay_registers(dev); */
  358. return 0;
  359. }
  360. static int mdfld_power_down(struct drm_device *dev)
  361. {
  362. /* FIXME */
  363. return 0;
  364. }
  365. static int mdfld_power_up(struct drm_device *dev)
  366. {
  367. /* FIXME */
  368. return 0;
  369. }
  370. /* Medfield */
  371. static const struct psb_offset mdfld_regmap[3] = {
  372. {
  373. .fp0 = MRST_FPA0,
  374. .fp1 = MRST_FPA1,
  375. .cntr = DSPACNTR,
  376. .conf = PIPEACONF,
  377. .src = PIPEASRC,
  378. .dpll = MRST_DPLL_A,
  379. .htotal = HTOTAL_A,
  380. .hblank = HBLANK_A,
  381. .hsync = HSYNC_A,
  382. .vtotal = VTOTAL_A,
  383. .vblank = VBLANK_A,
  384. .vsync = VSYNC_A,
  385. .stride = DSPASTRIDE,
  386. .size = DSPASIZE,
  387. .pos = DSPAPOS,
  388. .surf = DSPASURF,
  389. .addr = MRST_DSPABASE,
  390. .status = PIPEASTAT,
  391. .linoff = DSPALINOFF,
  392. .tileoff = DSPATILEOFF,
  393. .palette = PALETTE_A,
  394. },
  395. {
  396. .fp0 = MDFLD_DPLL_DIV0,
  397. .cntr = DSPBCNTR,
  398. .conf = PIPEBCONF,
  399. .src = PIPEBSRC,
  400. .dpll = MDFLD_DPLL_B,
  401. .htotal = HTOTAL_B,
  402. .hblank = HBLANK_B,
  403. .hsync = HSYNC_B,
  404. .vtotal = VTOTAL_B,
  405. .vblank = VBLANK_B,
  406. .vsync = VSYNC_B,
  407. .stride = DSPBSTRIDE,
  408. .size = DSPBSIZE,
  409. .pos = DSPBPOS,
  410. .surf = DSPBSURF,
  411. .addr = MRST_DSPBBASE,
  412. .status = PIPEBSTAT,
  413. .linoff = DSPBLINOFF,
  414. .tileoff = DSPBTILEOFF,
  415. .palette = PALETTE_B,
  416. },
  417. {
  418. .fp0 = MRST_FPA0, /* This is what the old code did ?? */
  419. .cntr = DSPCCNTR,
  420. .conf = PIPECCONF,
  421. .src = PIPECSRC,
  422. /* No DPLL_C */
  423. .dpll = MRST_DPLL_A,
  424. .htotal = HTOTAL_C,
  425. .hblank = HBLANK_C,
  426. .hsync = HSYNC_C,
  427. .vtotal = VTOTAL_C,
  428. .vblank = VBLANK_C,
  429. .vsync = VSYNC_C,
  430. .stride = DSPCSTRIDE,
  431. .size = DSPBSIZE,
  432. .pos = DSPCPOS,
  433. .surf = DSPCSURF,
  434. .addr = MDFLD_DSPCBASE,
  435. .status = PIPECSTAT,
  436. .linoff = DSPCLINOFF,
  437. .tileoff = DSPCTILEOFF,
  438. .palette = PALETTE_C,
  439. },
  440. };
  441. static int mdfld_chip_setup(struct drm_device *dev)
  442. {
  443. struct drm_psb_private *dev_priv = dev->dev_private;
  444. if (pci_enable_msi(dev->pdev))
  445. dev_warn(dev->dev, "Enabling MSI failed!\n");
  446. dev_priv->regmap = mdfld_regmap;
  447. return mid_chip_setup(dev);
  448. }
  449. const struct psb_ops mdfld_chip_ops = {
  450. .name = "mdfld",
  451. .accel_2d = 0,
  452. .pipes = 3,
  453. .crtcs = 3,
  454. .lvds_mask = (1 << 1),
  455. .hdmi_mask = (1 << 1),
  456. .cursor_needs_phys = 0,
  457. .sgx_offset = MRST_SGX_OFFSET,
  458. .chip_setup = mdfld_chip_setup,
  459. .crtc_helper = &mdfld_helper_funcs,
  460. .crtc_funcs = &psb_intel_crtc_funcs,
  461. .output_init = mdfld_output_init,
  462. #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
  463. .backlight_init = mdfld_backlight_init,
  464. #endif
  465. .save_regs = mdfld_save_registers,
  466. .restore_regs = mdfld_restore_registers,
  467. .power_down = mdfld_power_down,
  468. .power_up = mdfld_power_up,
  469. };