radeon_backlight.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Backlight code for ATI Radeon based graphic cards
  4. *
  5. * Copyright (c) 2000 Ani Joshi <ajoshi@kernel.crashing.org>
  6. * Copyright (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
  7. * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
  8. */
  9. #include "radeonfb.h"
  10. #include <linux/backlight.h>
  11. #include <linux/slab.h>
  12. #ifdef CONFIG_PMAC_BACKLIGHT
  13. #include <asm/backlight.h>
  14. #endif
  15. #define MAX_RADEON_LEVEL 0xFF
  16. struct radeon_bl_privdata {
  17. struct radeonfb_info *rinfo;
  18. uint8_t negative;
  19. };
  20. static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
  21. int level)
  22. {
  23. int rlevel;
  24. /* Get and convert the value */
  25. /* No locking of bl_curve since we read a single value */
  26. rlevel = pdata->rinfo->info->bl_curve[level] *
  27. FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL;
  28. if (rlevel < 0)
  29. rlevel = 0;
  30. else if (rlevel > MAX_RADEON_LEVEL)
  31. rlevel = MAX_RADEON_LEVEL;
  32. if (pdata->negative)
  33. rlevel = MAX_RADEON_LEVEL - rlevel;
  34. return rlevel;
  35. }
  36. static int radeon_bl_update_status(struct backlight_device *bd)
  37. {
  38. struct radeon_bl_privdata *pdata = bl_get_data(bd);
  39. struct radeonfb_info *rinfo = pdata->rinfo;
  40. u32 lvds_gen_cntl, tmpPixclksCntl;
  41. int level;
  42. if (rinfo->mon1_type != MT_LCD)
  43. return 0;
  44. /* We turn off the LCD completely instead of just dimming the
  45. * backlight. This provides some greater power saving and the display
  46. * is useless without backlight anyway.
  47. */
  48. level = backlight_get_brightness(bd);
  49. del_timer_sync(&rinfo->lvds_timer);
  50. radeon_engine_idle();
  51. lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
  52. if (level > 0) {
  53. lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
  54. if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
  55. lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
  56. lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
  57. OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
  58. lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
  59. lvds_gen_cntl |=
  60. (radeon_bl_get_level_brightness(pdata, level) <<
  61. LVDS_BL_MOD_LEVEL_SHIFT);
  62. lvds_gen_cntl |= LVDS_ON;
  63. lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
  64. rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
  65. mod_timer(&rinfo->lvds_timer,
  66. jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
  67. } else {
  68. lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
  69. lvds_gen_cntl |=
  70. (radeon_bl_get_level_brightness(pdata, level) <<
  71. LVDS_BL_MOD_LEVEL_SHIFT);
  72. OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
  73. }
  74. rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
  75. rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
  76. & LVDS_STATE_MASK;
  77. } else {
  78. /* Asic bug, when turning off LVDS_ON, we have to make sure
  79. RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
  80. */
  81. tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
  82. if (rinfo->is_mobility || rinfo->is_IGP)
  83. OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
  84. lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
  85. lvds_gen_cntl |= (radeon_bl_get_level_brightness(pdata, 0) <<
  86. LVDS_BL_MOD_LEVEL_SHIFT);
  87. lvds_gen_cntl |= LVDS_DISPLAY_DIS;
  88. OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
  89. udelay(100);
  90. lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
  91. OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
  92. lvds_gen_cntl &= ~(LVDS_DIGON);
  93. rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
  94. mod_timer(&rinfo->lvds_timer,
  95. jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
  96. if (rinfo->is_mobility || rinfo->is_IGP)
  97. OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
  98. }
  99. rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
  100. rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
  101. return 0;
  102. }
  103. static const struct backlight_ops radeon_bl_data = {
  104. .update_status = radeon_bl_update_status,
  105. };
  106. void radeonfb_bl_init(struct radeonfb_info *rinfo)
  107. {
  108. struct backlight_properties props;
  109. struct backlight_device *bd;
  110. struct radeon_bl_privdata *pdata;
  111. char name[12];
  112. if (rinfo->mon1_type != MT_LCD)
  113. return;
  114. #ifdef CONFIG_PMAC_BACKLIGHT
  115. if (!pmac_has_backlight_type("ati") &&
  116. !pmac_has_backlight_type("mnca"))
  117. return;
  118. #endif
  119. pdata = kmalloc(sizeof(struct radeon_bl_privdata), GFP_KERNEL);
  120. if (!pdata) {
  121. printk("radeonfb: Memory allocation failed\n");
  122. goto error;
  123. }
  124. snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
  125. memset(&props, 0, sizeof(struct backlight_properties));
  126. props.type = BACKLIGHT_RAW;
  127. props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
  128. bd = backlight_device_register(name, rinfo->info->device, pdata,
  129. &radeon_bl_data, &props);
  130. if (IS_ERR(bd)) {
  131. rinfo->info->bl_dev = NULL;
  132. printk("radeonfb: Backlight registration failed\n");
  133. goto error;
  134. }
  135. pdata->rinfo = rinfo;
  136. /* Pardon me for that hack... maybe some day we can figure out in what
  137. * direction backlight should work on a given panel?
  138. */
  139. pdata->negative =
  140. (rinfo->family != CHIP_FAMILY_RV200 &&
  141. rinfo->family != CHIP_FAMILY_RV250 &&
  142. rinfo->family != CHIP_FAMILY_RV280 &&
  143. rinfo->family != CHIP_FAMILY_RV350);
  144. #ifdef CONFIG_PMAC_BACKLIGHT
  145. pdata->negative = pdata->negative ||
  146. of_machine_is_compatible("PowerBook4,3") ||
  147. of_machine_is_compatible("PowerBook6,3") ||
  148. of_machine_is_compatible("PowerBook6,5");
  149. #endif
  150. rinfo->info->bl_dev = bd;
  151. fb_bl_default_curve(rinfo->info, 0,
  152. 63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL,
  153. 217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL);
  154. bd->props.brightness = bd->props.max_brightness;
  155. bd->props.power = FB_BLANK_UNBLANK;
  156. backlight_update_status(bd);
  157. printk("radeonfb: Backlight initialized (%s)\n", name);
  158. return;
  159. error:
  160. kfree(pdata);
  161. return;
  162. }
  163. void radeonfb_bl_exit(struct radeonfb_info *rinfo)
  164. {
  165. struct backlight_device *bd = rinfo->info->bl_dev;
  166. if (bd) {
  167. struct radeon_bl_privdata *pdata;
  168. pdata = bl_get_data(bd);
  169. backlight_device_unregister(bd);
  170. kfree(pdata);
  171. rinfo->info->bl_dev = NULL;
  172. printk("radeonfb: Backlight unloaded\n");
  173. }
  174. }