diff options
author | Alex Deucher <alexander.deucher@amd.com> | 2012-07-26 11:32:03 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2012-09-20 13:10:35 -0400 |
commit | f3728734ba78310525bf4a361c7787c7c6fa5d40 (patch) | |
tree | 8bb27dccaa73799497bb430d6554929a825e2e06 /drivers | |
parent | 910308802c528f8afe864b694d5456fedd0bb18f (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.c | 231 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_connectors.c | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_encoders.c | 18 |
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 | ||
32 | extern int atom_debug; | 33 | extern int atom_debug; |
33 | 34 | ||
35 | #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) | ||
36 | |||
37 | static u8 | ||
38 | radeon_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 | |||
54 | static void | ||
55 | radeon_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 | |||
75 | static void | ||
76 | atombios_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 | |||
120 | static 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 | |||
135 | static 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 | |||
149 | static 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 | |||
159 | static 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 | |||
164 | void 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 | |||
215 | error: | ||
216 | kfree(pdata); | ||
217 | return; | ||
218 | } | ||
219 | |||
220 | static 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 | |||
253 | void radeon_atom_backlight_init(struct radeon_encoder *encoder) | ||
254 | { | ||
255 | } | ||
256 | |||
257 | static 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 */ |
35 | bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, | 264 | bool 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 = { | |||
2286 | void radeon_enc_destroy(struct drm_encoder *encoder) | 2515 | void 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 | ||
43 | extern void | ||
44 | radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder, | ||
45 | struct drm_connector *drm_connector); | ||
46 | |||
47 | void radeon_connector_hotplug(struct drm_connector *connector) | 43 | void 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 | ||
32 | extern void | ||
33 | radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder, | ||
34 | struct drm_connector *drm_connector); | ||
35 | extern void | ||
36 | radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder, | ||
37 | struct drm_connector *drm_connector); | ||
38 | |||
39 | |||
32 | static uint32_t radeon_encoder_clones(struct drm_encoder *encoder) | 40 | static 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 | |||
153 | void | 161 | void |
154 | radeon_link_encoder_connector(struct drm_device *dev) | 162 | radeon_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 | } |