xref: /linux/drivers/gpu/drm/ast/ast_2100.c (revision 74ba587f402d5501af2c85e50cf1e4044263b6ca)
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 <airlied@redhat.com>
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