xref: /OK3568_Linux_fs/u-boot/drivers/video/fsl_diu_fb.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright 2007, 2010-2011 Freescale Semiconductor, Inc.
3*4882a593Smuzhiyun  * Authors: York Sun <yorksun@freescale.com>
4*4882a593Smuzhiyun  *          Timur Tabi <timur@freescale.com>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * FSL DIU Framebuffer driver
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <common.h>
12*4882a593Smuzhiyun #include <malloc.h>
13*4882a593Smuzhiyun #include <asm/io.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include "videomodes.h"
16*4882a593Smuzhiyun #include <video_fb.h>
17*4882a593Smuzhiyun #include <fsl_diu_fb.h>
18*4882a593Smuzhiyun #include <linux/list.h>
19*4882a593Smuzhiyun #include <linux/fb.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun /* This setting is used for the ifm pdm360ng with PRIMEVIEW PM070WL3 */
22*4882a593Smuzhiyun static struct fb_videomode fsl_diu_mode_800_480 = {
23*4882a593Smuzhiyun 	.name		= "800x480-60",
24*4882a593Smuzhiyun 	.refresh	= 60,
25*4882a593Smuzhiyun 	.xres		= 800,
26*4882a593Smuzhiyun 	.yres		= 480,
27*4882a593Smuzhiyun 	.pixclock	= 31250,
28*4882a593Smuzhiyun 	.left_margin	= 86,
29*4882a593Smuzhiyun 	.right_margin	= 42,
30*4882a593Smuzhiyun 	.upper_margin	= 33,
31*4882a593Smuzhiyun 	.lower_margin	= 10,
32*4882a593Smuzhiyun 	.hsync_len	= 128,
33*4882a593Smuzhiyun 	.vsync_len	= 2,
34*4882a593Smuzhiyun 	.sync		= 0,
35*4882a593Smuzhiyun 	.vmode		= FB_VMODE_NONINTERLACED
36*4882a593Smuzhiyun };
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun /* For the SHARP LQ084S3LG01, used on the P1022DS board */
39*4882a593Smuzhiyun static struct fb_videomode fsl_diu_mode_800_600 = {
40*4882a593Smuzhiyun 	.name		= "800x600-60",
41*4882a593Smuzhiyun 	.refresh	= 60,
42*4882a593Smuzhiyun 	.xres		= 800,
43*4882a593Smuzhiyun 	.yres		= 600,
44*4882a593Smuzhiyun 	.pixclock	= 25000,
45*4882a593Smuzhiyun 	.left_margin	= 88,
46*4882a593Smuzhiyun 	.right_margin	= 40,
47*4882a593Smuzhiyun 	.upper_margin	= 23,
48*4882a593Smuzhiyun 	.lower_margin	= 1,
49*4882a593Smuzhiyun 	.hsync_len	= 128,
50*4882a593Smuzhiyun 	.vsync_len	= 4,
51*4882a593Smuzhiyun 	.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
52*4882a593Smuzhiyun 	.vmode		= FB_VMODE_NONINTERLACED
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun /*
56*4882a593Smuzhiyun  * These parameters give default parameters
57*4882a593Smuzhiyun  * for video output 1024x768,
58*4882a593Smuzhiyun  * FIXME - change timing to proper amounts
59*4882a593Smuzhiyun  * hsync 31.5kHz, vsync 60Hz
60*4882a593Smuzhiyun  */
61*4882a593Smuzhiyun static struct fb_videomode fsl_diu_mode_1024_768 = {
62*4882a593Smuzhiyun 	.name		= "1024x768-60",
63*4882a593Smuzhiyun 	.refresh	= 60,
64*4882a593Smuzhiyun 	.xres		= 1024,
65*4882a593Smuzhiyun 	.yres		= 768,
66*4882a593Smuzhiyun 	.pixclock	= 15385,
67*4882a593Smuzhiyun 	.left_margin	= 160,
68*4882a593Smuzhiyun 	.right_margin	= 24,
69*4882a593Smuzhiyun 	.upper_margin	= 29,
70*4882a593Smuzhiyun 	.lower_margin	= 3,
71*4882a593Smuzhiyun 	.hsync_len	= 136,
72*4882a593Smuzhiyun 	.vsync_len	= 6,
73*4882a593Smuzhiyun 	.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
74*4882a593Smuzhiyun 	.vmode		= FB_VMODE_NONINTERLACED
75*4882a593Smuzhiyun };
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun static struct fb_videomode fsl_diu_mode_1280_1024 = {
78*4882a593Smuzhiyun 	.name		= "1280x1024-60",
79*4882a593Smuzhiyun 	.refresh	= 60,
80*4882a593Smuzhiyun 	.xres		= 1280,
81*4882a593Smuzhiyun 	.yres		= 1024,
82*4882a593Smuzhiyun 	.pixclock	= 9375,
83*4882a593Smuzhiyun 	.left_margin	= 38,
84*4882a593Smuzhiyun 	.right_margin	= 128,
85*4882a593Smuzhiyun 	.upper_margin	= 2,
86*4882a593Smuzhiyun 	.lower_margin	= 7,
87*4882a593Smuzhiyun 	.hsync_len	= 216,
88*4882a593Smuzhiyun 	.vsync_len	= 37,
89*4882a593Smuzhiyun 	.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
90*4882a593Smuzhiyun 	.vmode		= FB_VMODE_NONINTERLACED
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun static struct fb_videomode fsl_diu_mode_1280_720 = {
94*4882a593Smuzhiyun 	.name		= "1280x720-60",
95*4882a593Smuzhiyun 	.refresh	= 60,
96*4882a593Smuzhiyun 	.xres		= 1280,
97*4882a593Smuzhiyun 	.yres		= 720,
98*4882a593Smuzhiyun 	.pixclock	= 13426,
99*4882a593Smuzhiyun 	.left_margin	= 192,
100*4882a593Smuzhiyun 	.right_margin	= 64,
101*4882a593Smuzhiyun 	.upper_margin	= 22,
102*4882a593Smuzhiyun 	.lower_margin	= 1,
103*4882a593Smuzhiyun 	.hsync_len	= 136,
104*4882a593Smuzhiyun 	.vsync_len	= 3,
105*4882a593Smuzhiyun 	.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
106*4882a593Smuzhiyun 	.vmode		= FB_VMODE_NONINTERLACED
107*4882a593Smuzhiyun };
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun static struct fb_videomode fsl_diu_mode_1920_1080 = {
110*4882a593Smuzhiyun 	.name		= "1920x1080-60",
111*4882a593Smuzhiyun 	.refresh	= 60,
112*4882a593Smuzhiyun 	.xres		= 1920,
113*4882a593Smuzhiyun 	.yres		= 1080,
114*4882a593Smuzhiyun 	.pixclock	= 5787,
115*4882a593Smuzhiyun 	.left_margin	= 328,
116*4882a593Smuzhiyun 	.right_margin	= 120,
117*4882a593Smuzhiyun 	.upper_margin	= 34,
118*4882a593Smuzhiyun 	.lower_margin	= 1,
119*4882a593Smuzhiyun 	.hsync_len	= 208,
120*4882a593Smuzhiyun 	.vsync_len	= 3,
121*4882a593Smuzhiyun 	.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
122*4882a593Smuzhiyun 	.vmode		= FB_VMODE_NONINTERLACED
123*4882a593Smuzhiyun };
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun /*
126*4882a593Smuzhiyun  * These are the fields of area descriptor(in DDR memory) for every plane
127*4882a593Smuzhiyun  */
128*4882a593Smuzhiyun struct diu_ad {
129*4882a593Smuzhiyun 	/* Word 0(32-bit) in DDR memory */
130*4882a593Smuzhiyun 	__le32 pix_fmt; /* hard coding pixel format */
131*4882a593Smuzhiyun 	/* Word 1(32-bit) in DDR memory */
132*4882a593Smuzhiyun 	__le32 addr;
133*4882a593Smuzhiyun 	/* Word 2(32-bit) in DDR memory */
134*4882a593Smuzhiyun 	__le32 src_size_g_alpha;
135*4882a593Smuzhiyun 	/* Word 3(32-bit) in DDR memory */
136*4882a593Smuzhiyun 	__le32 aoi_size;
137*4882a593Smuzhiyun 	/* Word 4(32-bit) in DDR memory */
138*4882a593Smuzhiyun 	__le32 offset_xyi;
139*4882a593Smuzhiyun 	/* Word 5(32-bit) in DDR memory */
140*4882a593Smuzhiyun 	__le32 offset_xyd;
141*4882a593Smuzhiyun 	/* Word 6(32-bit) in DDR memory */
142*4882a593Smuzhiyun 	__le32 ckmax_r:8;
143*4882a593Smuzhiyun 	__le32 ckmax_g:8;
144*4882a593Smuzhiyun 	__le32 ckmax_b:8;
145*4882a593Smuzhiyun 	__le32 res9:8;
146*4882a593Smuzhiyun 	/* Word 7(32-bit) in DDR memory */
147*4882a593Smuzhiyun 	__le32 ckmin_r:8;
148*4882a593Smuzhiyun 	__le32 ckmin_g:8;
149*4882a593Smuzhiyun 	__le32 ckmin_b:8;
150*4882a593Smuzhiyun 	__le32 res10:8;
151*4882a593Smuzhiyun 	/* Word 8(32-bit) in DDR memory */
152*4882a593Smuzhiyun 	__le32 next_ad;
153*4882a593Smuzhiyun 	/* Word 9(32-bit) in DDR memory, just for 64-bit aligned */
154*4882a593Smuzhiyun 	__le32 res[3];
155*4882a593Smuzhiyun } __attribute__ ((packed));
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun /*
158*4882a593Smuzhiyun  * DIU register map
159*4882a593Smuzhiyun  */
160*4882a593Smuzhiyun struct diu {
161*4882a593Smuzhiyun 	__be32 desc[3];
162*4882a593Smuzhiyun 	__be32 gamma;
163*4882a593Smuzhiyun 	__be32 pallete;
164*4882a593Smuzhiyun 	__be32 cursor;
165*4882a593Smuzhiyun 	__be32 curs_pos;
166*4882a593Smuzhiyun 	__be32 diu_mode;
167*4882a593Smuzhiyun 	__be32 bgnd;
168*4882a593Smuzhiyun 	__be32 bgnd_wb;
169*4882a593Smuzhiyun 	__be32 disp_size;
170*4882a593Smuzhiyun 	__be32 wb_size;
171*4882a593Smuzhiyun 	__be32 wb_mem_addr;
172*4882a593Smuzhiyun 	__be32 hsyn_para;
173*4882a593Smuzhiyun 	__be32 vsyn_para;
174*4882a593Smuzhiyun 	__be32 syn_pol;
175*4882a593Smuzhiyun 	__be32 thresholds;
176*4882a593Smuzhiyun 	__be32 int_status;
177*4882a593Smuzhiyun 	__be32 int_mask;
178*4882a593Smuzhiyun 	__be32 colorbar[8];
179*4882a593Smuzhiyun 	__be32 filling;
180*4882a593Smuzhiyun 	__be32 plut;
181*4882a593Smuzhiyun } __attribute__ ((packed));
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun struct diu_addr {
184*4882a593Smuzhiyun 	void *vaddr;		/* Virtual address */
185*4882a593Smuzhiyun 	u32 paddr;		/* 32-bit physical address */
186*4882a593Smuzhiyun 	unsigned int offset;	/* Alignment offset */
187*4882a593Smuzhiyun };
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun static struct fb_info info;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun /*
192*4882a593Smuzhiyun  * Align to 64-bit(8-byte), 32-byte, etc.
193*4882a593Smuzhiyun  */
allocate_buf(struct diu_addr * buf,u32 size,u32 bytes_align)194*4882a593Smuzhiyun static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun 	u32 offset, ssize;
197*4882a593Smuzhiyun 	u32 mask;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	ssize = size + bytes_align;
200*4882a593Smuzhiyun 	buf->vaddr = malloc(ssize);
201*4882a593Smuzhiyun 	if (!buf->vaddr)
202*4882a593Smuzhiyun 		return -1;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	memset(buf->vaddr, 0, ssize);
205*4882a593Smuzhiyun 	mask = bytes_align - 1;
206*4882a593Smuzhiyun 	offset = (u32)buf->vaddr & mask;
207*4882a593Smuzhiyun 	if (offset) {
208*4882a593Smuzhiyun 		buf->offset = bytes_align - offset;
209*4882a593Smuzhiyun 		buf->vaddr += offset;
210*4882a593Smuzhiyun 	} else
211*4882a593Smuzhiyun 		buf->offset = 0;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	buf->paddr = virt_to_phys(buf->vaddr);
214*4882a593Smuzhiyun 	return 0;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun /*
218*4882a593Smuzhiyun  * Allocate a framebuffer and an Area Descriptor that points to it.  Both
219*4882a593Smuzhiyun  * are created in the same memory block.  The Area Descriptor is updated to
220*4882a593Smuzhiyun  * point to the framebuffer memory. Memory is aligned as needed.
221*4882a593Smuzhiyun  */
allocate_fb(unsigned int xres,unsigned int yres,unsigned int depth,char ** fb)222*4882a593Smuzhiyun static struct diu_ad *allocate_fb(unsigned int xres, unsigned int yres,
223*4882a593Smuzhiyun 				  unsigned int depth, char **fb)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun 	unsigned long size = xres * yres * depth;
226*4882a593Smuzhiyun 	struct diu_addr addr;
227*4882a593Smuzhiyun 	struct diu_ad *ad;
228*4882a593Smuzhiyun 	size_t ad_size = roundup(sizeof(struct diu_ad), 32);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	/*
231*4882a593Smuzhiyun 	 * Allocate a memory block that holds the Area Descriptor and the
232*4882a593Smuzhiyun 	 * frame buffer right behind it.  To keep the code simple, everything
233*4882a593Smuzhiyun 	 * is aligned on a 32-byte address.
234*4882a593Smuzhiyun 	 */
235*4882a593Smuzhiyun 	if (allocate_buf(&addr, ad_size + size, 32) < 0)
236*4882a593Smuzhiyun 		return NULL;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	ad = addr.vaddr;
239*4882a593Smuzhiyun 	ad->addr = cpu_to_le32(addr.paddr + ad_size);
240*4882a593Smuzhiyun 	ad->aoi_size = cpu_to_le32((yres << 16) | xres);
241*4882a593Smuzhiyun 	ad->src_size_g_alpha = cpu_to_le32((yres << 12) | xres);
242*4882a593Smuzhiyun 	ad->offset_xyi = 0;
243*4882a593Smuzhiyun 	ad->offset_xyd = 0;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	if (fb)
246*4882a593Smuzhiyun 		*fb = addr.vaddr + ad_size;
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	return ad;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun 
fsl_diu_init(u16 xres,u16 yres,u32 pixel_format,int gamma_fix)251*4882a593Smuzhiyun int fsl_diu_init(u16 xres, u16 yres, u32 pixel_format, int gamma_fix)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun 	struct fb_videomode *fsl_diu_mode_db;
254*4882a593Smuzhiyun 	struct diu_ad *ad;
255*4882a593Smuzhiyun 	struct diu *hw = (struct diu *)CONFIG_SYS_DIU_ADDR;
256*4882a593Smuzhiyun 	u8 *gamma_table_base;
257*4882a593Smuzhiyun 	unsigned int i, j;
258*4882a593Smuzhiyun 	struct diu_addr gamma;
259*4882a593Smuzhiyun 	struct diu_addr cursor;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun /* Convert the X,Y resolution pair into a single number */
262*4882a593Smuzhiyun #define RESOLUTION(x, y) (((u32)(x) << 16) | (y))
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	switch (RESOLUTION(xres, yres)) {
265*4882a593Smuzhiyun 	case RESOLUTION(800, 480):
266*4882a593Smuzhiyun 		fsl_diu_mode_db = &fsl_diu_mode_800_480;
267*4882a593Smuzhiyun 		break;
268*4882a593Smuzhiyun 	case RESOLUTION(800, 600):
269*4882a593Smuzhiyun 		fsl_diu_mode_db = &fsl_diu_mode_800_600;
270*4882a593Smuzhiyun 		break;
271*4882a593Smuzhiyun 	case RESOLUTION(1024, 768):
272*4882a593Smuzhiyun 		fsl_diu_mode_db = &fsl_diu_mode_1024_768;
273*4882a593Smuzhiyun 		break;
274*4882a593Smuzhiyun 	case RESOLUTION(1280, 1024):
275*4882a593Smuzhiyun 		fsl_diu_mode_db = &fsl_diu_mode_1280_1024;
276*4882a593Smuzhiyun 		break;
277*4882a593Smuzhiyun 	case RESOLUTION(1280, 720):
278*4882a593Smuzhiyun 		fsl_diu_mode_db = &fsl_diu_mode_1280_720;
279*4882a593Smuzhiyun 		break;
280*4882a593Smuzhiyun 	case RESOLUTION(1920, 1080):
281*4882a593Smuzhiyun 		fsl_diu_mode_db = &fsl_diu_mode_1920_1080;
282*4882a593Smuzhiyun 		break;
283*4882a593Smuzhiyun 	default:
284*4882a593Smuzhiyun 		printf("DIU:   Unsupported resolution %ux%u\n", xres, yres);
285*4882a593Smuzhiyun 		return -1;
286*4882a593Smuzhiyun 	}
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	/* read mode info */
289*4882a593Smuzhiyun 	info.var.xres = fsl_diu_mode_db->xres;
290*4882a593Smuzhiyun 	info.var.yres = fsl_diu_mode_db->yres;
291*4882a593Smuzhiyun 	info.var.bits_per_pixel = 32;
292*4882a593Smuzhiyun 	info.var.pixclock = fsl_diu_mode_db->pixclock;
293*4882a593Smuzhiyun 	info.var.left_margin = fsl_diu_mode_db->left_margin;
294*4882a593Smuzhiyun 	info.var.right_margin = fsl_diu_mode_db->right_margin;
295*4882a593Smuzhiyun 	info.var.upper_margin = fsl_diu_mode_db->upper_margin;
296*4882a593Smuzhiyun 	info.var.lower_margin = fsl_diu_mode_db->lower_margin;
297*4882a593Smuzhiyun 	info.var.hsync_len = fsl_diu_mode_db->hsync_len;
298*4882a593Smuzhiyun 	info.var.vsync_len = fsl_diu_mode_db->vsync_len;
299*4882a593Smuzhiyun 	info.var.sync = fsl_diu_mode_db->sync;
300*4882a593Smuzhiyun 	info.var.vmode = fsl_diu_mode_db->vmode;
301*4882a593Smuzhiyun 	info.fix.line_length = info.var.xres * info.var.bits_per_pixel / 8;
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	/* Memory allocation for framebuffer */
304*4882a593Smuzhiyun 	info.screen_size =
305*4882a593Smuzhiyun 		info.var.xres * info.var.yres * (info.var.bits_per_pixel / 8);
306*4882a593Smuzhiyun 	ad = allocate_fb(info.var.xres, info.var.yres,
307*4882a593Smuzhiyun 			 info.var.bits_per_pixel / 8, &info.screen_base);
308*4882a593Smuzhiyun 	if (!ad) {
309*4882a593Smuzhiyun 		printf("DIU:   Out of memory\n");
310*4882a593Smuzhiyun 		return -1;
311*4882a593Smuzhiyun 	}
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	ad->pix_fmt = pixel_format;
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	/* Disable chroma keying function */
316*4882a593Smuzhiyun 	ad->ckmax_r = 0;
317*4882a593Smuzhiyun 	ad->ckmax_g = 0;
318*4882a593Smuzhiyun 	ad->ckmax_b = 0;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	ad->ckmin_r = 255;
321*4882a593Smuzhiyun 	ad->ckmin_g = 255;
322*4882a593Smuzhiyun 	ad->ckmin_b = 255;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	/* Initialize the gamma table */
325*4882a593Smuzhiyun 	if (allocate_buf(&gamma, 256 * 3, 32) < 0) {
326*4882a593Smuzhiyun 		printf("DIU:   Out of memory\n");
327*4882a593Smuzhiyun 		return -1;
328*4882a593Smuzhiyun 	}
329*4882a593Smuzhiyun 	gamma_table_base = gamma.vaddr;
330*4882a593Smuzhiyun 	for (i = 0; i <= 2; i++)
331*4882a593Smuzhiyun 		for (j = 0; j < 256; j++)
332*4882a593Smuzhiyun 			*gamma_table_base++ = j;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	if (gamma_fix == 1) {	/* fix the gamma */
335*4882a593Smuzhiyun 		gamma_table_base = gamma.vaddr;
336*4882a593Smuzhiyun 		for (i = 0; i < 256 * 3; i++) {
337*4882a593Smuzhiyun 			gamma_table_base[i] = (gamma_table_base[i] << 2)
338*4882a593Smuzhiyun 				| ((gamma_table_base[i] >> 6) & 0x03);
339*4882a593Smuzhiyun 		}
340*4882a593Smuzhiyun 	}
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	/* Initialize the cursor */
343*4882a593Smuzhiyun 	if (allocate_buf(&cursor, 32 * 32 * 2, 32) < 0) {
344*4882a593Smuzhiyun 		printf("DIU:   Can't alloc cursor data\n");
345*4882a593Smuzhiyun 		return -1;
346*4882a593Smuzhiyun 	}
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	/* Program DIU registers */
349*4882a593Smuzhiyun 	out_be32(&hw->diu_mode, 0);	/* Temporarily disable the DIU */
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	out_be32(&hw->gamma, gamma.paddr);
352*4882a593Smuzhiyun 	out_be32(&hw->cursor, cursor.paddr);
353*4882a593Smuzhiyun 	out_be32(&hw->bgnd, 0x007F7F7F);
354*4882a593Smuzhiyun 	out_be32(&hw->disp_size, info.var.yres << 16 | info.var.xres);
355*4882a593Smuzhiyun 	out_be32(&hw->hsyn_para, info.var.left_margin << 22 |
356*4882a593Smuzhiyun 			info.var.hsync_len << 11 |
357*4882a593Smuzhiyun 			info.var.right_margin);
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	out_be32(&hw->vsyn_para, info.var.upper_margin << 22 |
360*4882a593Smuzhiyun 			info.var.vsync_len << 11 |
361*4882a593Smuzhiyun 			info.var.lower_margin);
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	/* Pixel Clock configuration */
364*4882a593Smuzhiyun 	diu_set_pixel_clock(info.var.pixclock);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	/* Set the frame buffers */
367*4882a593Smuzhiyun 	out_be32(&hw->desc[0], virt_to_phys(ad));
368*4882a593Smuzhiyun 	out_be32(&hw->desc[1], 0);
369*4882a593Smuzhiyun 	out_be32(&hw->desc[2], 0);
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	/* Enable the DIU, set display to all three planes */
372*4882a593Smuzhiyun 	out_be32(&hw->diu_mode, 1);
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	return 0;
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun 
video_hw_init(void)377*4882a593Smuzhiyun void *video_hw_init(void)
378*4882a593Smuzhiyun {
379*4882a593Smuzhiyun 	static GraphicDevice ctfb;
380*4882a593Smuzhiyun 	const char *options;
381*4882a593Smuzhiyun 	unsigned int depth = 0, freq = 0;
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	if (!video_get_video_mode(&ctfb.winSizeX, &ctfb.winSizeY, &depth, &freq,
384*4882a593Smuzhiyun 				  &options))
385*4882a593Smuzhiyun 		return NULL;
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	/* Find the monitor port, which is a required option */
388*4882a593Smuzhiyun 	if (!options)
389*4882a593Smuzhiyun 		return NULL;
390*4882a593Smuzhiyun 	if (strncmp(options, "monitor=", 8) != 0)
391*4882a593Smuzhiyun 		return NULL;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	if (platform_diu_init(ctfb.winSizeX, ctfb.winSizeY, options + 8) < 0)
394*4882a593Smuzhiyun 		return NULL;
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	/* fill in Graphic device struct */
397*4882a593Smuzhiyun 	sprintf(ctfb.modeIdent, "%ix%ix%i %ikHz %iHz",
398*4882a593Smuzhiyun 		ctfb.winSizeX, ctfb.winSizeY, depth, 64, freq);
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	ctfb.frameAdrs = (unsigned int)info.screen_base;
401*4882a593Smuzhiyun 	ctfb.plnSizeX = ctfb.winSizeX;
402*4882a593Smuzhiyun 	ctfb.plnSizeY = ctfb.winSizeY;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	ctfb.gdfBytesPP = 4;
405*4882a593Smuzhiyun 	ctfb.gdfIndex = GDF_32BIT_X888RGB;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	ctfb.isaBase = 0;
408*4882a593Smuzhiyun 	ctfb.pciBase = 0;
409*4882a593Smuzhiyun 	ctfb.memSize = info.screen_size;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	/* Cursor Start Address */
412*4882a593Smuzhiyun 	ctfb.dprBase = 0;
413*4882a593Smuzhiyun 	ctfb.vprBase = 0;
414*4882a593Smuzhiyun 	ctfb.cprBase = 0;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	return &ctfb;
417*4882a593Smuzhiyun }
418