File Index
Files and directories
Sign in
FILE

ast_2100.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/ast/ast_2100.c C
  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
 41static 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
 74static 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
127static 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
191static 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
208static 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
237static 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
247static 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
263static void cbrdlli_ast2150(struct ast_device *ast, int busw)
264{
265	u32 dll_min[4], dll_max[4], dlli, data, passcnt;
266
267cbr_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
300static 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
377int 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+ */
398bool __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+ */
411bool __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
424static 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
435static 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
440struct 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}
~/ Read-only file preview.