xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/ast/ast_mode.c (revision 41ec02673d281bbb3d38e6c78504ce6e30c228c1)
1*41ec0267Sriastradh /*	$NetBSD: ast_mode.c,v 1.3 2021/12/18 23:45:27 riastradh Exp $	*/
2efa246c0Sriastradh 
3fcd0cb28Sriastradh /*
4fcd0cb28Sriastradh  * Copyright 2012 Red Hat Inc.
5fcd0cb28Sriastradh  * Parts based on xf86-video-ast
6fcd0cb28Sriastradh  * Copyright (c) 2005 ASPEED Technology Inc.
7fcd0cb28Sriastradh  *
8fcd0cb28Sriastradh  * Permission is hereby granted, free of charge, to any person obtaining a
9fcd0cb28Sriastradh  * copy of this software and associated documentation files (the
10fcd0cb28Sriastradh  * "Software"), to deal in the Software without restriction, including
11fcd0cb28Sriastradh  * without limitation the rights to use, copy, modify, merge, publish,
12fcd0cb28Sriastradh  * distribute, sub license, and/or sell copies of the Software, and to
13fcd0cb28Sriastradh  * permit persons to whom the Software is furnished to do so, subject to
14fcd0cb28Sriastradh  * the following conditions:
15fcd0cb28Sriastradh  *
16fcd0cb28Sriastradh  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17fcd0cb28Sriastradh  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18fcd0cb28Sriastradh  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19fcd0cb28Sriastradh  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
20fcd0cb28Sriastradh  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21fcd0cb28Sriastradh  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22fcd0cb28Sriastradh  * USE OR OTHER DEALINGS IN THE SOFTWARE.
23fcd0cb28Sriastradh  *
24fcd0cb28Sriastradh  * The above copyright notice and this permission notice (including the
25fcd0cb28Sriastradh  * next paragraph) shall be included in all copies or substantial portions
26fcd0cb28Sriastradh  * of the Software.
27fcd0cb28Sriastradh  *
28fcd0cb28Sriastradh  */
29fcd0cb28Sriastradh /*
30fcd0cb28Sriastradh  * Authors: Dave Airlie <airlied@redhat.com>
31fcd0cb28Sriastradh  */
32*41ec0267Sriastradh 
33efa246c0Sriastradh #include <sys/cdefs.h>
34*41ec0267Sriastradh __KERNEL_RCSID(0, "$NetBSD: ast_mode.c,v 1.3 2021/12/18 23:45:27 riastradh Exp $");
35efa246c0Sriastradh 
36fcd0cb28Sriastradh #include <linux/export.h>
37*41ec0267Sriastradh #include <linux/pci.h>
38*41ec0267Sriastradh 
39*41ec0267Sriastradh #include <drm/drm_atomic.h>
40*41ec0267Sriastradh #include <drm/drm_atomic_helper.h>
41*41ec0267Sriastradh #include <drm/drm_atomic_state_helper.h>
42fcd0cb28Sriastradh #include <drm/drm_crtc.h>
43fcd0cb28Sriastradh #include <drm/drm_crtc_helper.h>
44*41ec0267Sriastradh #include <drm/drm_fourcc.h>
45*41ec0267Sriastradh #include <drm/drm_gem_vram_helper.h>
46efa246c0Sriastradh #include <drm/drm_plane_helper.h>
47*41ec0267Sriastradh #include <drm/drm_probe_helper.h>
48fcd0cb28Sriastradh 
49*41ec0267Sriastradh #include "ast_drv.h"
50fcd0cb28Sriastradh #include "ast_tables.h"
51fcd0cb28Sriastradh 
52fcd0cb28Sriastradh static struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev);
53fcd0cb28Sriastradh static void ast_i2c_destroy(struct ast_i2c_chan *i2c);
54*41ec0267Sriastradh static int ast_cursor_move(struct drm_crtc *crtc,
55*41ec0267Sriastradh 			   int x, int y);
56*41ec0267Sriastradh 
57*41ec0267Sriastradh 
58*41ec0267Sriastradh static u32 copy_cursor_image(u8 *src, u8 *dst, int width, int height);
59*41ec0267Sriastradh static int ast_cursor_update(void *dst, void *src, unsigned int width,
60*41ec0267Sriastradh 			     unsigned int height);
61*41ec0267Sriastradh static void ast_cursor_set_base(struct ast_private *ast, u64 address);
62fcd0cb28Sriastradh static int ast_cursor_move(struct drm_crtc *crtc,
63fcd0cb28Sriastradh 			   int x, int y);
64fcd0cb28Sriastradh 
ast_load_palette_index(struct ast_private * ast,u8 index,u8 red,u8 green,u8 blue)65fcd0cb28Sriastradh static inline void ast_load_palette_index(struct ast_private *ast,
66fcd0cb28Sriastradh 				     u8 index, u8 red, u8 green,
67fcd0cb28Sriastradh 				     u8 blue)
68fcd0cb28Sriastradh {
69fcd0cb28Sriastradh 	ast_io_write8(ast, AST_IO_DAC_INDEX_WRITE, index);
70fcd0cb28Sriastradh 	ast_io_read8(ast, AST_IO_SEQ_PORT);
71fcd0cb28Sriastradh 	ast_io_write8(ast, AST_IO_DAC_DATA, red);
72fcd0cb28Sriastradh 	ast_io_read8(ast, AST_IO_SEQ_PORT);
73fcd0cb28Sriastradh 	ast_io_write8(ast, AST_IO_DAC_DATA, green);
74fcd0cb28Sriastradh 	ast_io_read8(ast, AST_IO_SEQ_PORT);
75fcd0cb28Sriastradh 	ast_io_write8(ast, AST_IO_DAC_DATA, blue);
76fcd0cb28Sriastradh 	ast_io_read8(ast, AST_IO_SEQ_PORT);
77fcd0cb28Sriastradh }
78fcd0cb28Sriastradh 
ast_crtc_load_lut(struct ast_private * ast,struct drm_crtc * crtc)79*41ec0267Sriastradh static void ast_crtc_load_lut(struct ast_private *ast, struct drm_crtc *crtc)
80fcd0cb28Sriastradh {
81*41ec0267Sriastradh 	u16 *r, *g, *b;
82fcd0cb28Sriastradh 	int i;
83fcd0cb28Sriastradh 
84fcd0cb28Sriastradh 	if (!crtc->enabled)
85fcd0cb28Sriastradh 		return;
86fcd0cb28Sriastradh 
87*41ec0267Sriastradh 	r = crtc->gamma_store;
88*41ec0267Sriastradh 	g = r + crtc->gamma_size;
89*41ec0267Sriastradh 	b = g + crtc->gamma_size;
90*41ec0267Sriastradh 
91fcd0cb28Sriastradh 	for (i = 0; i < 256; i++)
92*41ec0267Sriastradh 		ast_load_palette_index(ast, i, *r++ >> 8, *g++ >> 8, *b++ >> 8);
93fcd0cb28Sriastradh }
94fcd0cb28Sriastradh 
ast_get_vbios_mode_info(const struct drm_format_info * format,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode,struct ast_vbios_mode_info * vbios_mode)95*41ec0267Sriastradh static bool ast_get_vbios_mode_info(const struct drm_format_info *format,
96*41ec0267Sriastradh 				    const struct drm_display_mode *mode,
97fcd0cb28Sriastradh 				    struct drm_display_mode *adjusted_mode,
98fcd0cb28Sriastradh 				    struct ast_vbios_mode_info *vbios_mode)
99fcd0cb28Sriastradh {
100*41ec0267Sriastradh 	u32 refresh_rate_index = 0, refresh_rate;
101*41ec0267Sriastradh 	const struct ast_vbios_enhtable *best = NULL;
102fcd0cb28Sriastradh 	u32 hborder, vborder;
103efa246c0Sriastradh 	bool check_sync;
104fcd0cb28Sriastradh 
105*41ec0267Sriastradh 	switch (format->cpp[0] * 8) {
106fcd0cb28Sriastradh 	case 8:
107fcd0cb28Sriastradh 		vbios_mode->std_table = &vbios_stdtable[VGAModeIndex];
108fcd0cb28Sriastradh 		break;
109fcd0cb28Sriastradh 	case 16:
110fcd0cb28Sriastradh 		vbios_mode->std_table = &vbios_stdtable[HiCModeIndex];
111fcd0cb28Sriastradh 		break;
112fcd0cb28Sriastradh 	case 24:
113fcd0cb28Sriastradh 	case 32:
114fcd0cb28Sriastradh 		vbios_mode->std_table = &vbios_stdtable[TrueCModeIndex];
115fcd0cb28Sriastradh 		break;
116fcd0cb28Sriastradh 	default:
117fcd0cb28Sriastradh 		return false;
118fcd0cb28Sriastradh 	}
119fcd0cb28Sriastradh 
120*41ec0267Sriastradh 	switch (mode->crtc_hdisplay) {
121fcd0cb28Sriastradh 	case 640:
122fcd0cb28Sriastradh 		vbios_mode->enh_table = &res_640x480[refresh_rate_index];
123fcd0cb28Sriastradh 		break;
124fcd0cb28Sriastradh 	case 800:
125fcd0cb28Sriastradh 		vbios_mode->enh_table = &res_800x600[refresh_rate_index];
126fcd0cb28Sriastradh 		break;
127fcd0cb28Sriastradh 	case 1024:
128fcd0cb28Sriastradh 		vbios_mode->enh_table = &res_1024x768[refresh_rate_index];
129fcd0cb28Sriastradh 		break;
130fcd0cb28Sriastradh 	case 1280:
131*41ec0267Sriastradh 		if (mode->crtc_vdisplay == 800)
132fcd0cb28Sriastradh 			vbios_mode->enh_table = &res_1280x800[refresh_rate_index];
133fcd0cb28Sriastradh 		else
134fcd0cb28Sriastradh 			vbios_mode->enh_table = &res_1280x1024[refresh_rate_index];
135fcd0cb28Sriastradh 		break;
136efa246c0Sriastradh 	case 1360:
137efa246c0Sriastradh 		vbios_mode->enh_table = &res_1360x768[refresh_rate_index];
138efa246c0Sriastradh 		break;
139fcd0cb28Sriastradh 	case 1440:
140fcd0cb28Sriastradh 		vbios_mode->enh_table = &res_1440x900[refresh_rate_index];
141fcd0cb28Sriastradh 		break;
142fcd0cb28Sriastradh 	case 1600:
143*41ec0267Sriastradh 		if (mode->crtc_vdisplay == 900)
144efa246c0Sriastradh 			vbios_mode->enh_table = &res_1600x900[refresh_rate_index];
145efa246c0Sriastradh 		else
146fcd0cb28Sriastradh 			vbios_mode->enh_table = &res_1600x1200[refresh_rate_index];
147fcd0cb28Sriastradh 		break;
148fcd0cb28Sriastradh 	case 1680:
149fcd0cb28Sriastradh 		vbios_mode->enh_table = &res_1680x1050[refresh_rate_index];
150fcd0cb28Sriastradh 		break;
151fcd0cb28Sriastradh 	case 1920:
152*41ec0267Sriastradh 		if (mode->crtc_vdisplay == 1080)
153fcd0cb28Sriastradh 			vbios_mode->enh_table = &res_1920x1080[refresh_rate_index];
154fcd0cb28Sriastradh 		else
155fcd0cb28Sriastradh 			vbios_mode->enh_table = &res_1920x1200[refresh_rate_index];
156fcd0cb28Sriastradh 		break;
157fcd0cb28Sriastradh 	default:
158fcd0cb28Sriastradh 		return false;
159fcd0cb28Sriastradh 	}
160fcd0cb28Sriastradh 
161fcd0cb28Sriastradh 	refresh_rate = drm_mode_vrefresh(mode);
162efa246c0Sriastradh 	check_sync = vbios_mode->enh_table->flags & WideScreenMode;
163*41ec0267Sriastradh 
164*41ec0267Sriastradh 	while (1) {
165*41ec0267Sriastradh 		const struct ast_vbios_enhtable *loop = vbios_mode->enh_table;
166efa246c0Sriastradh 
167efa246c0Sriastradh 		while (loop->refresh_rate != 0xff) {
168efa246c0Sriastradh 			if ((check_sync) &&
169efa246c0Sriastradh 			    (((mode->flags & DRM_MODE_FLAG_NVSYNC)  &&
170efa246c0Sriastradh 			      (loop->flags & PVSync))  ||
171efa246c0Sriastradh 			     ((mode->flags & DRM_MODE_FLAG_PVSYNC)  &&
172efa246c0Sriastradh 			      (loop->flags & NVSync))  ||
173efa246c0Sriastradh 			     ((mode->flags & DRM_MODE_FLAG_NHSYNC)  &&
174efa246c0Sriastradh 			      (loop->flags & PHSync))  ||
175efa246c0Sriastradh 			     ((mode->flags & DRM_MODE_FLAG_PHSYNC)  &&
176efa246c0Sriastradh 			      (loop->flags & NHSync)))) {
177efa246c0Sriastradh 				loop++;
178efa246c0Sriastradh 				continue;
179efa246c0Sriastradh 			}
180efa246c0Sriastradh 			if (loop->refresh_rate <= refresh_rate
181efa246c0Sriastradh 			    && (!best || loop->refresh_rate > best->refresh_rate))
182efa246c0Sriastradh 				best = loop;
183efa246c0Sriastradh 			loop++;
184efa246c0Sriastradh 		}
185efa246c0Sriastradh 		if (best || !check_sync)
186fcd0cb28Sriastradh 			break;
187efa246c0Sriastradh 		check_sync = 0;
188*41ec0267Sriastradh 	}
189*41ec0267Sriastradh 
190efa246c0Sriastradh 	if (best)
191efa246c0Sriastradh 		vbios_mode->enh_table = best;
192fcd0cb28Sriastradh 
193fcd0cb28Sriastradh 	hborder = (vbios_mode->enh_table->flags & HBorder) ? 8 : 0;
194fcd0cb28Sriastradh 	vborder = (vbios_mode->enh_table->flags & VBorder) ? 8 : 0;
195fcd0cb28Sriastradh 
196fcd0cb28Sriastradh 	adjusted_mode->crtc_htotal = vbios_mode->enh_table->ht;
197fcd0cb28Sriastradh 	adjusted_mode->crtc_hblank_start = vbios_mode->enh_table->hde + hborder;
198fcd0cb28Sriastradh 	adjusted_mode->crtc_hblank_end = vbios_mode->enh_table->ht - hborder;
199fcd0cb28Sriastradh 	adjusted_mode->crtc_hsync_start = vbios_mode->enh_table->hde + hborder +
200fcd0cb28Sriastradh 		vbios_mode->enh_table->hfp;
201fcd0cb28Sriastradh 	adjusted_mode->crtc_hsync_end = (vbios_mode->enh_table->hde + hborder +
202fcd0cb28Sriastradh 					 vbios_mode->enh_table->hfp +
203fcd0cb28Sriastradh 					 vbios_mode->enh_table->hsync);
204fcd0cb28Sriastradh 
205fcd0cb28Sriastradh 	adjusted_mode->crtc_vtotal = vbios_mode->enh_table->vt;
206fcd0cb28Sriastradh 	adjusted_mode->crtc_vblank_start = vbios_mode->enh_table->vde + vborder;
207fcd0cb28Sriastradh 	adjusted_mode->crtc_vblank_end = vbios_mode->enh_table->vt - vborder;
208fcd0cb28Sriastradh 	adjusted_mode->crtc_vsync_start = vbios_mode->enh_table->vde + vborder +
209fcd0cb28Sriastradh 		vbios_mode->enh_table->vfp;
210fcd0cb28Sriastradh 	adjusted_mode->crtc_vsync_end = (vbios_mode->enh_table->vde + vborder +
211fcd0cb28Sriastradh 					 vbios_mode->enh_table->vfp +
212fcd0cb28Sriastradh 					 vbios_mode->enh_table->vsync);
213fcd0cb28Sriastradh 
214*41ec0267Sriastradh 	return true;
215*41ec0267Sriastradh }
216*41ec0267Sriastradh 
ast_set_vbios_color_reg(struct ast_private * ast,const struct drm_format_info * format,const struct ast_vbios_mode_info * vbios_mode)217*41ec0267Sriastradh static void ast_set_vbios_color_reg(struct ast_private *ast,
218*41ec0267Sriastradh 				    const struct drm_format_info *format,
219*41ec0267Sriastradh 				    const struct ast_vbios_mode_info *vbios_mode)
220*41ec0267Sriastradh {
221*41ec0267Sriastradh 	u32 color_index;
222*41ec0267Sriastradh 
223*41ec0267Sriastradh 	switch (format->cpp[0]) {
224*41ec0267Sriastradh 	case 1:
225*41ec0267Sriastradh 		color_index = VGAModeIndex - 1;
226*41ec0267Sriastradh 		break;
227*41ec0267Sriastradh 	case 2:
228*41ec0267Sriastradh 		color_index = HiCModeIndex;
229*41ec0267Sriastradh 		break;
230*41ec0267Sriastradh 	case 3:
231*41ec0267Sriastradh 	case 4:
232*41ec0267Sriastradh 		color_index = TrueCModeIndex;
233*41ec0267Sriastradh 	default:
234*41ec0267Sriastradh 		return;
235*41ec0267Sriastradh 	}
236*41ec0267Sriastradh 
237*41ec0267Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8c, (u8)((color_index & 0x0f) << 4));
238*41ec0267Sriastradh 
239*41ec0267Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0x00);
240*41ec0267Sriastradh 
241*41ec0267Sriastradh 	if (vbios_mode->enh_table->flags & NewModeInfo) {
242*41ec0267Sriastradh 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8);
243*41ec0267Sriastradh 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, format->cpp[0] * 8);
244*41ec0267Sriastradh 	}
245*41ec0267Sriastradh }
246*41ec0267Sriastradh 
ast_set_vbios_mode_reg(struct ast_private * ast,const struct drm_display_mode * adjusted_mode,const struct ast_vbios_mode_info * vbios_mode)247*41ec0267Sriastradh static void ast_set_vbios_mode_reg(struct ast_private *ast,
248*41ec0267Sriastradh 				   const struct drm_display_mode *adjusted_mode,
249*41ec0267Sriastradh 				   const struct ast_vbios_mode_info *vbios_mode)
250*41ec0267Sriastradh {
251*41ec0267Sriastradh 	u32 refresh_rate_index, mode_id;
252*41ec0267Sriastradh 
253fcd0cb28Sriastradh 	refresh_rate_index = vbios_mode->enh_table->refresh_rate_index;
254fcd0cb28Sriastradh 	mode_id = vbios_mode->enh_table->mode_id;
255fcd0cb28Sriastradh 
256fcd0cb28Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8d, refresh_rate_index & 0xff);
257fcd0cb28Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8e, mode_id & 0xff);
258fcd0cb28Sriastradh 
259efa246c0Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0x00);
260*41ec0267Sriastradh 
261efa246c0Sriastradh 	if (vbios_mode->enh_table->flags & NewModeInfo) {
262fcd0cb28Sriastradh 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8);
263fcd0cb28Sriastradh 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x93, adjusted_mode->clock / 1000);
264fcd0cb28Sriastradh 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x94, adjusted_mode->crtc_hdisplay);
265fcd0cb28Sriastradh 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x95, adjusted_mode->crtc_hdisplay >> 8);
266fcd0cb28Sriastradh 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x96, adjusted_mode->crtc_vdisplay);
267fcd0cb28Sriastradh 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x97, adjusted_mode->crtc_vdisplay >> 8);
268fcd0cb28Sriastradh 	}
269efa246c0Sriastradh }
270fcd0cb28Sriastradh 
ast_set_std_reg(struct ast_private * ast,struct drm_display_mode * mode,struct ast_vbios_mode_info * vbios_mode)271*41ec0267Sriastradh static void ast_set_std_reg(struct ast_private *ast,
272*41ec0267Sriastradh 			    struct drm_display_mode *mode,
273fcd0cb28Sriastradh 			    struct ast_vbios_mode_info *vbios_mode)
274fcd0cb28Sriastradh {
275*41ec0267Sriastradh 	const struct ast_vbios_stdtable *stdtable;
276fcd0cb28Sriastradh 	u32 i;
277fcd0cb28Sriastradh 	u8 jreg;
278fcd0cb28Sriastradh 
279fcd0cb28Sriastradh 	stdtable = vbios_mode->std_table;
280fcd0cb28Sriastradh 
281fcd0cb28Sriastradh 	jreg = stdtable->misc;
282fcd0cb28Sriastradh 	ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, jreg);
283fcd0cb28Sriastradh 
284*41ec0267Sriastradh 	/* Set SEQ; except Screen Disable field */
285fcd0cb28Sriastradh 	ast_set_index_reg(ast, AST_IO_SEQ_PORT, 0x00, 0x03);
286*41ec0267Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x01, 0xdf, stdtable->seq[0]);
287*41ec0267Sriastradh 	for (i = 1; i < 4; i++) {
288fcd0cb28Sriastradh 		jreg = stdtable->seq[i];
289fcd0cb28Sriastradh 		ast_set_index_reg(ast, AST_IO_SEQ_PORT, (i + 1) , jreg);
290fcd0cb28Sriastradh 	}
291fcd0cb28Sriastradh 
292*41ec0267Sriastradh 	/* Set CRTC; except base address and offset */
293fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x7f, 0x00);
294*41ec0267Sriastradh 	for (i = 0; i < 12; i++)
295*41ec0267Sriastradh 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, i, stdtable->crtc[i]);
296*41ec0267Sriastradh 	for (i = 14; i < 19; i++)
297*41ec0267Sriastradh 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, i, stdtable->crtc[i]);
298*41ec0267Sriastradh 	for (i = 20; i < 25; i++)
299fcd0cb28Sriastradh 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, i, stdtable->crtc[i]);
300fcd0cb28Sriastradh 
301fcd0cb28Sriastradh 	/* set AR */
302fcd0cb28Sriastradh 	jreg = ast_io_read8(ast, AST_IO_INPUT_STATUS1_READ);
303fcd0cb28Sriastradh 	for (i = 0; i < 20; i++) {
304fcd0cb28Sriastradh 		jreg = stdtable->ar[i];
305fcd0cb28Sriastradh 		ast_io_write8(ast, AST_IO_AR_PORT_WRITE, (u8)i);
306fcd0cb28Sriastradh 		ast_io_write8(ast, AST_IO_AR_PORT_WRITE, jreg);
307fcd0cb28Sriastradh 	}
308fcd0cb28Sriastradh 	ast_io_write8(ast, AST_IO_AR_PORT_WRITE, 0x14);
309fcd0cb28Sriastradh 	ast_io_write8(ast, AST_IO_AR_PORT_WRITE, 0x00);
310fcd0cb28Sriastradh 
311fcd0cb28Sriastradh 	jreg = ast_io_read8(ast, AST_IO_INPUT_STATUS1_READ);
312fcd0cb28Sriastradh 	ast_io_write8(ast, AST_IO_AR_PORT_WRITE, 0x20);
313fcd0cb28Sriastradh 
314fcd0cb28Sriastradh 	/* Set GR */
315fcd0cb28Sriastradh 	for (i = 0; i < 9; i++)
316fcd0cb28Sriastradh 		ast_set_index_reg(ast, AST_IO_GR_PORT, i, stdtable->gr[i]);
317fcd0cb28Sriastradh }
318fcd0cb28Sriastradh 
ast_set_crtc_reg(struct ast_private * ast,struct drm_display_mode * mode,struct ast_vbios_mode_info * vbios_mode)319*41ec0267Sriastradh static void ast_set_crtc_reg(struct ast_private *ast,
320*41ec0267Sriastradh 			     struct drm_display_mode *mode,
321fcd0cb28Sriastradh 			     struct ast_vbios_mode_info *vbios_mode)
322fcd0cb28Sriastradh {
323fcd0cb28Sriastradh 	u8 jreg05 = 0, jreg07 = 0, jreg09 = 0, jregAC = 0, jregAD = 0, jregAE = 0;
324*41ec0267Sriastradh 	u16 temp, precache = 0;
325*41ec0267Sriastradh 
326*41ec0267Sriastradh 	if ((ast->chip == AST2500) &&
327*41ec0267Sriastradh 	    (vbios_mode->enh_table->flags & AST2500PreCatchCRT))
328*41ec0267Sriastradh 		precache = 40;
329fcd0cb28Sriastradh 
330fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x7f, 0x00);
331fcd0cb28Sriastradh 
332fcd0cb28Sriastradh 	temp = (mode->crtc_htotal >> 3) - 5;
333fcd0cb28Sriastradh 	if (temp & 0x100)
334fcd0cb28Sriastradh 		jregAC |= 0x01; /* HT D[8] */
335fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x00, 0x00, temp);
336fcd0cb28Sriastradh 
337fcd0cb28Sriastradh 	temp = (mode->crtc_hdisplay >> 3) - 1;
338fcd0cb28Sriastradh 	if (temp & 0x100)
339fcd0cb28Sriastradh 		jregAC |= 0x04; /* HDE D[8] */
340fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x01, 0x00, temp);
341fcd0cb28Sriastradh 
342fcd0cb28Sriastradh 	temp = (mode->crtc_hblank_start >> 3) - 1;
343fcd0cb28Sriastradh 	if (temp & 0x100)
344fcd0cb28Sriastradh 		jregAC |= 0x10; /* HBS D[8] */
345fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x02, 0x00, temp);
346fcd0cb28Sriastradh 
347fcd0cb28Sriastradh 	temp = ((mode->crtc_hblank_end >> 3) - 1) & 0x7f;
348fcd0cb28Sriastradh 	if (temp & 0x20)
349fcd0cb28Sriastradh 		jreg05 |= 0x80;  /* HBE D[5] */
350fcd0cb28Sriastradh 	if (temp & 0x40)
351fcd0cb28Sriastradh 		jregAD |= 0x01;  /* HBE D[5] */
352fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x03, 0xE0, (temp & 0x1f));
353fcd0cb28Sriastradh 
354*41ec0267Sriastradh 	temp = ((mode->crtc_hsync_start-precache) >> 3) - 1;
355fcd0cb28Sriastradh 	if (temp & 0x100)
356fcd0cb28Sriastradh 		jregAC |= 0x40; /* HRS D[5] */
357fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x04, 0x00, temp);
358fcd0cb28Sriastradh 
359*41ec0267Sriastradh 	temp = (((mode->crtc_hsync_end-precache) >> 3) - 1) & 0x3f;
360fcd0cb28Sriastradh 	if (temp & 0x20)
361fcd0cb28Sriastradh 		jregAD |= 0x04; /* HRE D[5] */
362fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x05, 0x60, (u8)((temp & 0x1f) | jreg05));
363fcd0cb28Sriastradh 
364fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xAC, 0x00, jregAC);
365fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xAD, 0x00, jregAD);
366fcd0cb28Sriastradh 
367fcd0cb28Sriastradh 	/* vert timings */
368fcd0cb28Sriastradh 	temp = (mode->crtc_vtotal) - 2;
369fcd0cb28Sriastradh 	if (temp & 0x100)
370fcd0cb28Sriastradh 		jreg07 |= 0x01;
371fcd0cb28Sriastradh 	if (temp & 0x200)
372fcd0cb28Sriastradh 		jreg07 |= 0x20;
373fcd0cb28Sriastradh 	if (temp & 0x400)
374fcd0cb28Sriastradh 		jregAE |= 0x01;
375fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x06, 0x00, temp);
376fcd0cb28Sriastradh 
377fcd0cb28Sriastradh 	temp = (mode->crtc_vsync_start) - 1;
378fcd0cb28Sriastradh 	if (temp & 0x100)
379fcd0cb28Sriastradh 		jreg07 |= 0x04;
380fcd0cb28Sriastradh 	if (temp & 0x200)
381fcd0cb28Sriastradh 		jreg07 |= 0x80;
382fcd0cb28Sriastradh 	if (temp & 0x400)
383fcd0cb28Sriastradh 		jregAE |= 0x08;
384fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x10, 0x00, temp);
385fcd0cb28Sriastradh 
386fcd0cb28Sriastradh 	temp = (mode->crtc_vsync_end - 1) & 0x3f;
387fcd0cb28Sriastradh 	if (temp & 0x10)
388fcd0cb28Sriastradh 		jregAE |= 0x20;
389fcd0cb28Sriastradh 	if (temp & 0x20)
390fcd0cb28Sriastradh 		jregAE |= 0x40;
391fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x70, temp & 0xf);
392fcd0cb28Sriastradh 
393fcd0cb28Sriastradh 	temp = mode->crtc_vdisplay - 1;
394fcd0cb28Sriastradh 	if (temp & 0x100)
395fcd0cb28Sriastradh 		jreg07 |= 0x02;
396fcd0cb28Sriastradh 	if (temp & 0x200)
397fcd0cb28Sriastradh 		jreg07 |= 0x40;
398fcd0cb28Sriastradh 	if (temp & 0x400)
399fcd0cb28Sriastradh 		jregAE |= 0x02;
400fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x12, 0x00, temp);
401fcd0cb28Sriastradh 
402fcd0cb28Sriastradh 	temp = mode->crtc_vblank_start - 1;
403fcd0cb28Sriastradh 	if (temp & 0x100)
404fcd0cb28Sriastradh 		jreg07 |= 0x08;
405fcd0cb28Sriastradh 	if (temp & 0x200)
406fcd0cb28Sriastradh 		jreg09 |= 0x20;
407fcd0cb28Sriastradh 	if (temp & 0x400)
408fcd0cb28Sriastradh 		jregAE |= 0x04;
409fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x15, 0x00, temp);
410fcd0cb28Sriastradh 
411fcd0cb28Sriastradh 	temp = mode->crtc_vblank_end - 1;
412fcd0cb28Sriastradh 	if (temp & 0x100)
413fcd0cb28Sriastradh 		jregAE |= 0x10;
414fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x16, 0x00, temp);
415fcd0cb28Sriastradh 
416fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x07, 0x00, jreg07);
417fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x09, 0xdf, jreg09);
418fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xAE, 0x00, (jregAE | 0x80));
419fcd0cb28Sriastradh 
420*41ec0267Sriastradh 	if (precache)
421*41ec0267Sriastradh 		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0x3f, 0x80);
422*41ec0267Sriastradh 	else
423*41ec0267Sriastradh 		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0x3f, 0x00);
424*41ec0267Sriastradh 
425fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x7f, 0x80);
426fcd0cb28Sriastradh }
427fcd0cb28Sriastradh 
ast_set_offset_reg(struct ast_private * ast,struct drm_framebuffer * fb)428*41ec0267Sriastradh static void ast_set_offset_reg(struct ast_private *ast,
429*41ec0267Sriastradh 			       struct drm_framebuffer *fb)
430fcd0cb28Sriastradh {
431fcd0cb28Sriastradh 	u16 offset;
432fcd0cb28Sriastradh 
433*41ec0267Sriastradh 	offset = fb->pitches[0] >> 3;
434fcd0cb28Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x13, (offset & 0xff));
435fcd0cb28Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xb0, (offset >> 8) & 0x3f);
436fcd0cb28Sriastradh }
437fcd0cb28Sriastradh 
ast_set_dclk_reg(struct ast_private * ast,struct drm_display_mode * mode,struct ast_vbios_mode_info * vbios_mode)438*41ec0267Sriastradh static void ast_set_dclk_reg(struct ast_private *ast,
439*41ec0267Sriastradh 			     struct drm_display_mode *mode,
440fcd0cb28Sriastradh 			     struct ast_vbios_mode_info *vbios_mode)
441fcd0cb28Sriastradh {
442*41ec0267Sriastradh 	const struct ast_vbios_dclk_info *clk_info;
443fcd0cb28Sriastradh 
444*41ec0267Sriastradh 	if (ast->chip == AST2500)
445*41ec0267Sriastradh 		clk_info = &dclk_table_ast2500[vbios_mode->enh_table->dclk_index];
446*41ec0267Sriastradh 	else
447fcd0cb28Sriastradh 		clk_info = &dclk_table[vbios_mode->enh_table->dclk_index];
448fcd0cb28Sriastradh 
449fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xc0, 0x00, clk_info->param1);
450fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xc1, 0x00, clk_info->param2);
451fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xbb, 0x0f,
452*41ec0267Sriastradh 			       (clk_info->param3 & 0xc0) |
453*41ec0267Sriastradh 			       ((clk_info->param3 & 0x3) << 4));
454fcd0cb28Sriastradh }
455fcd0cb28Sriastradh 
ast_set_color_reg(struct ast_private * ast,const struct drm_format_info * format)456*41ec0267Sriastradh static void ast_set_color_reg(struct ast_private *ast,
457*41ec0267Sriastradh 			      const struct drm_format_info *format)
458fcd0cb28Sriastradh {
459fcd0cb28Sriastradh 	u8 jregA0 = 0, jregA3 = 0, jregA8 = 0;
460fcd0cb28Sriastradh 
461*41ec0267Sriastradh 	switch (format->cpp[0] * 8) {
462fcd0cb28Sriastradh 	case 8:
463fcd0cb28Sriastradh 		jregA0 = 0x70;
464fcd0cb28Sriastradh 		jregA3 = 0x01;
465fcd0cb28Sriastradh 		jregA8 = 0x00;
466fcd0cb28Sriastradh 		break;
467fcd0cb28Sriastradh 	case 15:
468fcd0cb28Sriastradh 	case 16:
469fcd0cb28Sriastradh 		jregA0 = 0x70;
470fcd0cb28Sriastradh 		jregA3 = 0x04;
471fcd0cb28Sriastradh 		jregA8 = 0x02;
472fcd0cb28Sriastradh 		break;
473fcd0cb28Sriastradh 	case 32:
474fcd0cb28Sriastradh 		jregA0 = 0x70;
475fcd0cb28Sriastradh 		jregA3 = 0x08;
476fcd0cb28Sriastradh 		jregA8 = 0x02;
477fcd0cb28Sriastradh 		break;
478fcd0cb28Sriastradh 	}
479fcd0cb28Sriastradh 
480fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa0, 0x8f, jregA0);
481fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xf0, jregA3);
482fcd0cb28Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa8, 0xfd, jregA8);
483*41ec0267Sriastradh }
484fcd0cb28Sriastradh 
ast_set_crtthd_reg(struct ast_private * ast)485*41ec0267Sriastradh static void ast_set_crtthd_reg(struct ast_private *ast)
486*41ec0267Sriastradh {
487fcd0cb28Sriastradh 	/* Set Threshold */
488*41ec0267Sriastradh 	if (ast->chip == AST2300 || ast->chip == AST2400 ||
489*41ec0267Sriastradh 	    ast->chip == AST2500) {
490fcd0cb28Sriastradh 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x78);
491fcd0cb28Sriastradh 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x60);
492fcd0cb28Sriastradh 	} else if (ast->chip == AST2100 ||
493fcd0cb28Sriastradh 		   ast->chip == AST1100 ||
494fcd0cb28Sriastradh 		   ast->chip == AST2200 ||
495fcd0cb28Sriastradh 		   ast->chip == AST2150) {
496fcd0cb28Sriastradh 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x3f);
497fcd0cb28Sriastradh 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x2f);
498fcd0cb28Sriastradh 	} else {
499fcd0cb28Sriastradh 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x2f);
500fcd0cb28Sriastradh 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x1f);
501fcd0cb28Sriastradh 	}
502fcd0cb28Sriastradh }
503fcd0cb28Sriastradh 
ast_set_sync_reg(struct ast_private * ast,struct drm_display_mode * mode,struct ast_vbios_mode_info * vbios_mode)504*41ec0267Sriastradh static void ast_set_sync_reg(struct ast_private *ast,
505*41ec0267Sriastradh 			     struct drm_display_mode *mode,
506fcd0cb28Sriastradh 			     struct ast_vbios_mode_info *vbios_mode)
507fcd0cb28Sriastradh {
508fcd0cb28Sriastradh 	u8 jreg;
509fcd0cb28Sriastradh 
510fcd0cb28Sriastradh 	jreg  = ast_io_read8(ast, AST_IO_MISC_PORT_READ);
511efa246c0Sriastradh 	jreg &= ~0xC0;
512efa246c0Sriastradh 	if (vbios_mode->enh_table->flags & NVSync) jreg |= 0x80;
513efa246c0Sriastradh 	if (vbios_mode->enh_table->flags & NHSync) jreg |= 0x40;
514fcd0cb28Sriastradh 	ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, jreg);
515fcd0cb28Sriastradh }
516fcd0cb28Sriastradh 
ast_set_start_address_crt1(struct ast_private * ast,unsigned offset)517*41ec0267Sriastradh static void ast_set_start_address_crt1(struct ast_private *ast,
518*41ec0267Sriastradh 				       unsigned offset)
519fcd0cb28Sriastradh {
520fcd0cb28Sriastradh 	u32 addr;
521fcd0cb28Sriastradh 
522fcd0cb28Sriastradh 	addr = offset >> 2;
523fcd0cb28Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x0d, (u8)(addr & 0xff));
524fcd0cb28Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x0c, (u8)((addr >> 8) & 0xff));
525fcd0cb28Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xaf, (u8)((addr >> 16) & 0xff));
526fcd0cb28Sriastradh 
527fcd0cb28Sriastradh }
528fcd0cb28Sriastradh 
529*41ec0267Sriastradh /*
530*41ec0267Sriastradh  * Primary plane
531*41ec0267Sriastradh  */
532*41ec0267Sriastradh 
533*41ec0267Sriastradh static const uint32_t ast_primary_plane_formats[] = {
534*41ec0267Sriastradh 	DRM_FORMAT_XRGB8888,
535*41ec0267Sriastradh 	DRM_FORMAT_RGB565,
536*41ec0267Sriastradh 	DRM_FORMAT_C8,
537*41ec0267Sriastradh };
538*41ec0267Sriastradh 
ast_primary_plane_helper_atomic_check(struct drm_plane * plane,struct drm_plane_state * state)539*41ec0267Sriastradh static int ast_primary_plane_helper_atomic_check(struct drm_plane *plane,
540*41ec0267Sriastradh 						 struct drm_plane_state *state)
541*41ec0267Sriastradh {
542*41ec0267Sriastradh 	struct drm_crtc_state *crtc_state;
543*41ec0267Sriastradh 	struct ast_crtc_state *ast_crtc_state;
544*41ec0267Sriastradh 	int ret;
545*41ec0267Sriastradh 
546*41ec0267Sriastradh 	if (!state->crtc)
547*41ec0267Sriastradh 		return 0;
548*41ec0267Sriastradh 
549*41ec0267Sriastradh 	crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc);
550*41ec0267Sriastradh 
551*41ec0267Sriastradh 	ret = drm_atomic_helper_check_plane_state(state, crtc_state,
552*41ec0267Sriastradh 						  DRM_PLANE_HELPER_NO_SCALING,
553*41ec0267Sriastradh 						  DRM_PLANE_HELPER_NO_SCALING,
554*41ec0267Sriastradh 						  false, true);
555*41ec0267Sriastradh 	if (ret)
556*41ec0267Sriastradh 		return ret;
557*41ec0267Sriastradh 
558*41ec0267Sriastradh 	if (!state->visible)
559*41ec0267Sriastradh 		return 0;
560*41ec0267Sriastradh 
561*41ec0267Sriastradh 	ast_crtc_state = to_ast_crtc_state(crtc_state);
562*41ec0267Sriastradh 
563*41ec0267Sriastradh 	ast_crtc_state->format = state->fb->format;
564*41ec0267Sriastradh 
565*41ec0267Sriastradh 	return 0;
566*41ec0267Sriastradh }
567*41ec0267Sriastradh 
ast_primary_plane_helper_atomic_update(struct drm_plane * plane,struct drm_plane_state * old_state)568*41ec0267Sriastradh void ast_primary_plane_helper_atomic_update(struct drm_plane *plane,
569*41ec0267Sriastradh 					    struct drm_plane_state *old_state)
570*41ec0267Sriastradh {
571*41ec0267Sriastradh 	struct ast_private *ast = plane->dev->dev_private;
572*41ec0267Sriastradh 	struct drm_plane_state *state = plane->state;
573*41ec0267Sriastradh 	struct drm_gem_vram_object *gbo;
574*41ec0267Sriastradh 	s64 gpu_addr;
575*41ec0267Sriastradh 
576*41ec0267Sriastradh 	gbo = drm_gem_vram_of_gem(state->fb->obj[0]);
577*41ec0267Sriastradh 	gpu_addr = drm_gem_vram_offset(gbo);
578*41ec0267Sriastradh 	if (WARN_ON_ONCE(gpu_addr < 0))
579*41ec0267Sriastradh 		return; /* Bug: we didn't pin the BO to VRAM in prepare_fb. */
580*41ec0267Sriastradh 
581*41ec0267Sriastradh 	ast_set_offset_reg(ast, state->fb);
582*41ec0267Sriastradh 	ast_set_start_address_crt1(ast, (u32)gpu_addr);
583*41ec0267Sriastradh 
584*41ec0267Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x00);
585*41ec0267Sriastradh }
586*41ec0267Sriastradh 
587*41ec0267Sriastradh static void
ast_primary_plane_helper_atomic_disable(struct drm_plane * plane,struct drm_plane_state * old_state)588*41ec0267Sriastradh ast_primary_plane_helper_atomic_disable(struct drm_plane *plane,
589*41ec0267Sriastradh 					struct drm_plane_state *old_state)
590*41ec0267Sriastradh {
591*41ec0267Sriastradh 	struct ast_private *ast = plane->dev->dev_private;
592*41ec0267Sriastradh 
593*41ec0267Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x20);
594*41ec0267Sriastradh }
595*41ec0267Sriastradh 
596*41ec0267Sriastradh static const struct drm_plane_helper_funcs ast_primary_plane_helper_funcs = {
597*41ec0267Sriastradh 	.prepare_fb = drm_gem_vram_plane_helper_prepare_fb,
598*41ec0267Sriastradh 	.cleanup_fb = drm_gem_vram_plane_helper_cleanup_fb,
599*41ec0267Sriastradh 	.atomic_check = ast_primary_plane_helper_atomic_check,
600*41ec0267Sriastradh 	.atomic_update = ast_primary_plane_helper_atomic_update,
601*41ec0267Sriastradh 	.atomic_disable = ast_primary_plane_helper_atomic_disable,
602*41ec0267Sriastradh };
603*41ec0267Sriastradh 
604*41ec0267Sriastradh static const struct drm_plane_funcs ast_primary_plane_funcs = {
605*41ec0267Sriastradh 	.update_plane = drm_atomic_helper_update_plane,
606*41ec0267Sriastradh 	.disable_plane = drm_atomic_helper_disable_plane,
607*41ec0267Sriastradh 	.destroy = drm_plane_cleanup,
608*41ec0267Sriastradh 	.reset = drm_atomic_helper_plane_reset,
609*41ec0267Sriastradh 	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
610*41ec0267Sriastradh 	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
611*41ec0267Sriastradh };
612*41ec0267Sriastradh 
613*41ec0267Sriastradh /*
614*41ec0267Sriastradh  * Cursor plane
615*41ec0267Sriastradh  */
616*41ec0267Sriastradh 
617*41ec0267Sriastradh static const uint32_t ast_cursor_plane_formats[] = {
618*41ec0267Sriastradh 	DRM_FORMAT_ARGB8888,
619*41ec0267Sriastradh };
620*41ec0267Sriastradh 
621*41ec0267Sriastradh static int
ast_cursor_plane_helper_prepare_fb(struct drm_plane * plane,struct drm_plane_state * new_state)622*41ec0267Sriastradh ast_cursor_plane_helper_prepare_fb(struct drm_plane *plane,
623*41ec0267Sriastradh 				   struct drm_plane_state *new_state)
624*41ec0267Sriastradh {
625*41ec0267Sriastradh 	struct drm_framebuffer *fb = new_state->fb;
626*41ec0267Sriastradh 	struct drm_crtc *crtc = new_state->crtc;
627*41ec0267Sriastradh 	struct drm_gem_vram_object *gbo;
628*41ec0267Sriastradh 	struct ast_private *ast;
629*41ec0267Sriastradh 	int ret;
630*41ec0267Sriastradh 	void *src, *dst;
631*41ec0267Sriastradh 
632*41ec0267Sriastradh 	if (!crtc || !fb)
633*41ec0267Sriastradh 		return 0;
634*41ec0267Sriastradh 
635*41ec0267Sriastradh 	if (WARN_ON_ONCE(fb->width > AST_MAX_HWC_WIDTH) ||
636*41ec0267Sriastradh 	    WARN_ON_ONCE(fb->height > AST_MAX_HWC_HEIGHT))
637*41ec0267Sriastradh 		return -EINVAL; /* BUG: didn't test in atomic_check() */
638*41ec0267Sriastradh 
639*41ec0267Sriastradh 	ast = crtc->dev->dev_private;
640*41ec0267Sriastradh 
641*41ec0267Sriastradh 	gbo = drm_gem_vram_of_gem(fb->obj[0]);
642*41ec0267Sriastradh 	src = drm_gem_vram_vmap(gbo);
643*41ec0267Sriastradh 	if (IS_ERR(src)) {
644*41ec0267Sriastradh 		ret = PTR_ERR(src);
645*41ec0267Sriastradh 		goto err_drm_gem_vram_unpin;
646*41ec0267Sriastradh 	}
647*41ec0267Sriastradh 
648*41ec0267Sriastradh 	dst = drm_gem_vram_vmap(ast->cursor.gbo[ast->cursor.next_index]);
649*41ec0267Sriastradh 	if (IS_ERR(dst)) {
650*41ec0267Sriastradh 		ret = PTR_ERR(dst);
651*41ec0267Sriastradh 		goto err_drm_gem_vram_vunmap_src;
652*41ec0267Sriastradh 	}
653*41ec0267Sriastradh 
654*41ec0267Sriastradh 	ret = ast_cursor_update(dst, src, fb->width, fb->height);
655*41ec0267Sriastradh 	if (ret)
656*41ec0267Sriastradh 		goto err_drm_gem_vram_vunmap_dst;
657*41ec0267Sriastradh 
658*41ec0267Sriastradh 	/* Always unmap buffers here. Destination buffers are
659*41ec0267Sriastradh 	 * perma-pinned while the driver is active. We're only
660*41ec0267Sriastradh 	 * changing ref-counters here.
661*41ec0267Sriastradh 	 */
662*41ec0267Sriastradh 	drm_gem_vram_vunmap(ast->cursor.gbo[ast->cursor.next_index], dst);
663*41ec0267Sriastradh 	drm_gem_vram_vunmap(gbo, src);
664*41ec0267Sriastradh 
665*41ec0267Sriastradh 	return 0;
666*41ec0267Sriastradh 
667*41ec0267Sriastradh err_drm_gem_vram_vunmap_dst:
668*41ec0267Sriastradh 	drm_gem_vram_vunmap(ast->cursor.gbo[ast->cursor.next_index], dst);
669*41ec0267Sriastradh err_drm_gem_vram_vunmap_src:
670*41ec0267Sriastradh 	drm_gem_vram_vunmap(gbo, src);
671*41ec0267Sriastradh err_drm_gem_vram_unpin:
672*41ec0267Sriastradh 	drm_gem_vram_unpin(gbo);
673*41ec0267Sriastradh 	return ret;
674*41ec0267Sriastradh }
675*41ec0267Sriastradh 
ast_cursor_plane_helper_atomic_check(struct drm_plane * plane,struct drm_plane_state * state)676*41ec0267Sriastradh static int ast_cursor_plane_helper_atomic_check(struct drm_plane *plane,
677*41ec0267Sriastradh 						struct drm_plane_state *state)
678*41ec0267Sriastradh {
679*41ec0267Sriastradh 	struct drm_framebuffer *fb = state->fb;
680*41ec0267Sriastradh 	struct drm_crtc_state *crtc_state;
681*41ec0267Sriastradh 	int ret;
682*41ec0267Sriastradh 
683*41ec0267Sriastradh 	if (!state->crtc)
684*41ec0267Sriastradh 		return 0;
685*41ec0267Sriastradh 
686*41ec0267Sriastradh 	crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc);
687*41ec0267Sriastradh 
688*41ec0267Sriastradh 	ret = drm_atomic_helper_check_plane_state(state, crtc_state,
689*41ec0267Sriastradh 						  DRM_PLANE_HELPER_NO_SCALING,
690*41ec0267Sriastradh 						  DRM_PLANE_HELPER_NO_SCALING,
691*41ec0267Sriastradh 						  true, true);
692*41ec0267Sriastradh 	if (ret)
693*41ec0267Sriastradh 		return ret;
694*41ec0267Sriastradh 
695*41ec0267Sriastradh 	if (!state->visible)
696*41ec0267Sriastradh 		return 0;
697*41ec0267Sriastradh 
698*41ec0267Sriastradh 	if (fb->width > AST_MAX_HWC_WIDTH || fb->height > AST_MAX_HWC_HEIGHT)
699*41ec0267Sriastradh 		return -EINVAL;
700*41ec0267Sriastradh 
701*41ec0267Sriastradh 	return 0;
702*41ec0267Sriastradh }
703*41ec0267Sriastradh 
704*41ec0267Sriastradh static void
ast_cursor_plane_helper_atomic_update(struct drm_plane * plane,struct drm_plane_state * old_state)705*41ec0267Sriastradh ast_cursor_plane_helper_atomic_update(struct drm_plane *plane,
706*41ec0267Sriastradh 				      struct drm_plane_state *old_state)
707*41ec0267Sriastradh {
708*41ec0267Sriastradh 	struct drm_plane_state *state = plane->state;
709*41ec0267Sriastradh 	struct drm_crtc *crtc = state->crtc;
710*41ec0267Sriastradh 	struct drm_framebuffer *fb = state->fb;
711*41ec0267Sriastradh 	struct ast_private *ast = plane->dev->dev_private;
712*41ec0267Sriastradh 	struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
713*41ec0267Sriastradh 	struct drm_gem_vram_object *gbo;
714*41ec0267Sriastradh 	s64 off;
715*41ec0267Sriastradh 	u8 jreg;
716*41ec0267Sriastradh 
717*41ec0267Sriastradh 	ast_crtc->offset_x = AST_MAX_HWC_WIDTH - fb->width;
718*41ec0267Sriastradh 	ast_crtc->offset_y = AST_MAX_HWC_WIDTH - fb->height;
719*41ec0267Sriastradh 
720*41ec0267Sriastradh 	if (state->fb != old_state->fb) {
721*41ec0267Sriastradh 		/* A new cursor image was installed. */
722*41ec0267Sriastradh 		gbo = ast->cursor.gbo[ast->cursor.next_index];
723*41ec0267Sriastradh 		off = drm_gem_vram_offset(gbo);
724*41ec0267Sriastradh 		if (WARN_ON_ONCE(off < 0))
725*41ec0267Sriastradh 			return; /* Bug: we didn't pin cursor HW BO to VRAM. */
726*41ec0267Sriastradh 		ast_cursor_set_base(ast, off);
727*41ec0267Sriastradh 
728*41ec0267Sriastradh 		++ast->cursor.next_index;
729*41ec0267Sriastradh 		ast->cursor.next_index %= ARRAY_SIZE(ast->cursor.gbo);
730*41ec0267Sriastradh 	}
731*41ec0267Sriastradh 
732*41ec0267Sriastradh 	ast_cursor_move(crtc, state->crtc_x, state->crtc_y);
733*41ec0267Sriastradh 
734*41ec0267Sriastradh 	jreg = 0x2;
735*41ec0267Sriastradh 	/* enable ARGB cursor */
736*41ec0267Sriastradh 	jreg |= 1;
737*41ec0267Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, jreg);
738*41ec0267Sriastradh }
739*41ec0267Sriastradh 
740*41ec0267Sriastradh static void
ast_cursor_plane_helper_atomic_disable(struct drm_plane * plane,struct drm_plane_state * old_state)741*41ec0267Sriastradh ast_cursor_plane_helper_atomic_disable(struct drm_plane *plane,
742*41ec0267Sriastradh 				       struct drm_plane_state *old_state)
743*41ec0267Sriastradh {
744*41ec0267Sriastradh 	struct ast_private *ast = plane->dev->dev_private;
745*41ec0267Sriastradh 
746*41ec0267Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, 0x00);
747*41ec0267Sriastradh }
748*41ec0267Sriastradh 
749*41ec0267Sriastradh static const struct drm_plane_helper_funcs ast_cursor_plane_helper_funcs = {
750*41ec0267Sriastradh 	.prepare_fb = ast_cursor_plane_helper_prepare_fb,
751*41ec0267Sriastradh 	.cleanup_fb = NULL, /* not required for cursor plane */
752*41ec0267Sriastradh 	.atomic_check = ast_cursor_plane_helper_atomic_check,
753*41ec0267Sriastradh 	.atomic_update = ast_cursor_plane_helper_atomic_update,
754*41ec0267Sriastradh 	.atomic_disable = ast_cursor_plane_helper_atomic_disable,
755*41ec0267Sriastradh };
756*41ec0267Sriastradh 
757*41ec0267Sriastradh static const struct drm_plane_funcs ast_cursor_plane_funcs = {
758*41ec0267Sriastradh 	.update_plane = drm_atomic_helper_update_plane,
759*41ec0267Sriastradh 	.disable_plane = drm_atomic_helper_disable_plane,
760*41ec0267Sriastradh 	.destroy = drm_plane_cleanup,
761*41ec0267Sriastradh 	.reset = drm_atomic_helper_plane_reset,
762*41ec0267Sriastradh 	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
763*41ec0267Sriastradh 	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
764*41ec0267Sriastradh };
765*41ec0267Sriastradh 
766*41ec0267Sriastradh /*
767*41ec0267Sriastradh  * CRTC
768*41ec0267Sriastradh  */
769*41ec0267Sriastradh 
ast_crtc_dpms(struct drm_crtc * crtc,int mode)770fcd0cb28Sriastradh static void ast_crtc_dpms(struct drm_crtc *crtc, int mode)
771fcd0cb28Sriastradh {
772fcd0cb28Sriastradh 	struct ast_private *ast = crtc->dev->dev_private;
773fcd0cb28Sriastradh 
774fcd0cb28Sriastradh 	if (ast->chip == AST1180)
775fcd0cb28Sriastradh 		return;
776fcd0cb28Sriastradh 
777*41ec0267Sriastradh 	/* TODO: Maybe control display signal generation with
778*41ec0267Sriastradh 	 *       Sync Enable (bit CR17.7).
779*41ec0267Sriastradh 	 */
780fcd0cb28Sriastradh 	switch (mode) {
781fcd0cb28Sriastradh 	case DRM_MODE_DPMS_ON:
782fcd0cb28Sriastradh 	case DRM_MODE_DPMS_STANDBY:
783fcd0cb28Sriastradh 	case DRM_MODE_DPMS_SUSPEND:
784efa246c0Sriastradh 		if (ast->tx_chip_type == AST_TX_DP501)
785efa246c0Sriastradh 			ast_set_dp501_video_output(crtc->dev, 1);
786*41ec0267Sriastradh 		ast_crtc_load_lut(ast, crtc);
787fcd0cb28Sriastradh 		break;
788fcd0cb28Sriastradh 	case DRM_MODE_DPMS_OFF:
789efa246c0Sriastradh 		if (ast->tx_chip_type == AST_TX_DP501)
790efa246c0Sriastradh 			ast_set_dp501_video_output(crtc->dev, 0);
791fcd0cb28Sriastradh 		break;
792fcd0cb28Sriastradh 	}
793fcd0cb28Sriastradh }
794fcd0cb28Sriastradh 
ast_crtc_helper_atomic_check(struct drm_crtc * crtc,struct drm_crtc_state * state)795*41ec0267Sriastradh static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc,
796*41ec0267Sriastradh 					struct drm_crtc_state *state)
797fcd0cb28Sriastradh {
798fcd0cb28Sriastradh 	struct ast_private *ast = crtc->dev->dev_private;
799*41ec0267Sriastradh 	struct ast_crtc_state *ast_state;
800*41ec0267Sriastradh 	const struct drm_format_info *format;
801*41ec0267Sriastradh 	bool succ;
802fcd0cb28Sriastradh 
803fcd0cb28Sriastradh 	if (ast->chip == AST1180) {
804fcd0cb28Sriastradh 		DRM_ERROR("AST 1180 modesetting not supported\n");
805fcd0cb28Sriastradh 		return -EINVAL;
806fcd0cb28Sriastradh 	}
807fcd0cb28Sriastradh 
808*41ec0267Sriastradh 	ast_state = to_ast_crtc_state(state);
809*41ec0267Sriastradh 
810*41ec0267Sriastradh 	format = ast_state->format;
811*41ec0267Sriastradh 	if (!format)
812*41ec0267Sriastradh 		return 0;
813*41ec0267Sriastradh 
814*41ec0267Sriastradh 	succ = ast_get_vbios_mode_info(format, &state->mode,
815*41ec0267Sriastradh 				       &state->adjusted_mode,
816*41ec0267Sriastradh 				       &ast_state->vbios_mode_info);
817*41ec0267Sriastradh 	if (!succ)
818fcd0cb28Sriastradh 		return -EINVAL;
819fcd0cb28Sriastradh 
820fcd0cb28Sriastradh 	return 0;
821fcd0cb28Sriastradh }
822fcd0cb28Sriastradh 
ast_crtc_helper_atomic_begin(struct drm_crtc * crtc,struct drm_crtc_state * old_crtc_state)823*41ec0267Sriastradh static void ast_crtc_helper_atomic_begin(struct drm_crtc *crtc,
824*41ec0267Sriastradh 					 struct drm_crtc_state *old_crtc_state)
825fcd0cb28Sriastradh {
826fcd0cb28Sriastradh 	struct ast_private *ast = crtc->dev->dev_private;
827*41ec0267Sriastradh 
828*41ec0267Sriastradh 	ast_open_key(ast);
829fcd0cb28Sriastradh }
830fcd0cb28Sriastradh 
ast_crtc_helper_atomic_flush(struct drm_crtc * crtc,struct drm_crtc_state * old_crtc_state)831*41ec0267Sriastradh static void ast_crtc_helper_atomic_flush(struct drm_crtc *crtc,
832*41ec0267Sriastradh 					 struct drm_crtc_state *old_crtc_state)
833*41ec0267Sriastradh {
834*41ec0267Sriastradh 	struct drm_device *dev = crtc->dev;
835*41ec0267Sriastradh 	struct ast_private *ast = dev->dev_private;
836*41ec0267Sriastradh 	struct ast_crtc_state *ast_state;
837*41ec0267Sriastradh 	const struct drm_format_info *format;
838*41ec0267Sriastradh 	struct ast_vbios_mode_info *vbios_mode_info;
839*41ec0267Sriastradh 	struct drm_display_mode *adjusted_mode;
840*41ec0267Sriastradh 
841*41ec0267Sriastradh 	crtc->state->no_vblank = true;
842*41ec0267Sriastradh 
843*41ec0267Sriastradh 	ast_state = to_ast_crtc_state(crtc->state);
844*41ec0267Sriastradh 
845*41ec0267Sriastradh 	format = ast_state->format;
846*41ec0267Sriastradh 	if (!format)
847*41ec0267Sriastradh 		return;
848*41ec0267Sriastradh 
849*41ec0267Sriastradh 	vbios_mode_info = &ast_state->vbios_mode_info;
850*41ec0267Sriastradh 
851*41ec0267Sriastradh 	ast_set_color_reg(ast, format);
852*41ec0267Sriastradh 	ast_set_vbios_color_reg(ast, format, vbios_mode_info);
853*41ec0267Sriastradh 
854*41ec0267Sriastradh 	if (!crtc->state->mode_changed)
855*41ec0267Sriastradh 		return;
856*41ec0267Sriastradh 
857*41ec0267Sriastradh 	adjusted_mode = &crtc->state->adjusted_mode;
858*41ec0267Sriastradh 
859*41ec0267Sriastradh 	ast_set_vbios_mode_reg(ast, adjusted_mode, vbios_mode_info);
860*41ec0267Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x06);
861*41ec0267Sriastradh 	ast_set_std_reg(ast, adjusted_mode, vbios_mode_info);
862*41ec0267Sriastradh 	ast_set_crtc_reg(ast, adjusted_mode, vbios_mode_info);
863*41ec0267Sriastradh 	ast_set_dclk_reg(ast, adjusted_mode, vbios_mode_info);
864*41ec0267Sriastradh 	ast_set_crtthd_reg(ast);
865*41ec0267Sriastradh 	ast_set_sync_reg(ast, adjusted_mode, vbios_mode_info);
866*41ec0267Sriastradh }
867*41ec0267Sriastradh 
868*41ec0267Sriastradh static void
ast_crtc_helper_atomic_enable(struct drm_crtc * crtc,struct drm_crtc_state * old_crtc_state)869*41ec0267Sriastradh ast_crtc_helper_atomic_enable(struct drm_crtc *crtc,
870*41ec0267Sriastradh 			      struct drm_crtc_state *old_crtc_state)
871*41ec0267Sriastradh {
872*41ec0267Sriastradh 	ast_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
873*41ec0267Sriastradh }
874*41ec0267Sriastradh 
875*41ec0267Sriastradh static void
ast_crtc_helper_atomic_disable(struct drm_crtc * crtc,struct drm_crtc_state * old_crtc_state)876*41ec0267Sriastradh ast_crtc_helper_atomic_disable(struct drm_crtc *crtc,
877*41ec0267Sriastradh 			       struct drm_crtc_state *old_crtc_state)
878*41ec0267Sriastradh {
879*41ec0267Sriastradh 	ast_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
880*41ec0267Sriastradh }
881fcd0cb28Sriastradh 
882fcd0cb28Sriastradh static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = {
883*41ec0267Sriastradh 	.atomic_check = ast_crtc_helper_atomic_check,
884*41ec0267Sriastradh 	.atomic_begin = ast_crtc_helper_atomic_begin,
885*41ec0267Sriastradh 	.atomic_flush = ast_crtc_helper_atomic_flush,
886*41ec0267Sriastradh 	.atomic_enable = ast_crtc_helper_atomic_enable,
887*41ec0267Sriastradh 	.atomic_disable = ast_crtc_helper_atomic_disable,
888fcd0cb28Sriastradh };
889fcd0cb28Sriastradh 
ast_crtc_destroy(struct drm_crtc * crtc)890fcd0cb28Sriastradh static void ast_crtc_destroy(struct drm_crtc *crtc)
891fcd0cb28Sriastradh {
892fcd0cb28Sriastradh 	drm_crtc_cleanup(crtc);
893fcd0cb28Sriastradh 	kfree(crtc);
894fcd0cb28Sriastradh }
895fcd0cb28Sriastradh 
896*41ec0267Sriastradh static struct drm_crtc_state *
ast_crtc_atomic_duplicate_state(struct drm_crtc * crtc)897*41ec0267Sriastradh ast_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
898*41ec0267Sriastradh {
899*41ec0267Sriastradh 	struct ast_crtc_state *new_ast_state, *ast_state;
900*41ec0267Sriastradh 
901*41ec0267Sriastradh 	if (WARN_ON(!crtc->state))
902*41ec0267Sriastradh 		return NULL;
903*41ec0267Sriastradh 
904*41ec0267Sriastradh 	new_ast_state = kmalloc(sizeof(*new_ast_state), GFP_KERNEL);
905*41ec0267Sriastradh 	if (!new_ast_state)
906*41ec0267Sriastradh 		return NULL;
907*41ec0267Sriastradh 	__drm_atomic_helper_crtc_duplicate_state(crtc, &new_ast_state->base);
908*41ec0267Sriastradh 
909*41ec0267Sriastradh 	ast_state = to_ast_crtc_state(crtc->state);
910*41ec0267Sriastradh 
911*41ec0267Sriastradh 	new_ast_state->format = ast_state->format;
912*41ec0267Sriastradh 	memcpy(&new_ast_state->vbios_mode_info, &ast_state->vbios_mode_info,
913*41ec0267Sriastradh 	       sizeof(new_ast_state->vbios_mode_info));
914*41ec0267Sriastradh 
915*41ec0267Sriastradh 	return &new_ast_state->base;
916*41ec0267Sriastradh }
917*41ec0267Sriastradh 
ast_crtc_atomic_destroy_state(struct drm_crtc * crtc,struct drm_crtc_state * state)918*41ec0267Sriastradh static void ast_crtc_atomic_destroy_state(struct drm_crtc *crtc,
919*41ec0267Sriastradh 					  struct drm_crtc_state *state)
920*41ec0267Sriastradh {
921*41ec0267Sriastradh 	struct ast_crtc_state *ast_state = to_ast_crtc_state(state);
922*41ec0267Sriastradh 
923*41ec0267Sriastradh 	__drm_atomic_helper_crtc_destroy_state(&ast_state->base);
924*41ec0267Sriastradh 	kfree(ast_state);
925*41ec0267Sriastradh }
926*41ec0267Sriastradh 
927fcd0cb28Sriastradh static const struct drm_crtc_funcs ast_crtc_funcs = {
928*41ec0267Sriastradh 	.reset = drm_atomic_helper_crtc_reset,
929fcd0cb28Sriastradh 	.set_config = drm_crtc_helper_set_config,
930*41ec0267Sriastradh 	.gamma_set = drm_atomic_helper_legacy_gamma_set,
931fcd0cb28Sriastradh 	.destroy = ast_crtc_destroy,
932*41ec0267Sriastradh 	.set_config = drm_atomic_helper_set_config,
933*41ec0267Sriastradh 	.page_flip = drm_atomic_helper_page_flip,
934*41ec0267Sriastradh 	.atomic_duplicate_state = ast_crtc_atomic_duplicate_state,
935*41ec0267Sriastradh 	.atomic_destroy_state = ast_crtc_atomic_destroy_state,
936fcd0cb28Sriastradh };
937fcd0cb28Sriastradh 
ast_crtc_init(struct drm_device * dev)9389d20d926Sriastradh static int ast_crtc_init(struct drm_device *dev)
939fcd0cb28Sriastradh {
940*41ec0267Sriastradh 	struct ast_private *ast = dev->dev_private;
941fcd0cb28Sriastradh 	struct ast_crtc *crtc;
942*41ec0267Sriastradh 	int ret;
943fcd0cb28Sriastradh 
944fcd0cb28Sriastradh 	crtc = kzalloc(sizeof(struct ast_crtc), GFP_KERNEL);
945fcd0cb28Sriastradh 	if (!crtc)
946fcd0cb28Sriastradh 		return -ENOMEM;
947fcd0cb28Sriastradh 
948*41ec0267Sriastradh 	ret = drm_crtc_init_with_planes(dev, &crtc->base, &ast->primary_plane,
949*41ec0267Sriastradh 					&ast->cursor_plane, &ast_crtc_funcs,
950*41ec0267Sriastradh 					NULL);
951*41ec0267Sriastradh 	if (ret)
952*41ec0267Sriastradh 		goto err_kfree;
953*41ec0267Sriastradh 
954fcd0cb28Sriastradh 	drm_mode_crtc_set_gamma_size(&crtc->base, 256);
955fcd0cb28Sriastradh 	drm_crtc_helper_add(&crtc->base, &ast_crtc_helper_funcs);
956fcd0cb28Sriastradh 	return 0;
957*41ec0267Sriastradh 
958*41ec0267Sriastradh err_kfree:
959*41ec0267Sriastradh 	kfree(crtc);
960*41ec0267Sriastradh 	return ret;
961fcd0cb28Sriastradh }
962fcd0cb28Sriastradh 
963*41ec0267Sriastradh /*
964*41ec0267Sriastradh  * Encoder
965*41ec0267Sriastradh  */
966*41ec0267Sriastradh 
ast_encoder_destroy(struct drm_encoder * encoder)967fcd0cb28Sriastradh static void ast_encoder_destroy(struct drm_encoder *encoder)
968fcd0cb28Sriastradh {
969fcd0cb28Sriastradh 	drm_encoder_cleanup(encoder);
970fcd0cb28Sriastradh 	kfree(encoder);
971fcd0cb28Sriastradh }
972fcd0cb28Sriastradh 
973fcd0cb28Sriastradh static const struct drm_encoder_funcs ast_enc_funcs = {
974fcd0cb28Sriastradh 	.destroy = ast_encoder_destroy,
975fcd0cb28Sriastradh };
976fcd0cb28Sriastradh 
ast_encoder_init(struct drm_device * dev)9779d20d926Sriastradh static int ast_encoder_init(struct drm_device *dev)
978fcd0cb28Sriastradh {
979fcd0cb28Sriastradh 	struct ast_encoder *ast_encoder;
980fcd0cb28Sriastradh 
981fcd0cb28Sriastradh 	ast_encoder = kzalloc(sizeof(struct ast_encoder), GFP_KERNEL);
982fcd0cb28Sriastradh 	if (!ast_encoder)
983fcd0cb28Sriastradh 		return -ENOMEM;
984fcd0cb28Sriastradh 
985fcd0cb28Sriastradh 	drm_encoder_init(dev, &ast_encoder->base, &ast_enc_funcs,
986*41ec0267Sriastradh 			 DRM_MODE_ENCODER_DAC, NULL);
987fcd0cb28Sriastradh 
988fcd0cb28Sriastradh 	ast_encoder->base.possible_crtcs = 1;
989fcd0cb28Sriastradh 	return 0;
990fcd0cb28Sriastradh }
991fcd0cb28Sriastradh 
992*41ec0267Sriastradh /*
993*41ec0267Sriastradh  * Connector
994*41ec0267Sriastradh  */
995*41ec0267Sriastradh 
ast_get_modes(struct drm_connector * connector)996fcd0cb28Sriastradh static int ast_get_modes(struct drm_connector *connector)
997fcd0cb28Sriastradh {
998fcd0cb28Sriastradh 	struct ast_connector *ast_connector = to_ast_connector(connector);
999efa246c0Sriastradh 	struct ast_private *ast = connector->dev->dev_private;
1000fcd0cb28Sriastradh 	struct edid *edid;
1001fcd0cb28Sriastradh 	int ret;
1002efa246c0Sriastradh 	bool flags = false;
1003efa246c0Sriastradh 	if (ast->tx_chip_type == AST_TX_DP501) {
1004efa246c0Sriastradh 		ast->dp501_maxclk = 0xff;
1005efa246c0Sriastradh 		edid = kmalloc(128, GFP_KERNEL);
1006efa246c0Sriastradh 		if (!edid)
1007efa246c0Sriastradh 			return -ENOMEM;
1008fcd0cb28Sriastradh 
1009efa246c0Sriastradh 		flags = ast_dp501_read_edid(connector->dev, (u8 *)edid);
1010efa246c0Sriastradh 		if (flags)
1011efa246c0Sriastradh 			ast->dp501_maxclk = ast_get_dp501_max_clk(connector->dev);
1012efa246c0Sriastradh 		else
1013efa246c0Sriastradh 			kfree(edid);
1014efa246c0Sriastradh 	}
1015efa246c0Sriastradh 	if (!flags)
1016fcd0cb28Sriastradh 		edid = drm_get_edid(connector, &ast_connector->i2c->adapter);
1017fcd0cb28Sriastradh 	if (edid) {
1018*41ec0267Sriastradh 		drm_connector_update_edid_property(&ast_connector->base, edid);
1019fcd0cb28Sriastradh 		ret = drm_add_edid_modes(connector, edid);
1020fcd0cb28Sriastradh 		kfree(edid);
1021fcd0cb28Sriastradh 		return ret;
1022fcd0cb28Sriastradh 	} else
1023*41ec0267Sriastradh 		drm_connector_update_edid_property(&ast_connector->base, NULL);
1024fcd0cb28Sriastradh 	return 0;
1025fcd0cb28Sriastradh }
1026fcd0cb28Sriastradh 
ast_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)1027*41ec0267Sriastradh static enum drm_mode_status ast_mode_valid(struct drm_connector *connector,
1028fcd0cb28Sriastradh 			  struct drm_display_mode *mode)
1029fcd0cb28Sriastradh {
1030efa246c0Sriastradh 	struct ast_private *ast = connector->dev->dev_private;
1031efa246c0Sriastradh 	int flags = MODE_NOMODE;
1032efa246c0Sriastradh 	uint32_t jtemp;
1033efa246c0Sriastradh 
1034efa246c0Sriastradh 	if (ast->support_wide_screen) {
1035efa246c0Sriastradh 		if ((mode->hdisplay == 1680) && (mode->vdisplay == 1050))
1036fcd0cb28Sriastradh 			return MODE_OK;
1037efa246c0Sriastradh 		if ((mode->hdisplay == 1280) && (mode->vdisplay == 800))
1038efa246c0Sriastradh 			return MODE_OK;
1039efa246c0Sriastradh 		if ((mode->hdisplay == 1440) && (mode->vdisplay == 900))
1040efa246c0Sriastradh 			return MODE_OK;
1041efa246c0Sriastradh 		if ((mode->hdisplay == 1360) && (mode->vdisplay == 768))
1042efa246c0Sriastradh 			return MODE_OK;
1043efa246c0Sriastradh 		if ((mode->hdisplay == 1600) && (mode->vdisplay == 900))
1044efa246c0Sriastradh 			return MODE_OK;
1045efa246c0Sriastradh 
1046*41ec0267Sriastradh 		if ((ast->chip == AST2100) || (ast->chip == AST2200) ||
1047*41ec0267Sriastradh 		    (ast->chip == AST2300) || (ast->chip == AST2400) ||
1048*41ec0267Sriastradh 		    (ast->chip == AST2500) || (ast->chip == AST1180)) {
1049efa246c0Sriastradh 			if ((mode->hdisplay == 1920) && (mode->vdisplay == 1080))
1050efa246c0Sriastradh 				return MODE_OK;
1051efa246c0Sriastradh 
1052efa246c0Sriastradh 			if ((mode->hdisplay == 1920) && (mode->vdisplay == 1200)) {
1053efa246c0Sriastradh 				jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 0xff);
1054efa246c0Sriastradh 				if (jtemp & 0x01)
1055efa246c0Sriastradh 					return MODE_NOMODE;
1056efa246c0Sriastradh 				else
1057efa246c0Sriastradh 					return MODE_OK;
1058efa246c0Sriastradh 			}
1059efa246c0Sriastradh 		}
1060efa246c0Sriastradh 	}
1061efa246c0Sriastradh 	switch (mode->hdisplay) {
1062efa246c0Sriastradh 	case 640:
1063efa246c0Sriastradh 		if (mode->vdisplay == 480) flags = MODE_OK;
1064efa246c0Sriastradh 		break;
1065efa246c0Sriastradh 	case 800:
1066efa246c0Sriastradh 		if (mode->vdisplay == 600) flags = MODE_OK;
1067efa246c0Sriastradh 		break;
1068efa246c0Sriastradh 	case 1024:
1069efa246c0Sriastradh 		if (mode->vdisplay == 768) flags = MODE_OK;
1070efa246c0Sriastradh 		break;
1071efa246c0Sriastradh 	case 1280:
1072efa246c0Sriastradh 		if (mode->vdisplay == 1024) flags = MODE_OK;
1073efa246c0Sriastradh 		break;
1074efa246c0Sriastradh 	case 1600:
1075efa246c0Sriastradh 		if (mode->vdisplay == 1200) flags = MODE_OK;
1076efa246c0Sriastradh 		break;
1077efa246c0Sriastradh 	default:
1078efa246c0Sriastradh 		return flags;
1079efa246c0Sriastradh 	}
1080efa246c0Sriastradh 
1081efa246c0Sriastradh 	return flags;
1082fcd0cb28Sriastradh }
1083fcd0cb28Sriastradh 
ast_connector_destroy(struct drm_connector * connector)1084fcd0cb28Sriastradh static void ast_connector_destroy(struct drm_connector *connector)
1085fcd0cb28Sriastradh {
1086fcd0cb28Sriastradh 	struct ast_connector *ast_connector = to_ast_connector(connector);
1087fcd0cb28Sriastradh 	ast_i2c_destroy(ast_connector->i2c);
1088efa246c0Sriastradh 	drm_connector_unregister(connector);
1089fcd0cb28Sriastradh 	drm_connector_cleanup(connector);
1090fcd0cb28Sriastradh 	kfree(connector);
1091fcd0cb28Sriastradh }
1092fcd0cb28Sriastradh 
1093fcd0cb28Sriastradh static const struct drm_connector_helper_funcs ast_connector_helper_funcs = {
1094fcd0cb28Sriastradh 	.get_modes = ast_get_modes,
1095*41ec0267Sriastradh 	.mode_valid = ast_mode_valid,
1096fcd0cb28Sriastradh };
1097fcd0cb28Sriastradh 
1098fcd0cb28Sriastradh static const struct drm_connector_funcs ast_connector_funcs = {
1099*41ec0267Sriastradh 	.reset = drm_atomic_helper_connector_reset,
1100fcd0cb28Sriastradh 	.fill_modes = drm_helper_probe_single_connector_modes,
1101fcd0cb28Sriastradh 	.destroy = ast_connector_destroy,
1102*41ec0267Sriastradh 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
1103*41ec0267Sriastradh 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
1104fcd0cb28Sriastradh };
1105fcd0cb28Sriastradh 
ast_connector_init(struct drm_device * dev)11069d20d926Sriastradh static int ast_connector_init(struct drm_device *dev)
1107fcd0cb28Sriastradh {
1108fcd0cb28Sriastradh 	struct ast_connector *ast_connector;
1109fcd0cb28Sriastradh 	struct drm_connector *connector;
1110fcd0cb28Sriastradh 	struct drm_encoder *encoder;
1111fcd0cb28Sriastradh 
1112fcd0cb28Sriastradh 	ast_connector = kzalloc(sizeof(struct ast_connector), GFP_KERNEL);
1113fcd0cb28Sriastradh 	if (!ast_connector)
1114fcd0cb28Sriastradh 		return -ENOMEM;
1115fcd0cb28Sriastradh 
1116fcd0cb28Sriastradh 	connector = &ast_connector->base;
1117*41ec0267Sriastradh 	ast_connector->i2c = ast_i2c_create(dev);
1118*41ec0267Sriastradh 	if (!ast_connector->i2c)
1119*41ec0267Sriastradh 		DRM_ERROR("failed to add ddc bus for connector\n");
1120*41ec0267Sriastradh 
1121*41ec0267Sriastradh 	drm_connector_init_with_ddc(dev, connector,
1122*41ec0267Sriastradh 				    &ast_connector_funcs,
1123*41ec0267Sriastradh 				    DRM_MODE_CONNECTOR_VGA,
1124*41ec0267Sriastradh 				    &ast_connector->i2c->adapter);
1125fcd0cb28Sriastradh 
1126fcd0cb28Sriastradh 	drm_connector_helper_add(connector, &ast_connector_helper_funcs);
1127fcd0cb28Sriastradh 
1128fcd0cb28Sriastradh 	connector->interlace_allowed = 0;
1129fcd0cb28Sriastradh 	connector->doublescan_allowed = 0;
1130fcd0cb28Sriastradh 
1131efa246c0Sriastradh 	drm_connector_register(connector);
1132fcd0cb28Sriastradh 
1133fcd0cb28Sriastradh 	connector->polled = DRM_CONNECTOR_POLL_CONNECT;
1134fcd0cb28Sriastradh 
1135fcd0cb28Sriastradh 	encoder = list_first_entry(&dev->mode_config.encoder_list, struct drm_encoder, head);
1136*41ec0267Sriastradh 	drm_connector_attach_encoder(connector, encoder);
1137fcd0cb28Sriastradh 
1138fcd0cb28Sriastradh 	return 0;
1139fcd0cb28Sriastradh }
1140fcd0cb28Sriastradh 
1141fcd0cb28Sriastradh /* allocate cursor cache and pin at start of VRAM */
ast_cursor_init(struct drm_device * dev)11429d20d926Sriastradh static int ast_cursor_init(struct drm_device *dev)
1143fcd0cb28Sriastradh {
1144fcd0cb28Sriastradh 	struct ast_private *ast = dev->dev_private;
1145*41ec0267Sriastradh 	size_t size, i;
1146*41ec0267Sriastradh 	struct drm_gem_vram_object *gbo;
1147fcd0cb28Sriastradh 	int ret;
1148fcd0cb28Sriastradh 
1149*41ec0267Sriastradh 	size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE);
1150fcd0cb28Sriastradh 
1151*41ec0267Sriastradh 	for (i = 0; i < ARRAY_SIZE(ast->cursor.gbo); ++i) {
1152*41ec0267Sriastradh 		gbo = drm_gem_vram_create(dev, size, 0);
1153*41ec0267Sriastradh 		if (IS_ERR(gbo)) {
1154*41ec0267Sriastradh 			ret = PTR_ERR(gbo);
1155*41ec0267Sriastradh 			goto err_drm_gem_vram_put;
1156*41ec0267Sriastradh 		}
1157*41ec0267Sriastradh 		ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM |
1158*41ec0267Sriastradh 					    DRM_GEM_VRAM_PL_FLAG_TOPDOWN);
1159*41ec0267Sriastradh 		if (ret) {
1160*41ec0267Sriastradh 			drm_gem_vram_put(gbo);
1161*41ec0267Sriastradh 			goto err_drm_gem_vram_put;
1162*41ec0267Sriastradh 		}
1163fcd0cb28Sriastradh 
1164*41ec0267Sriastradh 		ast->cursor.gbo[i] = gbo;
1165*41ec0267Sriastradh 	}
1166fcd0cb28Sriastradh 
1167fcd0cb28Sriastradh 	return 0;
1168*41ec0267Sriastradh 
1169*41ec0267Sriastradh err_drm_gem_vram_put:
1170*41ec0267Sriastradh 	while (i) {
1171*41ec0267Sriastradh 		--i;
1172*41ec0267Sriastradh 		gbo = ast->cursor.gbo[i];
1173*41ec0267Sriastradh 		drm_gem_vram_unpin(gbo);
1174*41ec0267Sriastradh 		drm_gem_vram_put(gbo);
1175*41ec0267Sriastradh 		ast->cursor.gbo[i] = NULL;
1176*41ec0267Sriastradh 	}
1177fcd0cb28Sriastradh 	return ret;
1178fcd0cb28Sriastradh }
1179fcd0cb28Sriastradh 
ast_cursor_fini(struct drm_device * dev)11809d20d926Sriastradh static void ast_cursor_fini(struct drm_device *dev)
1181fcd0cb28Sriastradh {
1182fcd0cb28Sriastradh 	struct ast_private *ast = dev->dev_private;
1183*41ec0267Sriastradh 	size_t i;
1184*41ec0267Sriastradh 	struct drm_gem_vram_object *gbo;
1185*41ec0267Sriastradh 
1186*41ec0267Sriastradh 	for (i = 0; i < ARRAY_SIZE(ast->cursor.gbo); ++i) {
1187*41ec0267Sriastradh 		gbo = ast->cursor.gbo[i];
1188*41ec0267Sriastradh 		drm_gem_vram_unpin(gbo);
1189*41ec0267Sriastradh 		drm_gem_vram_put(gbo);
1190*41ec0267Sriastradh 	}
1191fcd0cb28Sriastradh }
1192fcd0cb28Sriastradh 
ast_mode_init(struct drm_device * dev)1193fcd0cb28Sriastradh int ast_mode_init(struct drm_device *dev)
1194fcd0cb28Sriastradh {
1195*41ec0267Sriastradh 	struct ast_private *ast = dev->dev_private;
1196*41ec0267Sriastradh 	int ret;
1197*41ec0267Sriastradh 
1198*41ec0267Sriastradh 	memset(&ast->primary_plane, 0, sizeof(ast->primary_plane));
1199*41ec0267Sriastradh 	ret = drm_universal_plane_init(dev, &ast->primary_plane, 0x01,
1200*41ec0267Sriastradh 				       &ast_primary_plane_funcs,
1201*41ec0267Sriastradh 				       ast_primary_plane_formats,
1202*41ec0267Sriastradh 				       ARRAY_SIZE(ast_primary_plane_formats),
1203*41ec0267Sriastradh 				       NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
1204*41ec0267Sriastradh 	if (ret) {
1205*41ec0267Sriastradh 		DRM_ERROR("ast: drm_universal_plane_init() failed: %d\n", ret);
1206*41ec0267Sriastradh 		return ret;
1207*41ec0267Sriastradh 	}
1208*41ec0267Sriastradh 	drm_plane_helper_add(&ast->primary_plane,
1209*41ec0267Sriastradh 			     &ast_primary_plane_helper_funcs);
1210*41ec0267Sriastradh 
1211*41ec0267Sriastradh 	ret = drm_universal_plane_init(dev, &ast->cursor_plane, 0x01,
1212*41ec0267Sriastradh 				       &ast_cursor_plane_funcs,
1213*41ec0267Sriastradh 				       ast_cursor_plane_formats,
1214*41ec0267Sriastradh 				       ARRAY_SIZE(ast_cursor_plane_formats),
1215*41ec0267Sriastradh 				       NULL, DRM_PLANE_TYPE_CURSOR, NULL);
1216*41ec0267Sriastradh 	if (ret) {
1217*41ec0267Sriastradh 		DRM_ERROR("drm_universal_plane_failed(): %d\n", ret);
1218*41ec0267Sriastradh 		return ret;
1219*41ec0267Sriastradh 	}
1220*41ec0267Sriastradh 	drm_plane_helper_add(&ast->cursor_plane,
1221*41ec0267Sriastradh 			     &ast_cursor_plane_helper_funcs);
1222*41ec0267Sriastradh 
1223fcd0cb28Sriastradh 	ast_cursor_init(dev);
1224fcd0cb28Sriastradh 	ast_crtc_init(dev);
1225fcd0cb28Sriastradh 	ast_encoder_init(dev);
1226fcd0cb28Sriastradh 	ast_connector_init(dev);
1227*41ec0267Sriastradh 
1228fcd0cb28Sriastradh 	return 0;
1229fcd0cb28Sriastradh }
1230fcd0cb28Sriastradh 
ast_mode_fini(struct drm_device * dev)1231fcd0cb28Sriastradh void ast_mode_fini(struct drm_device *dev)
1232fcd0cb28Sriastradh {
1233fcd0cb28Sriastradh 	ast_cursor_fini(dev);
1234fcd0cb28Sriastradh }
1235fcd0cb28Sriastradh 
get_clock(void * i2c_priv)1236fcd0cb28Sriastradh static int get_clock(void *i2c_priv)
1237fcd0cb28Sriastradh {
1238fcd0cb28Sriastradh 	struct ast_i2c_chan *i2c = i2c_priv;
1239fcd0cb28Sriastradh 	struct ast_private *ast = i2c->dev->dev_private;
1240*41ec0267Sriastradh 	uint32_t val, val2, count, pass;
1241fcd0cb28Sriastradh 
1242*41ec0267Sriastradh 	count = 0;
1243*41ec0267Sriastradh 	pass = 0;
1244*41ec0267Sriastradh 	val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x10) >> 4) & 0x01;
1245*41ec0267Sriastradh 	do {
1246*41ec0267Sriastradh 		val2 = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x10) >> 4) & 0x01;
1247*41ec0267Sriastradh 		if (val == val2) {
1248*41ec0267Sriastradh 			pass++;
1249*41ec0267Sriastradh 		} else {
1250*41ec0267Sriastradh 			pass = 0;
1251*41ec0267Sriastradh 			val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x10) >> 4) & 0x01;
1252*41ec0267Sriastradh 		}
1253*41ec0267Sriastradh 	} while ((pass < 5) && (count++ < 0x10000));
1254*41ec0267Sriastradh 
1255fcd0cb28Sriastradh 	return val & 1 ? 1 : 0;
1256fcd0cb28Sriastradh }
1257fcd0cb28Sriastradh 
get_data(void * i2c_priv)1258fcd0cb28Sriastradh static int get_data(void *i2c_priv)
1259fcd0cb28Sriastradh {
1260fcd0cb28Sriastradh 	struct ast_i2c_chan *i2c = i2c_priv;
1261fcd0cb28Sriastradh 	struct ast_private *ast = i2c->dev->dev_private;
1262*41ec0267Sriastradh 	uint32_t val, val2, count, pass;
1263fcd0cb28Sriastradh 
1264*41ec0267Sriastradh 	count = 0;
1265*41ec0267Sriastradh 	pass = 0;
1266*41ec0267Sriastradh 	val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x20) >> 5) & 0x01;
1267*41ec0267Sriastradh 	do {
1268*41ec0267Sriastradh 		val2 = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x20) >> 5) & 0x01;
1269*41ec0267Sriastradh 		if (val == val2) {
1270*41ec0267Sriastradh 			pass++;
1271*41ec0267Sriastradh 		} else {
1272*41ec0267Sriastradh 			pass = 0;
1273*41ec0267Sriastradh 			val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x20) >> 5) & 0x01;
1274*41ec0267Sriastradh 		}
1275*41ec0267Sriastradh 	} while ((pass < 5) && (count++ < 0x10000));
1276*41ec0267Sriastradh 
1277fcd0cb28Sriastradh 	return val & 1 ? 1 : 0;
1278fcd0cb28Sriastradh }
1279fcd0cb28Sriastradh 
set_clock(void * i2c_priv,int clock)1280fcd0cb28Sriastradh static void set_clock(void *i2c_priv, int clock)
1281fcd0cb28Sriastradh {
1282fcd0cb28Sriastradh 	struct ast_i2c_chan *i2c = i2c_priv;
1283fcd0cb28Sriastradh 	struct ast_private *ast = i2c->dev->dev_private;
1284fcd0cb28Sriastradh 	int i;
1285fcd0cb28Sriastradh 	u8 ujcrb7, jtemp;
1286fcd0cb28Sriastradh 
1287fcd0cb28Sriastradh 	for (i = 0; i < 0x10000; i++) {
1288fcd0cb28Sriastradh 		ujcrb7 = ((clock & 0x01) ? 0 : 1);
1289*41ec0267Sriastradh 		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xf4, ujcrb7);
1290fcd0cb28Sriastradh 		jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x01);
1291fcd0cb28Sriastradh 		if (ujcrb7 == jtemp)
1292fcd0cb28Sriastradh 			break;
1293fcd0cb28Sriastradh 	}
1294fcd0cb28Sriastradh }
1295fcd0cb28Sriastradh 
set_data(void * i2c_priv,int data)1296fcd0cb28Sriastradh static void set_data(void *i2c_priv, int data)
1297fcd0cb28Sriastradh {
1298fcd0cb28Sriastradh 	struct ast_i2c_chan *i2c = i2c_priv;
1299fcd0cb28Sriastradh 	struct ast_private *ast = i2c->dev->dev_private;
1300fcd0cb28Sriastradh 	int i;
1301fcd0cb28Sriastradh 	u8 ujcrb7, jtemp;
1302fcd0cb28Sriastradh 
1303fcd0cb28Sriastradh 	for (i = 0; i < 0x10000; i++) {
1304fcd0cb28Sriastradh 		ujcrb7 = ((data & 0x01) ? 0 : 1) << 2;
1305*41ec0267Sriastradh 		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xf1, ujcrb7);
1306fcd0cb28Sriastradh 		jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x04);
1307fcd0cb28Sriastradh 		if (ujcrb7 == jtemp)
1308fcd0cb28Sriastradh 			break;
1309fcd0cb28Sriastradh 	}
1310fcd0cb28Sriastradh }
1311fcd0cb28Sriastradh 
ast_i2c_create(struct drm_device * dev)1312fcd0cb28Sriastradh static struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev)
1313fcd0cb28Sriastradh {
1314fcd0cb28Sriastradh 	struct ast_i2c_chan *i2c;
1315fcd0cb28Sriastradh 	int ret;
1316fcd0cb28Sriastradh 
1317fcd0cb28Sriastradh 	i2c = kzalloc(sizeof(struct ast_i2c_chan), GFP_KERNEL);
1318fcd0cb28Sriastradh 	if (!i2c)
1319fcd0cb28Sriastradh 		return NULL;
1320fcd0cb28Sriastradh 
1321fcd0cb28Sriastradh 	i2c->adapter.owner = THIS_MODULE;
1322fcd0cb28Sriastradh 	i2c->adapter.class = I2C_CLASS_DDC;
1323fcd0cb28Sriastradh 	i2c->adapter.dev.parent = &dev->pdev->dev;
1324fcd0cb28Sriastradh 	i2c->dev = dev;
1325fcd0cb28Sriastradh 	i2c_set_adapdata(&i2c->adapter, i2c);
1326fcd0cb28Sriastradh 	snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
1327fcd0cb28Sriastradh 		 "AST i2c bit bus");
1328fcd0cb28Sriastradh 	i2c->adapter.algo_data = &i2c->bit;
1329fcd0cb28Sriastradh 
1330fcd0cb28Sriastradh 	i2c->bit.udelay = 20;
1331fcd0cb28Sriastradh 	i2c->bit.timeout = 2;
1332fcd0cb28Sriastradh 	i2c->bit.data = i2c;
1333fcd0cb28Sriastradh 	i2c->bit.setsda = set_data;
1334fcd0cb28Sriastradh 	i2c->bit.setscl = set_clock;
1335fcd0cb28Sriastradh 	i2c->bit.getsda = get_data;
1336fcd0cb28Sriastradh 	i2c->bit.getscl = get_clock;
1337fcd0cb28Sriastradh 	ret = i2c_bit_add_bus(&i2c->adapter);
1338fcd0cb28Sriastradh 	if (ret) {
1339fcd0cb28Sriastradh 		DRM_ERROR("Failed to register bit i2c\n");
1340fcd0cb28Sriastradh 		goto out_free;
1341fcd0cb28Sriastradh 	}
1342fcd0cb28Sriastradh 
1343fcd0cb28Sriastradh 	return i2c;
1344fcd0cb28Sriastradh out_free:
1345fcd0cb28Sriastradh 	kfree(i2c);
1346fcd0cb28Sriastradh 	return NULL;
1347fcd0cb28Sriastradh }
1348fcd0cb28Sriastradh 
ast_i2c_destroy(struct ast_i2c_chan * i2c)1349fcd0cb28Sriastradh static void ast_i2c_destroy(struct ast_i2c_chan *i2c)
1350fcd0cb28Sriastradh {
1351fcd0cb28Sriastradh 	if (!i2c)
1352fcd0cb28Sriastradh 		return;
1353fcd0cb28Sriastradh 	i2c_del_adapter(&i2c->adapter);
1354fcd0cb28Sriastradh 	kfree(i2c);
1355fcd0cb28Sriastradh }
1356fcd0cb28Sriastradh 
copy_cursor_image(u8 * src,u8 * dst,int width,int height)1357fcd0cb28Sriastradh static u32 copy_cursor_image(u8 *src, u8 *dst, int width, int height)
1358fcd0cb28Sriastradh {
1359fcd0cb28Sriastradh 	union {
1360fcd0cb28Sriastradh 		u32 ul;
1361fcd0cb28Sriastradh 		u8 b[4];
1362fcd0cb28Sriastradh 	} srcdata32[2], data32;
1363fcd0cb28Sriastradh 	union {
1364fcd0cb28Sriastradh 		u16 us;
1365fcd0cb28Sriastradh 		u8 b[2];
1366fcd0cb28Sriastradh 	} data16;
1367fcd0cb28Sriastradh 	u32 csum = 0;
1368fcd0cb28Sriastradh 	s32 alpha_dst_delta, last_alpha_dst_delta;
1369fcd0cb28Sriastradh 	u8 *srcxor, *dstxor;
1370fcd0cb28Sriastradh 	int i, j;
1371fcd0cb28Sriastradh 	u32 per_pixel_copy, two_pixel_copy;
1372fcd0cb28Sriastradh 
1373fcd0cb28Sriastradh 	alpha_dst_delta = AST_MAX_HWC_WIDTH << 1;
1374fcd0cb28Sriastradh 	last_alpha_dst_delta = alpha_dst_delta - (width << 1);
1375fcd0cb28Sriastradh 
1376fcd0cb28Sriastradh 	srcxor = src;
1377fcd0cb28Sriastradh 	dstxor = (u8 *)dst + last_alpha_dst_delta + (AST_MAX_HWC_HEIGHT - height) * alpha_dst_delta;
1378fcd0cb28Sriastradh 	per_pixel_copy = width & 1;
1379fcd0cb28Sriastradh 	two_pixel_copy = width >> 1;
1380fcd0cb28Sriastradh 
1381fcd0cb28Sriastradh 	for (j = 0; j < height; j++) {
1382fcd0cb28Sriastradh 		for (i = 0; i < two_pixel_copy; i++) {
1383fcd0cb28Sriastradh 			srcdata32[0].ul = *((u32 *)srcxor) & 0xf0f0f0f0;
1384fcd0cb28Sriastradh 			srcdata32[1].ul = *((u32 *)(srcxor + 4)) & 0xf0f0f0f0;
1385fcd0cb28Sriastradh 			data32.b[0] = srcdata32[0].b[1] | (srcdata32[0].b[0] >> 4);
1386fcd0cb28Sriastradh 			data32.b[1] = srcdata32[0].b[3] | (srcdata32[0].b[2] >> 4);
1387efa246c0Sriastradh 			data32.b[2] = srcdata32[1].b[1] | (srcdata32[1].b[0] >> 4);
1388efa246c0Sriastradh 			data32.b[3] = srcdata32[1].b[3] | (srcdata32[1].b[2] >> 4);
1389fcd0cb28Sriastradh 
1390fcd0cb28Sriastradh 			writel(data32.ul, dstxor);
1391fcd0cb28Sriastradh 			csum += data32.ul;
1392fcd0cb28Sriastradh 
1393fcd0cb28Sriastradh 			dstxor += 4;
1394fcd0cb28Sriastradh 			srcxor += 8;
1395fcd0cb28Sriastradh 
1396fcd0cb28Sriastradh 		}
1397fcd0cb28Sriastradh 
1398fcd0cb28Sriastradh 		for (i = 0; i < per_pixel_copy; i++) {
1399fcd0cb28Sriastradh 			srcdata32[0].ul = *((u32 *)srcxor) & 0xf0f0f0f0;
1400fcd0cb28Sriastradh 			data16.b[0] = srcdata32[0].b[1] | (srcdata32[0].b[0] >> 4);
1401fcd0cb28Sriastradh 			data16.b[1] = srcdata32[0].b[3] | (srcdata32[0].b[2] >> 4);
1402fcd0cb28Sriastradh 			writew(data16.us, dstxor);
1403fcd0cb28Sriastradh 			csum += (u32)data16.us;
1404fcd0cb28Sriastradh 
1405fcd0cb28Sriastradh 			dstxor += 2;
1406fcd0cb28Sriastradh 			srcxor += 4;
1407fcd0cb28Sriastradh 		}
1408fcd0cb28Sriastradh 		dstxor += last_alpha_dst_delta;
1409fcd0cb28Sriastradh 	}
1410fcd0cb28Sriastradh 	return csum;
1411fcd0cb28Sriastradh }
1412fcd0cb28Sriastradh 
ast_cursor_update(void * dst,void * src,unsigned int width,unsigned int height)1413*41ec0267Sriastradh static int ast_cursor_update(void *dst, void *src, unsigned int width,
1414*41ec0267Sriastradh 			     unsigned int height)
1415fcd0cb28Sriastradh {
1416fcd0cb28Sriastradh 	u32 csum;
1417fcd0cb28Sriastradh 
1418fcd0cb28Sriastradh 	/* do data transfer to cursor cache */
1419fcd0cb28Sriastradh 	csum = copy_cursor_image(src, dst, width, height);
1420fcd0cb28Sriastradh 
1421fcd0cb28Sriastradh 	/* write checksum + signature */
1422*41ec0267Sriastradh 	dst += AST_HWC_SIZE;
1423fcd0cb28Sriastradh 	writel(csum, dst);
1424fcd0cb28Sriastradh 	writel(width, dst + AST_HWC_SIGNATURE_SizeX);
1425fcd0cb28Sriastradh 	writel(height, dst + AST_HWC_SIGNATURE_SizeY);
1426fcd0cb28Sriastradh 	writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTX);
1427fcd0cb28Sriastradh 	writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTY);
1428fcd0cb28Sriastradh 
1429fcd0cb28Sriastradh 	return 0;
1430*41ec0267Sriastradh }
1431*41ec0267Sriastradh 
ast_cursor_set_base(struct ast_private * ast,u64 address)1432*41ec0267Sriastradh static void ast_cursor_set_base(struct ast_private *ast, u64 address)
1433*41ec0267Sriastradh {
1434*41ec0267Sriastradh 	u8 addr0 = (address >> 3) & 0xff;
1435*41ec0267Sriastradh 	u8 addr1 = (address >> 11) & 0xff;
1436*41ec0267Sriastradh 	u8 addr2 = (address >> 19) & 0xff;
1437*41ec0267Sriastradh 
1438*41ec0267Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc8, addr0);
1439*41ec0267Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc9, addr1);
1440*41ec0267Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xca, addr2);
1441fcd0cb28Sriastradh }
1442fcd0cb28Sriastradh 
ast_cursor_move(struct drm_crtc * crtc,int x,int y)1443fcd0cb28Sriastradh static int ast_cursor_move(struct drm_crtc *crtc,
1444fcd0cb28Sriastradh 			   int x, int y)
1445fcd0cb28Sriastradh {
1446fcd0cb28Sriastradh 	struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
1447fcd0cb28Sriastradh 	struct ast_private *ast = crtc->dev->dev_private;
1448*41ec0267Sriastradh 	struct drm_gem_vram_object *gbo;
1449fcd0cb28Sriastradh 	int x_offset, y_offset;
1450*41ec0267Sriastradh 	u8 *dst, *sig;
1451*41ec0267Sriastradh 	u8 jreg;
1452fcd0cb28Sriastradh 
1453*41ec0267Sriastradh 	gbo = ast->cursor.gbo[ast->cursor.next_index];
1454*41ec0267Sriastradh 	dst = drm_gem_vram_vmap(gbo);
1455*41ec0267Sriastradh 	if (IS_ERR(dst))
1456*41ec0267Sriastradh 		return PTR_ERR(dst);
1457*41ec0267Sriastradh 
1458*41ec0267Sriastradh 	sig = dst + AST_HWC_SIZE;
1459fcd0cb28Sriastradh 	writel(x, sig + AST_HWC_SIGNATURE_X);
1460fcd0cb28Sriastradh 	writel(y, sig + AST_HWC_SIGNATURE_Y);
1461fcd0cb28Sriastradh 
1462fcd0cb28Sriastradh 	x_offset = ast_crtc->offset_x;
1463fcd0cb28Sriastradh 	y_offset = ast_crtc->offset_y;
1464fcd0cb28Sriastradh 	if (x < 0) {
1465fcd0cb28Sriastradh 		x_offset = (-x) + ast_crtc->offset_x;
1466fcd0cb28Sriastradh 		x = 0;
1467fcd0cb28Sriastradh 	}
1468fcd0cb28Sriastradh 
1469fcd0cb28Sriastradh 	if (y < 0) {
1470fcd0cb28Sriastradh 		y_offset = (-y) + ast_crtc->offset_y;
1471fcd0cb28Sriastradh 		y = 0;
1472fcd0cb28Sriastradh 	}
1473fcd0cb28Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc2, x_offset);
1474fcd0cb28Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc3, y_offset);
1475fcd0cb28Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc4, (x & 0xff));
1476fcd0cb28Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc5, ((x >> 8) & 0x0f));
1477fcd0cb28Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc6, (y & 0xff));
1478fcd0cb28Sriastradh 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc7, ((y >> 8) & 0x07));
1479fcd0cb28Sriastradh 
1480fcd0cb28Sriastradh 	/* dummy write to fire HWC */
1481*41ec0267Sriastradh 	jreg = 0x02 |
1482*41ec0267Sriastradh 	       0x01; /* enable ARGB4444 cursor */
1483*41ec0267Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, jreg);
1484*41ec0267Sriastradh 
1485*41ec0267Sriastradh 	drm_gem_vram_vunmap(gbo, dst);
1486fcd0cb28Sriastradh 
1487fcd0cb28Sriastradh 	return 0;
1488fcd0cb28Sriastradh }
1489