mdfld_device.c 14 KB

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