]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/radeon/radeon_legacy_crtc.c
60c0dcb8e11ef9f9c6994d82f2ad6b7c1706af4e
[karo-tx-linux.git] / drivers / gpu / drm / radeon / radeon_legacy_crtc.c
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
33 static void radeon_overscan_setup(struct drm_crtc *crtc,
34                                   struct drm_display_mode *mode)
35 {
36         struct drm_device *dev = crtc->dev;
37         struct radeon_device *rdev = dev->dev_private;
38         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
39
40         WREG32(RADEON_OVR_CLR + radeon_crtc->crtc_offset, 0);
41         WREG32(RADEON_OVR_WID_LEFT_RIGHT + radeon_crtc->crtc_offset, 0);
42         WREG32(RADEON_OVR_WID_TOP_BOTTOM + radeon_crtc->crtc_offset, 0);
43 }
44
45 static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc,
46                                        struct drm_display_mode *mode)
47 {
48         struct drm_device *dev = crtc->dev;
49         struct radeon_device *rdev = dev->dev_private;
50         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
51         int xres = mode->hdisplay;
52         int yres = mode->vdisplay;
53         bool hscale = true, vscale = true;
54         int hsync_wid;
55         int vsync_wid;
56         int hsync_start;
57         int blank_width;
58         u32 scale, inc, crtc_more_cntl;
59         u32 fp_horz_stretch, fp_vert_stretch, fp_horz_vert_active;
60         u32 fp_h_sync_strt_wid, fp_crtc_h_total_disp;
61         u32 fp_v_sync_strt_wid, fp_crtc_v_total_disp;
62         struct drm_display_mode *native_mode = &radeon_crtc->native_mode;
63
64         fp_vert_stretch = RREG32(RADEON_FP_VERT_STRETCH) &
65                 (RADEON_VERT_STRETCH_RESERVED |
66                  RADEON_VERT_AUTO_RATIO_INC);
67         fp_horz_stretch = RREG32(RADEON_FP_HORZ_STRETCH) &
68                 (RADEON_HORZ_FP_LOOP_STRETCH |
69                  RADEON_HORZ_AUTO_RATIO_INC);
70
71         crtc_more_cntl = 0;
72         if ((rdev->family == CHIP_RS100) ||
73             (rdev->family == CHIP_RS200)) {
74                 /* This is to workaround the asic bug for RMX, some versions
75                    of BIOS dosen't have this register initialized correctly. */
76                 crtc_more_cntl |= RADEON_CRTC_H_CUTOFF_ACTIVE_EN;
77         }
78
79
80         fp_crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff)
81                                 | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
82
83         hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
84         if (!hsync_wid)
85                 hsync_wid = 1;
86         hsync_start = mode->crtc_hsync_start - 8;
87
88         fp_h_sync_strt_wid = ((hsync_start & 0x1fff)
89                               | ((hsync_wid & 0x3f) << 16)
90                               | ((mode->flags & DRM_MODE_FLAG_NHSYNC)
91                                  ? RADEON_CRTC_H_SYNC_POL
92                                  : 0));
93
94         fp_crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff)
95                                 | ((mode->crtc_vdisplay - 1) << 16));
96
97         vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
98         if (!vsync_wid)
99                 vsync_wid = 1;
100
101         fp_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff)
102                               | ((vsync_wid & 0x1f) << 16)
103                               | ((mode->flags & DRM_MODE_FLAG_NVSYNC)
104                                  ? RADEON_CRTC_V_SYNC_POL
105                                  : 0));
106
107         fp_horz_vert_active = 0;
108
109         if (native_mode->hdisplay == 0 ||
110             native_mode->vdisplay == 0) {
111                 hscale = false;
112                 vscale = false;
113         } else {
114                 if (xres > native_mode->hdisplay)
115                         xres = native_mode->hdisplay;
116                 if (yres > native_mode->vdisplay)
117                         yres = native_mode->vdisplay;
118
119                 if (xres == native_mode->hdisplay)
120                         hscale = false;
121                 if (yres == native_mode->vdisplay)
122                         vscale = false;
123         }
124
125         switch (radeon_crtc->rmx_type) {
126         case RMX_FULL:
127         case RMX_ASPECT:
128                 if (!hscale)
129                         fp_horz_stretch |= ((xres/8-1) << 16);
130                 else {
131                         inc = (fp_horz_stretch & RADEON_HORZ_AUTO_RATIO_INC) ? 1 : 0;
132                         scale = ((xres + inc) * RADEON_HORZ_STRETCH_RATIO_MAX)
133                                 / native_mode->hdisplay + 1;
134                         fp_horz_stretch |= (((scale) & RADEON_HORZ_STRETCH_RATIO_MASK) |
135                                         RADEON_HORZ_STRETCH_BLEND |
136                                         RADEON_HORZ_STRETCH_ENABLE |
137                                         ((native_mode->hdisplay/8-1) << 16));
138                 }
139
140                 if (!vscale)
141                         fp_vert_stretch |= ((yres-1) << 12);
142                 else {
143                         inc = (fp_vert_stretch & RADEON_VERT_AUTO_RATIO_INC) ? 1 : 0;
144                         scale = ((yres + inc) * RADEON_VERT_STRETCH_RATIO_MAX)
145                                 / native_mode->vdisplay + 1;
146                         fp_vert_stretch |= (((scale) & RADEON_VERT_STRETCH_RATIO_MASK) |
147                                         RADEON_VERT_STRETCH_ENABLE |
148                                         RADEON_VERT_STRETCH_BLEND |
149                                         ((native_mode->vdisplay-1) << 12));
150                 }
151                 break;
152         case RMX_CENTER:
153                 fp_horz_stretch |= ((xres/8-1) << 16);
154                 fp_vert_stretch |= ((yres-1) << 12);
155
156                 crtc_more_cntl |= (RADEON_CRTC_AUTO_HORZ_CENTER_EN |
157                                 RADEON_CRTC_AUTO_VERT_CENTER_EN);
158
159                 blank_width = (mode->crtc_hblank_end - mode->crtc_hblank_start) / 8;
160                 if (blank_width > 110)
161                         blank_width = 110;
162
163                 fp_crtc_h_total_disp = (((blank_width) & 0x3ff)
164                                 | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
165
166                 hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
167                 if (!hsync_wid)
168                         hsync_wid = 1;
169
170                 fp_h_sync_strt_wid = ((((mode->crtc_hsync_start - mode->crtc_hblank_start) / 8) & 0x1fff)
171                                 | ((hsync_wid & 0x3f) << 16)
172                                 | ((mode->flags & DRM_MODE_FLAG_NHSYNC)
173                                         ? RADEON_CRTC_H_SYNC_POL
174                                         : 0));
175
176                 fp_crtc_v_total_disp = (((mode->crtc_vblank_end - mode->crtc_vblank_start) & 0xffff)
177                                 | ((mode->crtc_vdisplay - 1) << 16));
178
179                 vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
180                 if (!vsync_wid)
181                         vsync_wid = 1;
182
183                 fp_v_sync_strt_wid = ((((mode->crtc_vsync_start - mode->crtc_vblank_start) & 0xfff)
184                                         | ((vsync_wid & 0x1f) << 16)
185                                         | ((mode->flags & DRM_MODE_FLAG_NVSYNC)
186                                                 ? RADEON_CRTC_V_SYNC_POL
187                                                 : 0)));
188
189                 fp_horz_vert_active = (((native_mode->vdisplay) & 0xfff) |
190                                 (((native_mode->hdisplay / 8) & 0x1ff) << 16));
191                 break;
192         case RMX_OFF:
193         default:
194                 fp_horz_stretch |= ((xres/8-1) << 16);
195                 fp_vert_stretch |= ((yres-1) << 12);
196                 break;
197         }
198
199         WREG32(RADEON_FP_HORZ_STRETCH,      fp_horz_stretch);
200         WREG32(RADEON_FP_VERT_STRETCH,      fp_vert_stretch);
201         WREG32(RADEON_CRTC_MORE_CNTL,       crtc_more_cntl);
202         WREG32(RADEON_FP_HORZ_VERT_ACTIVE,  fp_horz_vert_active);
203         WREG32(RADEON_FP_H_SYNC_STRT_WID,   fp_h_sync_strt_wid);
204         WREG32(RADEON_FP_V_SYNC_STRT_WID,   fp_v_sync_strt_wid);
205         WREG32(RADEON_FP_CRTC_H_TOTAL_DISP, fp_crtc_h_total_disp);
206         WREG32(RADEON_FP_CRTC_V_TOTAL_DISP, fp_crtc_v_total_disp);
207 }
208
209 void radeon_restore_common_regs(struct drm_device *dev)
210 {
211         /* don't need this yet */
212 }
213
214 static void radeon_pll_wait_for_read_update_complete(struct drm_device *dev)
215 {
216         struct radeon_device *rdev = dev->dev_private;
217         int i = 0;
218
219         /* FIXME: Certain revisions of R300 can't recover here.  Not sure of
220            the cause yet, but this workaround will mask the problem for now.
221            Other chips usually will pass at the very first test, so the
222            workaround shouldn't have any effect on them. */
223         for (i = 0;
224              (i < 10000 &&
225               RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R);
226              i++);
227 }
228
229 static void radeon_pll_write_update(struct drm_device *dev)
230 {
231         struct radeon_device *rdev = dev->dev_private;
232
233         while (RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R);
234
235         WREG32_PLL_P(RADEON_PPLL_REF_DIV,
236                            RADEON_PPLL_ATOMIC_UPDATE_W,
237                            ~(RADEON_PPLL_ATOMIC_UPDATE_W));
238 }
239
240 static void radeon_pll2_wait_for_read_update_complete(struct drm_device *dev)
241 {
242         struct radeon_device *rdev = dev->dev_private;
243         int i = 0;
244
245
246         /* FIXME: Certain revisions of R300 can't recover here.  Not sure of
247            the cause yet, but this workaround will mask the problem for now.
248            Other chips usually will pass at the very first test, so the
249            workaround shouldn't have any effect on them. */
250         for (i = 0;
251              (i < 10000 &&
252               RREG32_PLL(RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R);
253              i++);
254 }
255
256 static void radeon_pll2_write_update(struct drm_device *dev)
257 {
258         struct radeon_device *rdev = dev->dev_private;
259
260         while (RREG32_PLL(RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R);
261
262         WREG32_PLL_P(RADEON_P2PLL_REF_DIV,
263                            RADEON_P2PLL_ATOMIC_UPDATE_W,
264                            ~(RADEON_P2PLL_ATOMIC_UPDATE_W));
265 }
266
267 static uint8_t radeon_compute_pll_gain(uint16_t ref_freq, uint16_t ref_div,
268                                        uint16_t fb_div)
269 {
270         unsigned int vcoFreq;
271
272         if (!ref_div)
273                 return 1;
274
275         vcoFreq = ((unsigned)ref_freq & fb_div) / ref_div;
276
277         /*
278          * This is horribly crude: the VCO frequency range is divided into
279          * 3 parts, each part having a fixed PLL gain value.
280          */
281         if (vcoFreq >= 30000)
282                 /*
283                  * [300..max] MHz : 7
284                  */
285                 return 7;
286         else if (vcoFreq >= 18000)
287                 /*
288                  * [180..300) MHz : 4
289                  */
290                 return 4;
291         else
292                 /*
293                  * [0..180) MHz : 1
294                  */
295                 return 1;
296 }
297
298 void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
299 {
300         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
301         struct drm_device *dev = crtc->dev;
302         struct radeon_device *rdev = dev->dev_private;
303         uint32_t mask;
304
305         if (radeon_crtc->crtc_id)
306                 mask = (RADEON_CRTC2_DISP_DIS |
307                         RADEON_CRTC2_VSYNC_DIS |
308                         RADEON_CRTC2_HSYNC_DIS |
309                         RADEON_CRTC2_DISP_REQ_EN_B);
310         else
311                 mask = (RADEON_CRTC_DISPLAY_DIS |
312                         RADEON_CRTC_VSYNC_DIS |
313                         RADEON_CRTC_HSYNC_DIS);
314
315         switch (mode) {
316         case DRM_MODE_DPMS_ON:
317                 if (radeon_crtc->crtc_id)
318                         WREG32_P(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_EN, ~(RADEON_CRTC2_EN | mask));
319                 else {
320                         WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_EN, ~(RADEON_CRTC_EN |
321                                                                          RADEON_CRTC_DISP_REQ_EN_B));
322                         WREG32_P(RADEON_CRTC_EXT_CNTL, 0, ~mask);
323                 }
324                 drm_vblank_post_modeset(dev, radeon_crtc->crtc_id);
325                 radeon_crtc_load_lut(crtc);
326                 break;
327         case DRM_MODE_DPMS_STANDBY:
328         case DRM_MODE_DPMS_SUSPEND:
329         case DRM_MODE_DPMS_OFF:
330                 drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id);
331                 if (radeon_crtc->crtc_id)
332                         WREG32_P(RADEON_CRTC2_GEN_CNTL, mask, ~(RADEON_CRTC2_EN | mask));
333                 else {
334                         WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~(RADEON_CRTC_EN |
335                                                                                     RADEON_CRTC_DISP_REQ_EN_B));
336                         WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~mask);
337                 }
338                 break;
339         }
340
341         /* adjust pm to dpms change */
342         radeon_pm_compute_clocks(rdev);
343 }
344
345 int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
346                          struct drm_framebuffer *old_fb)
347 {
348         struct drm_device *dev = crtc->dev;
349         struct radeon_device *rdev = dev->dev_private;
350         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
351         struct radeon_framebuffer *radeon_fb;
352         struct drm_gem_object *obj;
353         struct radeon_bo *rbo;
354         uint64_t base;
355         uint32_t crtc_offset, crtc_offset_cntl, crtc_tile_x0_y0 = 0;
356         uint32_t crtc_pitch, pitch_pixels;
357         uint32_t tiling_flags;
358         int format;
359         uint32_t gen_cntl_reg, gen_cntl_val;
360         int r;
361
362         DRM_DEBUG("\n");
363         /* no fb bound */
364         if (!crtc->fb) {
365                 DRM_DEBUG("No FB bound\n");
366                 return 0;
367         }
368
369         radeon_fb = to_radeon_framebuffer(crtc->fb);
370
371         switch (crtc->fb->bits_per_pixel) {
372         case 8:
373                 format = 2;
374                 break;
375         case 15:      /*  555 */
376                 format = 3;
377                 break;
378         case 16:      /*  565 */
379                 format = 4;
380                 break;
381         case 24:      /*  RGB */
382                 format = 5;
383                 break;
384         case 32:      /* xRGB */
385                 format = 6;
386                 break;
387         default:
388                 return false;
389         }
390
391         /* Pin framebuffer & get tilling informations */
392         obj = radeon_fb->obj;
393         rbo = obj->driver_private;
394         r = radeon_bo_reserve(rbo, false);
395         if (unlikely(r != 0))
396                 return r;
397         r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &base);
398         if (unlikely(r != 0)) {
399                 radeon_bo_unreserve(rbo);
400                 return -EINVAL;
401         }
402         radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
403         radeon_bo_unreserve(rbo);
404         if (tiling_flags & RADEON_TILING_MICRO)
405                 DRM_ERROR("trying to scanout microtiled buffer\n");
406
407         /* if scanout was in GTT this really wouldn't work */
408         /* crtc offset is from display base addr not FB location */
409         radeon_crtc->legacy_display_base_addr = rdev->mc.vram_start;
410
411         base -= radeon_crtc->legacy_display_base_addr;
412
413         crtc_offset_cntl = 0;
414
415         pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
416         crtc_pitch  = (((pitch_pixels * crtc->fb->bits_per_pixel) +
417                         ((crtc->fb->bits_per_pixel * 8) - 1)) /
418                        (crtc->fb->bits_per_pixel * 8));
419         crtc_pitch |= crtc_pitch << 16;
420
421
422         if (tiling_flags & RADEON_TILING_MACRO) {
423                 if (ASIC_IS_R300(rdev))
424                         crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN |
425                                              R300_CRTC_MICRO_TILE_BUFFER_DIS |
426                                              R300_CRTC_MACRO_TILE_EN);
427                 else
428                         crtc_offset_cntl |= RADEON_CRTC_TILE_EN;
429         } else {
430                 if (ASIC_IS_R300(rdev))
431                         crtc_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN |
432                                               R300_CRTC_MICRO_TILE_BUFFER_DIS |
433                                               R300_CRTC_MACRO_TILE_EN);
434                 else
435                         crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN;
436         }
437
438         if (tiling_flags & RADEON_TILING_MACRO) {
439                 if (ASIC_IS_R300(rdev)) {
440                         crtc_tile_x0_y0 = x | (y << 16);
441                         base &= ~0x7ff;
442                 } else {
443                         int byteshift = crtc->fb->bits_per_pixel >> 4;
444                         int tile_addr = (((y >> 3) * pitch_pixels +  x) >> (8 - byteshift)) << 11;
445                         base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8);
446                         crtc_offset_cntl |= (y % 16);
447                 }
448         } else {
449                 int offset = y * pitch_pixels + x;
450                 switch (crtc->fb->bits_per_pixel) {
451                 case 8:
452                         offset *= 1;
453                         break;
454                 case 15:
455                 case 16:
456                         offset *= 2;
457                         break;
458                 case 24:
459                         offset *= 3;
460                         break;
461                 case 32:
462                         offset *= 4;
463                         break;
464                 default:
465                         return false;
466                 }
467                 base += offset;
468         }
469
470         base &= ~7;
471
472         if (radeon_crtc->crtc_id == 1)
473                 gen_cntl_reg = RADEON_CRTC2_GEN_CNTL;
474         else
475                 gen_cntl_reg = RADEON_CRTC_GEN_CNTL;
476
477         gen_cntl_val = RREG32(gen_cntl_reg);
478         gen_cntl_val &= ~(0xf << 8);
479         gen_cntl_val |= (format << 8);
480         WREG32(gen_cntl_reg, gen_cntl_val);
481
482         crtc_offset = (u32)base;
483
484         WREG32(RADEON_DISPLAY_BASE_ADDR + radeon_crtc->crtc_offset, radeon_crtc->legacy_display_base_addr);
485
486         if (ASIC_IS_R300(rdev)) {
487                 if (radeon_crtc->crtc_id)
488                         WREG32(R300_CRTC2_TILE_X0_Y0, crtc_tile_x0_y0);
489                 else
490                         WREG32(R300_CRTC_TILE_X0_Y0, crtc_tile_x0_y0);
491         }
492         WREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset, crtc_offset_cntl);
493         WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset);
494         WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch);
495
496         if (old_fb && old_fb != crtc->fb) {
497                 radeon_fb = to_radeon_framebuffer(old_fb);
498                 rbo = radeon_fb->obj->driver_private;
499                 r = radeon_bo_reserve(rbo, false);
500                 if (unlikely(r != 0))
501                         return r;
502                 radeon_bo_unpin(rbo);
503                 radeon_bo_unreserve(rbo);
504         }
505
506         /* Bytes per pixel may have changed */
507         radeon_bandwidth_update(rdev);
508
509         return 0;
510 }
511
512 static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mode *mode)
513 {
514         struct drm_device *dev = crtc->dev;
515         struct radeon_device *rdev = dev->dev_private;
516         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
517         struct drm_encoder *encoder;
518         int format;
519         int hsync_start;
520         int hsync_wid;
521         int vsync_wid;
522         uint32_t crtc_h_total_disp;
523         uint32_t crtc_h_sync_strt_wid;
524         uint32_t crtc_v_total_disp;
525         uint32_t crtc_v_sync_strt_wid;
526         bool is_tv = false;
527
528         DRM_DEBUG("\n");
529         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
530                 if (encoder->crtc == crtc) {
531                         struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
532                         if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) {
533                                 is_tv = true;
534                                 DRM_INFO("crtc %d is connected to a TV\n", radeon_crtc->crtc_id);
535                                 break;
536                         }
537                 }
538         }
539
540         switch (crtc->fb->bits_per_pixel) {
541         case 8:
542                 format = 2;
543                 break;
544         case 15:      /*  555 */
545                 format = 3;
546                 break;
547         case 16:      /*  565 */
548                 format = 4;
549                 break;
550         case 24:      /*  RGB */
551                 format = 5;
552                 break;
553         case 32:      /* xRGB */
554                 format = 6;
555                 break;
556         default:
557                 return false;
558         }
559
560         crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff)
561                              | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
562
563         hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
564         if (!hsync_wid)
565                 hsync_wid = 1;
566         hsync_start = mode->crtc_hsync_start - 8;
567
568         crtc_h_sync_strt_wid = ((hsync_start & 0x1fff)
569                                 | ((hsync_wid & 0x3f) << 16)
570                                 | ((mode->flags & DRM_MODE_FLAG_NHSYNC)
571                                    ? RADEON_CRTC_H_SYNC_POL
572                                    : 0));
573
574         /* This works for double scan mode. */
575         crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff)
576                              | ((mode->crtc_vdisplay - 1) << 16));
577
578         vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
579         if (!vsync_wid)
580                 vsync_wid = 1;
581
582         crtc_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff)
583                                 | ((vsync_wid & 0x1f) << 16)
584                                 | ((mode->flags & DRM_MODE_FLAG_NVSYNC)
585                                    ? RADEON_CRTC_V_SYNC_POL
586                                    : 0));
587
588         if (radeon_crtc->crtc_id) {
589                 uint32_t crtc2_gen_cntl;
590                 uint32_t disp2_merge_cntl;
591
592                 /* if TV DAC is enabled for another crtc and keep it enabled */
593                 crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL) & 0x00718080;
594                 crtc2_gen_cntl |= ((format << 8)
595                                    | RADEON_CRTC2_VSYNC_DIS
596                                    | RADEON_CRTC2_HSYNC_DIS
597                                    | RADEON_CRTC2_DISP_DIS
598                                    | RADEON_CRTC2_DISP_REQ_EN_B
599                                    | ((mode->flags & DRM_MODE_FLAG_DBLSCAN)
600                                       ? RADEON_CRTC2_DBL_SCAN_EN
601                                       : 0)
602                                    | ((mode->flags & DRM_MODE_FLAG_CSYNC)
603                                       ? RADEON_CRTC2_CSYNC_EN
604                                       : 0)
605                                    | ((mode->flags & DRM_MODE_FLAG_INTERLACE)
606                                       ? RADEON_CRTC2_INTERLACE_EN
607                                       : 0));
608
609                 /* rs4xx chips seem to like to have the crtc enabled when the timing is set */
610                 if ((rdev->family == CHIP_RS400) || (rdev->family == CHIP_RS480))
611                         crtc2_gen_cntl |= RADEON_CRTC2_EN;
612
613                 disp2_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL);
614                 disp2_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN;
615
616                 WREG32(RADEON_DISP2_MERGE_CNTL, disp2_merge_cntl);
617                 WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
618
619                 WREG32(RADEON_FP_H2_SYNC_STRT_WID, crtc_h_sync_strt_wid);
620                 WREG32(RADEON_FP_V2_SYNC_STRT_WID, crtc_v_sync_strt_wid);
621         } else {
622                 uint32_t crtc_gen_cntl;
623                 uint32_t crtc_ext_cntl;
624                 uint32_t disp_merge_cntl;
625
626                 crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL) & 0x00718000;
627                 crtc_gen_cntl |= (RADEON_CRTC_EXT_DISP_EN
628                                  | (format << 8)
629                                  | RADEON_CRTC_DISP_REQ_EN_B
630                                  | ((mode->flags & DRM_MODE_FLAG_DBLSCAN)
631                                     ? RADEON_CRTC_DBL_SCAN_EN
632                                     : 0)
633                                  | ((mode->flags & DRM_MODE_FLAG_CSYNC)
634                                     ? RADEON_CRTC_CSYNC_EN
635                                     : 0)
636                                  | ((mode->flags & DRM_MODE_FLAG_INTERLACE)
637                                     ? RADEON_CRTC_INTERLACE_EN
638                                     : 0));
639
640                 /* rs4xx chips seem to like to have the crtc enabled when the timing is set */
641                 if ((rdev->family == CHIP_RS400) || (rdev->family == CHIP_RS480))
642                         crtc_gen_cntl |= RADEON_CRTC_EN;
643
644                 crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
645                 crtc_ext_cntl |= (RADEON_XCRT_CNT_EN |
646                                   RADEON_CRTC_VSYNC_DIS |
647                                   RADEON_CRTC_HSYNC_DIS |
648                                   RADEON_CRTC_DISPLAY_DIS);
649
650                 disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL);
651                 disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN;
652
653                 WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl);
654                 WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl);
655                 WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
656         }
657
658         if (is_tv)
659                 radeon_legacy_tv_adjust_crtc_reg(encoder, &crtc_h_total_disp,
660                                                  &crtc_h_sync_strt_wid, &crtc_v_total_disp,
661                                                  &crtc_v_sync_strt_wid);
662
663         WREG32(RADEON_CRTC_H_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_h_total_disp);
664         WREG32(RADEON_CRTC_H_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_h_sync_strt_wid);
665         WREG32(RADEON_CRTC_V_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_v_total_disp);
666         WREG32(RADEON_CRTC_V_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_v_sync_strt_wid);
667
668         return true;
669 }
670
671 static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
672 {
673         struct drm_device *dev = crtc->dev;
674         struct radeon_device *rdev = dev->dev_private;
675         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
676         struct drm_encoder *encoder;
677         uint32_t feedback_div = 0;
678         uint32_t frac_fb_div = 0;
679         uint32_t reference_div = 0;
680         uint32_t post_divider = 0;
681         uint32_t freq = 0;
682         uint8_t pll_gain;
683         bool use_bios_divs = false;
684         /* PLL registers */
685         uint32_t pll_ref_div = 0;
686         uint32_t pll_fb_post_div = 0;
687         uint32_t htotal_cntl = 0;
688         bool is_tv = false;
689         struct radeon_pll *pll;
690
691         struct {
692                 int divider;
693                 int bitvalue;
694         } *post_div, post_divs[]   = {
695                 /* From RAGE 128 VR/RAGE 128 GL Register
696                  * Reference Manual (Technical Reference
697                  * Manual P/N RRG-G04100-C Rev. 0.04), page
698                  * 3-17 (PLL_DIV_[3:0]).
699                  */
700                 {  1, 0 },              /* VCLK_SRC                 */
701                 {  2, 1 },              /* VCLK_SRC/2               */
702                 {  4, 2 },              /* VCLK_SRC/4               */
703                 {  8, 3 },              /* VCLK_SRC/8               */
704                 {  3, 4 },              /* VCLK_SRC/3               */
705                 { 16, 5 },              /* VCLK_SRC/16              */
706                 {  6, 6 },              /* VCLK_SRC/6               */
707                 { 12, 7 },              /* VCLK_SRC/12              */
708                 {  0, 0 }
709         };
710
711         if (radeon_crtc->crtc_id)
712                 pll = &rdev->clock.p2pll;
713         else
714                 pll = &rdev->clock.p1pll;
715
716         pll->flags = RADEON_PLL_LEGACY;
717         if (radeon_new_pll == 1)
718                 pll->algo = PLL_ALGO_NEW;
719         else
720                 pll->algo = PLL_ALGO_LEGACY;
721
722         if (mode->clock > 200000) /* range limits??? */
723                 pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
724         else
725                 pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
726
727         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
728                 if (encoder->crtc == crtc) {
729                         struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
730
731                         if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) {
732                                 is_tv = true;
733                                 break;
734                         }
735
736                         if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
737                                 pll->flags |= RADEON_PLL_NO_ODD_POST_DIV;
738                         if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) {
739                                 if (!rdev->is_atom_bios) {
740                                         struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
741                                         struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv;
742                                         if (lvds) {
743                                                 if (lvds->use_bios_dividers) {
744                                                         pll_ref_div = lvds->panel_ref_divider;
745                                                         pll_fb_post_div   = (lvds->panel_fb_divider |
746                                                                              (lvds->panel_post_divider << 16));
747                                                         htotal_cntl  = 0;
748                                                         use_bios_divs = true;
749                                                 }
750                                         }
751                                 }
752                                 pll->flags |= RADEON_PLL_USE_REF_DIV;
753                         }
754                 }
755         }
756
757         DRM_DEBUG("\n");
758
759         if (!use_bios_divs) {
760                 radeon_compute_pll(pll, mode->clock,
761                                    &freq, &feedback_div, &frac_fb_div,
762                                    &reference_div, &post_divider);
763
764                 for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
765                         if (post_div->divider == post_divider)
766                                 break;
767                 }
768
769                 if (!post_div->divider)
770                         post_div = &post_divs[0];
771
772                 DRM_DEBUG("dc=%u, fd=%d, rd=%d, pd=%d\n",
773                           (unsigned)freq,
774                           feedback_div,
775                           reference_div,
776                           post_divider);
777
778                 pll_ref_div   = reference_div;
779 #if defined(__powerpc__) && (0) /* TODO */
780                 /* apparently programming this otherwise causes a hang??? */
781                 if (info->MacModel == RADEON_MAC_IBOOK)
782                         pll_fb_post_div = 0x000600ad;
783                 else
784 #endif
785                         pll_fb_post_div     = (feedback_div | (post_div->bitvalue << 16));
786
787                 htotal_cntl    = mode->htotal & 0x7;
788
789         }
790
791         pll_gain = radeon_compute_pll_gain(pll->reference_freq,
792                                            pll_ref_div & 0x3ff,
793                                            pll_fb_post_div & 0x7ff);
794
795         if (radeon_crtc->crtc_id) {
796                 uint32_t pixclks_cntl = ((RREG32_PLL(RADEON_PIXCLKS_CNTL) &
797                                           ~(RADEON_PIX2CLK_SRC_SEL_MASK)) |
798                                          RADEON_PIX2CLK_SRC_SEL_P2PLLCLK);
799
800                 if (is_tv) {
801                         radeon_legacy_tv_adjust_pll2(encoder, &htotal_cntl,
802                                                      &pll_ref_div, &pll_fb_post_div,
803                                                      &pixclks_cntl);
804                 }
805
806                 WREG32_PLL_P(RADEON_PIXCLKS_CNTL,
807                              RADEON_PIX2CLK_SRC_SEL_CPUCLK,
808                              ~(RADEON_PIX2CLK_SRC_SEL_MASK));
809
810                 WREG32_PLL_P(RADEON_P2PLL_CNTL,
811                              RADEON_P2PLL_RESET
812                              | RADEON_P2PLL_ATOMIC_UPDATE_EN
813                              | ((uint32_t)pll_gain << RADEON_P2PLL_PVG_SHIFT),
814                              ~(RADEON_P2PLL_RESET
815                                | RADEON_P2PLL_ATOMIC_UPDATE_EN
816                                | RADEON_P2PLL_PVG_MASK));
817
818                 WREG32_PLL_P(RADEON_P2PLL_REF_DIV,
819                              pll_ref_div,
820                              ~RADEON_P2PLL_REF_DIV_MASK);
821
822                 WREG32_PLL_P(RADEON_P2PLL_DIV_0,
823                              pll_fb_post_div,
824                              ~RADEON_P2PLL_FB0_DIV_MASK);
825
826                 WREG32_PLL_P(RADEON_P2PLL_DIV_0,
827                              pll_fb_post_div,
828                              ~RADEON_P2PLL_POST0_DIV_MASK);
829
830                 radeon_pll2_write_update(dev);
831                 radeon_pll2_wait_for_read_update_complete(dev);
832
833                 WREG32_PLL(RADEON_HTOTAL2_CNTL, htotal_cntl);
834
835                 WREG32_PLL_P(RADEON_P2PLL_CNTL,
836                              0,
837                              ~(RADEON_P2PLL_RESET
838                                | RADEON_P2PLL_SLEEP
839                                | RADEON_P2PLL_ATOMIC_UPDATE_EN));
840
841                 DRM_DEBUG("Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
842                           (unsigned)pll_ref_div,
843                           (unsigned)pll_fb_post_div,
844                           (unsigned)htotal_cntl,
845                           RREG32_PLL(RADEON_P2PLL_CNTL));
846                 DRM_DEBUG("Wrote2: rd=%u, fd=%u, pd=%u\n",
847                           (unsigned)pll_ref_div & RADEON_P2PLL_REF_DIV_MASK,
848                           (unsigned)pll_fb_post_div & RADEON_P2PLL_FB0_DIV_MASK,
849                           (unsigned)((pll_fb_post_div &
850                                       RADEON_P2PLL_POST0_DIV_MASK) >> 16));
851
852                 mdelay(50); /* Let the clock to lock */
853
854                 WREG32_PLL_P(RADEON_PIXCLKS_CNTL,
855                              RADEON_PIX2CLK_SRC_SEL_P2PLLCLK,
856                              ~(RADEON_PIX2CLK_SRC_SEL_MASK));
857
858                 WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
859         } else {
860                 uint32_t pixclks_cntl;
861
862
863                 if (is_tv) {
864                         pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL);
865                         radeon_legacy_tv_adjust_pll1(encoder, &htotal_cntl, &pll_ref_div,
866                                                      &pll_fb_post_div, &pixclks_cntl);
867                 }
868
869                 if (rdev->flags & RADEON_IS_MOBILITY) {
870                         /* A temporal workaround for the occational blanking on certain laptop panels.
871                            This appears to related to the PLL divider registers (fail to lock?).
872                            It occurs even when all dividers are the same with their old settings.
873                            In this case we really don't need to fiddle with PLL registers.
874                            By doing this we can avoid the blanking problem with some panels.
875                         */
876                         if ((pll_ref_div == (RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_REF_DIV_MASK)) &&
877                             (pll_fb_post_div == (RREG32_PLL(RADEON_PPLL_DIV_3) &
878                                                  (RADEON_PPLL_POST3_DIV_MASK | RADEON_PPLL_FB3_DIV_MASK)))) {
879                                 WREG32_P(RADEON_CLOCK_CNTL_INDEX,
880                                          RADEON_PLL_DIV_SEL,
881                                          ~(RADEON_PLL_DIV_SEL));
882                                 r100_pll_errata_after_index(rdev);
883                                 return;
884                         }
885                 }
886
887                 WREG32_PLL_P(RADEON_VCLK_ECP_CNTL,
888                              RADEON_VCLK_SRC_SEL_CPUCLK,
889                              ~(RADEON_VCLK_SRC_SEL_MASK));
890                 WREG32_PLL_P(RADEON_PPLL_CNTL,
891                              RADEON_PPLL_RESET
892                              | RADEON_PPLL_ATOMIC_UPDATE_EN
893                              | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN
894                              | ((uint32_t)pll_gain << RADEON_PPLL_PVG_SHIFT),
895                              ~(RADEON_PPLL_RESET
896                                | RADEON_PPLL_ATOMIC_UPDATE_EN
897                                | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN
898                                | RADEON_PPLL_PVG_MASK));
899
900                 WREG32_P(RADEON_CLOCK_CNTL_INDEX,
901                          RADEON_PLL_DIV_SEL,
902                          ~(RADEON_PLL_DIV_SEL));
903                 r100_pll_errata_after_index(rdev);
904
905                 if (ASIC_IS_R300(rdev) ||
906                     (rdev->family == CHIP_RS300) ||
907                     (rdev->family == CHIP_RS400) ||
908                     (rdev->family == CHIP_RS480)) {
909                         if (pll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
910                                 /* When restoring console mode, use saved PPLL_REF_DIV
911                                  * setting.
912                                  */
913                                 WREG32_PLL_P(RADEON_PPLL_REF_DIV,
914                                              pll_ref_div,
915                                              0);
916                         } else {
917                                 /* R300 uses ref_div_acc field as real ref divider */
918                                 WREG32_PLL_P(RADEON_PPLL_REF_DIV,
919                                              (pll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT),
920                                              ~R300_PPLL_REF_DIV_ACC_MASK);
921                         }
922                 } else
923                         WREG32_PLL_P(RADEON_PPLL_REF_DIV,
924                                      pll_ref_div,
925                                      ~RADEON_PPLL_REF_DIV_MASK);
926
927                 WREG32_PLL_P(RADEON_PPLL_DIV_3,
928                              pll_fb_post_div,
929                              ~RADEON_PPLL_FB3_DIV_MASK);
930
931                 WREG32_PLL_P(RADEON_PPLL_DIV_3,
932                              pll_fb_post_div,
933                              ~RADEON_PPLL_POST3_DIV_MASK);
934
935                 radeon_pll_write_update(dev);
936                 radeon_pll_wait_for_read_update_complete(dev);
937
938                 WREG32_PLL(RADEON_HTOTAL_CNTL, htotal_cntl);
939
940                 WREG32_PLL_P(RADEON_PPLL_CNTL,
941                              0,
942                              ~(RADEON_PPLL_RESET
943                                | RADEON_PPLL_SLEEP
944                                | RADEON_PPLL_ATOMIC_UPDATE_EN
945                                | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN));
946
947                 DRM_DEBUG("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
948                           pll_ref_div,
949                           pll_fb_post_div,
950                           (unsigned)htotal_cntl,
951                           RREG32_PLL(RADEON_PPLL_CNTL));
952                 DRM_DEBUG("Wrote: rd=%d, fd=%d, pd=%d\n",
953                           pll_ref_div & RADEON_PPLL_REF_DIV_MASK,
954                           pll_fb_post_div & RADEON_PPLL_FB3_DIV_MASK,
955                           (pll_fb_post_div & RADEON_PPLL_POST3_DIV_MASK) >> 16);
956
957                 mdelay(50); /* Let the clock to lock */
958
959                 WREG32_PLL_P(RADEON_VCLK_ECP_CNTL,
960                              RADEON_VCLK_SRC_SEL_PPLLCLK,
961                              ~(RADEON_VCLK_SRC_SEL_MASK));
962
963                 if (is_tv)
964                         WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
965         }
966 }
967
968 static bool radeon_crtc_mode_fixup(struct drm_crtc *crtc,
969                                    struct drm_display_mode *mode,
970                                    struct drm_display_mode *adjusted_mode)
971 {
972         struct drm_device *dev = crtc->dev;
973         struct radeon_device *rdev = dev->dev_private;
974
975         /* adjust pm to upcoming mode change */
976         radeon_pm_compute_clocks(rdev);
977
978         if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
979                 return false;
980         return true;
981 }
982
983 static int radeon_crtc_mode_set(struct drm_crtc *crtc,
984                                  struct drm_display_mode *mode,
985                                  struct drm_display_mode *adjusted_mode,
986                                  int x, int y, struct drm_framebuffer *old_fb)
987 {
988         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
989
990         /* TODO TV */
991         radeon_crtc_set_base(crtc, x, y, old_fb);
992         radeon_set_crtc_timing(crtc, adjusted_mode);
993         radeon_set_pll(crtc, adjusted_mode);
994         radeon_overscan_setup(crtc, adjusted_mode);
995         if (radeon_crtc->crtc_id == 0) {
996                 radeon_legacy_rmx_mode_set(crtc, adjusted_mode);
997         } else {
998                 if (radeon_crtc->rmx_type != RMX_OFF) {
999                         /* FIXME: only first crtc has rmx what should we
1000                          * do ?
1001                          */
1002                         DRM_ERROR("Mode need scaling but only first crtc can do that.\n");
1003                 }
1004         }
1005         return 0;
1006 }
1007
1008 static void radeon_crtc_prepare(struct drm_crtc *crtc)
1009 {
1010         struct drm_device *dev = crtc->dev;
1011         struct drm_crtc *crtci;
1012
1013         /*
1014         * The hardware wedges sometimes if you reconfigure one CRTC
1015         * whilst another is running (see fdo bug #24611).
1016         */
1017         list_for_each_entry(crtci, &dev->mode_config.crtc_list, head)
1018                 radeon_crtc_dpms(crtci, DRM_MODE_DPMS_OFF);
1019 }
1020
1021 static void radeon_crtc_commit(struct drm_crtc *crtc)
1022 {
1023         struct drm_device *dev = crtc->dev;
1024         struct drm_crtc *crtci;
1025
1026         /*
1027         * Reenable the CRTCs that should be running.
1028         */
1029         list_for_each_entry(crtci, &dev->mode_config.crtc_list, head) {
1030                 if (crtci->enabled)
1031                         radeon_crtc_dpms(crtci, DRM_MODE_DPMS_ON);
1032         }
1033 }
1034
1035 static const struct drm_crtc_helper_funcs legacy_helper_funcs = {
1036         .dpms = radeon_crtc_dpms,
1037         .mode_fixup = radeon_crtc_mode_fixup,
1038         .mode_set = radeon_crtc_mode_set,
1039         .mode_set_base = radeon_crtc_set_base,
1040         .prepare = radeon_crtc_prepare,
1041         .commit = radeon_crtc_commit,
1042         .load_lut = radeon_crtc_load_lut,
1043 };
1044
1045
1046 void radeon_legacy_init_crtc(struct drm_device *dev,
1047                                struct radeon_crtc *radeon_crtc)
1048 {
1049         if (radeon_crtc->crtc_id == 1)
1050                 radeon_crtc->crtc_offset = RADEON_CRTC2_H_TOTAL_DISP - RADEON_CRTC_H_TOTAL_DISP;
1051         drm_crtc_helper_add(&radeon_crtc->base, &legacy_helper_funcs);
1052 }