aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlex Deucher <alexander.deucher@amd.com>2012-07-26 11:32:03 -0400
committerAlex Deucher <alexander.deucher@amd.com>2012-09-20 13:10:35 -0400
commitf3728734ba78310525bf4a361c7787c7c6fa5d40 (patch)
tree8bb27dccaa73799497bb430d6554929a825e2e06 /drivers
parent910308802c528f8afe864b694d5456fedd0bb18f (diff)
drm/radeon: add backlight control for atom devices (v2)
On systems that use the build in GPU backlight controller, we can use atom tables to change the brightness level. v2: use firmware flags Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/radeon/atombios_encoders.c231
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c15
-rw-r--r--drivers/gpu/drm/radeon/radeon_encoders.c18
3 files changed, 248 insertions, 16 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index 6e8803a1170c..f3645e15ef11 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -28,9 +28,238 @@
28#include "radeon_drm.h" 28#include "radeon_drm.h"
29#include "radeon.h" 29#include "radeon.h"
30#include "atom.h" 30#include "atom.h"
31#include <linux/backlight.h>
31 32
32extern int atom_debug; 33extern int atom_debug;
33 34
35#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
36
37static u8
38radeon_atom_get_backlight_level_from_reg(struct radeon_device *rdev)
39{
40 u8 backlight_level;
41 u32 bios_2_scratch;
42
43 if (rdev->family >= CHIP_R600)
44 bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH);
45 else
46 bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH);
47
48 backlight_level = ((bios_2_scratch & ATOM_S2_CURRENT_BL_LEVEL_MASK) >>
49 ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
50
51 return backlight_level;
52}
53
54static void
55radeon_atom_set_backlight_level_to_reg(struct radeon_device *rdev,
56 u8 backlight_level)
57{
58 u32 bios_2_scratch;
59
60 if (rdev->family >= CHIP_R600)
61 bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH);
62 else
63 bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH);
64
65 bios_2_scratch &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK;
66 bios_2_scratch |= ((backlight_level << ATOM_S2_CURRENT_BL_LEVEL_SHIFT) &
67 ATOM_S2_CURRENT_BL_LEVEL_MASK);
68
69 if (rdev->family >= CHIP_R600)
70 WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);
71 else
72 WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch);
73}
74
75static void
76atombios_set_panel_brightness(struct radeon_encoder *radeon_encoder)
77{
78 struct drm_encoder *encoder = &radeon_encoder->base;
79 struct drm_device *dev = radeon_encoder->base.dev;
80 struct radeon_device *rdev = dev->dev_private;
81 struct radeon_encoder_atom_dig *dig;
82 DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args;
83 int index;
84
85 if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
86 dig = radeon_encoder->enc_priv;
87 radeon_atom_set_backlight_level_to_reg(rdev, dig->backlight_level);
88
89 switch (radeon_encoder->encoder_id) {
90 case ENCODER_OBJECT_ID_INTERNAL_LVDS:
91 case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
92 index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
93 if (dig->backlight_level == 0) {
94 args.ucAction = ATOM_LCD_BLOFF;
95 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
96 } else {
97 args.ucAction = ATOM_LCD_BL_BRIGHTNESS_CONTROL;
98 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
99 args.ucAction = ATOM_LCD_BLON;
100 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
101 }
102 break;
103 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
104 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
105 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
106 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
107 if (dig->backlight_level == 0)
108 atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
109 else {
110 atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL, 0, 0);
111 atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0);
112 }
113 break;
114 default:
115 break;
116 }
117 }
118}
119
120static u8 radeon_atom_bl_level(struct backlight_device *bd)
121{
122 u8 level;
123
124 /* Convert brightness to hardware level */
125 if (bd->props.brightness < 0)
126 level = 0;
127 else if (bd->props.brightness > RADEON_MAX_BL_LEVEL)
128 level = RADEON_MAX_BL_LEVEL;
129 else
130 level = bd->props.brightness;
131
132 return level;
133}
134
135static int radeon_atom_backlight_update_status(struct backlight_device *bd)
136{
137 struct radeon_backlight_privdata *pdata = bl_get_data(bd);
138 struct radeon_encoder *radeon_encoder = pdata->encoder;
139
140 if (radeon_encoder->enc_priv) {
141 struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
142 dig->backlight_level = radeon_atom_bl_level(bd);
143 atombios_set_panel_brightness(radeon_encoder);
144 }
145
146 return 0;
147}
148
149static int radeon_atom_backlight_get_brightness(struct backlight_device *bd)
150{
151 struct radeon_backlight_privdata *pdata = bl_get_data(bd);
152 struct radeon_encoder *radeon_encoder = pdata->encoder;
153 struct drm_device *dev = radeon_encoder->base.dev;
154 struct radeon_device *rdev = dev->dev_private;
155
156 return radeon_atom_get_backlight_level_from_reg(rdev);
157}
158
159static const struct backlight_ops radeon_atom_backlight_ops = {
160 .get_brightness = radeon_atom_backlight_get_brightness,
161 .update_status = radeon_atom_backlight_update_status,
162};
163
164void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder,
165 struct drm_connector *drm_connector)
166{
167 struct drm_device *dev = radeon_encoder->base.dev;
168 struct radeon_device *rdev = dev->dev_private;
169 struct backlight_device *bd;
170 struct backlight_properties props;
171 struct radeon_backlight_privdata *pdata;
172 struct radeon_encoder_atom_dig *dig;
173 u8 backlight_level;
174
175 if (!radeon_encoder->enc_priv)
176 return;
177
178 if (!rdev->is_atom_bios)
179 return;
180
181 if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
182 return;
183
184 pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL);
185 if (!pdata) {
186 DRM_ERROR("Memory allocation failed\n");
187 goto error;
188 }
189
190 memset(&props, 0, sizeof(props));
191 props.max_brightness = RADEON_MAX_BL_LEVEL;
192 props.type = BACKLIGHT_RAW;
193 bd = backlight_device_register("radeon_bl", &drm_connector->kdev,
194 pdata, &radeon_atom_backlight_ops, &props);
195 if (IS_ERR(bd)) {
196 DRM_ERROR("Backlight registration failed\n");
197 goto error;
198 }
199
200 pdata->encoder = radeon_encoder;
201
202 backlight_level = radeon_atom_get_backlight_level_from_reg(rdev);
203
204 dig = radeon_encoder->enc_priv;
205 dig->bl_dev = bd;
206
207 bd->props.brightness = radeon_atom_backlight_get_brightness(bd);
208 bd->props.power = FB_BLANK_UNBLANK;
209 backlight_update_status(bd);
210
211 DRM_INFO("radeon atom DIG backlight initialized\n");
212
213 return;
214
215error:
216 kfree(pdata);
217 return;
218}
219
220static void radeon_atom_backlight_exit(struct radeon_encoder *radeon_encoder)
221{
222 struct drm_device *dev = radeon_encoder->base.dev;
223 struct radeon_device *rdev = dev->dev_private;
224 struct backlight_device *bd = NULL;
225 struct radeon_encoder_atom_dig *dig;
226
227 if (!radeon_encoder->enc_priv)
228 return;
229
230 if (!rdev->is_atom_bios)
231 return;
232
233 if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
234 return;
235
236 dig = radeon_encoder->enc_priv;
237 bd = dig->bl_dev;
238 dig->bl_dev = NULL;
239
240 if (bd) {
241 struct radeon_legacy_backlight_privdata *pdata;
242
243 pdata = bl_get_data(bd);
244 backlight_device_unregister(bd);
245 kfree(pdata);
246
247 DRM_INFO("radeon atom LVDS backlight unloaded\n");
248 }
249}
250
251#else /* !CONFIG_BACKLIGHT_CLASS_DEVICE */
252
253void radeon_atom_backlight_init(struct radeon_encoder *encoder)
254{
255}
256
257static void radeon_atom_backlight_exit(struct radeon_encoder *encoder)
258{
259}
260
261#endif
262
34/* evil but including atombios.h is much worse */ 263/* evil but including atombios.h is much worse */
35bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, 264bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
36 struct drm_display_mode *mode); 265 struct drm_display_mode *mode);
@@ -2286,6 +2515,8 @@ static const struct drm_encoder_helper_funcs radeon_atom_dac_helper_funcs = {
2286void radeon_enc_destroy(struct drm_encoder *encoder) 2515void radeon_enc_destroy(struct drm_encoder *encoder)
2287{ 2516{
2288 struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 2517 struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
2518 if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
2519 radeon_atom_backlight_exit(radeon_encoder);
2289 kfree(radeon_encoder->enc_priv); 2520 kfree(radeon_encoder->enc_priv);
2290 drm_encoder_cleanup(encoder); 2521 drm_encoder_cleanup(encoder);
2291 kfree(radeon_encoder); 2522 kfree(radeon_encoder);
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 895e628b60f8..748c5f229c28 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -40,10 +40,6 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
40 struct drm_encoder *encoder, 40 struct drm_encoder *encoder,
41 bool connected); 41 bool connected);
42 42
43extern void
44radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder,
45 struct drm_connector *drm_connector);
46
47void radeon_connector_hotplug(struct drm_connector *connector) 43void radeon_connector_hotplug(struct drm_connector *connector)
48{ 44{
49 struct drm_device *dev = connector->dev; 45 struct drm_device *dev = connector->dev;
@@ -2008,15 +2004,4 @@ radeon_add_legacy_connector(struct drm_device *dev,
2008 connector->polled = DRM_CONNECTOR_POLL_HPD; 2004 connector->polled = DRM_CONNECTOR_POLL_HPD;
2009 connector->display_info.subpixel_order = subpixel_order; 2005 connector->display_info.subpixel_order = subpixel_order;
2010 drm_sysfs_connector_add(connector); 2006 drm_sysfs_connector_add(connector);
2011 if (connector_type == DRM_MODE_CONNECTOR_LVDS) {
2012 struct drm_encoder *drm_encoder;
2013
2014 list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) {
2015 struct radeon_encoder *radeon_encoder;
2016
2017 radeon_encoder = to_radeon_encoder(drm_encoder);
2018 if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_LVDS)
2019 radeon_legacy_backlight_init(radeon_encoder, connector);
2020 }
2021 }
2022} 2007}
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
index 74670696277d..93b0d64b3f6d 100644
--- a/drivers/gpu/drm/radeon/radeon_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_encoders.c
@@ -29,6 +29,14 @@
29#include "radeon.h" 29#include "radeon.h"
30#include "atom.h" 30#include "atom.h"
31 31
32extern void
33radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder,
34 struct drm_connector *drm_connector);
35extern void
36radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder,
37 struct drm_connector *drm_connector);
38
39
32static uint32_t radeon_encoder_clones(struct drm_encoder *encoder) 40static uint32_t radeon_encoder_clones(struct drm_encoder *encoder)
33{ 41{
34 struct drm_device *dev = encoder->dev; 42 struct drm_device *dev = encoder->dev;
@@ -153,6 +161,7 @@ radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, uint8
153void 161void
154radeon_link_encoder_connector(struct drm_device *dev) 162radeon_link_encoder_connector(struct drm_device *dev)
155{ 163{
164 struct radeon_device *rdev = dev->dev_private;
156 struct drm_connector *connector; 165 struct drm_connector *connector;
157 struct radeon_connector *radeon_connector; 166 struct radeon_connector *radeon_connector;
158 struct drm_encoder *encoder; 167 struct drm_encoder *encoder;
@@ -163,8 +172,15 @@ radeon_link_encoder_connector(struct drm_device *dev)
163 radeon_connector = to_radeon_connector(connector); 172 radeon_connector = to_radeon_connector(connector);
164 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 173 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
165 radeon_encoder = to_radeon_encoder(encoder); 174 radeon_encoder = to_radeon_encoder(encoder);
166 if (radeon_encoder->devices & radeon_connector->devices) 175 if (radeon_encoder->devices & radeon_connector->devices) {
167 drm_mode_connector_attach_encoder(connector, encoder); 176 drm_mode_connector_attach_encoder(connector, encoder);
177 if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
178 if (rdev->is_atom_bios)
179 radeon_atom_backlight_init(radeon_encoder, connector);
180 else
181 radeon_legacy_backlight_init(radeon_encoder, connector);
182 }
183 }
168 } 184 }
169 } 185 }
170} 186}