aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/radeon_display.c
diff options
context:
space:
mode:
authorJerome Glisse <jglisse@redhat.com>2009-06-05 08:42:42 -0400
committerDave Airlie <airlied@redhat.com>2009-06-14 22:01:53 -0400
commit771fe6b912fca54f03e8a72eb63058b582775362 (patch)
tree58aa5469ba8058c2b564d50807395ad6cd7bd7e4 /drivers/gpu/drm/radeon/radeon_display.c
parentba4e7d973dd09b66912ac4c0856add8b0703a997 (diff)
drm/radeon: introduce kernel modesetting for radeon hardware
Add kernel modesetting support to radeon driver, use the ttm memory manager to manage memory and DRM/GEM to provide userspace API. In order to avoid backward compatibility issue and to allow clean design and code the radeon kernel modesetting use different code path than old radeon/drm driver. When kernel modesetting is enabled the IOCTL of radeon/drm driver are considered as invalid and an error message is printed in the log and they return failure. KMS enabled userspace will use new API to talk with the radeon/drm driver. The new API provide functions to create/destroy/share/mmap buffer object which are then managed by the kernel memory manager (here TTM). In order to submit command to the GPU the userspace provide a buffer holding the command stream, along this buffer userspace have to provide a list of buffer object used by the command stream. The kernel radeon driver will then place buffer in GPU accessible memory and will update command stream to reflect the position of the different buffers. The kernel will also perform security check on command stream provided by the user, we want to catch and forbid any illegal use of the GPU such as DMA into random system memory or into memory not owned by the process supplying the command stream. This part of the code is still incomplete and this why we propose that patch as a staging driver addition, future security might forbid current experimental userspace to run. This code support the following hardware : R1XX,R2XX,R3XX,R4XX,R5XX (radeon up to X1950). Works is underway to provide support for R6XX, R7XX and newer hardware (radeon from HD2XXX to HD4XXX). Authors: Jerome Glisse <jglisse@redhat.com> Dave Airlie <airlied@redhat.com> Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Jerome Glisse <jglisse@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_display.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c692
1 files changed, 692 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
new file mode 100644
index 000000000000..5452bb9d925e
--- /dev/null
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -0,0 +1,692 @@
1/*
2 * Copyright 2007-8 Advanced Micro Devices, Inc.
3 * Copyright 2008 Red Hat Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * Authors: Dave Airlie
24 * Alex Deucher
25 */
26#include "drmP.h"
27#include "radeon_drm.h"
28#include "radeon.h"
29
30#include "atom.h"
31#include <asm/div64.h>
32
33#include "drm_crtc_helper.h"
34#include "drm_edid.h"
35
36static int radeon_ddc_dump(struct drm_connector *connector);
37
38static void avivo_crtc_load_lut(struct drm_crtc *crtc)
39{
40 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
41 struct drm_device *dev = crtc->dev;
42 struct radeon_device *rdev = dev->dev_private;
43 int i;
44
45 DRM_DEBUG("%d\n", radeon_crtc->crtc_id);
46 WREG32(AVIVO_DC_LUTA_CONTROL + radeon_crtc->crtc_offset, 0);
47
48 WREG32(AVIVO_DC_LUTA_BLACK_OFFSET_BLUE + radeon_crtc->crtc_offset, 0);
49 WREG32(AVIVO_DC_LUTA_BLACK_OFFSET_GREEN + radeon_crtc->crtc_offset, 0);
50 WREG32(AVIVO_DC_LUTA_BLACK_OFFSET_RED + radeon_crtc->crtc_offset, 0);
51
52 WREG32(AVIVO_DC_LUTA_WHITE_OFFSET_BLUE + radeon_crtc->crtc_offset, 0xffff);
53 WREG32(AVIVO_DC_LUTA_WHITE_OFFSET_GREEN + radeon_crtc->crtc_offset, 0xffff);
54 WREG32(AVIVO_DC_LUTA_WHITE_OFFSET_RED + radeon_crtc->crtc_offset, 0xffff);
55
56 WREG32(AVIVO_DC_LUT_RW_SELECT, radeon_crtc->crtc_id);
57 WREG32(AVIVO_DC_LUT_RW_MODE, 0);
58 WREG32(AVIVO_DC_LUT_WRITE_EN_MASK, 0x0000003f);
59
60 WREG8(AVIVO_DC_LUT_RW_INDEX, 0);
61 for (i = 0; i < 256; i++) {
62 WREG32(AVIVO_DC_LUT_30_COLOR,
63 (radeon_crtc->lut_r[i] << 20) |
64 (radeon_crtc->lut_g[i] << 10) |
65 (radeon_crtc->lut_b[i] << 0));
66 }
67
68 WREG32(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id);
69}
70
71static void legacy_crtc_load_lut(struct drm_crtc *crtc)
72{
73 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
74 struct drm_device *dev = crtc->dev;
75 struct radeon_device *rdev = dev->dev_private;
76 int i;
77 uint32_t dac2_cntl;
78
79 dac2_cntl = RREG32(RADEON_DAC_CNTL2);
80 if (radeon_crtc->crtc_id == 0)
81 dac2_cntl &= (uint32_t)~RADEON_DAC2_PALETTE_ACC_CTL;
82 else
83 dac2_cntl |= RADEON_DAC2_PALETTE_ACC_CTL;
84 WREG32(RADEON_DAC_CNTL2, dac2_cntl);
85
86 WREG8(RADEON_PALETTE_INDEX, 0);
87 for (i = 0; i < 256; i++) {
88 WREG32(RADEON_PALETTE_30_DATA,
89 (radeon_crtc->lut_r[i] << 20) |
90 (radeon_crtc->lut_g[i] << 10) |
91 (radeon_crtc->lut_b[i] << 0));
92 }
93}
94
95void radeon_crtc_load_lut(struct drm_crtc *crtc)
96{
97 struct drm_device *dev = crtc->dev;
98 struct radeon_device *rdev = dev->dev_private;
99
100 if (!crtc->enabled)
101 return;
102
103 if (ASIC_IS_AVIVO(rdev))
104 avivo_crtc_load_lut(crtc);
105 else
106 legacy_crtc_load_lut(crtc);
107}
108
109/** Sets the color ramps on behalf of RandR */
110void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
111 u16 blue, int regno)
112{
113 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
114
115 if (regno == 0)
116 DRM_DEBUG("gamma set %d\n", radeon_crtc->crtc_id);
117 radeon_crtc->lut_r[regno] = red >> 6;
118 radeon_crtc->lut_g[regno] = green >> 6;
119 radeon_crtc->lut_b[regno] = blue >> 6;
120}
121
122static void radeon_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
123 u16 *blue, uint32_t size)
124{
125 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
126 int i, j;
127
128 if (size != 256) {
129 return;
130 }
131 if (crtc->fb == NULL) {
132 return;
133 }
134
135 if (crtc->fb->depth == 16) {
136 for (i = 0; i < 64; i++) {
137 if (i <= 31) {
138 for (j = 0; j < 8; j++) {
139 radeon_crtc->lut_r[i * 8 + j] = red[i] >> 6;
140 radeon_crtc->lut_b[i * 8 + j] = blue[i] >> 6;
141 }
142 }
143 for (j = 0; j < 4; j++)
144 radeon_crtc->lut_g[i * 4 + j] = green[i] >> 6;
145 }
146 } else {
147 for (i = 0; i < 256; i++) {
148 radeon_crtc->lut_r[i] = red[i] >> 6;
149 radeon_crtc->lut_g[i] = green[i] >> 6;
150 radeon_crtc->lut_b[i] = blue[i] >> 6;
151 }
152 }
153
154 radeon_crtc_load_lut(crtc);
155}
156
157static void radeon_crtc_destroy(struct drm_crtc *crtc)
158{
159 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
160
161 if (radeon_crtc->mode_set.mode) {
162 drm_mode_destroy(crtc->dev, radeon_crtc->mode_set.mode);
163 }
164 drm_crtc_cleanup(crtc);
165 kfree(radeon_crtc);
166}
167
168static const struct drm_crtc_funcs radeon_crtc_funcs = {
169 .cursor_set = radeon_crtc_cursor_set,
170 .cursor_move = radeon_crtc_cursor_move,
171 .gamma_set = radeon_crtc_gamma_set,
172 .set_config = drm_crtc_helper_set_config,
173 .destroy = radeon_crtc_destroy,
174};
175
176static void radeon_crtc_init(struct drm_device *dev, int index)
177{
178 struct radeon_device *rdev = dev->dev_private;
179 struct radeon_crtc *radeon_crtc;
180 int i;
181
182 radeon_crtc = kzalloc(sizeof(struct radeon_crtc) + (RADEONFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL);
183 if (radeon_crtc == NULL)
184 return;
185
186 drm_crtc_init(dev, &radeon_crtc->base, &radeon_crtc_funcs);
187
188 drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256);
189 radeon_crtc->crtc_id = index;
190
191 radeon_crtc->mode_set.crtc = &radeon_crtc->base;
192 radeon_crtc->mode_set.connectors = (struct drm_connector **)(radeon_crtc + 1);
193 radeon_crtc->mode_set.num_connectors = 0;
194
195 for (i = 0; i < 256; i++) {
196 radeon_crtc->lut_r[i] = i << 2;
197 radeon_crtc->lut_g[i] = i << 2;
198 radeon_crtc->lut_b[i] = i << 2;
199 }
200
201 if (rdev->is_atom_bios && (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom))
202 radeon_atombios_init_crtc(dev, radeon_crtc);
203 else
204 radeon_legacy_init_crtc(dev, radeon_crtc);
205}
206
207static const char *encoder_names[34] = {
208 "NONE",
209 "INTERNAL_LVDS",
210 "INTERNAL_TMDS1",
211 "INTERNAL_TMDS2",
212 "INTERNAL_DAC1",
213 "INTERNAL_DAC2",
214 "INTERNAL_SDVOA",
215 "INTERNAL_SDVOB",
216 "SI170B",
217 "CH7303",
218 "CH7301",
219 "INTERNAL_DVO1",
220 "EXTERNAL_SDVOA",
221 "EXTERNAL_SDVOB",
222 "TITFP513",
223 "INTERNAL_LVTM1",
224 "VT1623",
225 "HDMI_SI1930",
226 "HDMI_INTERNAL",
227 "INTERNAL_KLDSCP_TMDS1",
228 "INTERNAL_KLDSCP_DVO1",
229 "INTERNAL_KLDSCP_DAC1",
230 "INTERNAL_KLDSCP_DAC2",
231 "SI178",
232 "MVPU_FPGA",
233 "INTERNAL_DDI",
234 "VT1625",
235 "HDMI_SI1932",
236 "DP_AN9801",
237 "DP_DP501",
238 "INTERNAL_UNIPHY",
239 "INTERNAL_KLDSCP_LVTMA",
240 "INTERNAL_UNIPHY1",
241 "INTERNAL_UNIPHY2",
242};
243
244static const char *connector_names[13] = {
245 "Unknown",
246 "VGA",
247 "DVI-I",
248 "DVI-D",
249 "DVI-A",
250 "Composite",
251 "S-video",
252 "LVDS",
253 "Component",
254 "DIN",
255 "DisplayPort",
256 "HDMI-A",
257 "HDMI-B",
258};
259
260static void radeon_print_display_setup(struct drm_device *dev)
261{
262 struct drm_connector *connector;
263 struct radeon_connector *radeon_connector;
264 struct drm_encoder *encoder;
265 struct radeon_encoder *radeon_encoder;
266 uint32_t devices;
267 int i = 0;
268
269 DRM_INFO("Radeon Display Connectors\n");
270 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
271 radeon_connector = to_radeon_connector(connector);
272 DRM_INFO("Connector %d:\n", i);
273 DRM_INFO(" %s\n", connector_names[connector->connector_type]);
274 if (radeon_connector->ddc_bus)
275 DRM_INFO(" DDC: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
276 radeon_connector->ddc_bus->rec.mask_clk_reg,
277 radeon_connector->ddc_bus->rec.mask_data_reg,
278 radeon_connector->ddc_bus->rec.a_clk_reg,
279 radeon_connector->ddc_bus->rec.a_data_reg,
280 radeon_connector->ddc_bus->rec.put_clk_reg,
281 radeon_connector->ddc_bus->rec.put_data_reg,
282 radeon_connector->ddc_bus->rec.get_clk_reg,
283 radeon_connector->ddc_bus->rec.get_data_reg);
284 DRM_INFO(" Encoders:\n");
285 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
286 radeon_encoder = to_radeon_encoder(encoder);
287 devices = radeon_encoder->devices & radeon_connector->devices;
288 if (devices) {
289 if (devices & ATOM_DEVICE_CRT1_SUPPORT)
290 DRM_INFO(" CRT1: %s\n", encoder_names[radeon_encoder->encoder_id]);
291 if (devices & ATOM_DEVICE_CRT2_SUPPORT)
292 DRM_INFO(" CRT2: %s\n", encoder_names[radeon_encoder->encoder_id]);
293 if (devices & ATOM_DEVICE_LCD1_SUPPORT)
294 DRM_INFO(" LCD1: %s\n", encoder_names[radeon_encoder->encoder_id]);
295 if (devices & ATOM_DEVICE_DFP1_SUPPORT)
296 DRM_INFO(" DFP1: %s\n", encoder_names[radeon_encoder->encoder_id]);
297 if (devices & ATOM_DEVICE_DFP2_SUPPORT)
298 DRM_INFO(" DFP2: %s\n", encoder_names[radeon_encoder->encoder_id]);
299 if (devices & ATOM_DEVICE_DFP3_SUPPORT)
300 DRM_INFO(" DFP3: %s\n", encoder_names[radeon_encoder->encoder_id]);
301 if (devices & ATOM_DEVICE_DFP4_SUPPORT)
302 DRM_INFO(" DFP4: %s\n", encoder_names[radeon_encoder->encoder_id]);
303 if (devices & ATOM_DEVICE_DFP5_SUPPORT)
304 DRM_INFO(" DFP5: %s\n", encoder_names[radeon_encoder->encoder_id]);
305 if (devices & ATOM_DEVICE_TV1_SUPPORT)
306 DRM_INFO(" TV1: %s\n", encoder_names[radeon_encoder->encoder_id]);
307 if (devices & ATOM_DEVICE_CV_SUPPORT)
308 DRM_INFO(" CV: %s\n", encoder_names[radeon_encoder->encoder_id]);
309 }
310 }
311 i++;
312 }
313}
314
315bool radeon_setup_enc_conn(struct drm_device *dev)
316{
317 struct radeon_device *rdev = dev->dev_private;
318 struct drm_connector *drm_connector;
319 bool ret = false;
320
321 if (rdev->bios) {
322 if (rdev->is_atom_bios) {
323 if (rdev->family >= CHIP_R600)
324 ret = radeon_get_atom_connector_info_from_object_table(dev);
325 else
326 ret = radeon_get_atom_connector_info_from_supported_devices_table(dev);
327 } else
328 ret = radeon_get_legacy_connector_info_from_bios(dev);
329 } else {
330 if (!ASIC_IS_AVIVO(rdev))
331 ret = radeon_get_legacy_connector_info_from_table(dev);
332 }
333 if (ret) {
334 radeon_print_display_setup(dev);
335 list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head)
336 radeon_ddc_dump(drm_connector);
337 }
338
339 return ret;
340}
341
342int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
343{
344 struct edid *edid;
345 int ret = 0;
346
347 if (!radeon_connector->ddc_bus)
348 return -1;
349 radeon_i2c_do_lock(radeon_connector, 1);
350 edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
351 radeon_i2c_do_lock(radeon_connector, 0);
352 if (edid) {
353 /* update digital bits here */
354 if (edid->digital)
355 radeon_connector->use_digital = 1;
356 else
357 radeon_connector->use_digital = 0;
358 drm_mode_connector_update_edid_property(&radeon_connector->base, edid);
359 ret = drm_add_edid_modes(&radeon_connector->base, edid);
360 kfree(edid);
361 return ret;
362 }
363 drm_mode_connector_update_edid_property(&radeon_connector->base, NULL);
364 return -1;
365}
366
367static int radeon_ddc_dump(struct drm_connector *connector)
368{
369 struct edid *edid;
370 struct radeon_connector *radeon_connector = to_radeon_connector(connector);
371 int ret = 0;
372
373 if (!radeon_connector->ddc_bus)
374 return -1;
375 radeon_i2c_do_lock(radeon_connector, 1);
376 edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter);
377 radeon_i2c_do_lock(radeon_connector, 0);
378 if (edid) {
379 kfree(edid);
380 }
381 return ret;
382}
383
384static inline uint32_t radeon_div(uint64_t n, uint32_t d)
385{
386 uint64_t mod;
387
388 n += d / 2;
389
390 mod = do_div(n, d);
391 return n;
392}
393
394void radeon_compute_pll(struct radeon_pll *pll,
395 uint64_t freq,
396 uint32_t *dot_clock_p,
397 uint32_t *fb_div_p,
398 uint32_t *frac_fb_div_p,
399 uint32_t *ref_div_p,
400 uint32_t *post_div_p,
401 int flags)
402{
403 uint32_t min_ref_div = pll->min_ref_div;
404 uint32_t max_ref_div = pll->max_ref_div;
405 uint32_t min_fractional_feed_div = 0;
406 uint32_t max_fractional_feed_div = 0;
407 uint32_t best_vco = pll->best_vco;
408 uint32_t best_post_div = 1;
409 uint32_t best_ref_div = 1;
410 uint32_t best_feedback_div = 1;
411 uint32_t best_frac_feedback_div = 0;
412 uint32_t best_freq = -1;
413 uint32_t best_error = 0xffffffff;
414 uint32_t best_vco_diff = 1;
415 uint32_t post_div;
416
417 DRM_DEBUG("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div);
418 freq = freq * 1000;
419
420 if (flags & RADEON_PLL_USE_REF_DIV)
421 min_ref_div = max_ref_div = pll->reference_div;
422 else {
423 while (min_ref_div < max_ref_div-1) {
424 uint32_t mid = (min_ref_div + max_ref_div) / 2;
425 uint32_t pll_in = pll->reference_freq / mid;
426 if (pll_in < pll->pll_in_min)
427 max_ref_div = mid;
428 else if (pll_in > pll->pll_in_max)
429 min_ref_div = mid;
430 else
431 break;
432 }
433 }
434
435 if (flags & RADEON_PLL_USE_FRAC_FB_DIV) {
436 min_fractional_feed_div = pll->min_frac_feedback_div;
437 max_fractional_feed_div = pll->max_frac_feedback_div;
438 }
439
440 for (post_div = pll->min_post_div; post_div <= pll->max_post_div; ++post_div) {
441 uint32_t ref_div;
442
443 if ((flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
444 continue;
445
446 /* legacy radeons only have a few post_divs */
447 if (flags & RADEON_PLL_LEGACY) {
448 if ((post_div == 5) ||
449 (post_div == 7) ||
450 (post_div == 9) ||
451 (post_div == 10) ||
452 (post_div == 11) ||
453 (post_div == 13) ||
454 (post_div == 14) ||
455 (post_div == 15))
456 continue;
457 }
458
459 for (ref_div = min_ref_div; ref_div <= max_ref_div; ++ref_div) {
460 uint32_t feedback_div, current_freq = 0, error, vco_diff;
461 uint32_t pll_in = pll->reference_freq / ref_div;
462 uint32_t min_feed_div = pll->min_feedback_div;
463 uint32_t max_feed_div = pll->max_feedback_div + 1;
464
465 if (pll_in < pll->pll_in_min || pll_in > pll->pll_in_max)
466 continue;
467
468 while (min_feed_div < max_feed_div) {
469 uint32_t vco;
470 uint32_t min_frac_feed_div = min_fractional_feed_div;
471 uint32_t max_frac_feed_div = max_fractional_feed_div + 1;
472 uint32_t frac_feedback_div;
473 uint64_t tmp;
474
475 feedback_div = (min_feed_div + max_feed_div) / 2;
476
477 tmp = (uint64_t)pll->reference_freq * feedback_div;
478 vco = radeon_div(tmp, ref_div);
479
480 if (vco < pll->pll_out_min) {
481 min_feed_div = feedback_div + 1;
482 continue;
483 } else if (vco > pll->pll_out_max) {
484 max_feed_div = feedback_div;
485 continue;
486 }
487
488 while (min_frac_feed_div < max_frac_feed_div) {
489 frac_feedback_div = (min_frac_feed_div + max_frac_feed_div) / 2;
490 tmp = (uint64_t)pll->reference_freq * 10000 * feedback_div;
491 tmp += (uint64_t)pll->reference_freq * 1000 * frac_feedback_div;
492 current_freq = radeon_div(tmp, ref_div * post_div);
493
494 error = abs(current_freq - freq);
495 vco_diff = abs(vco - best_vco);
496
497 if ((best_vco == 0 && error < best_error) ||
498 (best_vco != 0 &&
499 (error < best_error - 100 ||
500 (abs(error - best_error) < 100 && vco_diff < best_vco_diff)))) {
501 best_post_div = post_div;
502 best_ref_div = ref_div;
503 best_feedback_div = feedback_div;
504 best_frac_feedback_div = frac_feedback_div;
505 best_freq = current_freq;
506 best_error = error;
507 best_vco_diff = vco_diff;
508 } else if (current_freq == freq) {
509 if (best_freq == -1) {
510 best_post_div = post_div;
511 best_ref_div = ref_div;
512 best_feedback_div = feedback_div;
513 best_frac_feedback_div = frac_feedback_div;
514 best_freq = current_freq;
515 best_error = error;
516 best_vco_diff = vco_diff;
517 } else if (((flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) ||
518 ((flags & RADEON_PLL_PREFER_HIGH_REF_DIV) && (ref_div > best_ref_div)) ||
519 ((flags & RADEON_PLL_PREFER_LOW_FB_DIV) && (feedback_div < best_feedback_div)) ||
520 ((flags & RADEON_PLL_PREFER_HIGH_FB_DIV) && (feedback_div > best_feedback_div)) ||
521 ((flags & RADEON_PLL_PREFER_LOW_POST_DIV) && (post_div < best_post_div)) ||
522 ((flags & RADEON_PLL_PREFER_HIGH_POST_DIV) && (post_div > best_post_div))) {
523 best_post_div = post_div;
524 best_ref_div = ref_div;
525 best_feedback_div = feedback_div;
526 best_frac_feedback_div = frac_feedback_div;
527 best_freq = current_freq;
528 best_error = error;
529 best_vco_diff = vco_diff;
530 }
531 }
532 if (current_freq < freq)
533 min_frac_feed_div = frac_feedback_div + 1;
534 else
535 max_frac_feed_div = frac_feedback_div;
536 }
537 if (current_freq < freq)
538 min_feed_div = feedback_div + 1;
539 else
540 max_feed_div = feedback_div;
541 }
542 }
543 }
544
545 *dot_clock_p = best_freq / 10000;
546 *fb_div_p = best_feedback_div;
547 *frac_fb_div_p = best_frac_feedback_div;
548 *ref_div_p = best_ref_div;
549 *post_div_p = best_post_div;
550}
551
552static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
553{
554 struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb);
555 struct drm_device *dev = fb->dev;
556
557 if (fb->fbdev)
558 radeonfb_remove(dev, fb);
559
560 if (radeon_fb->obj) {
561 radeon_gem_object_unpin(radeon_fb->obj);
562 mutex_lock(&dev->struct_mutex);
563 drm_gem_object_unreference(radeon_fb->obj);
564 mutex_unlock(&dev->struct_mutex);
565 }
566 drm_framebuffer_cleanup(fb);
567 kfree(radeon_fb);
568}
569
570static int radeon_user_framebuffer_create_handle(struct drm_framebuffer *fb,
571 struct drm_file *file_priv,
572 unsigned int *handle)
573{
574 struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb);
575
576 return drm_gem_handle_create(file_priv, radeon_fb->obj, handle);
577}
578
579static const struct drm_framebuffer_funcs radeon_fb_funcs = {
580 .destroy = radeon_user_framebuffer_destroy,
581 .create_handle = radeon_user_framebuffer_create_handle,
582};
583
584struct drm_framebuffer *
585radeon_framebuffer_create(struct drm_device *dev,
586 struct drm_mode_fb_cmd *mode_cmd,
587 struct drm_gem_object *obj)
588{
589 struct radeon_framebuffer *radeon_fb;
590
591 radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL);
592 if (radeon_fb == NULL) {
593 return NULL;
594 }
595 drm_framebuffer_init(dev, &radeon_fb->base, &radeon_fb_funcs);
596 drm_helper_mode_fill_fb_struct(&radeon_fb->base, mode_cmd);
597 radeon_fb->obj = obj;
598 return &radeon_fb->base;
599}
600
601static struct drm_framebuffer *
602radeon_user_framebuffer_create(struct drm_device *dev,
603 struct drm_file *file_priv,
604 struct drm_mode_fb_cmd *mode_cmd)
605{
606 struct drm_gem_object *obj;
607
608 obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
609
610 return radeon_framebuffer_create(dev, mode_cmd, obj);
611}
612
613static const struct drm_mode_config_funcs radeon_mode_funcs = {
614 .fb_create = radeon_user_framebuffer_create,
615 .fb_changed = radeonfb_probe,
616};
617
618int radeon_modeset_init(struct radeon_device *rdev)
619{
620 int num_crtc = 2, i;
621 int ret;
622
623 drm_mode_config_init(rdev->ddev);
624 rdev->mode_info.mode_config_initialized = true;
625
626 rdev->ddev->mode_config.funcs = (void *)&radeon_mode_funcs;
627
628 if (ASIC_IS_AVIVO(rdev)) {
629 rdev->ddev->mode_config.max_width = 8192;
630 rdev->ddev->mode_config.max_height = 8192;
631 } else {
632 rdev->ddev->mode_config.max_width = 4096;
633 rdev->ddev->mode_config.max_height = 4096;
634 }
635
636 rdev->ddev->mode_config.fb_base = rdev->mc.aper_base;
637
638 /* allocate crtcs - TODO single crtc */
639 for (i = 0; i < num_crtc; i++) {
640 radeon_crtc_init(rdev->ddev, i);
641 }
642
643 /* okay we should have all the bios connectors */
644 ret = radeon_setup_enc_conn(rdev->ddev);
645 if (!ret) {
646 return ret;
647 }
648 drm_helper_initial_config(rdev->ddev);
649 return 0;
650}
651
652void radeon_modeset_fini(struct radeon_device *rdev)
653{
654 if (rdev->mode_info.mode_config_initialized) {
655 drm_mode_config_cleanup(rdev->ddev);
656 rdev->mode_info.mode_config_initialized = false;
657 }
658}
659
660void radeon_init_disp_bandwidth(struct drm_device *dev)
661{
662 struct radeon_device *rdev = dev->dev_private;
663 struct drm_display_mode *modes[2];
664 int pixel_bytes[2];
665 struct drm_crtc *crtc;
666
667 pixel_bytes[0] = pixel_bytes[1] = 0;
668 modes[0] = modes[1] = NULL;
669
670 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
671 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
672
673 if (crtc->enabled && crtc->fb) {
674 modes[radeon_crtc->crtc_id] = &crtc->mode;
675 pixel_bytes[radeon_crtc->crtc_id] = crtc->fb->bits_per_pixel / 8;
676 }
677 }
678
679 if (ASIC_IS_AVIVO(rdev)) {
680 radeon_init_disp_bw_avivo(dev,
681 modes[0],
682 pixel_bytes[0],
683 modes[1],
684 pixel_bytes[1]);
685 } else {
686 radeon_init_disp_bw_legacy(dev,
687 modes[0],
688 pixel_bytes[0],
689 modes[1],
690 pixel_bytes[1]);
691 }
692}