Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/drm/ast/ast_2100.c
51344 views
1
// SPDX-License-Identifier: MIT
2
/*
3
* Copyright 2012 Red Hat Inc.
4
*
5
* Permission is hereby granted, free of charge, to any person obtaining a
6
* copy of this software and associated documentation files (the
7
* "Software"), to deal in the Software without restriction, including
8
* without limitation the rights to use, copy, modify, merge, publish,
9
* distribute, sub license, and/or sell copies of the Software, and to
10
* permit persons to whom the Software is furnished to do so, subject to
11
* the following conditions:
12
*
13
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
16
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
17
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
19
* USE OR OTHER DEALINGS IN THE SOFTWARE.
20
*
21
* The above copyright notice and this permission notice (including the
22
* next paragraph) shall be included in all copies or substantial portions
23
* of the Software.
24
*/
25
/*
26
* Authors: Dave Airlie <[email protected]>
27
*/
28
29
#include <linux/delay.h>
30
#include <linux/pci.h>
31
32
#include <drm/drm_drv.h>
33
34
#include "ast_drv.h"
35
#include "ast_post.h"
36
37
/*
38
* DRAM type
39
*/
40
41
static enum ast_dram_layout ast_2100_get_dram_layout_p2a(struct ast_device *ast)
42
{
43
u32 mcr_cfg;
44
enum ast_dram_layout dram_layout;
45
46
ast_write32(ast, 0xf004, 0x1e6e0000);
47
ast_write32(ast, 0xf000, 0x1);
48
mcr_cfg = ast_read32(ast, 0x10004);
49
50
switch (mcr_cfg & 0x0c) {
51
case 0:
52
case 4:
53
default:
54
dram_layout = AST_DRAM_512Mx16;
55
break;
56
case 8:
57
if (mcr_cfg & 0x40)
58
dram_layout = AST_DRAM_1Gx16;
59
else
60
dram_layout = AST_DRAM_512Mx32;
61
break;
62
case 0xc:
63
dram_layout = AST_DRAM_1Gx32;
64
break;
65
}
66
67
return dram_layout;
68
}
69
70
/*
71
* POST
72
*/
73
74
static const struct ast_dramstruct ast1100_dram_table_data[] = {
75
{ 0x2000, 0x1688a8a8 },
76
{ 0x2020, 0x000041f0 },
77
AST_DRAMSTRUCT_UDELAY(67u),
78
{ 0x0000, 0xfc600309 },
79
{ 0x006C, 0x00909090 },
80
{ 0x0064, 0x00050000 },
81
AST_DRAMSTRUCT_INIT(DRAM_TYPE, 0x00000585),
82
{ 0x0008, 0x0011030f },
83
{ 0x0010, 0x22201724 },
84
{ 0x0018, 0x1e29011a },
85
{ 0x0020, 0x00c82222 },
86
{ 0x0014, 0x01001523 },
87
{ 0x001C, 0x1024010d },
88
{ 0x0024, 0x00cb2522 },
89
{ 0x0038, 0xffffff82 },
90
{ 0x003C, 0x00000000 },
91
{ 0x0040, 0x00000000 },
92
{ 0x0044, 0x00000000 },
93
{ 0x0048, 0x00000000 },
94
{ 0x004C, 0x00000000 },
95
{ 0x0050, 0x00000000 },
96
{ 0x0054, 0x00000000 },
97
{ 0x0058, 0x00000000 },
98
{ 0x005C, 0x00000000 },
99
{ 0x0060, 0x032aa02a },
100
{ 0x0064, 0x002d3000 },
101
{ 0x0068, 0x00000000 },
102
{ 0x0070, 0x00000000 },
103
{ 0x0074, 0x00000000 },
104
{ 0x0078, 0x00000000 },
105
{ 0x007C, 0x00000000 },
106
{ 0x0034, 0x00000001 },
107
AST_DRAMSTRUCT_UDELAY(67u),
108
{ 0x002C, 0x00000732 },
109
{ 0x0030, 0x00000040 },
110
{ 0x0028, 0x00000005 },
111
{ 0x0028, 0x00000007 },
112
{ 0x0028, 0x00000003 },
113
{ 0x0028, 0x00000001 },
114
{ 0x000C, 0x00005a08 },
115
{ 0x002C, 0x00000632 },
116
{ 0x0028, 0x00000001 },
117
{ 0x0030, 0x000003c0 },
118
{ 0x0028, 0x00000003 },
119
{ 0x0030, 0x00000040 },
120
{ 0x0028, 0x00000003 },
121
{ 0x000C, 0x00005a21 },
122
{ 0x0034, 0x00007c03 },
123
{ 0x0120, 0x00004c41 },
124
AST_DRAMSTRUCT_INVALID,
125
};
126
127
static const struct ast_dramstruct ast2100_dram_table_data[] = {
128
{ 0x2000, 0x1688a8a8 },
129
{ 0x2020, 0x00004120 },
130
AST_DRAMSTRUCT_UDELAY(67u),
131
{ 0x0000, 0xfc600309 },
132
{ 0x006C, 0x00909090 },
133
{ 0x0064, 0x00070000 },
134
AST_DRAMSTRUCT_INIT(DRAM_TYPE, 0x00000489),
135
{ 0x0008, 0x0011030f },
136
{ 0x0010, 0x32302926 },
137
{ 0x0018, 0x274c0122 },
138
{ 0x0020, 0x00ce2222 },
139
{ 0x0014, 0x01001523 },
140
{ 0x001C, 0x1024010d },
141
{ 0x0024, 0x00cb2522 },
142
{ 0x0038, 0xffffff82 },
143
{ 0x003C, 0x00000000 },
144
{ 0x0040, 0x00000000 },
145
{ 0x0044, 0x00000000 },
146
{ 0x0048, 0x00000000 },
147
{ 0x004C, 0x00000000 },
148
{ 0x0050, 0x00000000 },
149
{ 0x0054, 0x00000000 },
150
{ 0x0058, 0x00000000 },
151
{ 0x005C, 0x00000000 },
152
{ 0x0060, 0x0f2aa02a },
153
{ 0x0064, 0x003f3005 },
154
{ 0x0068, 0x02020202 },
155
{ 0x0070, 0x00000000 },
156
{ 0x0074, 0x00000000 },
157
{ 0x0078, 0x00000000 },
158
{ 0x007C, 0x00000000 },
159
{ 0x0034, 0x00000001 },
160
AST_DRAMSTRUCT_UDELAY(67u),
161
{ 0x002C, 0x00000942 },
162
{ 0x0030, 0x00000040 },
163
{ 0x0028, 0x00000005 },
164
{ 0x0028, 0x00000007 },
165
{ 0x0028, 0x00000003 },
166
{ 0x0028, 0x00000001 },
167
{ 0x000C, 0x00005a08 },
168
{ 0x002C, 0x00000842 },
169
{ 0x0028, 0x00000001 },
170
{ 0x0030, 0x000003c0 },
171
{ 0x0028, 0x00000003 },
172
{ 0x0030, 0x00000040 },
173
{ 0x0028, 0x00000003 },
174
{ 0x000C, 0x00005a21 },
175
{ 0x0034, 0x00007c03 },
176
{ 0x0120, 0x00005061 },
177
AST_DRAMSTRUCT_INVALID,
178
};
179
180
/*
181
* AST2100/2150 DLL CBR Setting
182
*/
183
#define CBR_SIZE_AST2150 ((16 << 10) - 1)
184
#define CBR_PASSNUM_AST2150 5
185
#define CBR_THRESHOLD_AST2150 10
186
#define CBR_THRESHOLD2_AST2150 10
187
#define TIMEOUT_AST2150 5000000
188
189
#define CBR_PATNUM_AST2150 8
190
191
static const u32 pattern_AST2150[14] = {
192
0xFF00FF00,
193
0xCC33CC33,
194
0xAA55AA55,
195
0xFFFE0001,
196
0x683501FE,
197
0x0F1929B0,
198
0x2D0B4346,
199
0x60767F02,
200
0x6FBE36A6,
201
0x3A253035,
202
0x3019686D,
203
0x41C6167E,
204
0x620152BF,
205
0x20F050E0
206
};
207
208
static u32 mmctestburst2_ast2150(struct ast_device *ast, u32 datagen)
209
{
210
u32 data, timeout;
211
212
ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
213
ast_moutdwm(ast, 0x1e6e0070, 0x00000001 | (datagen << 3));
214
timeout = 0;
215
do {
216
data = ast_mindwm(ast, 0x1e6e0070) & 0x40;
217
if (++timeout > TIMEOUT_AST2150) {
218
ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
219
return 0xffffffff;
220
}
221
} while (!data);
222
ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
223
ast_moutdwm(ast, 0x1e6e0070, 0x00000003 | (datagen << 3));
224
timeout = 0;
225
do {
226
data = ast_mindwm(ast, 0x1e6e0070) & 0x40;
227
if (++timeout > TIMEOUT_AST2150) {
228
ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
229
return 0xffffffff;
230
}
231
} while (!data);
232
data = (ast_mindwm(ast, 0x1e6e0070) & 0x80) >> 7;
233
ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
234
return data;
235
}
236
237
static int cbrtest_ast2150(struct ast_device *ast)
238
{
239
int i;
240
241
for (i = 0; i < 8; i++)
242
if (mmctestburst2_ast2150(ast, i))
243
return 0;
244
return 1;
245
}
246
247
static int cbrscan_ast2150(struct ast_device *ast, int busw)
248
{
249
u32 patcnt, loop;
250
251
for (patcnt = 0; patcnt < CBR_PATNUM_AST2150; patcnt++) {
252
ast_moutdwm(ast, 0x1e6e007c, pattern_AST2150[patcnt]);
253
for (loop = 0; loop < CBR_PASSNUM_AST2150; loop++) {
254
if (cbrtest_ast2150(ast))
255
break;
256
}
257
if (loop == CBR_PASSNUM_AST2150)
258
return 0;
259
}
260
return 1;
261
}
262
263
static void cbrdlli_ast2150(struct ast_device *ast, int busw)
264
{
265
u32 dll_min[4], dll_max[4], dlli, data, passcnt;
266
267
cbr_start:
268
dll_min[0] = 0xff;
269
dll_min[1] = 0xff;
270
dll_min[2] = 0xff;
271
dll_min[3] = 0xff;
272
dll_max[0] = 0x00;
273
dll_max[1] = 0x00;
274
dll_max[2] = 0x00;
275
dll_max[3] = 0x00;
276
passcnt = 0;
277
278
for (dlli = 0; dlli < 100; dlli++) {
279
ast_moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24));
280
data = cbrscan_ast2150(ast, busw);
281
if (data != 0) {
282
if (data & 0x1) {
283
if (dll_min[0] > dlli)
284
dll_min[0] = dlli;
285
if (dll_max[0] < dlli)
286
dll_max[0] = dlli;
287
}
288
passcnt++;
289
} else if (passcnt >= CBR_THRESHOLD_AST2150) {
290
goto cbr_start;
291
}
292
}
293
if (dll_max[0] == 0 || (dll_max[0] - dll_min[0]) < CBR_THRESHOLD_AST2150)
294
goto cbr_start;
295
296
dlli = dll_min[0] + (((dll_max[0] - dll_min[0]) * 7) >> 4);
297
ast_moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24));
298
}
299
300
static void ast_post_chip_2100(struct ast_device *ast)
301
{
302
u8 j;
303
u32 data, temp, i;
304
const struct ast_dramstruct *dram_reg_info;
305
enum ast_dram_layout dram_layout = ast_2100_get_dram_layout_p2a(ast);
306
307
j = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff);
308
309
if ((j & 0x80) == 0) { /* VGA only */
310
if (ast->chip == AST2100 || ast->chip == AST2200)
311
dram_reg_info = ast2100_dram_table_data;
312
else
313
dram_reg_info = ast1100_dram_table_data;
314
315
ast_write32(ast, 0xf004, 0x1e6e0000);
316
ast_write32(ast, 0xf000, 0x1);
317
ast_write32(ast, 0x12000, 0x1688A8A8);
318
do {
319
;
320
} while (ast_read32(ast, 0x12000) != 0x01);
321
322
ast_write32(ast, 0x10000, 0xfc600309);
323
do {
324
;
325
} while (ast_read32(ast, 0x10000) != 0x01);
326
327
while (!AST_DRAMSTRUCT_IS(dram_reg_info, INVALID)) {
328
if (AST_DRAMSTRUCT_IS(dram_reg_info, UDELAY)) {
329
for (i = 0; i < 15; i++)
330
udelay(dram_reg_info->data);
331
} else if (AST_DRAMSTRUCT_IS(dram_reg_info, DRAM_TYPE)) {
332
switch (dram_layout) {
333
case AST_DRAM_1Gx16:
334
data = 0x00000d89;
335
break;
336
case AST_DRAM_1Gx32:
337
data = 0x00000c8d;
338
break;
339
default:
340
data = dram_reg_info->data;
341
break;
342
}
343
344
temp = ast_read32(ast, 0x12070);
345
temp &= 0xc;
346
temp <<= 2;
347
ast_write32(ast, 0x10000 + dram_reg_info->index, data | temp);
348
} else {
349
ast_write32(ast, 0x10000 + dram_reg_info->index,
350
dram_reg_info->data);
351
}
352
dram_reg_info++;
353
}
354
355
/* AST 2100/2150 DRAM calibration */
356
data = ast_read32(ast, 0x10120);
357
if (data == 0x5061) { /* 266Mhz */
358
data = ast_read32(ast, 0x10004);
359
if (data & 0x40)
360
cbrdlli_ast2150(ast, 16); /* 16 bits */
361
else
362
cbrdlli_ast2150(ast, 32); /* 32 bits */
363
}
364
365
temp = ast_read32(ast, 0x1200c);
366
ast_write32(ast, 0x1200c, temp & 0xfffffffd);
367
temp = ast_read32(ast, 0x12040);
368
ast_write32(ast, 0x12040, temp | 0x40);
369
}
370
371
/* wait ready */
372
do {
373
j = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff);
374
} while ((j & 0x40) == 0);
375
}
376
377
int ast_2100_post(struct ast_device *ast)
378
{
379
ast_2000_set_def_ext_reg(ast);
380
381
if (ast->config_mode == ast_use_p2a) {
382
ast_post_chip_2100(ast);
383
} else {
384
if (ast->tx_chip == AST_TX_SIL164) {
385
/* Enable DVO */
386
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x80);
387
}
388
}
389
390
return 0;
391
}
392
393
/*
394
* Widescreen detection
395
*/
396
397
/* Try to detect WSXGA+ on Gen2+ */
398
bool __ast_2100_detect_wsxga_p(struct ast_device *ast)
399
{
400
u8 vgacrd0 = ast_get_index_reg(ast, AST_IO_VGACRI, 0xd0);
401
402
if (!(vgacrd0 & AST_IO_VGACRD0_VRAM_INIT_BY_BMC))
403
return true;
404
if (vgacrd0 & AST_IO_VGACRD0_IKVM_WIDESCREEN)
405
return true;
406
407
return false;
408
}
409
410
/* Try to detect WUXGA on Gen2+ */
411
bool __ast_2100_detect_wuxga(struct ast_device *ast)
412
{
413
u8 vgacrd1;
414
415
if (ast->support_fullhd) {
416
vgacrd1 = ast_get_index_reg(ast, AST_IO_VGACRI, 0xd1);
417
if (!(vgacrd1 & AST_IO_VGACRD1_SUPPORTS_WUXGA))
418
return true;
419
}
420
421
return false;
422
}
423
424
static void ast_2100_detect_widescreen(struct ast_device *ast)
425
{
426
if (__ast_2100_detect_wsxga_p(ast)) {
427
ast->support_wsxga_p = true;
428
if (ast->chip == AST2100)
429
ast->support_fullhd = true;
430
}
431
if (__ast_2100_detect_wuxga(ast))
432
ast->support_wuxga = true;
433
}
434
435
static const struct ast_device_quirks ast_2100_device_quirks = {
436
.crtc_mem_req_threshold_low = 47,
437
.crtc_mem_req_threshold_high = 63,
438
};
439
440
struct drm_device *ast_2100_device_create(struct pci_dev *pdev,
441
const struct drm_driver *drv,
442
enum ast_chip chip,
443
enum ast_config_mode config_mode,
444
void __iomem *regs,
445
void __iomem *ioregs,
446
bool need_post)
447
{
448
struct drm_device *dev;
449
struct ast_device *ast;
450
int ret;
451
452
ast = devm_drm_dev_alloc(&pdev->dev, drv, struct ast_device, base);
453
if (IS_ERR(ast))
454
return ERR_CAST(ast);
455
dev = &ast->base;
456
457
ast_device_init(ast, chip, config_mode, regs, ioregs, &ast_2100_device_quirks);
458
459
ast->dclk_table = ast_2000_dclk_table;
460
461
ast_2000_detect_tx_chip(ast, need_post);
462
463
if (need_post) {
464
ret = ast_post_gpu(ast);
465
if (ret)
466
return ERR_PTR(ret);
467
}
468
469
ret = ast_mm_init(ast);
470
if (ret)
471
return ERR_PTR(ret);
472
473
ast_2100_detect_widescreen(ast);
474
475
ret = ast_mode_config_init(ast);
476
if (ret)
477
return ERR_PTR(ret);
478
479
return dev;
480
}
481
482