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