Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/drm/ast/ast_mode.c
49766 views
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 <[email protected]>
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_color_mgmt.h>
37
#include <drm/drm_crtc.h>
38
#include <drm/drm_damage_helper.h>
39
#include <drm/drm_format_helper.h>
40
#include <drm/drm_fourcc.h>
41
#include <drm/drm_gem_atomic_helper.h>
42
#include <drm/drm_gem_framebuffer_helper.h>
43
#include <drm/drm_gem_shmem_helper.h>
44
#include <drm/drm_managed.h>
45
#include <drm/drm_panic.h>
46
#include <drm/drm_print.h>
47
#include <drm/drm_probe_helper.h>
48
49
#include "ast_drv.h"
50
#include "ast_tables.h"
51
#include "ast_vbios.h"
52
53
#define AST_LUT_SIZE 256
54
55
#define AST_PRIMARY_PLANE_MAX_OFFSET (BIT(16) - 1)
56
57
static unsigned long ast_fb_vram_offset(void)
58
{
59
return 0; // with shmem, the primary plane is always at offset 0
60
}
61
62
static unsigned long ast_fb_vram_size(struct ast_device *ast)
63
{
64
struct drm_device *dev = &ast->base;
65
unsigned long offset = ast_fb_vram_offset(); // starts at offset
66
long cursor_offset = ast_cursor_vram_offset(ast); // ends at cursor offset
67
68
if (cursor_offset < 0)
69
cursor_offset = ast->vram_size; // no cursor; it's all ours
70
if (drm_WARN_ON_ONCE(dev, offset > cursor_offset))
71
return 0; // cannot legally happen; signal error
72
return cursor_offset - offset;
73
}
74
75
static void ast_set_gamma_lut(struct drm_crtc *crtc, unsigned int index,
76
u16 red, u16 green, u16 blue)
77
{
78
struct drm_device *dev = crtc->dev;
79
struct ast_device *ast = to_ast_device(dev);
80
u8 i8 = index & 0xff;
81
u8 r8 = red >> 8;
82
u8 g8 = green >> 8;
83
u8 b8 = blue >> 8;
84
85
if (drm_WARN_ON_ONCE(dev, index != i8))
86
return; /* driver bug */
87
88
ast_io_write8(ast, AST_IO_VGADWR, i8);
89
ast_io_read8(ast, AST_IO_VGASRI);
90
ast_io_write8(ast, AST_IO_VGAPDR, r8);
91
ast_io_read8(ast, AST_IO_VGASRI);
92
ast_io_write8(ast, AST_IO_VGAPDR, g8);
93
ast_io_read8(ast, AST_IO_VGASRI);
94
ast_io_write8(ast, AST_IO_VGAPDR, b8);
95
ast_io_read8(ast, AST_IO_VGASRI);
96
}
97
98
static void ast_crtc_fill_gamma(struct ast_device *ast,
99
const struct drm_format_info *format)
100
{
101
struct drm_crtc *crtc = &ast->crtc;
102
103
switch (format->format) {
104
case DRM_FORMAT_C8:
105
/* gamma table is used as color palette */
106
drm_crtc_fill_palette_8(crtc, ast_set_gamma_lut);
107
break;
108
case DRM_FORMAT_RGB565:
109
/* also uses 8-bit gamma ramp on low-color modes */
110
fallthrough;
111
case DRM_FORMAT_XRGB8888:
112
drm_crtc_fill_gamma_888(crtc, ast_set_gamma_lut);
113
break;
114
default:
115
drm_warn_once(&ast->base, "Unsupported format %p4cc for gamma correction\n",
116
&format->format);
117
break;
118
}
119
}
120
121
static void ast_crtc_load_gamma(struct ast_device *ast,
122
const struct drm_format_info *format,
123
struct drm_color_lut *lut)
124
{
125
struct drm_crtc *crtc = &ast->crtc;
126
127
switch (format->format) {
128
case DRM_FORMAT_C8:
129
/* gamma table is used as color palette */
130
drm_crtc_load_palette_8(crtc, lut, ast_set_gamma_lut);
131
break;
132
case DRM_FORMAT_RGB565:
133
/* also uses 8-bit gamma ramp on low-color modes */
134
fallthrough;
135
case DRM_FORMAT_XRGB8888:
136
drm_crtc_load_gamma_888(crtc, lut, ast_set_gamma_lut);
137
break;
138
default:
139
drm_warn_once(&ast->base, "Unsupported format %p4cc for gamma correction\n",
140
&format->format);
141
break;
142
}
143
}
144
145
static void ast_set_vbios_color_reg(struct ast_device *ast,
146
const struct drm_format_info *format,
147
const struct ast_vbios_enhtable *vmode)
148
{
149
u32 color_index;
150
151
switch (format->cpp[0]) {
152
case 1:
153
color_index = VGAModeIndex - 1;
154
break;
155
case 2:
156
color_index = HiCModeIndex;
157
break;
158
case 3:
159
case 4:
160
color_index = TrueCModeIndex;
161
break;
162
default:
163
return;
164
}
165
166
ast_set_index_reg(ast, AST_IO_VGACRI, 0x8c, (u8)((color_index & 0x0f) << 4));
167
168
ast_set_index_reg(ast, AST_IO_VGACRI, 0x91, 0x00);
169
170
if (vmode->flags & NewModeInfo) {
171
ast_set_index_reg(ast, AST_IO_VGACRI, 0x91, 0xa8);
172
ast_set_index_reg(ast, AST_IO_VGACRI, 0x92, format->cpp[0] * 8);
173
}
174
}
175
176
static void ast_set_vbios_mode_reg(struct ast_device *ast,
177
const struct drm_display_mode *adjusted_mode,
178
const struct ast_vbios_enhtable *vmode)
179
{
180
u32 refresh_rate_index, mode_id;
181
182
refresh_rate_index = vmode->refresh_rate_index;
183
mode_id = vmode->mode_id;
184
185
ast_set_index_reg(ast, AST_IO_VGACRI, 0x8d, refresh_rate_index & 0xff);
186
ast_set_index_reg(ast, AST_IO_VGACRI, 0x8e, mode_id & 0xff);
187
188
ast_set_index_reg(ast, AST_IO_VGACRI, 0x91, 0x00);
189
190
if (vmode->flags & NewModeInfo) {
191
ast_set_index_reg(ast, AST_IO_VGACRI, 0x91, 0xa8);
192
ast_set_index_reg(ast, AST_IO_VGACRI, 0x93, adjusted_mode->clock / 1000);
193
ast_set_index_reg(ast, AST_IO_VGACRI, 0x94, adjusted_mode->crtc_hdisplay);
194
ast_set_index_reg(ast, AST_IO_VGACRI, 0x95, adjusted_mode->crtc_hdisplay >> 8);
195
ast_set_index_reg(ast, AST_IO_VGACRI, 0x96, adjusted_mode->crtc_vdisplay);
196
ast_set_index_reg(ast, AST_IO_VGACRI, 0x97, adjusted_mode->crtc_vdisplay >> 8);
197
}
198
}
199
200
static void ast_set_std_reg(struct ast_device *ast,
201
struct drm_display_mode *mode,
202
const struct ast_vbios_stdtable *stdtable)
203
{
204
u32 i;
205
u8 jreg;
206
207
jreg = stdtable->misc;
208
ast_io_write8(ast, AST_IO_VGAMR_W, jreg);
209
210
/* Set SEQ; except Screen Disable field */
211
ast_set_index_reg(ast, AST_IO_VGASRI, 0x00, 0x03);
212
ast_set_index_reg_mask(ast, AST_IO_VGASRI, 0x01, 0x20, stdtable->seq[0]);
213
for (i = 1; i < 4; i++) {
214
jreg = stdtable->seq[i];
215
ast_set_index_reg(ast, AST_IO_VGASRI, (i + 1), jreg);
216
}
217
218
/* Set CRTC; except base address and offset */
219
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x11, 0x7f, 0x00);
220
for (i = 0; i < 12; i++)
221
ast_set_index_reg(ast, AST_IO_VGACRI, i, stdtable->crtc[i]);
222
for (i = 14; i < 19; i++)
223
ast_set_index_reg(ast, AST_IO_VGACRI, i, stdtable->crtc[i]);
224
for (i = 20; i < 25; i++)
225
ast_set_index_reg(ast, AST_IO_VGACRI, i, stdtable->crtc[i]);
226
227
/* set AR */
228
jreg = ast_io_read8(ast, AST_IO_VGAIR1_R);
229
for (i = 0; i < 20; i++) {
230
jreg = stdtable->ar[i];
231
ast_io_write8(ast, AST_IO_VGAARI_W, (u8)i);
232
ast_io_write8(ast, AST_IO_VGAARI_W, jreg);
233
}
234
ast_io_write8(ast, AST_IO_VGAARI_W, 0x14);
235
ast_io_write8(ast, AST_IO_VGAARI_W, 0x00);
236
237
jreg = ast_io_read8(ast, AST_IO_VGAIR1_R);
238
ast_io_write8(ast, AST_IO_VGAARI_W, 0x20);
239
240
/* Set GR */
241
for (i = 0; i < 9; i++)
242
ast_set_index_reg(ast, AST_IO_VGAGRI, i, stdtable->gr[i]);
243
}
244
245
static void ast_set_crtc_reg(struct ast_device *ast, struct drm_display_mode *mode,
246
const struct ast_vbios_enhtable *vmode)
247
{
248
u8 jreg05 = 0, jreg07 = 0, jreg09 = 0, jregAC = 0, jregAD = 0, jregAE = 0;
249
u16 temp;
250
unsigned char crtc_hsync_precatch = 0;
251
252
if (ast->quirks->crtc_hsync_precatch_needed && (vmode->flags & AST2500PreCatchCRT))
253
crtc_hsync_precatch = 40;
254
255
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x11, 0x7f, 0x00);
256
257
temp = (mode->crtc_htotal >> 3) - 5;
258
if (temp & 0x100)
259
jregAC |= 0x01; /* HT D[8] */
260
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x00, 0x00, temp);
261
262
temp = (mode->crtc_hdisplay >> 3) - 1;
263
if (temp & 0x100)
264
jregAC |= 0x04; /* HDE D[8] */
265
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x01, 0x00, temp);
266
267
temp = (mode->crtc_hblank_start >> 3) - 1;
268
if (temp & 0x100)
269
jregAC |= 0x10; /* HBS D[8] */
270
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x02, 0x00, temp);
271
272
temp = ((mode->crtc_hblank_end >> 3) - 1) & 0x7f;
273
if (temp & 0x20)
274
jreg05 |= 0x80; /* HBE D[5] */
275
if (temp & 0x40)
276
jregAD |= 0x01; /* HBE D[5] */
277
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x03, 0xE0, (temp & 0x1f));
278
279
temp = ((mode->crtc_hsync_start - crtc_hsync_precatch) >> 3) - 1;
280
if (temp & 0x100)
281
jregAC |= 0x40; /* HRS D[5] */
282
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x04, 0x00, temp);
283
284
temp = (((mode->crtc_hsync_end - crtc_hsync_precatch) >> 3) - 1) & 0x3f;
285
if (temp & 0x20)
286
jregAD |= 0x04; /* HRE D[5] */
287
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x05, 0x60, (u8)((temp & 0x1f) | jreg05));
288
289
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xAC, 0x00, jregAC);
290
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xAD, 0x00, jregAD);
291
292
if (ast->quirks->crtc_hsync_add4_needed && mode->crtc_vdisplay == 1080)
293
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xFC, 0xFD, 0x02);
294
else
295
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xFC, 0xFD, 0x00);
296
297
/* vert timings */
298
temp = (mode->crtc_vtotal) - 2;
299
if (temp & 0x100)
300
jreg07 |= 0x01;
301
if (temp & 0x200)
302
jreg07 |= 0x20;
303
if (temp & 0x400)
304
jregAE |= 0x01;
305
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x06, 0x00, temp);
306
307
temp = (mode->crtc_vsync_start) - 1;
308
if (temp & 0x100)
309
jreg07 |= 0x04;
310
if (temp & 0x200)
311
jreg07 |= 0x80;
312
if (temp & 0x400)
313
jregAE |= 0x08;
314
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x10, 0x00, temp);
315
316
temp = (mode->crtc_vsync_end - 1) & 0x3f;
317
if (temp & 0x10)
318
jregAE |= 0x20;
319
if (temp & 0x20)
320
jregAE |= 0x40;
321
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x11, 0x70, temp & 0xf);
322
323
temp = mode->crtc_vdisplay - 1;
324
if (temp & 0x100)
325
jreg07 |= 0x02;
326
if (temp & 0x200)
327
jreg07 |= 0x40;
328
if (temp & 0x400)
329
jregAE |= 0x02;
330
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x12, 0x00, temp);
331
332
temp = mode->crtc_vblank_start - 1;
333
if (temp & 0x100)
334
jreg07 |= 0x08;
335
if (temp & 0x200)
336
jreg09 |= 0x20;
337
if (temp & 0x400)
338
jregAE |= 0x04;
339
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x15, 0x00, temp);
340
341
temp = mode->crtc_vblank_end - 1;
342
if (temp & 0x100)
343
jregAE |= 0x10;
344
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x16, 0x00, temp);
345
346
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x07, 0x00, jreg07);
347
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x09, 0xdf, jreg09);
348
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xAE, 0x00, (jregAE | 0x80));
349
350
if (crtc_hsync_precatch)
351
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb6, 0x3f, 0x80);
352
else
353
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb6, 0x3f, 0x00);
354
355
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x11, 0x7f, 0x80);
356
}
357
358
static void ast_set_offset_reg(struct ast_device *ast,
359
struct drm_framebuffer *fb)
360
{
361
u16 offset;
362
363
offset = fb->pitches[0] >> 3;
364
ast_set_index_reg(ast, AST_IO_VGACRI, 0x13, (offset & 0xff));
365
ast_set_index_reg(ast, AST_IO_VGACRI, 0xb0, (offset >> 8) & 0x3f);
366
}
367
368
static void ast_set_dclk_reg(struct ast_device *ast,
369
struct drm_display_mode *mode,
370
const struct ast_vbios_enhtable *vmode)
371
{
372
const struct ast_vbios_dclk_info *clk_info = &ast->dclk_table[vmode->dclk_index];
373
374
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xc0, 0x00, clk_info->param1);
375
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xc1, 0x00, clk_info->param2);
376
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xbb, 0x0f,
377
(clk_info->param3 & 0xc0) |
378
((clk_info->param3 & 0x3) << 4));
379
}
380
381
static void ast_set_color_reg(struct ast_device *ast,
382
const struct drm_format_info *format)
383
{
384
u8 jregA0 = 0, jregA3 = 0, jregA8 = 0;
385
386
switch (format->cpp[0] * 8) {
387
case 8:
388
jregA0 = 0x70;
389
jregA3 = 0x01;
390
jregA8 = 0x00;
391
break;
392
case 15:
393
case 16:
394
jregA0 = 0x70;
395
jregA3 = 0x04;
396
jregA8 = 0x02;
397
break;
398
case 32:
399
jregA0 = 0x70;
400
jregA3 = 0x08;
401
jregA8 = 0x02;
402
break;
403
}
404
405
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa0, 0x8f, jregA0);
406
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xf0, jregA3);
407
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa8, 0xfd, jregA8);
408
}
409
410
static void ast_set_crtthd_reg(struct ast_device *ast)
411
{
412
u8 vgacra6 = ast->quirks->crtc_mem_req_threshold_low;
413
u8 vgacra7 = ast->quirks->crtc_mem_req_threshold_high;
414
415
ast_set_index_reg(ast, AST_IO_VGACRI, 0xa7, vgacra7);
416
ast_set_index_reg(ast, AST_IO_VGACRI, 0xa6, vgacra6);
417
}
418
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
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
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
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
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
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
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
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
/* if the buffer comes from another device */
561
if (drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE) == 0) {
562
drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
563
drm_atomic_for_each_plane_damage(&iter, &damage) {
564
ast_handle_damage(ast_plane, shadow_plane_state->data, fb, &damage);
565
}
566
567
drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
568
}
569
570
/*
571
* Some BMCs stop scanning out the video signal after the driver
572
* reprogrammed the offset. This stalls display output for several
573
* seconds and makes the display unusable. Therefore only update
574
* the offset if it changes.
575
*/
576
if (!old_fb || old_fb->pitches[0] != fb->pitches[0])
577
ast_set_offset_reg(ast, fb);
578
}
579
580
static void ast_primary_plane_helper_atomic_enable(struct drm_plane *plane,
581
struct drm_atomic_state *state)
582
{
583
struct ast_device *ast = to_ast_device(plane->dev);
584
struct ast_plane *ast_plane = to_ast_plane(plane);
585
586
/*
587
* Some BMCs stop scanning out the video signal after the driver
588
* reprogrammed the scanout address. This stalls display
589
* output for several seconds and makes the display unusable.
590
* Therefore only reprogram the address after enabling the plane.
591
*/
592
ast_set_start_address_crt1(ast, (u32)ast_plane->offset);
593
}
594
595
static void ast_primary_plane_helper_atomic_disable(struct drm_plane *plane,
596
struct drm_atomic_state *state)
597
{
598
/*
599
* Keep this empty function to avoid calling
600
* atomic_update when disabling the plane.
601
*/
602
}
603
604
static int ast_primary_plane_helper_get_scanout_buffer(struct drm_plane *plane,
605
struct drm_scanout_buffer *sb)
606
{
607
struct ast_plane *ast_plane = to_ast_plane(plane);
608
609
if (plane->state && plane->state->fb) {
610
sb->format = plane->state->fb->format;
611
sb->width = plane->state->fb->width;
612
sb->height = plane->state->fb->height;
613
sb->pitch[0] = plane->state->fb->pitches[0];
614
iosys_map_set_vaddr_iomem(&sb->map[0], ast_plane_vaddr(ast_plane));
615
return 0;
616
}
617
return -ENODEV;
618
}
619
620
static const struct drm_plane_helper_funcs ast_primary_plane_helper_funcs = {
621
DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
622
.atomic_check = ast_primary_plane_helper_atomic_check,
623
.atomic_update = ast_primary_plane_helper_atomic_update,
624
.atomic_enable = ast_primary_plane_helper_atomic_enable,
625
.atomic_disable = ast_primary_plane_helper_atomic_disable,
626
.get_scanout_buffer = ast_primary_plane_helper_get_scanout_buffer,
627
};
628
629
static const struct drm_plane_funcs ast_primary_plane_funcs = {
630
.update_plane = drm_atomic_helper_update_plane,
631
.disable_plane = drm_atomic_helper_disable_plane,
632
.destroy = drm_plane_cleanup,
633
DRM_GEM_SHADOW_PLANE_FUNCS,
634
};
635
636
static int ast_primary_plane_init(struct ast_device *ast)
637
{
638
struct drm_device *dev = &ast->base;
639
struct ast_plane *ast_primary_plane = &ast->primary_plane;
640
struct drm_plane *primary_plane = &ast_primary_plane->base;
641
u64 offset = ast_fb_vram_offset();
642
unsigned long size = ast_fb_vram_size(ast);
643
int ret;
644
645
ret = ast_plane_init(dev, ast_primary_plane, offset, size,
646
0x01, &ast_primary_plane_funcs,
647
ast_primary_plane_formats, ARRAY_SIZE(ast_primary_plane_formats),
648
NULL, DRM_PLANE_TYPE_PRIMARY);
649
if (ret) {
650
drm_err(dev, "ast_plane_init() failed: %d\n", ret);
651
return ret;
652
}
653
drm_plane_helper_add(primary_plane, &ast_primary_plane_helper_funcs);
654
drm_plane_enable_fb_damage_clips(primary_plane);
655
656
return 0;
657
}
658
659
/*
660
* CRTC
661
*/
662
663
static enum drm_mode_status
664
ast_crtc_helper_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
665
{
666
struct ast_device *ast = to_ast_device(crtc->dev);
667
const struct ast_vbios_enhtable *vmode;
668
669
vmode = ast_vbios_find_mode(ast, mode);
670
if (!vmode)
671
return MODE_NOMODE;
672
673
return MODE_OK;
674
}
675
676
static void ast_crtc_helper_mode_set_nofb(struct drm_crtc *crtc)
677
{
678
struct drm_device *dev = crtc->dev;
679
struct ast_device *ast = to_ast_device(dev);
680
struct drm_crtc_state *crtc_state = crtc->state;
681
struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state);
682
const struct ast_vbios_stdtable *std_table = ast_crtc_state->std_table;
683
const struct ast_vbios_enhtable *vmode = ast_crtc_state->vmode;
684
struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
685
686
/*
687
* Ensure that no scanout takes place before reprogramming mode
688
* and format registers.
689
*
690
* TODO: Get vblank interrupts working and remove this line.
691
*/
692
ast_wait_for_vretrace(ast);
693
694
ast_set_vbios_mode_reg(ast, adjusted_mode, vmode);
695
ast_set_index_reg(ast, AST_IO_VGACRI, 0xa1, 0x06);
696
ast_set_std_reg(ast, adjusted_mode, std_table);
697
ast_set_crtc_reg(ast, adjusted_mode, vmode);
698
ast_set_dclk_reg(ast, adjusted_mode, vmode);
699
ast_set_crtthd_reg(ast);
700
ast_set_sync_reg(ast, adjusted_mode, vmode);
701
}
702
703
static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc,
704
struct drm_atomic_state *state)
705
{
706
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
707
struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
708
struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
709
struct ast_crtc_state *old_ast_crtc_state = to_ast_crtc_state(old_crtc_state);
710
struct drm_device *dev = crtc->dev;
711
struct ast_device *ast = to_ast_device(dev);
712
struct ast_crtc_state *ast_state;
713
const struct drm_format_info *format;
714
const struct ast_vbios_enhtable *vmode;
715
unsigned int hborder = 0;
716
unsigned int vborder = 0;
717
int ret;
718
719
if (!crtc_state->enable)
720
return 0;
721
722
ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state);
723
if (ret)
724
return ret;
725
726
ast_state = to_ast_crtc_state(crtc_state);
727
728
format = ast_state->format;
729
if (drm_WARN_ON_ONCE(dev, !format))
730
return -EINVAL; /* BUG: We didn't set format in primary check(). */
731
732
/*
733
* The gamma LUT has to be reloaded after changing the primary
734
* plane's color format.
735
*/
736
if (old_ast_crtc_state->format != format)
737
crtc_state->color_mgmt_changed = true;
738
739
if (crtc_state->color_mgmt_changed && crtc_state->gamma_lut) {
740
if (crtc_state->gamma_lut->length !=
741
AST_LUT_SIZE * sizeof(struct drm_color_lut)) {
742
drm_err(dev, "Wrong size for gamma_lut %zu\n",
743
crtc_state->gamma_lut->length);
744
return -EINVAL;
745
}
746
}
747
748
/*
749
* Set register tables.
750
*
751
* TODO: These tables mix all kinds of fields and should
752
* probably be resolved into various helper functions.
753
*/
754
switch (format->format) {
755
case DRM_FORMAT_C8:
756
ast_state->std_table = &vbios_stdtable[VGAModeIndex];
757
break;
758
case DRM_FORMAT_RGB565:
759
ast_state->std_table = &vbios_stdtable[HiCModeIndex];
760
break;
761
case DRM_FORMAT_RGB888:
762
case DRM_FORMAT_XRGB8888:
763
ast_state->std_table = &vbios_stdtable[TrueCModeIndex];
764
break;
765
default:
766
return -EINVAL;
767
}
768
769
/*
770
* Find the VBIOS mode and adjust the DRM display mode accordingly
771
* if a full modeset is required. Otherwise keep the existing values.
772
*/
773
if (drm_atomic_crtc_needs_modeset(crtc_state)) {
774
vmode = ast_vbios_find_mode(ast, &crtc_state->mode);
775
if (!vmode)
776
return -EINVAL;
777
ast_state->vmode = vmode;
778
779
if (vmode->flags & HBorder)
780
hborder = 8;
781
if (vmode->flags & VBorder)
782
vborder = 8;
783
784
adjusted_mode->crtc_hdisplay = vmode->hde;
785
adjusted_mode->crtc_hblank_start = vmode->hde + hborder;
786
adjusted_mode->crtc_hblank_end = vmode->ht - hborder;
787
adjusted_mode->crtc_hsync_start = vmode->hde + hborder + vmode->hfp;
788
adjusted_mode->crtc_hsync_end = vmode->hde + hborder + vmode->hfp + vmode->hsync;
789
adjusted_mode->crtc_htotal = vmode->ht;
790
791
adjusted_mode->crtc_vdisplay = vmode->vde;
792
adjusted_mode->crtc_vblank_start = vmode->vde + vborder;
793
adjusted_mode->crtc_vblank_end = vmode->vt - vborder;
794
adjusted_mode->crtc_vsync_start = vmode->vde + vborder + vmode->vfp;
795
adjusted_mode->crtc_vsync_end = vmode->vde + vborder + vmode->vfp + vmode->vsync;
796
adjusted_mode->crtc_vtotal = vmode->vt;
797
}
798
799
return 0;
800
}
801
802
static void
803
ast_crtc_helper_atomic_flush(struct drm_crtc *crtc,
804
struct drm_atomic_state *state)
805
{
806
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
807
crtc);
808
struct drm_device *dev = crtc->dev;
809
struct ast_device *ast = to_ast_device(dev);
810
struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state);
811
812
/*
813
* The gamma LUT has to be reloaded after changing the primary
814
* plane's color format.
815
*/
816
if (crtc_state->enable && crtc_state->color_mgmt_changed) {
817
if (crtc_state->gamma_lut)
818
ast_crtc_load_gamma(ast,
819
ast_crtc_state->format,
820
crtc_state->gamma_lut->data);
821
else
822
ast_crtc_fill_gamma(ast, ast_crtc_state->format);
823
}
824
}
825
826
static void ast_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state)
827
{
828
struct ast_device *ast = to_ast_device(crtc->dev);
829
u8 vgacr17 = 0x00;
830
u8 vgacrb6 = 0xff;
831
832
vgacr17 |= AST_IO_VGACR17_SYNC_ENABLE;
833
vgacrb6 &= ~(AST_IO_VGACRB6_VSYNC_OFF | AST_IO_VGACRB6_HSYNC_OFF);
834
835
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x17, 0x7f, vgacr17);
836
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb6, 0xfc, vgacrb6);
837
}
838
839
static void ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state)
840
{
841
struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
842
struct ast_device *ast = to_ast_device(crtc->dev);
843
u8 vgacr17 = 0xff;
844
845
vgacr17 &= ~AST_IO_VGACR17_SYNC_ENABLE;
846
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x17, 0x7f, vgacr17);
847
848
/*
849
* HW cursors require the underlying primary plane and CRTC to
850
* display a valid mode and image. This is not the case during
851
* full modeset operations. So we temporarily disable any active
852
* plane, including the HW cursor. Each plane's atomic_update()
853
* helper will re-enable it if necessary.
854
*
855
* We only do this during *full* modesets. It does not affect
856
* simple pageflips on the planes.
857
*/
858
drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false);
859
}
860
861
static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = {
862
.mode_valid = ast_crtc_helper_mode_valid,
863
.mode_set_nofb = ast_crtc_helper_mode_set_nofb,
864
.atomic_check = ast_crtc_helper_atomic_check,
865
.atomic_flush = ast_crtc_helper_atomic_flush,
866
.atomic_enable = ast_crtc_helper_atomic_enable,
867
.atomic_disable = ast_crtc_helper_atomic_disable,
868
};
869
870
static void ast_crtc_reset(struct drm_crtc *crtc)
871
{
872
struct ast_crtc_state *ast_state =
873
kzalloc(sizeof(*ast_state), GFP_KERNEL);
874
875
if (crtc->state)
876
crtc->funcs->atomic_destroy_state(crtc, crtc->state);
877
878
if (ast_state)
879
__drm_atomic_helper_crtc_reset(crtc, &ast_state->base);
880
else
881
__drm_atomic_helper_crtc_reset(crtc, NULL);
882
}
883
884
static struct drm_crtc_state *
885
ast_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
886
{
887
struct ast_crtc_state *new_ast_state, *ast_state;
888
struct drm_device *dev = crtc->dev;
889
890
if (drm_WARN_ON(dev, !crtc->state))
891
return NULL;
892
893
new_ast_state = kmalloc(sizeof(*new_ast_state), GFP_KERNEL);
894
if (!new_ast_state)
895
return NULL;
896
__drm_atomic_helper_crtc_duplicate_state(crtc, &new_ast_state->base);
897
898
ast_state = to_ast_crtc_state(crtc->state);
899
900
new_ast_state->format = ast_state->format;
901
new_ast_state->std_table = ast_state->std_table;
902
new_ast_state->vmode = ast_state->vmode;
903
904
return &new_ast_state->base;
905
}
906
907
static void ast_crtc_atomic_destroy_state(struct drm_crtc *crtc,
908
struct drm_crtc_state *state)
909
{
910
struct ast_crtc_state *ast_state = to_ast_crtc_state(state);
911
912
__drm_atomic_helper_crtc_destroy_state(&ast_state->base);
913
kfree(ast_state);
914
}
915
916
static const struct drm_crtc_funcs ast_crtc_funcs = {
917
.reset = ast_crtc_reset,
918
.destroy = drm_crtc_cleanup,
919
.set_config = drm_atomic_helper_set_config,
920
.page_flip = drm_atomic_helper_page_flip,
921
.atomic_duplicate_state = ast_crtc_atomic_duplicate_state,
922
.atomic_destroy_state = ast_crtc_atomic_destroy_state,
923
};
924
925
static int ast_crtc_init(struct ast_device *ast)
926
{
927
struct drm_device *dev = &ast->base;
928
struct drm_crtc *crtc = &ast->crtc;
929
int ret;
930
931
ret = drm_crtc_init_with_planes(dev, crtc, &ast->primary_plane.base,
932
&ast->cursor_plane.base.base, &ast_crtc_funcs,
933
NULL);
934
if (ret)
935
return ret;
936
937
drm_mode_crtc_set_gamma_size(crtc, AST_LUT_SIZE);
938
drm_crtc_enable_color_mgmt(crtc, 0, false, AST_LUT_SIZE);
939
940
drm_crtc_helper_add(crtc, &ast_crtc_helper_funcs);
941
942
return 0;
943
}
944
945
/*
946
* Mode config
947
*/
948
949
static void ast_mode_config_helper_atomic_commit_tail(struct drm_atomic_state *state)
950
{
951
struct ast_device *ast = to_ast_device(state->dev);
952
953
/*
954
* Concurrent operations could possibly trigger a call to
955
* drm_connector_helper_funcs.get_modes by reading the display
956
* modes. Protect access to registers by acquiring the modeset
957
* lock.
958
*/
959
mutex_lock(&ast->modeset_lock);
960
drm_atomic_helper_commit_tail(state);
961
mutex_unlock(&ast->modeset_lock);
962
}
963
964
static const struct drm_mode_config_helper_funcs ast_mode_config_helper_funcs = {
965
.atomic_commit_tail = ast_mode_config_helper_atomic_commit_tail,
966
};
967
968
static enum drm_mode_status ast_mode_config_mode_valid(struct drm_device *dev,
969
const struct drm_display_mode *mode)
970
{
971
const struct drm_format_info *info = drm_format_info(DRM_FORMAT_XRGB8888);
972
struct ast_device *ast = to_ast_device(dev);
973
unsigned long max_fb_size = ast_fb_vram_size(ast);
974
u64 pitch;
975
976
if (drm_WARN_ON_ONCE(dev, !info))
977
return MODE_ERROR; /* driver bug */
978
979
pitch = drm_format_info_min_pitch(info, 0, mode->hdisplay);
980
if (!pitch)
981
return MODE_BAD_WIDTH;
982
if (pitch > AST_PRIMARY_PLANE_MAX_OFFSET)
983
return MODE_BAD_WIDTH; /* maximum programmable pitch */
984
if (pitch > max_fb_size / mode->vdisplay)
985
return MODE_MEM;
986
987
return MODE_OK;
988
}
989
990
static const struct drm_mode_config_funcs ast_mode_config_funcs = {
991
.fb_create = drm_gem_fb_create_with_dirty,
992
.mode_valid = ast_mode_config_mode_valid,
993
.atomic_check = drm_atomic_helper_check,
994
.atomic_commit = drm_atomic_helper_commit,
995
};
996
997
int ast_mode_config_init(struct ast_device *ast)
998
{
999
struct drm_device *dev = &ast->base;
1000
int ret;
1001
1002
ret = drmm_mutex_init(dev, &ast->modeset_lock);
1003
if (ret)
1004
return ret;
1005
1006
ret = drmm_mode_config_init(dev);
1007
if (ret)
1008
return ret;
1009
1010
dev->mode_config.funcs = &ast_mode_config_funcs;
1011
dev->mode_config.min_width = 0;
1012
dev->mode_config.min_height = 0;
1013
dev->mode_config.preferred_depth = 24;
1014
1015
if (ast->support_fullhd) {
1016
dev->mode_config.max_width = 1920;
1017
dev->mode_config.max_height = 2048;
1018
} else {
1019
dev->mode_config.max_width = 1600;
1020
dev->mode_config.max_height = 1200;
1021
}
1022
1023
dev->mode_config.helper_private = &ast_mode_config_helper_funcs;
1024
1025
ret = ast_primary_plane_init(ast);
1026
if (ret)
1027
return ret;
1028
1029
ret = ast_cursor_plane_init(ast);
1030
if (ret)
1031
return ret;
1032
1033
ret = ast_crtc_init(ast);
1034
if (ret)
1035
return ret;
1036
1037
switch (ast->tx_chip) {
1038
case AST_TX_NONE:
1039
ret = ast_vga_output_init(ast);
1040
break;
1041
case AST_TX_SIL164:
1042
ret = ast_sil164_output_init(ast);
1043
break;
1044
case AST_TX_DP501:
1045
ret = ast_dp501_output_init(ast);
1046
break;
1047
case AST_TX_ASTDP:
1048
ret = ast_astdp_output_init(ast);
1049
break;
1050
}
1051
if (ret)
1052
return ret;
1053
1054
drm_mode_config_reset(dev);
1055
drmm_kms_helper_poll_init(dev);
1056
1057
return 0;
1058
}
1059
1060