xref: /linux/drivers/gpu/drm/ast/ast_2100.c (revision 07fdad3a93756b872da7b53647715c48d0f4a2d0)
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 
31 #include "ast_drv.h"
32 #include "ast_post.h"
33 
34 /*
35  * DRAM type
36  */
37 
38 static enum ast_dram_layout ast_2100_get_dram_layout_p2a(struct ast_device *ast)
39 {
40 	u32 mcr_cfg;
41 	enum ast_dram_layout dram_layout;
42 
43 	ast_write32(ast, 0xf004, 0x1e6e0000);
44 	ast_write32(ast, 0xf000, 0x1);
45 	mcr_cfg = ast_read32(ast, 0x10004);
46 
47 	switch (mcr_cfg & 0x0c) {
48 	case 0:
49 	case 4:
50 	default:
51 		dram_layout = AST_DRAM_512Mx16;
52 		break;
53 	case 8:
54 		if (mcr_cfg & 0x40)
55 			dram_layout = AST_DRAM_1Gx16;
56 		else
57 			dram_layout = AST_DRAM_512Mx32;
58 		break;
59 	case 0xc:
60 		dram_layout = AST_DRAM_1Gx32;
61 		break;
62 	}
63 
64 	return dram_layout;
65 }
66 
67 /*
68  * POST
69  */
70 
71 static const struct ast_dramstruct ast1100_dram_table_data[] = {
72 	{ 0x2000, 0x1688a8a8 },
73 	{ 0x2020, 0x000041f0 },
74 	AST_DRAMSTRUCT_UDELAY(67u),
75 	{ 0x0000, 0xfc600309 },
76 	{ 0x006C, 0x00909090 },
77 	{ 0x0064, 0x00050000 },
78 	AST_DRAMSTRUCT_INIT(DRAM_TYPE, 0x00000585),
79 	{ 0x0008, 0x0011030f },
80 	{ 0x0010, 0x22201724 },
81 	{ 0x0018, 0x1e29011a },
82 	{ 0x0020, 0x00c82222 },
83 	{ 0x0014, 0x01001523 },
84 	{ 0x001C, 0x1024010d },
85 	{ 0x0024, 0x00cb2522 },
86 	{ 0x0038, 0xffffff82 },
87 	{ 0x003C, 0x00000000 },
88 	{ 0x0040, 0x00000000 },
89 	{ 0x0044, 0x00000000 },
90 	{ 0x0048, 0x00000000 },
91 	{ 0x004C, 0x00000000 },
92 	{ 0x0050, 0x00000000 },
93 	{ 0x0054, 0x00000000 },
94 	{ 0x0058, 0x00000000 },
95 	{ 0x005C, 0x00000000 },
96 	{ 0x0060, 0x032aa02a },
97 	{ 0x0064, 0x002d3000 },
98 	{ 0x0068, 0x00000000 },
99 	{ 0x0070, 0x00000000 },
100 	{ 0x0074, 0x00000000 },
101 	{ 0x0078, 0x00000000 },
102 	{ 0x007C, 0x00000000 },
103 	{ 0x0034, 0x00000001 },
104 	AST_DRAMSTRUCT_UDELAY(67u),
105 	{ 0x002C, 0x00000732 },
106 	{ 0x0030, 0x00000040 },
107 	{ 0x0028, 0x00000005 },
108 	{ 0x0028, 0x00000007 },
109 	{ 0x0028, 0x00000003 },
110 	{ 0x0028, 0x00000001 },
111 	{ 0x000C, 0x00005a08 },
112 	{ 0x002C, 0x00000632 },
113 	{ 0x0028, 0x00000001 },
114 	{ 0x0030, 0x000003c0 },
115 	{ 0x0028, 0x00000003 },
116 	{ 0x0030, 0x00000040 },
117 	{ 0x0028, 0x00000003 },
118 	{ 0x000C, 0x00005a21 },
119 	{ 0x0034, 0x00007c03 },
120 	{ 0x0120, 0x00004c41 },
121 	AST_DRAMSTRUCT_INVALID,
122 };
123 
124 static const struct ast_dramstruct ast2100_dram_table_data[] = {
125 	{ 0x2000, 0x1688a8a8 },
126 	{ 0x2020, 0x00004120 },
127 	AST_DRAMSTRUCT_UDELAY(67u),
128 	{ 0x0000, 0xfc600309 },
129 	{ 0x006C, 0x00909090 },
130 	{ 0x0064, 0x00070000 },
131 	AST_DRAMSTRUCT_INIT(DRAM_TYPE, 0x00000489),
132 	{ 0x0008, 0x0011030f },
133 	{ 0x0010, 0x32302926 },
134 	{ 0x0018, 0x274c0122 },
135 	{ 0x0020, 0x00ce2222 },
136 	{ 0x0014, 0x01001523 },
137 	{ 0x001C, 0x1024010d },
138 	{ 0x0024, 0x00cb2522 },
139 	{ 0x0038, 0xffffff82 },
140 	{ 0x003C, 0x00000000 },
141 	{ 0x0040, 0x00000000 },
142 	{ 0x0044, 0x00000000 },
143 	{ 0x0048, 0x00000000 },
144 	{ 0x004C, 0x00000000 },
145 	{ 0x0050, 0x00000000 },
146 	{ 0x0054, 0x00000000 },
147 	{ 0x0058, 0x00000000 },
148 	{ 0x005C, 0x00000000 },
149 	{ 0x0060, 0x0f2aa02a },
150 	{ 0x0064, 0x003f3005 },
151 	{ 0x0068, 0x02020202 },
152 	{ 0x0070, 0x00000000 },
153 	{ 0x0074, 0x00000000 },
154 	{ 0x0078, 0x00000000 },
155 	{ 0x007C, 0x00000000 },
156 	{ 0x0034, 0x00000001 },
157 	AST_DRAMSTRUCT_UDELAY(67u),
158 	{ 0x002C, 0x00000942 },
159 	{ 0x0030, 0x00000040 },
160 	{ 0x0028, 0x00000005 },
161 	{ 0x0028, 0x00000007 },
162 	{ 0x0028, 0x00000003 },
163 	{ 0x0028, 0x00000001 },
164 	{ 0x000C, 0x00005a08 },
165 	{ 0x002C, 0x00000842 },
166 	{ 0x0028, 0x00000001 },
167 	{ 0x0030, 0x000003c0 },
168 	{ 0x0028, 0x00000003 },
169 	{ 0x0030, 0x00000040 },
170 	{ 0x0028, 0x00000003 },
171 	{ 0x000C, 0x00005a21 },
172 	{ 0x0034, 0x00007c03 },
173 	{ 0x0120, 0x00005061 },
174 	AST_DRAMSTRUCT_INVALID,
175 };
176 
177 /*
178  * AST2100/2150 DLL CBR Setting
179  */
180 #define CBR_SIZE_AST2150	     ((16 << 10) - 1)
181 #define CBR_PASSNUM_AST2150          5
182 #define CBR_THRESHOLD_AST2150        10
183 #define CBR_THRESHOLD2_AST2150       10
184 #define TIMEOUT_AST2150              5000000
185 
186 #define CBR_PATNUM_AST2150           8
187 
188 static const u32 pattern_AST2150[14] = {
189 	0xFF00FF00,
190 	0xCC33CC33,
191 	0xAA55AA55,
192 	0xFFFE0001,
193 	0x683501FE,
194 	0x0F1929B0,
195 	0x2D0B4346,
196 	0x60767F02,
197 	0x6FBE36A6,
198 	0x3A253035,
199 	0x3019686D,
200 	0x41C6167E,
201 	0x620152BF,
202 	0x20F050E0
203 };
204 
205 static u32 mmctestburst2_ast2150(struct ast_device *ast, u32 datagen)
206 {
207 	u32 data, timeout;
208 
209 	ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
210 	ast_moutdwm(ast, 0x1e6e0070, 0x00000001 | (datagen << 3));
211 	timeout = 0;
212 	do {
213 		data = ast_mindwm(ast, 0x1e6e0070) & 0x40;
214 		if (++timeout > TIMEOUT_AST2150) {
215 			ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
216 			return 0xffffffff;
217 		}
218 	} while (!data);
219 	ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
220 	ast_moutdwm(ast, 0x1e6e0070, 0x00000003 | (datagen << 3));
221 	timeout = 0;
222 	do {
223 		data = ast_mindwm(ast, 0x1e6e0070) & 0x40;
224 		if (++timeout > TIMEOUT_AST2150) {
225 			ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
226 			return 0xffffffff;
227 		}
228 	} while (!data);
229 	data = (ast_mindwm(ast, 0x1e6e0070) & 0x80) >> 7;
230 	ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
231 	return data;
232 }
233 
234 static int cbrtest_ast2150(struct ast_device *ast)
235 {
236 	int i;
237 
238 	for (i = 0; i < 8; i++)
239 		if (mmctestburst2_ast2150(ast, i))
240 			return 0;
241 	return 1;
242 }
243 
244 static int cbrscan_ast2150(struct ast_device *ast, int busw)
245 {
246 	u32 patcnt, loop;
247 
248 	for (patcnt = 0; patcnt < CBR_PATNUM_AST2150; patcnt++) {
249 		ast_moutdwm(ast, 0x1e6e007c, pattern_AST2150[patcnt]);
250 		for (loop = 0; loop < CBR_PASSNUM_AST2150; loop++) {
251 			if (cbrtest_ast2150(ast))
252 				break;
253 		}
254 		if (loop == CBR_PASSNUM_AST2150)
255 			return 0;
256 	}
257 	return 1;
258 }
259 
260 static void cbrdlli_ast2150(struct ast_device *ast, int busw)
261 {
262 	u32 dll_min[4], dll_max[4], dlli, data, passcnt;
263 
264 cbr_start:
265 	dll_min[0] = 0xff;
266 	dll_min[1] = 0xff;
267 	dll_min[2] = 0xff;
268 	dll_min[3] = 0xff;
269 	dll_max[0] = 0x00;
270 	dll_max[1] = 0x00;
271 	dll_max[2] = 0x00;
272 	dll_max[3] = 0x00;
273 	passcnt = 0;
274 
275 	for (dlli = 0; dlli < 100; dlli++) {
276 		ast_moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24));
277 		data = cbrscan_ast2150(ast, busw);
278 		if (data != 0) {
279 			if (data & 0x1) {
280 				if (dll_min[0] > dlli)
281 					dll_min[0] = dlli;
282 				if (dll_max[0] < dlli)
283 					dll_max[0] = dlli;
284 			}
285 			passcnt++;
286 		} else if (passcnt >= CBR_THRESHOLD_AST2150) {
287 			goto cbr_start;
288 		}
289 	}
290 	if (dll_max[0] == 0 || (dll_max[0] - dll_min[0]) < CBR_THRESHOLD_AST2150)
291 		goto cbr_start;
292 
293 	dlli = dll_min[0] + (((dll_max[0] - dll_min[0]) * 7) >> 4);
294 	ast_moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24));
295 }
296 
297 static void ast_post_chip_2100(struct ast_device *ast)
298 {
299 	u8 j;
300 	u32 data, temp, i;
301 	const struct ast_dramstruct *dram_reg_info;
302 	enum ast_dram_layout dram_layout  = ast_2100_get_dram_layout_p2a(ast);
303 
304 	j = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff);
305 
306 	if ((j & 0x80) == 0) { /* VGA only */
307 		if (ast->chip == AST2100 || ast->chip == AST2200)
308 			dram_reg_info = ast2100_dram_table_data;
309 		else
310 			dram_reg_info = ast1100_dram_table_data;
311 
312 		ast_write32(ast, 0xf004, 0x1e6e0000);
313 		ast_write32(ast, 0xf000, 0x1);
314 		ast_write32(ast, 0x12000, 0x1688A8A8);
315 		do {
316 			;
317 		} while (ast_read32(ast, 0x12000) != 0x01);
318 
319 		ast_write32(ast, 0x10000, 0xfc600309);
320 		do {
321 			;
322 		} while (ast_read32(ast, 0x10000) != 0x01);
323 
324 		while (!AST_DRAMSTRUCT_IS(dram_reg_info, INVALID)) {
325 			if (AST_DRAMSTRUCT_IS(dram_reg_info, UDELAY)) {
326 				for (i = 0; i < 15; i++)
327 					udelay(dram_reg_info->data);
328 			} else if (AST_DRAMSTRUCT_IS(dram_reg_info, DRAM_TYPE)) {
329 				switch (dram_layout) {
330 				case AST_DRAM_1Gx16:
331 					data = 0x00000d89;
332 					break;
333 				case AST_DRAM_1Gx32:
334 					data = 0x00000c8d;
335 					break;
336 				default:
337 					data = dram_reg_info->data;
338 					break;
339 				}
340 
341 				temp = ast_read32(ast, 0x12070);
342 				temp &= 0xc;
343 				temp <<= 2;
344 				ast_write32(ast, 0x10000 + dram_reg_info->index, data | temp);
345 			} else {
346 				ast_write32(ast, 0x10000 + dram_reg_info->index,
347 					    dram_reg_info->data);
348 			}
349 			dram_reg_info++;
350 		}
351 
352 		/* AST 2100/2150 DRAM calibration */
353 		data = ast_read32(ast, 0x10120);
354 		if (data == 0x5061) { /* 266Mhz */
355 			data = ast_read32(ast, 0x10004);
356 			if (data & 0x40)
357 				cbrdlli_ast2150(ast, 16); /* 16 bits */
358 			else
359 				cbrdlli_ast2150(ast, 32); /* 32 bits */
360 		}
361 
362 		temp = ast_read32(ast, 0x1200c);
363 		ast_write32(ast, 0x1200c, temp & 0xfffffffd);
364 		temp = ast_read32(ast, 0x12040);
365 		ast_write32(ast, 0x12040, temp | 0x40);
366 	}
367 
368 	/* wait ready */
369 	do {
370 		j = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff);
371 	} while ((j & 0x40) == 0);
372 }
373 
374 int ast_2100_post(struct ast_device *ast)
375 {
376 	ast_2000_set_def_ext_reg(ast);
377 
378 	if (ast->config_mode == ast_use_p2a) {
379 		ast_post_chip_2100(ast);
380 	} else {
381 		if (ast->tx_chip == AST_TX_SIL164) {
382 			/* Enable DVO */
383 			ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x80);
384 		}
385 	}
386 
387 	return 0;
388 }
389