aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/atombios_crtc.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/atombios_crtc.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/atombios_crtc.c')
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c695
1 files changed, 695 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
new file mode 100644
index 000000000000..c0080cc9bf8d
--- /dev/null
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -0,0 +1,695 @@
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 <drm/drmP.h>
27#include <drm/drm_crtc_helper.h>
28#include <drm/radeon_drm.h>
29#include "radeon_fixed.h"
30#include "radeon.h"
31#include "atom.h"
32#include "atom-bits.h"
33
34static void atombios_lock_crtc(struct drm_crtc *crtc, int lock)
35{
36 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
37 struct drm_device *dev = crtc->dev;
38 struct radeon_device *rdev = dev->dev_private;
39 int index =
40 GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters);
41 ENABLE_CRTC_PS_ALLOCATION args;
42
43 memset(&args, 0, sizeof(args));
44
45 args.ucCRTC = radeon_crtc->crtc_id;
46 args.ucEnable = lock;
47
48 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
49}
50
51static void atombios_enable_crtc(struct drm_crtc *crtc, int state)
52{
53 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
54 struct drm_device *dev = crtc->dev;
55 struct radeon_device *rdev = dev->dev_private;
56 int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC);
57 ENABLE_CRTC_PS_ALLOCATION args;
58
59 memset(&args, 0, sizeof(args));
60
61 args.ucCRTC = radeon_crtc->crtc_id;
62 args.ucEnable = state;
63
64 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
65}
66
67static void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state)
68{
69 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
70 struct drm_device *dev = crtc->dev;
71 struct radeon_device *rdev = dev->dev_private;
72 int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq);
73 ENABLE_CRTC_PS_ALLOCATION args;
74
75 memset(&args, 0, sizeof(args));
76
77 args.ucCRTC = radeon_crtc->crtc_id;
78 args.ucEnable = state;
79
80 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
81}
82
83static void atombios_blank_crtc(struct drm_crtc *crtc, int state)
84{
85 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
86 struct drm_device *dev = crtc->dev;
87 struct radeon_device *rdev = dev->dev_private;
88 int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC);
89 BLANK_CRTC_PS_ALLOCATION args;
90
91 memset(&args, 0, sizeof(args));
92
93 args.ucCRTC = radeon_crtc->crtc_id;
94 args.ucBlanking = state;
95
96 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
97}
98
99void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
100{
101 struct drm_device *dev = crtc->dev;
102 struct radeon_device *rdev = dev->dev_private;
103
104 switch (mode) {
105 case DRM_MODE_DPMS_ON:
106 if (ASIC_IS_DCE3(rdev))
107 atombios_enable_crtc_memreq(crtc, 1);
108 atombios_enable_crtc(crtc, 1);
109 atombios_blank_crtc(crtc, 0);
110 break;
111 case DRM_MODE_DPMS_STANDBY:
112 case DRM_MODE_DPMS_SUSPEND:
113 case DRM_MODE_DPMS_OFF:
114 atombios_blank_crtc(crtc, 1);
115 atombios_enable_crtc(crtc, 0);
116 if (ASIC_IS_DCE3(rdev))
117 atombios_enable_crtc_memreq(crtc, 0);
118 break;
119 }
120
121 if (mode != DRM_MODE_DPMS_OFF) {
122 radeon_crtc_load_lut(crtc);
123 }
124}
125
126static void
127atombios_set_crtc_dtd_timing(struct drm_crtc *crtc,
128 SET_CRTC_USING_DTD_TIMING_PARAMETERS * crtc_param)
129{
130 struct drm_device *dev = crtc->dev;
131 struct radeon_device *rdev = dev->dev_private;
132 SET_CRTC_USING_DTD_TIMING_PARAMETERS conv_param;
133 int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming);
134
135 conv_param.usH_Size = cpu_to_le16(crtc_param->usH_Size);
136 conv_param.usH_Blanking_Time =
137 cpu_to_le16(crtc_param->usH_Blanking_Time);
138 conv_param.usV_Size = cpu_to_le16(crtc_param->usV_Size);
139 conv_param.usV_Blanking_Time =
140 cpu_to_le16(crtc_param->usV_Blanking_Time);
141 conv_param.usH_SyncOffset = cpu_to_le16(crtc_param->usH_SyncOffset);
142 conv_param.usH_SyncWidth = cpu_to_le16(crtc_param->usH_SyncWidth);
143 conv_param.usV_SyncOffset = cpu_to_le16(crtc_param->usV_SyncOffset);
144 conv_param.usV_SyncWidth = cpu_to_le16(crtc_param->usV_SyncWidth);
145 conv_param.susModeMiscInfo.usAccess =
146 cpu_to_le16(crtc_param->susModeMiscInfo.usAccess);
147 conv_param.ucCRTC = crtc_param->ucCRTC;
148
149 printk("executing set crtc dtd timing\n");
150 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&conv_param);
151}
152
153void atombios_crtc_set_timing(struct drm_crtc *crtc,
154 SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION *
155 crtc_param)
156{
157 struct drm_device *dev = crtc->dev;
158 struct radeon_device *rdev = dev->dev_private;
159 SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION conv_param;
160 int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing);
161
162 conv_param.usH_Total = cpu_to_le16(crtc_param->usH_Total);
163 conv_param.usH_Disp = cpu_to_le16(crtc_param->usH_Disp);
164 conv_param.usH_SyncStart = cpu_to_le16(crtc_param->usH_SyncStart);
165 conv_param.usH_SyncWidth = cpu_to_le16(crtc_param->usH_SyncWidth);
166 conv_param.usV_Total = cpu_to_le16(crtc_param->usV_Total);
167 conv_param.usV_Disp = cpu_to_le16(crtc_param->usV_Disp);
168 conv_param.usV_SyncStart = cpu_to_le16(crtc_param->usV_SyncStart);
169 conv_param.usV_SyncWidth = cpu_to_le16(crtc_param->usV_SyncWidth);
170 conv_param.susModeMiscInfo.usAccess =
171 cpu_to_le16(crtc_param->susModeMiscInfo.usAccess);
172 conv_param.ucCRTC = crtc_param->ucCRTC;
173 conv_param.ucOverscanRight = crtc_param->ucOverscanRight;
174 conv_param.ucOverscanLeft = crtc_param->ucOverscanLeft;
175 conv_param.ucOverscanBottom = crtc_param->ucOverscanBottom;
176 conv_param.ucOverscanTop = crtc_param->ucOverscanTop;
177 conv_param.ucReserved = crtc_param->ucReserved;
178
179 printk("executing set crtc timing\n");
180 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&conv_param);
181}
182
183void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
184{
185 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
186 struct drm_device *dev = crtc->dev;
187 struct radeon_device *rdev = dev->dev_private;
188 struct drm_encoder *encoder = NULL;
189 struct radeon_encoder *radeon_encoder = NULL;
190 uint8_t frev, crev;
191 int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
192 SET_PIXEL_CLOCK_PS_ALLOCATION args;
193 PIXEL_CLOCK_PARAMETERS *spc1_ptr;
194 PIXEL_CLOCK_PARAMETERS_V2 *spc2_ptr;
195 PIXEL_CLOCK_PARAMETERS_V3 *spc3_ptr;
196 uint32_t sclock = mode->clock;
197 uint32_t ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
198 struct radeon_pll *pll;
199 int pll_flags = 0;
200
201 memset(&args, 0, sizeof(args));
202
203 if (ASIC_IS_AVIVO(rdev)) {
204 uint32_t ss_cntl;
205
206 if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */
207 pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
208 else
209 pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
210
211 /* disable spread spectrum clocking for now -- thanks Hedy Lamarr */
212 if (radeon_crtc->crtc_id == 0) {
213 ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL);
214 WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl & ~1);
215 } else {
216 ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL);
217 WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl & ~1);
218 }
219 } else {
220 pll_flags |= RADEON_PLL_LEGACY;
221
222 if (mode->clock > 200000) /* range limits??? */
223 pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
224 else
225 pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
226
227 }
228
229 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
230 if (encoder->crtc == crtc) {
231 if (!ASIC_IS_AVIVO(rdev)) {
232 if (encoder->encoder_type !=
233 DRM_MODE_ENCODER_DAC)
234 pll_flags |= RADEON_PLL_NO_ODD_POST_DIV;
235 if (!ASIC_IS_AVIVO(rdev)
236 && (encoder->encoder_type ==
237 DRM_MODE_ENCODER_LVDS))
238 pll_flags |= RADEON_PLL_USE_REF_DIV;
239 }
240 radeon_encoder = to_radeon_encoder(encoder);
241 }
242 }
243
244 if (radeon_crtc->crtc_id == 0)
245 pll = &rdev->clock.p1pll;
246 else
247 pll = &rdev->clock.p2pll;
248
249 radeon_compute_pll(pll, mode->clock, &sclock, &fb_div, &frac_fb_div,
250 &ref_div, &post_div, pll_flags);
251
252 atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
253 &crev);
254
255 switch (frev) {
256 case 1:
257 switch (crev) {
258 case 1:
259 spc1_ptr = (PIXEL_CLOCK_PARAMETERS *) & args.sPCLKInput;
260 spc1_ptr->usPixelClock = cpu_to_le16(sclock);
261 spc1_ptr->usRefDiv = cpu_to_le16(ref_div);
262 spc1_ptr->usFbDiv = cpu_to_le16(fb_div);
263 spc1_ptr->ucFracFbDiv = frac_fb_div;
264 spc1_ptr->ucPostDiv = post_div;
265 spc1_ptr->ucPpll =
266 radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
267 spc1_ptr->ucCRTC = radeon_crtc->crtc_id;
268 spc1_ptr->ucRefDivSrc = 1;
269 break;
270 case 2:
271 spc2_ptr =
272 (PIXEL_CLOCK_PARAMETERS_V2 *) & args.sPCLKInput;
273 spc2_ptr->usPixelClock = cpu_to_le16(sclock);
274 spc2_ptr->usRefDiv = cpu_to_le16(ref_div);
275 spc2_ptr->usFbDiv = cpu_to_le16(fb_div);
276 spc2_ptr->ucFracFbDiv = frac_fb_div;
277 spc2_ptr->ucPostDiv = post_div;
278 spc2_ptr->ucPpll =
279 radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
280 spc2_ptr->ucCRTC = radeon_crtc->crtc_id;
281 spc2_ptr->ucRefDivSrc = 1;
282 break;
283 case 3:
284 if (!encoder)
285 return;
286 spc3_ptr =
287 (PIXEL_CLOCK_PARAMETERS_V3 *) & args.sPCLKInput;
288 spc3_ptr->usPixelClock = cpu_to_le16(sclock);
289 spc3_ptr->usRefDiv = cpu_to_le16(ref_div);
290 spc3_ptr->usFbDiv = cpu_to_le16(fb_div);
291 spc3_ptr->ucFracFbDiv = frac_fb_div;
292 spc3_ptr->ucPostDiv = post_div;
293 spc3_ptr->ucPpll =
294 radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
295 spc3_ptr->ucMiscInfo = (radeon_crtc->crtc_id << 2);
296 spc3_ptr->ucTransmitterId = radeon_encoder->encoder_id;
297 spc3_ptr->ucEncoderMode =
298 atombios_get_encoder_mode(encoder);
299 break;
300 default:
301 DRM_ERROR("Unknown table version %d %d\n", frev, crev);
302 return;
303 }
304 break;
305 default:
306 DRM_ERROR("Unknown table version %d %d\n", frev, crev);
307 return;
308 }
309
310 printk("executing set pll\n");
311 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
312}
313
314int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
315 struct drm_framebuffer *old_fb)
316{
317 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
318 struct drm_device *dev = crtc->dev;
319 struct radeon_device *rdev = dev->dev_private;
320 struct radeon_framebuffer *radeon_fb;
321 struct drm_gem_object *obj;
322 struct drm_radeon_gem_object *obj_priv;
323 uint64_t fb_location;
324 uint32_t fb_format, fb_pitch_pixels;
325
326 if (!crtc->fb)
327 return -EINVAL;
328
329 radeon_fb = to_radeon_framebuffer(crtc->fb);
330
331 obj = radeon_fb->obj;
332 obj_priv = obj->driver_private;
333
334 if (radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &fb_location)) {
335 return -EINVAL;
336 }
337
338 switch (crtc->fb->bits_per_pixel) {
339 case 15:
340 fb_format =
341 AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
342 AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555;
343 break;
344 case 16:
345 fb_format =
346 AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
347 AVIVO_D1GRPH_CONTROL_16BPP_RGB565;
348 break;
349 case 24:
350 case 32:
351 fb_format =
352 AVIVO_D1GRPH_CONTROL_DEPTH_32BPP |
353 AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888;
354 break;
355 default:
356 DRM_ERROR("Unsupported screen depth %d\n",
357 crtc->fb->bits_per_pixel);
358 return -EINVAL;
359 }
360
361 /* TODO tiling */
362 if (radeon_crtc->crtc_id == 0)
363 WREG32(AVIVO_D1VGA_CONTROL, 0);
364 else
365 WREG32(AVIVO_D2VGA_CONTROL, 0);
366 WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
367 (u32) fb_location);
368 WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS +
369 radeon_crtc->crtc_offset, (u32) fb_location);
370 WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
371
372 WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
373 WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
374 WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0);
375 WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0);
376 WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width);
377 WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height);
378
379 fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
380 WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
381 WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
382
383 WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
384 crtc->mode.vdisplay);
385 x &= ~3;
386 y &= ~1;
387 WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset,
388 (x << 16) | y);
389 WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
390 (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay);
391
392 if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
393 WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset,
394 AVIVO_D1MODE_INTERLEAVE_EN);
395 else
396 WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
397
398 if (old_fb && old_fb != crtc->fb) {
399 radeon_fb = to_radeon_framebuffer(old_fb);
400 radeon_gem_object_unpin(radeon_fb->obj);
401 }
402 return 0;
403}
404
405int atombios_crtc_mode_set(struct drm_crtc *crtc,
406 struct drm_display_mode *mode,
407 struct drm_display_mode *adjusted_mode,
408 int x, int y, struct drm_framebuffer *old_fb)
409{
410 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
411 struct drm_device *dev = crtc->dev;
412 struct radeon_device *rdev = dev->dev_private;
413 struct drm_encoder *encoder;
414 SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION crtc_timing;
415
416 /* TODO color tiling */
417 memset(&crtc_timing, 0, sizeof(crtc_timing));
418
419 /* TODO tv */
420 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
421
422 }
423
424 crtc_timing.ucCRTC = radeon_crtc->crtc_id;
425 crtc_timing.usH_Total = adjusted_mode->crtc_htotal;
426 crtc_timing.usH_Disp = adjusted_mode->crtc_hdisplay;
427 crtc_timing.usH_SyncStart = adjusted_mode->crtc_hsync_start;
428 crtc_timing.usH_SyncWidth =
429 adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
430
431 crtc_timing.usV_Total = adjusted_mode->crtc_vtotal;
432 crtc_timing.usV_Disp = adjusted_mode->crtc_vdisplay;
433 crtc_timing.usV_SyncStart = adjusted_mode->crtc_vsync_start;
434 crtc_timing.usV_SyncWidth =
435 adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
436
437 if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
438 crtc_timing.susModeMiscInfo.usAccess |= ATOM_VSYNC_POLARITY;
439
440 if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
441 crtc_timing.susModeMiscInfo.usAccess |= ATOM_HSYNC_POLARITY;
442
443 if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC)
444 crtc_timing.susModeMiscInfo.usAccess |= ATOM_COMPOSITESYNC;
445
446 if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
447 crtc_timing.susModeMiscInfo.usAccess |= ATOM_INTERLACE;
448
449 if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
450 crtc_timing.susModeMiscInfo.usAccess |= ATOM_DOUBLE_CLOCK_MODE;
451
452 atombios_crtc_set_pll(crtc, adjusted_mode);
453 atombios_crtc_set_timing(crtc, &crtc_timing);
454
455 if (ASIC_IS_AVIVO(rdev))
456 atombios_crtc_set_base(crtc, x, y, old_fb);
457 else {
458 if (radeon_crtc->crtc_id == 0) {
459 SET_CRTC_USING_DTD_TIMING_PARAMETERS crtc_dtd_timing;
460 memset(&crtc_dtd_timing, 0, sizeof(crtc_dtd_timing));
461
462 /* setup FP shadow regs on R4xx */
463 crtc_dtd_timing.ucCRTC = radeon_crtc->crtc_id;
464 crtc_dtd_timing.usH_Size = adjusted_mode->crtc_hdisplay;
465 crtc_dtd_timing.usV_Size = adjusted_mode->crtc_vdisplay;
466 crtc_dtd_timing.usH_Blanking_Time =
467 adjusted_mode->crtc_hblank_end -
468 adjusted_mode->crtc_hdisplay;
469 crtc_dtd_timing.usV_Blanking_Time =
470 adjusted_mode->crtc_vblank_end -
471 adjusted_mode->crtc_vdisplay;
472 crtc_dtd_timing.usH_SyncOffset =
473 adjusted_mode->crtc_hsync_start -
474 adjusted_mode->crtc_hdisplay;
475 crtc_dtd_timing.usV_SyncOffset =
476 adjusted_mode->crtc_vsync_start -
477 adjusted_mode->crtc_vdisplay;
478 crtc_dtd_timing.usH_SyncWidth =
479 adjusted_mode->crtc_hsync_end -
480 adjusted_mode->crtc_hsync_start;
481 crtc_dtd_timing.usV_SyncWidth =
482 adjusted_mode->crtc_vsync_end -
483 adjusted_mode->crtc_vsync_start;
484 /* crtc_dtd_timing.ucH_Border = adjusted_mode->crtc_hborder; */
485 /* crtc_dtd_timing.ucV_Border = adjusted_mode->crtc_vborder; */
486
487 if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
488 crtc_dtd_timing.susModeMiscInfo.usAccess |=
489 ATOM_VSYNC_POLARITY;
490
491 if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
492 crtc_dtd_timing.susModeMiscInfo.usAccess |=
493 ATOM_HSYNC_POLARITY;
494
495 if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC)
496 crtc_dtd_timing.susModeMiscInfo.usAccess |=
497 ATOM_COMPOSITESYNC;
498
499 if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
500 crtc_dtd_timing.susModeMiscInfo.usAccess |=
501 ATOM_INTERLACE;
502
503 if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
504 crtc_dtd_timing.susModeMiscInfo.usAccess |=
505 ATOM_DOUBLE_CLOCK_MODE;
506
507 atombios_set_crtc_dtd_timing(crtc, &crtc_dtd_timing);
508 }
509 radeon_crtc_set_base(crtc, x, y, old_fb);
510 radeon_legacy_atom_set_surface(crtc);
511 }
512 return 0;
513}
514
515static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
516 struct drm_display_mode *mode,
517 struct drm_display_mode *adjusted_mode)
518{
519 return true;
520}
521
522static void atombios_crtc_prepare(struct drm_crtc *crtc)
523{
524 atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
525 atombios_lock_crtc(crtc, 1);
526}
527
528static void atombios_crtc_commit(struct drm_crtc *crtc)
529{
530 atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
531 atombios_lock_crtc(crtc, 0);
532}
533
534static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
535 .dpms = atombios_crtc_dpms,
536 .mode_fixup = atombios_crtc_mode_fixup,
537 .mode_set = atombios_crtc_mode_set,
538 .mode_set_base = atombios_crtc_set_base,
539 .prepare = atombios_crtc_prepare,
540 .commit = atombios_crtc_commit,
541};
542
543void radeon_atombios_init_crtc(struct drm_device *dev,
544 struct radeon_crtc *radeon_crtc)
545{
546 if (radeon_crtc->crtc_id == 1)
547 radeon_crtc->crtc_offset =
548 AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL;
549 drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs);
550}
551
552void radeon_init_disp_bw_avivo(struct drm_device *dev,
553 struct drm_display_mode *mode1,
554 uint32_t pixel_bytes1,
555 struct drm_display_mode *mode2,
556 uint32_t pixel_bytes2)
557{
558 struct radeon_device *rdev = dev->dev_private;
559 fixed20_12 min_mem_eff;
560 fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff;
561 fixed20_12 sclk_ff, mclk_ff;
562 uint32_t dc_lb_memory_split, temp;
563
564 min_mem_eff.full = rfixed_const_8(0);
565 if (rdev->disp_priority == 2) {
566 uint32_t mc_init_misc_lat_timer = 0;
567 if (rdev->family == CHIP_RV515)
568 mc_init_misc_lat_timer =
569 RREG32_MC(RV515_MC_INIT_MISC_LAT_TIMER);
570 else if (rdev->family == CHIP_RS690)
571 mc_init_misc_lat_timer =
572 RREG32_MC(RS690_MC_INIT_MISC_LAT_TIMER);
573
574 mc_init_misc_lat_timer &=
575 ~(R300_MC_DISP1R_INIT_LAT_MASK <<
576 R300_MC_DISP1R_INIT_LAT_SHIFT);
577 mc_init_misc_lat_timer &=
578 ~(R300_MC_DISP0R_INIT_LAT_MASK <<
579 R300_MC_DISP0R_INIT_LAT_SHIFT);
580
581 if (mode2)
582 mc_init_misc_lat_timer |=
583 (1 << R300_MC_DISP1R_INIT_LAT_SHIFT);
584 if (mode1)
585 mc_init_misc_lat_timer |=
586 (1 << R300_MC_DISP0R_INIT_LAT_SHIFT);
587
588 if (rdev->family == CHIP_RV515)
589 WREG32_MC(RV515_MC_INIT_MISC_LAT_TIMER,
590 mc_init_misc_lat_timer);
591 else if (rdev->family == CHIP_RS690)
592 WREG32_MC(RS690_MC_INIT_MISC_LAT_TIMER,
593 mc_init_misc_lat_timer);
594 }
595
596 /*
597 * determine is there is enough bw for current mode
598 */
599 temp_ff.full = rfixed_const(100);
600 mclk_ff.full = rfixed_const(rdev->clock.default_mclk);
601 mclk_ff.full = rfixed_div(mclk_ff, temp_ff);
602 sclk_ff.full = rfixed_const(rdev->clock.default_sclk);
603 sclk_ff.full = rfixed_div(sclk_ff, temp_ff);
604
605 temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1);
606 temp_ff.full = rfixed_const(temp);
607 mem_bw.full = rfixed_mul(mclk_ff, temp_ff);
608 mem_bw.full = rfixed_mul(mem_bw, min_mem_eff);
609
610 pix_clk.full = 0;
611 pix_clk2.full = 0;
612 peak_disp_bw.full = 0;
613 if (mode1) {
614 temp_ff.full = rfixed_const(1000);
615 pix_clk.full = rfixed_const(mode1->clock); /* convert to fixed point */
616 pix_clk.full = rfixed_div(pix_clk, temp_ff);
617 temp_ff.full = rfixed_const(pixel_bytes1);
618 peak_disp_bw.full += rfixed_mul(pix_clk, temp_ff);
619 }
620 if (mode2) {
621 temp_ff.full = rfixed_const(1000);
622 pix_clk2.full = rfixed_const(mode2->clock); /* convert to fixed point */
623 pix_clk2.full = rfixed_div(pix_clk2, temp_ff);
624 temp_ff.full = rfixed_const(pixel_bytes2);
625 peak_disp_bw.full += rfixed_mul(pix_clk2, temp_ff);
626 }
627
628 if (peak_disp_bw.full >= mem_bw.full) {
629 DRM_ERROR
630 ("You may not have enough display bandwidth for current mode\n"
631 "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n");
632 printk("peak disp bw %d, mem_bw %d\n",
633 rfixed_trunc(peak_disp_bw), rfixed_trunc(mem_bw));
634 }
635
636 /*
637 * Line Buffer Setup
638 * There is a single line buffer shared by both display controllers.
639 * DC_LB_MEMORY_SPLIT controls how that line buffer is shared between the display
640 * controllers. The paritioning can either be done manually or via one of four
641 * preset allocations specified in bits 1:0:
642 * 0 - line buffer is divided in half and shared between each display controller
643 * 1 - D1 gets 3/4 of the line buffer, D2 gets 1/4
644 * 2 - D1 gets the whole buffer
645 * 3 - D1 gets 1/4 of the line buffer, D2 gets 3/4
646 * Setting bit 2 of DC_LB_MEMORY_SPLIT controls switches to manual allocation mode.
647 * In manual allocation mode, D1 always starts at 0, D1 end/2 is specified in bits
648 * 14:4; D2 allocation follows D1.
649 */
650
651 /* is auto or manual better ? */
652 dc_lb_memory_split =
653 RREG32(AVIVO_DC_LB_MEMORY_SPLIT) & ~AVIVO_DC_LB_MEMORY_SPLIT_MASK;
654 dc_lb_memory_split &= ~AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE;
655#if 1
656 /* auto */
657 if (mode1 && mode2) {
658 if (mode1->hdisplay > mode2->hdisplay) {
659 if (mode1->hdisplay > 2560)
660 dc_lb_memory_split |=
661 AVIVO_DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q;
662 else
663 dc_lb_memory_split |=
664 AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
665 } else if (mode2->hdisplay > mode1->hdisplay) {
666 if (mode2->hdisplay > 2560)
667 dc_lb_memory_split |=
668 AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q;
669 else
670 dc_lb_memory_split |=
671 AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
672 } else
673 dc_lb_memory_split |=
674 AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
675 } else if (mode1) {
676 dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_ONLY;
677 } else if (mode2) {
678 dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q;
679 }
680#else
681 /* manual */
682 dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE;
683 dc_lb_memory_split &=
684 ~(AVIVO_DC_LB_DISP1_END_ADR_MASK <<
685 AVIVO_DC_LB_DISP1_END_ADR_SHIFT);
686 if (mode1) {
687 dc_lb_memory_split |=
688 ((((mode1->hdisplay / 2) + 64) & AVIVO_DC_LB_DISP1_END_ADR_MASK)
689 << AVIVO_DC_LB_DISP1_END_ADR_SHIFT);
690 } else if (mode2) {
691 dc_lb_memory_split |= (0 << AVIVO_DC_LB_DISP1_END_ADR_SHIFT);
692 }
693#endif
694 WREG32(AVIVO_DC_LB_MEMORY_SPLIT, dc_lb_memory_split);
695}