1 /*
2 * Copyright 2012 Red Hat Inc.
3 * Parts based on xf86-video-ast
4 * Copyright (c) 2005 ASPEED Technology Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
24 * of the Software.
25 *
26 */
27 /*
28 * Authors: Dave Airlie <airlied@redhat.com>
29 */
30
31 #include <linux/delay.h>
32 #include <linux/pci.h>
33
34 #include <drm/drm_atomic.h>
35 #include <drm/drm_atomic_helper.h>
36 #include <drm/drm_crtc.h>
37 #include <drm/drm_damage_helper.h>
38 #include <drm/drm_format_helper.h>
39 #include <drm/drm_fourcc.h>
40 #include <drm/drm_gem_atomic_helper.h>
41 #include <drm/drm_gem_framebuffer_helper.h>
42 #include <drm/drm_gem_shmem_helper.h>
43 #include <drm/drm_managed.h>
44 #include <drm/drm_panic.h>
45 #include <drm/drm_probe_helper.h>
46
47 #include "ast_drv.h"
48 #include "ast_tables.h"
49 #include "ast_vbios.h"
50
51 #define AST_LUT_SIZE 256
52
53 #define AST_PRIMARY_PLANE_MAX_OFFSET (BIT(16) - 1)
54
ast_fb_vram_offset(void)55 static unsigned long ast_fb_vram_offset(void)
56 {
57 return 0; // with shmem, the primary plane is always at offset 0
58 }
59
ast_fb_vram_size(struct ast_device * ast)60 static unsigned long ast_fb_vram_size(struct ast_device *ast)
61 {
62 struct drm_device *dev = &ast->base;
63 unsigned long offset = ast_fb_vram_offset(); // starts at offset
64 long cursor_offset = ast_cursor_vram_offset(ast); // ends at cursor offset
65
66 if (cursor_offset < 0)
67 cursor_offset = ast->vram_size; // no cursor; it's all ours
68 if (drm_WARN_ON_ONCE(dev, offset > cursor_offset))
69 return 0; // cannot legally happen; signal error
70 return cursor_offset - offset;
71 }
72
ast_load_palette_index(struct ast_device * ast,u8 index,u8 red,u8 green,u8 blue)73 static inline void ast_load_palette_index(struct ast_device *ast,
74 u8 index, u8 red, u8 green,
75 u8 blue)
76 {
77 ast_io_write8(ast, AST_IO_VGADWR, index);
78 ast_io_read8(ast, AST_IO_VGASRI);
79 ast_io_write8(ast, AST_IO_VGAPDR, red);
80 ast_io_read8(ast, AST_IO_VGASRI);
81 ast_io_write8(ast, AST_IO_VGAPDR, green);
82 ast_io_read8(ast, AST_IO_VGASRI);
83 ast_io_write8(ast, AST_IO_VGAPDR, blue);
84 ast_io_read8(ast, AST_IO_VGASRI);
85 }
86
ast_crtc_set_gamma_linear(struct ast_device * ast,const struct drm_format_info * format)87 static void ast_crtc_set_gamma_linear(struct ast_device *ast,
88 const struct drm_format_info *format)
89 {
90 int i;
91
92 switch (format->format) {
93 case DRM_FORMAT_C8: /* In this case, gamma table is used as color palette */
94 case DRM_FORMAT_RGB565:
95 case DRM_FORMAT_XRGB8888:
96 for (i = 0; i < AST_LUT_SIZE; i++)
97 ast_load_palette_index(ast, i, i, i, i);
98 break;
99 default:
100 drm_warn_once(&ast->base, "Unsupported format %p4cc for gamma correction\n",
101 &format->format);
102 break;
103 }
104 }
105
ast_crtc_set_gamma(struct ast_device * ast,const struct drm_format_info * format,struct drm_color_lut * lut)106 static void ast_crtc_set_gamma(struct ast_device *ast,
107 const struct drm_format_info *format,
108 struct drm_color_lut *lut)
109 {
110 int i;
111
112 switch (format->format) {
113 case DRM_FORMAT_C8: /* In this case, gamma table is used as color palette */
114 case DRM_FORMAT_RGB565:
115 case DRM_FORMAT_XRGB8888:
116 for (i = 0; i < AST_LUT_SIZE; i++)
117 ast_load_palette_index(ast, i,
118 lut[i].red >> 8,
119 lut[i].green >> 8,
120 lut[i].blue >> 8);
121 break;
122 default:
123 drm_warn_once(&ast->base, "Unsupported format %p4cc for gamma correction\n",
124 &format->format);
125 break;
126 }
127 }
128
ast_set_vbios_color_reg(struct ast_device * ast,const struct drm_format_info * format,const struct ast_vbios_enhtable * vmode)129 static void ast_set_vbios_color_reg(struct ast_device *ast,
130 const struct drm_format_info *format,
131 const struct ast_vbios_enhtable *vmode)
132 {
133 u32 color_index;
134
135 switch (format->cpp[0]) {
136 case 1:
137 color_index = VGAModeIndex - 1;
138 break;
139 case 2:
140 color_index = HiCModeIndex;
141 break;
142 case 3:
143 case 4:
144 color_index = TrueCModeIndex;
145 break;
146 default:
147 return;
148 }
149
150 ast_set_index_reg(ast, AST_IO_VGACRI, 0x8c, (u8)((color_index & 0x0f) << 4));
151
152 ast_set_index_reg(ast, AST_IO_VGACRI, 0x91, 0x00);
153
154 if (vmode->flags & NewModeInfo) {
155 ast_set_index_reg(ast, AST_IO_VGACRI, 0x91, 0xa8);
156 ast_set_index_reg(ast, AST_IO_VGACRI, 0x92, format->cpp[0] * 8);
157 }
158 }
159
ast_set_vbios_mode_reg(struct ast_device * ast,const struct drm_display_mode * adjusted_mode,const struct ast_vbios_enhtable * vmode)160 static void ast_set_vbios_mode_reg(struct ast_device *ast,
161 const struct drm_display_mode *adjusted_mode,
162 const struct ast_vbios_enhtable *vmode)
163 {
164 u32 refresh_rate_index, mode_id;
165
166 refresh_rate_index = vmode->refresh_rate_index;
167 mode_id = vmode->mode_id;
168
169 ast_set_index_reg(ast, AST_IO_VGACRI, 0x8d, refresh_rate_index & 0xff);
170 ast_set_index_reg(ast, AST_IO_VGACRI, 0x8e, mode_id & 0xff);
171
172 ast_set_index_reg(ast, AST_IO_VGACRI, 0x91, 0x00);
173
174 if (vmode->flags & NewModeInfo) {
175 ast_set_index_reg(ast, AST_IO_VGACRI, 0x91, 0xa8);
176 ast_set_index_reg(ast, AST_IO_VGACRI, 0x93, adjusted_mode->clock / 1000);
177 ast_set_index_reg(ast, AST_IO_VGACRI, 0x94, adjusted_mode->crtc_hdisplay);
178 ast_set_index_reg(ast, AST_IO_VGACRI, 0x95, adjusted_mode->crtc_hdisplay >> 8);
179 ast_set_index_reg(ast, AST_IO_VGACRI, 0x96, adjusted_mode->crtc_vdisplay);
180 ast_set_index_reg(ast, AST_IO_VGACRI, 0x97, adjusted_mode->crtc_vdisplay >> 8);
181 }
182 }
183
ast_set_std_reg(struct ast_device * ast,struct drm_display_mode * mode,const struct ast_vbios_stdtable * stdtable)184 static void ast_set_std_reg(struct ast_device *ast,
185 struct drm_display_mode *mode,
186 const struct ast_vbios_stdtable *stdtable)
187 {
188 u32 i;
189 u8 jreg;
190
191 jreg = stdtable->misc;
192 ast_io_write8(ast, AST_IO_VGAMR_W, jreg);
193
194 /* Set SEQ; except Screen Disable field */
195 ast_set_index_reg(ast, AST_IO_VGASRI, 0x00, 0x03);
196 ast_set_index_reg_mask(ast, AST_IO_VGASRI, 0x01, 0x20, stdtable->seq[0]);
197 for (i = 1; i < 4; i++) {
198 jreg = stdtable->seq[i];
199 ast_set_index_reg(ast, AST_IO_VGASRI, (i + 1), jreg);
200 }
201
202 /* Set CRTC; except base address and offset */
203 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x11, 0x7f, 0x00);
204 for (i = 0; i < 12; i++)
205 ast_set_index_reg(ast, AST_IO_VGACRI, i, stdtable->crtc[i]);
206 for (i = 14; i < 19; i++)
207 ast_set_index_reg(ast, AST_IO_VGACRI, i, stdtable->crtc[i]);
208 for (i = 20; i < 25; i++)
209 ast_set_index_reg(ast, AST_IO_VGACRI, i, stdtable->crtc[i]);
210
211 /* set AR */
212 jreg = ast_io_read8(ast, AST_IO_VGAIR1_R);
213 for (i = 0; i < 20; i++) {
214 jreg = stdtable->ar[i];
215 ast_io_write8(ast, AST_IO_VGAARI_W, (u8)i);
216 ast_io_write8(ast, AST_IO_VGAARI_W, jreg);
217 }
218 ast_io_write8(ast, AST_IO_VGAARI_W, 0x14);
219 ast_io_write8(ast, AST_IO_VGAARI_W, 0x00);
220
221 jreg = ast_io_read8(ast, AST_IO_VGAIR1_R);
222 ast_io_write8(ast, AST_IO_VGAARI_W, 0x20);
223
224 /* Set GR */
225 for (i = 0; i < 9; i++)
226 ast_set_index_reg(ast, AST_IO_VGAGRI, i, stdtable->gr[i]);
227 }
228
ast_set_crtc_reg(struct ast_device * ast,struct drm_display_mode * mode,const struct ast_vbios_enhtable * vmode)229 static void ast_set_crtc_reg(struct ast_device *ast,
230 struct drm_display_mode *mode,
231 const struct ast_vbios_enhtable *vmode)
232 {
233 u8 jreg05 = 0, jreg07 = 0, jreg09 = 0, jregAC = 0, jregAD = 0, jregAE = 0;
234 u16 temp, precache = 0;
235
236 if ((IS_AST_GEN6(ast) || IS_AST_GEN7(ast)) &&
237 (vmode->flags & AST2500PreCatchCRT))
238 precache = 40;
239
240 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x11, 0x7f, 0x00);
241
242 temp = (mode->crtc_htotal >> 3) - 5;
243 if (temp & 0x100)
244 jregAC |= 0x01; /* HT D[8] */
245 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x00, 0x00, temp);
246
247 temp = (mode->crtc_hdisplay >> 3) - 1;
248 if (temp & 0x100)
249 jregAC |= 0x04; /* HDE D[8] */
250 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x01, 0x00, temp);
251
252 temp = (mode->crtc_hblank_start >> 3) - 1;
253 if (temp & 0x100)
254 jregAC |= 0x10; /* HBS D[8] */
255 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x02, 0x00, temp);
256
257 temp = ((mode->crtc_hblank_end >> 3) - 1) & 0x7f;
258 if (temp & 0x20)
259 jreg05 |= 0x80; /* HBE D[5] */
260 if (temp & 0x40)
261 jregAD |= 0x01; /* HBE D[5] */
262 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x03, 0xE0, (temp & 0x1f));
263
264 temp = ((mode->crtc_hsync_start-precache) >> 3) - 1;
265 if (temp & 0x100)
266 jregAC |= 0x40; /* HRS D[5] */
267 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x04, 0x00, temp);
268
269 temp = (((mode->crtc_hsync_end-precache) >> 3) - 1) & 0x3f;
270 if (temp & 0x20)
271 jregAD |= 0x04; /* HRE D[5] */
272 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x05, 0x60, (u8)((temp & 0x1f) | jreg05));
273
274 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xAC, 0x00, jregAC);
275 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xAD, 0x00, jregAD);
276
277 // Workaround for HSync Time non octave pixels (1920x1080@60Hz HSync 44 pixels);
278 if (IS_AST_GEN7(ast) && (mode->crtc_vdisplay == 1080))
279 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xFC, 0xFD, 0x02);
280 else
281 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xFC, 0xFD, 0x00);
282
283 /* vert timings */
284 temp = (mode->crtc_vtotal) - 2;
285 if (temp & 0x100)
286 jreg07 |= 0x01;
287 if (temp & 0x200)
288 jreg07 |= 0x20;
289 if (temp & 0x400)
290 jregAE |= 0x01;
291 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x06, 0x00, temp);
292
293 temp = (mode->crtc_vsync_start) - 1;
294 if (temp & 0x100)
295 jreg07 |= 0x04;
296 if (temp & 0x200)
297 jreg07 |= 0x80;
298 if (temp & 0x400)
299 jregAE |= 0x08;
300 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x10, 0x00, temp);
301
302 temp = (mode->crtc_vsync_end - 1) & 0x3f;
303 if (temp & 0x10)
304 jregAE |= 0x20;
305 if (temp & 0x20)
306 jregAE |= 0x40;
307 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x11, 0x70, temp & 0xf);
308
309 temp = mode->crtc_vdisplay - 1;
310 if (temp & 0x100)
311 jreg07 |= 0x02;
312 if (temp & 0x200)
313 jreg07 |= 0x40;
314 if (temp & 0x400)
315 jregAE |= 0x02;
316 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x12, 0x00, temp);
317
318 temp = mode->crtc_vblank_start - 1;
319 if (temp & 0x100)
320 jreg07 |= 0x08;
321 if (temp & 0x200)
322 jreg09 |= 0x20;
323 if (temp & 0x400)
324 jregAE |= 0x04;
325 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x15, 0x00, temp);
326
327 temp = mode->crtc_vblank_end - 1;
328 if (temp & 0x100)
329 jregAE |= 0x10;
330 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x16, 0x00, temp);
331
332 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x07, 0x00, jreg07);
333 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x09, 0xdf, jreg09);
334 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xAE, 0x00, (jregAE | 0x80));
335
336 if (precache)
337 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb6, 0x3f, 0x80);
338 else
339 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb6, 0x3f, 0x00);
340
341 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x11, 0x7f, 0x80);
342 }
343
ast_set_offset_reg(struct ast_device * ast,struct drm_framebuffer * fb)344 static void ast_set_offset_reg(struct ast_device *ast,
345 struct drm_framebuffer *fb)
346 {
347 u16 offset;
348
349 offset = fb->pitches[0] >> 3;
350 ast_set_index_reg(ast, AST_IO_VGACRI, 0x13, (offset & 0xff));
351 ast_set_index_reg(ast, AST_IO_VGACRI, 0xb0, (offset >> 8) & 0x3f);
352 }
353
ast_set_dclk_reg(struct ast_device * ast,struct drm_display_mode * mode,const struct ast_vbios_enhtable * vmode)354 static void ast_set_dclk_reg(struct ast_device *ast,
355 struct drm_display_mode *mode,
356 const struct ast_vbios_enhtable *vmode)
357 {
358 const struct ast_vbios_dclk_info *clk_info;
359
360 if (IS_AST_GEN6(ast) || IS_AST_GEN7(ast))
361 clk_info = &dclk_table_ast2500[vmode->dclk_index];
362 else
363 clk_info = &dclk_table[vmode->dclk_index];
364
365 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xc0, 0x00, clk_info->param1);
366 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xc1, 0x00, clk_info->param2);
367 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xbb, 0x0f,
368 (clk_info->param3 & 0xc0) |
369 ((clk_info->param3 & 0x3) << 4));
370 }
371
ast_set_color_reg(struct ast_device * ast,const struct drm_format_info * format)372 static void ast_set_color_reg(struct ast_device *ast,
373 const struct drm_format_info *format)
374 {
375 u8 jregA0 = 0, jregA3 = 0, jregA8 = 0;
376
377 switch (format->cpp[0] * 8) {
378 case 8:
379 jregA0 = 0x70;
380 jregA3 = 0x01;
381 jregA8 = 0x00;
382 break;
383 case 15:
384 case 16:
385 jregA0 = 0x70;
386 jregA3 = 0x04;
387 jregA8 = 0x02;
388 break;
389 case 32:
390 jregA0 = 0x70;
391 jregA3 = 0x08;
392 jregA8 = 0x02;
393 break;
394 }
395
396 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa0, 0x8f, jregA0);
397 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xf0, jregA3);
398 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa8, 0xfd, jregA8);
399 }
400
ast_set_crtthd_reg(struct ast_device * ast)401 static void ast_set_crtthd_reg(struct ast_device *ast)
402 {
403 /* Set Threshold */
404 if (IS_AST_GEN7(ast)) {
405 ast_set_index_reg(ast, AST_IO_VGACRI, 0xa7, 0xe0);
406 ast_set_index_reg(ast, AST_IO_VGACRI, 0xa6, 0xa0);
407 } else if (IS_AST_GEN6(ast) || IS_AST_GEN5(ast) || IS_AST_GEN4(ast)) {
408 ast_set_index_reg(ast, AST_IO_VGACRI, 0xa7, 0x78);
409 ast_set_index_reg(ast, AST_IO_VGACRI, 0xa6, 0x60);
410 } else if (IS_AST_GEN3(ast) || IS_AST_GEN2(ast)) {
411 ast_set_index_reg(ast, AST_IO_VGACRI, 0xa7, 0x3f);
412 ast_set_index_reg(ast, AST_IO_VGACRI, 0xa6, 0x2f);
413 } else {
414 ast_set_index_reg(ast, AST_IO_VGACRI, 0xa7, 0x2f);
415 ast_set_index_reg(ast, AST_IO_VGACRI, 0xa6, 0x1f);
416 }
417 }
418
ast_set_sync_reg(struct ast_device * ast,struct drm_display_mode * mode,const struct ast_vbios_enhtable * vmode)419 static void ast_set_sync_reg(struct ast_device *ast,
420 struct drm_display_mode *mode,
421 const struct ast_vbios_enhtable *vmode)
422 {
423 u8 jreg;
424
425 jreg = ast_io_read8(ast, AST_IO_VGAMR_R);
426 jreg &= ~0xC0;
427 if (vmode->flags & NVSync)
428 jreg |= 0x80;
429 if (vmode->flags & NHSync)
430 jreg |= 0x40;
431 ast_io_write8(ast, AST_IO_VGAMR_W, jreg);
432 }
433
ast_set_start_address_crt1(struct ast_device * ast,unsigned int offset)434 static void ast_set_start_address_crt1(struct ast_device *ast,
435 unsigned int offset)
436 {
437 u32 addr;
438
439 addr = offset >> 2;
440 ast_set_index_reg(ast, AST_IO_VGACRI, 0x0d, (u8)(addr & 0xff));
441 ast_set_index_reg(ast, AST_IO_VGACRI, 0x0c, (u8)((addr >> 8) & 0xff));
442 ast_set_index_reg(ast, AST_IO_VGACRI, 0xaf, (u8)((addr >> 16) & 0xff));
443
444 }
445
ast_wait_for_vretrace(struct ast_device * ast)446 static void ast_wait_for_vretrace(struct ast_device *ast)
447 {
448 unsigned long timeout = jiffies + HZ;
449 u8 vgair1;
450
451 do {
452 vgair1 = ast_io_read8(ast, AST_IO_VGAIR1_R);
453 } while (!(vgair1 & AST_IO_VGAIR1_VREFRESH) && time_before(jiffies, timeout));
454 }
455
456 /*
457 * Planes
458 */
459
ast_plane_init(struct drm_device * dev,struct ast_plane * ast_plane,u64 offset,unsigned long size,uint32_t possible_crtcs,const struct drm_plane_funcs * funcs,const uint32_t * formats,unsigned int format_count,const uint64_t * format_modifiers,enum drm_plane_type type)460 int ast_plane_init(struct drm_device *dev, struct ast_plane *ast_plane,
461 u64 offset, unsigned long size,
462 uint32_t possible_crtcs,
463 const struct drm_plane_funcs *funcs,
464 const uint32_t *formats, unsigned int format_count,
465 const uint64_t *format_modifiers,
466 enum drm_plane_type type)
467 {
468 struct drm_plane *plane = &ast_plane->base;
469
470 ast_plane->offset = offset;
471 ast_plane->size = size;
472
473 return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
474 formats, format_count, format_modifiers,
475 type, NULL);
476 }
477
ast_plane_vaddr(struct ast_plane * ast_plane)478 void __iomem *ast_plane_vaddr(struct ast_plane *ast_plane)
479 {
480 struct ast_device *ast = to_ast_device(ast_plane->base.dev);
481
482 return ast->vram + ast_plane->offset;
483 }
484
485 /*
486 * Primary plane
487 */
488
489 static const uint32_t ast_primary_plane_formats[] = {
490 DRM_FORMAT_XRGB8888,
491 DRM_FORMAT_RGB565,
492 DRM_FORMAT_C8,
493 };
494
ast_primary_plane_helper_atomic_check(struct drm_plane * plane,struct drm_atomic_state * state)495 static int ast_primary_plane_helper_atomic_check(struct drm_plane *plane,
496 struct drm_atomic_state *state)
497 {
498 struct drm_device *dev = plane->dev;
499 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
500 struct drm_crtc_state *new_crtc_state = NULL;
501 struct ast_crtc_state *new_ast_crtc_state;
502 int ret;
503
504 if (new_plane_state->crtc)
505 new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc);
506
507 ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
508 DRM_PLANE_NO_SCALING,
509 DRM_PLANE_NO_SCALING,
510 false, true);
511 if (ret) {
512 return ret;
513 } else if (!new_plane_state->visible) {
514 if (drm_WARN_ON(dev, new_plane_state->crtc)) /* cannot legally happen */
515 return -EINVAL;
516 else
517 return 0;
518 }
519
520 new_ast_crtc_state = to_ast_crtc_state(new_crtc_state);
521
522 new_ast_crtc_state->format = new_plane_state->fb->format;
523
524 return 0;
525 }
526
ast_handle_damage(struct ast_plane * ast_plane,struct iosys_map * src,struct drm_framebuffer * fb,const struct drm_rect * clip)527 static void ast_handle_damage(struct ast_plane *ast_plane, struct iosys_map *src,
528 struct drm_framebuffer *fb,
529 const struct drm_rect *clip)
530 {
531 struct iosys_map dst = IOSYS_MAP_INIT_VADDR_IOMEM(ast_plane_vaddr(ast_plane));
532
533 iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0], fb->format, clip));
534 drm_fb_memcpy(&dst, fb->pitches, src, fb, clip);
535 }
536
ast_primary_plane_helper_atomic_update(struct drm_plane * plane,struct drm_atomic_state * state)537 static void ast_primary_plane_helper_atomic_update(struct drm_plane *plane,
538 struct drm_atomic_state *state)
539 {
540 struct drm_device *dev = plane->dev;
541 struct ast_device *ast = to_ast_device(dev);
542 struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
543 struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
544 struct drm_framebuffer *fb = plane_state->fb;
545 struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
546 struct drm_framebuffer *old_fb = old_plane_state->fb;
547 struct ast_plane *ast_plane = to_ast_plane(plane);
548 struct drm_crtc *crtc = plane_state->crtc;
549 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
550 struct drm_rect damage;
551 struct drm_atomic_helper_damage_iter iter;
552
553 if (!old_fb || (fb->format != old_fb->format) || crtc_state->mode_changed) {
554 struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state);
555
556 ast_set_color_reg(ast, fb->format);
557 ast_set_vbios_color_reg(ast, fb->format, ast_crtc_state->vmode);
558 }
559
560 drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
561 drm_atomic_for_each_plane_damage(&iter, &damage) {
562 ast_handle_damage(ast_plane, shadow_plane_state->data, fb, &damage);
563 }
564
565 /*
566 * Some BMCs stop scanning out the video signal after the driver
567 * reprogrammed the offset. This stalls display output for several
568 * seconds and makes the display unusable. Therefore only update
569 * the offset if it changes.
570 */
571 if (!old_fb || old_fb->pitches[0] != fb->pitches[0])
572 ast_set_offset_reg(ast, fb);
573 }
574
ast_primary_plane_helper_atomic_enable(struct drm_plane * plane,struct drm_atomic_state * state)575 static void ast_primary_plane_helper_atomic_enable(struct drm_plane *plane,
576 struct drm_atomic_state *state)
577 {
578 struct ast_device *ast = to_ast_device(plane->dev);
579 struct ast_plane *ast_plane = to_ast_plane(plane);
580
581 /*
582 * Some BMCs stop scanning out the video signal after the driver
583 * reprogrammed the scanout address. This stalls display
584 * output for several seconds and makes the display unusable.
585 * Therefore only reprogram the address after enabling the plane.
586 */
587 ast_set_start_address_crt1(ast, (u32)ast_plane->offset);
588 }
589
ast_primary_plane_helper_atomic_disable(struct drm_plane * plane,struct drm_atomic_state * state)590 static void ast_primary_plane_helper_atomic_disable(struct drm_plane *plane,
591 struct drm_atomic_state *state)
592 {
593 /*
594 * Keep this empty function to avoid calling
595 * atomic_update when disabling the plane.
596 */
597 }
598
ast_primary_plane_helper_get_scanout_buffer(struct drm_plane * plane,struct drm_scanout_buffer * sb)599 static int ast_primary_plane_helper_get_scanout_buffer(struct drm_plane *plane,
600 struct drm_scanout_buffer *sb)
601 {
602 struct ast_plane *ast_plane = to_ast_plane(plane);
603
604 if (plane->state && plane->state->fb) {
605 sb->format = plane->state->fb->format;
606 sb->width = plane->state->fb->width;
607 sb->height = plane->state->fb->height;
608 sb->pitch[0] = plane->state->fb->pitches[0];
609 iosys_map_set_vaddr_iomem(&sb->map[0], ast_plane_vaddr(ast_plane));
610 return 0;
611 }
612 return -ENODEV;
613 }
614
615 static const struct drm_plane_helper_funcs ast_primary_plane_helper_funcs = {
616 DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
617 .atomic_check = ast_primary_plane_helper_atomic_check,
618 .atomic_update = ast_primary_plane_helper_atomic_update,
619 .atomic_enable = ast_primary_plane_helper_atomic_enable,
620 .atomic_disable = ast_primary_plane_helper_atomic_disable,
621 .get_scanout_buffer = ast_primary_plane_helper_get_scanout_buffer,
622 };
623
624 static const struct drm_plane_funcs ast_primary_plane_funcs = {
625 .update_plane = drm_atomic_helper_update_plane,
626 .disable_plane = drm_atomic_helper_disable_plane,
627 .destroy = drm_plane_cleanup,
628 DRM_GEM_SHADOW_PLANE_FUNCS,
629 };
630
ast_primary_plane_init(struct ast_device * ast)631 static int ast_primary_plane_init(struct ast_device *ast)
632 {
633 struct drm_device *dev = &ast->base;
634 struct ast_plane *ast_primary_plane = &ast->primary_plane;
635 struct drm_plane *primary_plane = &ast_primary_plane->base;
636 u64 offset = ast_fb_vram_offset();
637 unsigned long size = ast_fb_vram_size(ast);
638 int ret;
639
640 ret = ast_plane_init(dev, ast_primary_plane, offset, size,
641 0x01, &ast_primary_plane_funcs,
642 ast_primary_plane_formats, ARRAY_SIZE(ast_primary_plane_formats),
643 NULL, DRM_PLANE_TYPE_PRIMARY);
644 if (ret) {
645 drm_err(dev, "ast_plane_init() failed: %d\n", ret);
646 return ret;
647 }
648 drm_plane_helper_add(primary_plane, &ast_primary_plane_helper_funcs);
649 drm_plane_enable_fb_damage_clips(primary_plane);
650
651 return 0;
652 }
653
654 /*
655 * CRTC
656 */
657
658 static enum drm_mode_status
ast_crtc_helper_mode_valid(struct drm_crtc * crtc,const struct drm_display_mode * mode)659 ast_crtc_helper_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
660 {
661 struct ast_device *ast = to_ast_device(crtc->dev);
662 const struct ast_vbios_enhtable *vmode;
663
664 vmode = ast_vbios_find_mode(ast, mode);
665 if (!vmode)
666 return MODE_NOMODE;
667
668 return MODE_OK;
669 }
670
ast_crtc_helper_mode_set_nofb(struct drm_crtc * crtc)671 static void ast_crtc_helper_mode_set_nofb(struct drm_crtc *crtc)
672 {
673 struct drm_device *dev = crtc->dev;
674 struct ast_device *ast = to_ast_device(dev);
675 struct drm_crtc_state *crtc_state = crtc->state;
676 struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state);
677 const struct ast_vbios_stdtable *std_table = ast_crtc_state->std_table;
678 const struct ast_vbios_enhtable *vmode = ast_crtc_state->vmode;
679 struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
680
681 /*
682 * Ensure that no scanout takes place before reprogramming mode
683 * and format registers.
684 *
685 * TODO: Get vblank interrupts working and remove this line.
686 */
687 ast_wait_for_vretrace(ast);
688
689 ast_set_vbios_mode_reg(ast, adjusted_mode, vmode);
690 ast_set_index_reg(ast, AST_IO_VGACRI, 0xa1, 0x06);
691 ast_set_std_reg(ast, adjusted_mode, std_table);
692 ast_set_crtc_reg(ast, adjusted_mode, vmode);
693 ast_set_dclk_reg(ast, adjusted_mode, vmode);
694 ast_set_crtthd_reg(ast);
695 ast_set_sync_reg(ast, adjusted_mode, vmode);
696 }
697
ast_crtc_helper_atomic_check(struct drm_crtc * crtc,struct drm_atomic_state * state)698 static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc,
699 struct drm_atomic_state *state)
700 {
701 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
702 struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
703 struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
704 struct ast_crtc_state *old_ast_crtc_state = to_ast_crtc_state(old_crtc_state);
705 struct drm_device *dev = crtc->dev;
706 struct ast_device *ast = to_ast_device(dev);
707 struct ast_crtc_state *ast_state;
708 const struct drm_format_info *format;
709 const struct ast_vbios_enhtable *vmode;
710 unsigned int hborder = 0;
711 unsigned int vborder = 0;
712 int ret;
713
714 if (!crtc_state->enable)
715 return 0;
716
717 ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state);
718 if (ret)
719 return ret;
720
721 ast_state = to_ast_crtc_state(crtc_state);
722
723 format = ast_state->format;
724 if (drm_WARN_ON_ONCE(dev, !format))
725 return -EINVAL; /* BUG: We didn't set format in primary check(). */
726
727 /*
728 * The gamma LUT has to be reloaded after changing the primary
729 * plane's color format.
730 */
731 if (old_ast_crtc_state->format != format)
732 crtc_state->color_mgmt_changed = true;
733
734 if (crtc_state->color_mgmt_changed && crtc_state->gamma_lut) {
735 if (crtc_state->gamma_lut->length !=
736 AST_LUT_SIZE * sizeof(struct drm_color_lut)) {
737 drm_err(dev, "Wrong size for gamma_lut %zu\n",
738 crtc_state->gamma_lut->length);
739 return -EINVAL;
740 }
741 }
742
743 /*
744 * Set register tables.
745 *
746 * TODO: These tables mix all kinds of fields and should
747 * probably be resolved into various helper functions.
748 */
749 switch (format->format) {
750 case DRM_FORMAT_C8:
751 ast_state->std_table = &vbios_stdtable[VGAModeIndex];
752 break;
753 case DRM_FORMAT_RGB565:
754 ast_state->std_table = &vbios_stdtable[HiCModeIndex];
755 break;
756 case DRM_FORMAT_RGB888:
757 case DRM_FORMAT_XRGB8888:
758 ast_state->std_table = &vbios_stdtable[TrueCModeIndex];
759 break;
760 default:
761 return -EINVAL;
762 }
763
764 /*
765 * Find the VBIOS mode and adjust the DRM display mode accordingly
766 * if a full modeset is required. Otherwise keep the existing values.
767 */
768 if (drm_atomic_crtc_needs_modeset(crtc_state)) {
769 vmode = ast_vbios_find_mode(ast, &crtc_state->mode);
770 if (!vmode)
771 return -EINVAL;
772 ast_state->vmode = vmode;
773
774 if (vmode->flags & HBorder)
775 hborder = 8;
776 if (vmode->flags & VBorder)
777 vborder = 8;
778
779 adjusted_mode->crtc_hdisplay = vmode->hde;
780 adjusted_mode->crtc_hblank_start = vmode->hde + hborder;
781 adjusted_mode->crtc_hblank_end = vmode->ht - hborder;
782 adjusted_mode->crtc_hsync_start = vmode->hde + hborder + vmode->hfp;
783 adjusted_mode->crtc_hsync_end = vmode->hde + hborder + vmode->hfp + vmode->hsync;
784 adjusted_mode->crtc_htotal = vmode->ht;
785
786 adjusted_mode->crtc_vdisplay = vmode->vde;
787 adjusted_mode->crtc_vblank_start = vmode->vde + vborder;
788 adjusted_mode->crtc_vblank_end = vmode->vt - vborder;
789 adjusted_mode->crtc_vsync_start = vmode->vde + vborder + vmode->vfp;
790 adjusted_mode->crtc_vsync_end = vmode->vde + vborder + vmode->vfp + vmode->vsync;
791 adjusted_mode->crtc_vtotal = vmode->vt;
792 }
793
794 return 0;
795 }
796
797 static void
ast_crtc_helper_atomic_flush(struct drm_crtc * crtc,struct drm_atomic_state * state)798 ast_crtc_helper_atomic_flush(struct drm_crtc *crtc,
799 struct drm_atomic_state *state)
800 {
801 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
802 crtc);
803 struct drm_device *dev = crtc->dev;
804 struct ast_device *ast = to_ast_device(dev);
805 struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state);
806
807 /*
808 * The gamma LUT has to be reloaded after changing the primary
809 * plane's color format.
810 */
811 if (crtc_state->enable && crtc_state->color_mgmt_changed) {
812 if (crtc_state->gamma_lut)
813 ast_crtc_set_gamma(ast,
814 ast_crtc_state->format,
815 crtc_state->gamma_lut->data);
816 else
817 ast_crtc_set_gamma_linear(ast, ast_crtc_state->format);
818 }
819 }
820
ast_crtc_helper_atomic_enable(struct drm_crtc * crtc,struct drm_atomic_state * state)821 static void ast_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state)
822 {
823 struct ast_device *ast = to_ast_device(crtc->dev);
824
825 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb6, 0xfc, 0x00);
826 ast_set_index_reg_mask(ast, AST_IO_VGASRI, 0x01, 0xdf, 0x00);
827 }
828
ast_crtc_helper_atomic_disable(struct drm_crtc * crtc,struct drm_atomic_state * state)829 static void ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state)
830 {
831 struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
832 struct ast_device *ast = to_ast_device(crtc->dev);
833 u8 vgacrb6;
834
835 ast_set_index_reg_mask(ast, AST_IO_VGASRI, 0x01, 0xdf, AST_IO_VGASR1_SD);
836
837 vgacrb6 = AST_IO_VGACRB6_VSYNC_OFF |
838 AST_IO_VGACRB6_HSYNC_OFF;
839 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb6, 0xfc, vgacrb6);
840
841 /*
842 * HW cursors require the underlying primary plane and CRTC to
843 * display a valid mode and image. This is not the case during
844 * full modeset operations. So we temporarily disable any active
845 * plane, including the HW cursor. Each plane's atomic_update()
846 * helper will re-enable it if necessary.
847 *
848 * We only do this during *full* modesets. It does not affect
849 * simple pageflips on the planes.
850 */
851 drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false);
852 }
853
854 static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = {
855 .mode_valid = ast_crtc_helper_mode_valid,
856 .mode_set_nofb = ast_crtc_helper_mode_set_nofb,
857 .atomic_check = ast_crtc_helper_atomic_check,
858 .atomic_flush = ast_crtc_helper_atomic_flush,
859 .atomic_enable = ast_crtc_helper_atomic_enable,
860 .atomic_disable = ast_crtc_helper_atomic_disable,
861 };
862
ast_crtc_reset(struct drm_crtc * crtc)863 static void ast_crtc_reset(struct drm_crtc *crtc)
864 {
865 struct ast_crtc_state *ast_state =
866 kzalloc(sizeof(*ast_state), GFP_KERNEL);
867
868 if (crtc->state)
869 crtc->funcs->atomic_destroy_state(crtc, crtc->state);
870
871 if (ast_state)
872 __drm_atomic_helper_crtc_reset(crtc, &ast_state->base);
873 else
874 __drm_atomic_helper_crtc_reset(crtc, NULL);
875 }
876
877 static struct drm_crtc_state *
ast_crtc_atomic_duplicate_state(struct drm_crtc * crtc)878 ast_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
879 {
880 struct ast_crtc_state *new_ast_state, *ast_state;
881 struct drm_device *dev = crtc->dev;
882
883 if (drm_WARN_ON(dev, !crtc->state))
884 return NULL;
885
886 new_ast_state = kmalloc(sizeof(*new_ast_state), GFP_KERNEL);
887 if (!new_ast_state)
888 return NULL;
889 __drm_atomic_helper_crtc_duplicate_state(crtc, &new_ast_state->base);
890
891 ast_state = to_ast_crtc_state(crtc->state);
892
893 new_ast_state->format = ast_state->format;
894 new_ast_state->std_table = ast_state->std_table;
895 new_ast_state->vmode = ast_state->vmode;
896
897 return &new_ast_state->base;
898 }
899
ast_crtc_atomic_destroy_state(struct drm_crtc * crtc,struct drm_crtc_state * state)900 static void ast_crtc_atomic_destroy_state(struct drm_crtc *crtc,
901 struct drm_crtc_state *state)
902 {
903 struct ast_crtc_state *ast_state = to_ast_crtc_state(state);
904
905 __drm_atomic_helper_crtc_destroy_state(&ast_state->base);
906 kfree(ast_state);
907 }
908
909 static const struct drm_crtc_funcs ast_crtc_funcs = {
910 .reset = ast_crtc_reset,
911 .destroy = drm_crtc_cleanup,
912 .set_config = drm_atomic_helper_set_config,
913 .page_flip = drm_atomic_helper_page_flip,
914 .atomic_duplicate_state = ast_crtc_atomic_duplicate_state,
915 .atomic_destroy_state = ast_crtc_atomic_destroy_state,
916 };
917
ast_crtc_init(struct ast_device * ast)918 static int ast_crtc_init(struct ast_device *ast)
919 {
920 struct drm_device *dev = &ast->base;
921 struct drm_crtc *crtc = &ast->crtc;
922 int ret;
923
924 ret = drm_crtc_init_with_planes(dev, crtc, &ast->primary_plane.base,
925 &ast->cursor_plane.base.base, &ast_crtc_funcs,
926 NULL);
927 if (ret)
928 return ret;
929
930 drm_mode_crtc_set_gamma_size(crtc, AST_LUT_SIZE);
931 drm_crtc_enable_color_mgmt(crtc, 0, false, AST_LUT_SIZE);
932
933 drm_crtc_helper_add(crtc, &ast_crtc_helper_funcs);
934
935 return 0;
936 }
937
938 /*
939 * Mode config
940 */
941
ast_mode_config_helper_atomic_commit_tail(struct drm_atomic_state * state)942 static void ast_mode_config_helper_atomic_commit_tail(struct drm_atomic_state *state)
943 {
944 struct ast_device *ast = to_ast_device(state->dev);
945
946 /*
947 * Concurrent operations could possibly trigger a call to
948 * drm_connector_helper_funcs.get_modes by reading the display
949 * modes. Protect access to registers by acquiring the modeset
950 * lock.
951 */
952 mutex_lock(&ast->modeset_lock);
953 drm_atomic_helper_commit_tail(state);
954 mutex_unlock(&ast->modeset_lock);
955 }
956
957 static const struct drm_mode_config_helper_funcs ast_mode_config_helper_funcs = {
958 .atomic_commit_tail = ast_mode_config_helper_atomic_commit_tail,
959 };
960
ast_mode_config_mode_valid(struct drm_device * dev,const struct drm_display_mode * mode)961 static enum drm_mode_status ast_mode_config_mode_valid(struct drm_device *dev,
962 const struct drm_display_mode *mode)
963 {
964 const struct drm_format_info *info = drm_format_info(DRM_FORMAT_XRGB8888);
965 struct ast_device *ast = to_ast_device(dev);
966 unsigned long max_fb_size = ast_fb_vram_size(ast);
967 u64 pitch;
968
969 if (drm_WARN_ON_ONCE(dev, !info))
970 return MODE_ERROR; /* driver bug */
971
972 pitch = drm_format_info_min_pitch(info, 0, mode->hdisplay);
973 if (!pitch)
974 return MODE_BAD_WIDTH;
975 if (pitch > AST_PRIMARY_PLANE_MAX_OFFSET)
976 return MODE_BAD_WIDTH; /* maximum programmable pitch */
977 if (pitch > max_fb_size / mode->vdisplay)
978 return MODE_MEM;
979
980 return MODE_OK;
981 }
982
983 static const struct drm_mode_config_funcs ast_mode_config_funcs = {
984 .fb_create = drm_gem_fb_create_with_dirty,
985 .mode_valid = ast_mode_config_mode_valid,
986 .atomic_check = drm_atomic_helper_check,
987 .atomic_commit = drm_atomic_helper_commit,
988 };
989
ast_mode_config_init(struct ast_device * ast)990 int ast_mode_config_init(struct ast_device *ast)
991 {
992 struct drm_device *dev = &ast->base;
993 int ret;
994
995 ret = drmm_mutex_init(dev, &ast->modeset_lock);
996 if (ret)
997 return ret;
998
999 ret = drmm_mode_config_init(dev);
1000 if (ret)
1001 return ret;
1002
1003 dev->mode_config.funcs = &ast_mode_config_funcs;
1004 dev->mode_config.min_width = 0;
1005 dev->mode_config.min_height = 0;
1006 dev->mode_config.preferred_depth = 24;
1007
1008 if (ast->support_fullhd) {
1009 dev->mode_config.max_width = 1920;
1010 dev->mode_config.max_height = 2048;
1011 } else {
1012 dev->mode_config.max_width = 1600;
1013 dev->mode_config.max_height = 1200;
1014 }
1015
1016 dev->mode_config.helper_private = &ast_mode_config_helper_funcs;
1017
1018 ret = ast_primary_plane_init(ast);
1019 if (ret)
1020 return ret;
1021
1022 ret = ast_cursor_plane_init(ast);
1023 if (ret)
1024 return ret;
1025
1026 ret = ast_crtc_init(ast);
1027 if (ret)
1028 return ret;
1029
1030 switch (ast->tx_chip) {
1031 case AST_TX_NONE:
1032 ret = ast_vga_output_init(ast);
1033 break;
1034 case AST_TX_SIL164:
1035 ret = ast_sil164_output_init(ast);
1036 break;
1037 case AST_TX_DP501:
1038 ret = ast_dp501_output_init(ast);
1039 break;
1040 case AST_TX_ASTDP:
1041 ret = ast_astdp_output_init(ast);
1042 break;
1043 }
1044 if (ret)
1045 return ret;
1046
1047 drm_mode_config_reset(dev);
1048 drmm_kms_helper_poll_init(dev);
1049
1050 return 0;
1051 }
1052