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