• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/video/
1/*
2 * Frame buffer driver for the Carmine GPU.
3 *
4 * The driver configures the GPU as follows
5 * - FB0 is display 0 with unique memory area
6 * - FB1 is display 1 with unique memory area
7 * - both display use 32 bit colors
8 */
9#include <linux/delay.h>
10#include <linux/errno.h>
11#include <linux/fb.h>
12#include <linux/interrupt.h>
13#include <linux/pci.h>
14#include <linux/slab.h>
15
16#include "carminefb.h"
17#include "carminefb_regs.h"
18
19#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
20#error  "The endianness of the target host has not been defined."
21#endif
22
23/*
24 * The initial video mode can be supplied via two different ways:
25 * - as a string that is passed to fb_find_mode() (module option fb_mode_str)
26 * - as an integer that picks the video mode from carmine_modedb[] (module
27 *   option fb_mode)
28 *
29 * If nothing is used than the initial video mode will be the
30 * CARMINEFB_DEFAULT_VIDEO_MODE member of the carmine_modedb[].
31 */
32#define CARMINEFB_DEFAULT_VIDEO_MODE	1
33
34static unsigned int fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
35module_param(fb_mode, uint, 444);
36MODULE_PARM_DESC(fb_mode, "Initial video mode as integer.");
37
38static char *fb_mode_str;
39module_param(fb_mode_str, charp, 444);
40MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters.");
41
42/*
43 * Carminefb displays:
44 * 0b000 None
45 * 0b001 Display 0
46 * 0b010 Display 1
47 */
48static int fb_displays = CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1;
49module_param(fb_displays, int, 444);
50MODULE_PARM_DESC(fb_displays, "Bit mode, which displays are used");
51
52struct carmine_hw {
53	void __iomem *v_regs;
54	void __iomem *screen_mem;
55	struct fb_info *fb[MAX_DISPLAY];
56};
57
58struct carmine_resolution {
59	u32 htp;
60	u32 hsp;
61	u32 hsw;
62	u32 hdp;
63	u32 vtr;
64	u32 vsp;
65	u32 vsw;
66	u32 vdp;
67	u32 disp_mode;
68};
69
70struct carmine_fb {
71	void __iomem *display_reg;
72	void __iomem *screen_base;
73	u32 smem_offset;
74	u32 cur_mode;
75	u32 new_mode;
76	struct carmine_resolution *res;
77	u32 pseudo_palette[16];
78};
79
80static struct fb_fix_screeninfo carminefb_fix __devinitdata = {
81	.id = "Carmine",
82	.type = FB_TYPE_PACKED_PIXELS,
83	.visual = FB_VISUAL_TRUECOLOR,
84	.accel = FB_ACCEL_NONE,
85};
86
87static const struct fb_videomode carmine_modedb[] = {
88	{
89		.name		= "640x480",
90		.xres		= 640,
91		.yres		= 480,
92	}, {
93		.name		= "800x600",
94		.xres		= 800,
95		.yres		= 600,
96	},
97};
98
99static struct carmine_resolution car_modes[] = {
100	{
101		/* 640x480 */
102		.htp = 800,
103		.hsp = 672,
104		.hsw = 96,
105		.hdp = 640,
106		.vtr = 525,
107		.vsp = 490,
108		.vsw = 2,
109		.vdp = 480,
110		.disp_mode = 0x1400,
111	},
112	{
113		/* 800x600 */
114		.htp = 1060,
115		.hsp = 864,
116		.hsw = 72,
117		.hdp = 800,
118		.vtr = 628,
119		.vsp = 601,
120		.vsw = 2,
121		.vdp = 600,
122		.disp_mode = 0x0d00,
123	}
124};
125
126static int carmine_find_mode(const struct fb_var_screeninfo *var)
127{
128	int i;
129
130	for (i = 0; i < ARRAY_SIZE(car_modes); i++)
131		if (car_modes[i].hdp == var->xres &&
132		    car_modes[i].vdp == var->yres)
133			return i;
134	return -EINVAL;
135}
136
137static void c_set_disp_reg(const struct carmine_fb *par,
138		u32 offset, u32 val)
139{
140	writel(val, par->display_reg + offset);
141}
142
143static u32 c_get_disp_reg(const struct carmine_fb *par,
144		u32 offset)
145{
146	return readl(par->display_reg + offset);
147}
148
149static void c_set_hw_reg(const struct carmine_hw *hw,
150		u32 offset, u32 val)
151{
152	writel(val, hw->v_regs + offset);
153}
154
155static u32 c_get_hw_reg(const struct carmine_hw *hw,
156		u32 offset)
157{
158	return readl(hw->v_regs + offset);
159}
160
161static int carmine_setcolreg(unsigned regno, unsigned red, unsigned green,
162		unsigned blue, unsigned transp, struct fb_info *info)
163{
164	if (regno >= 16)
165		return 1;
166
167	red >>= 8;
168	green >>= 8;
169	blue >>= 8;
170	transp >>= 8;
171
172	((__be32 *)info->pseudo_palette)[regno] = cpu_to_be32(transp << 24 |
173		red << 0 | green << 8 | blue << 16);
174	return 0;
175}
176
177static int carmine_check_var(struct fb_var_screeninfo *var,
178		struct fb_info *info)
179{
180	int ret;
181
182	ret = carmine_find_mode(var);
183	if (ret < 0)
184		return ret;
185
186	if (var->grayscale || var->rotate || var->nonstd)
187		return -EINVAL;
188
189	var->xres_virtual = var->xres;
190	var->yres_virtual = var->yres;
191
192	var->bits_per_pixel = 32;
193
194#ifdef __BIG_ENDIAN
195	var->transp.offset = 24;
196	var->red.offset = 0;
197	var->green.offset = 8;
198	var->blue.offset = 16;
199#else
200	var->transp.offset = 24;
201	var->red.offset = 16;
202	var->green.offset = 8;
203	var->blue.offset = 0;
204#endif
205
206	var->red.length = 8;
207	var->green.length = 8;
208	var->blue.length = 8;
209	var->transp.length = 8;
210
211	var->red.msb_right = 0;
212	var->green.msb_right = 0;
213	var->blue.msb_right = 0;
214	var->transp.msb_right = 0;
215	return 0;
216}
217
218static void carmine_init_display_param(struct carmine_fb *par)
219{
220	u32 width;
221	u32 height;
222	u32 param;
223	u32 window_size;
224	u32 soffset = par->smem_offset;
225
226	c_set_disp_reg(par, CARMINE_DISP_REG_C_TRANS, 0);
227	c_set_disp_reg(par, CARMINE_DISP_REG_MLMR_TRANS, 0);
228	c_set_disp_reg(par, CARMINE_DISP_REG_CURSOR_MODE,
229			CARMINE_CURSOR0_PRIORITY_MASK |
230			CARMINE_CURSOR1_PRIORITY_MASK |
231			CARMINE_CURSOR_CUTZ_MASK);
232
233	/* Set default cursor position */
234	c_set_disp_reg(par, CARMINE_DISP_REG_CUR1_POS, 0 << 16 | 0);
235	c_set_disp_reg(par, CARMINE_DISP_REG_CUR2_POS, 0 << 16 | 0);
236
237	/* Set default display mode */
238	c_set_disp_reg(par, CARMINE_DISP_REG_L0_EXT_MODE, CARMINE_WINDOW_MODE |
239			CARMINE_EXT_CMODE_DIRECT24_RGBA);
240	c_set_disp_reg(par, CARMINE_DISP_REG_L1_EXT_MODE,
241			CARMINE_EXT_CMODE_DIRECT24_RGBA);
242	c_set_disp_reg(par, CARMINE_DISP_REG_L2_EXT_MODE, CARMINE_EXTEND_MODE |
243			CARMINE_EXT_CMODE_DIRECT24_RGBA);
244	c_set_disp_reg(par, CARMINE_DISP_REG_L3_EXT_MODE, CARMINE_EXTEND_MODE |
245			CARMINE_EXT_CMODE_DIRECT24_RGBA);
246	c_set_disp_reg(par, CARMINE_DISP_REG_L4_EXT_MODE, CARMINE_EXTEND_MODE |
247			CARMINE_EXT_CMODE_DIRECT24_RGBA);
248	c_set_disp_reg(par, CARMINE_DISP_REG_L5_EXT_MODE, CARMINE_EXTEND_MODE |
249			CARMINE_EXT_CMODE_DIRECT24_RGBA);
250	c_set_disp_reg(par, CARMINE_DISP_REG_L6_EXT_MODE, CARMINE_EXTEND_MODE |
251			CARMINE_EXT_CMODE_DIRECT24_RGBA);
252	c_set_disp_reg(par, CARMINE_DISP_REG_L7_EXT_MODE, CARMINE_EXTEND_MODE |
253			CARMINE_EXT_CMODE_DIRECT24_RGBA);
254
255	/* Set default frame size to layer mode register */
256	width = par->res->hdp * 4 / CARMINE_DISP_WIDTH_UNIT;
257	width = width << CARMINE_DISP_WIDTH_SHIFT;
258
259	height = par->res->vdp - 1;
260	param = width | height;
261
262	c_set_disp_reg(par, CARMINE_DISP_REG_L0_MODE_W_H, param);
263	c_set_disp_reg(par, CARMINE_DISP_REG_L1_WIDTH, width);
264	c_set_disp_reg(par, CARMINE_DISP_REG_L2_MODE_W_H, param);
265	c_set_disp_reg(par, CARMINE_DISP_REG_L3_MODE_W_H, param);
266	c_set_disp_reg(par, CARMINE_DISP_REG_L4_MODE_W_H, param);
267	c_set_disp_reg(par, CARMINE_DISP_REG_L5_MODE_W_H, param);
268	c_set_disp_reg(par, CARMINE_DISP_REG_L6_MODE_W_H, param);
269	c_set_disp_reg(par, CARMINE_DISP_REG_L7_MODE_W_H, param);
270
271	/* Set default pos and size */
272	window_size = (par->res->vdp - 1) << CARMINE_DISP_WIN_H_SHIFT;
273	window_size |= par->res->hdp;
274
275	c_set_disp_reg(par, CARMINE_DISP_REG_L0_WIN_POS, 0);
276	c_set_disp_reg(par, CARMINE_DISP_REG_L0_WIN_SIZE, window_size);
277	c_set_disp_reg(par, CARMINE_DISP_REG_L1_WIN_POS, 0);
278	c_set_disp_reg(par, CARMINE_DISP_REG_L1_WIN_SIZE, window_size);
279	c_set_disp_reg(par, CARMINE_DISP_REG_L2_WIN_POS, 0);
280	c_set_disp_reg(par, CARMINE_DISP_REG_L2_WIN_SIZE, window_size);
281	c_set_disp_reg(par, CARMINE_DISP_REG_L3_WIN_POS, 0);
282	c_set_disp_reg(par, CARMINE_DISP_REG_L3_WIN_SIZE, window_size);
283	c_set_disp_reg(par, CARMINE_DISP_REG_L4_WIN_POS, 0);
284	c_set_disp_reg(par, CARMINE_DISP_REG_L4_WIN_SIZE, window_size);
285	c_set_disp_reg(par, CARMINE_DISP_REG_L5_WIN_POS, 0);
286	c_set_disp_reg(par, CARMINE_DISP_REG_L5_WIN_SIZE, window_size);
287	c_set_disp_reg(par, CARMINE_DISP_REG_L6_WIN_POS, 0);
288	c_set_disp_reg(par, CARMINE_DISP_REG_L6_WIN_SIZE, window_size);
289	c_set_disp_reg(par, CARMINE_DISP_REG_L7_WIN_POS, 0);
290	c_set_disp_reg(par, CARMINE_DISP_REG_L7_WIN_SIZE, window_size);
291
292	/* Set default origin address */
293	c_set_disp_reg(par, CARMINE_DISP_REG_L0_ORG_ADR, soffset);
294	c_set_disp_reg(par, CARMINE_DISP_REG_L1_ORG_ADR, soffset);
295	c_set_disp_reg(par, CARMINE_DISP_REG_L2_ORG_ADR1, soffset);
296	c_set_disp_reg(par, CARMINE_DISP_REG_L3_ORG_ADR1, soffset);
297	c_set_disp_reg(par, CARMINE_DISP_REG_L4_ORG_ADR1, soffset);
298	c_set_disp_reg(par, CARMINE_DISP_REG_L5_ORG_ADR1, soffset);
299	c_set_disp_reg(par, CARMINE_DISP_REG_L6_ORG_ADR1, soffset);
300	c_set_disp_reg(par, CARMINE_DISP_REG_L7_ORG_ADR1, soffset);
301
302	/* Set default display address */
303	c_set_disp_reg(par, CARMINE_DISP_REG_L0_DISP_ADR, soffset);
304	c_set_disp_reg(par, CARMINE_DISP_REG_L2_DISP_ADR1, soffset);
305	c_set_disp_reg(par, CARMINE_DISP_REG_L3_DISP_ADR1, soffset);
306	c_set_disp_reg(par, CARMINE_DISP_REG_L4_DISP_ADR1, soffset);
307	c_set_disp_reg(par, CARMINE_DISP_REG_L5_DISP_ADR1, soffset);
308	c_set_disp_reg(par, CARMINE_DISP_REG_L6_DISP_ADR0, soffset);
309	c_set_disp_reg(par, CARMINE_DISP_REG_L7_DISP_ADR0, soffset);
310
311	/* Set default display position */
312	c_set_disp_reg(par, CARMINE_DISP_REG_L0_DISP_POS, 0);
313	c_set_disp_reg(par, CARMINE_DISP_REG_L2_DISP_POS, 0);
314	c_set_disp_reg(par, CARMINE_DISP_REG_L3_DISP_POS, 0);
315	c_set_disp_reg(par, CARMINE_DISP_REG_L4_DISP_POS, 0);
316	c_set_disp_reg(par, CARMINE_DISP_REG_L5_DISP_POS, 0);
317	c_set_disp_reg(par, CARMINE_DISP_REG_L6_DISP_POS, 0);
318	c_set_disp_reg(par, CARMINE_DISP_REG_L7_DISP_POS, 0);
319
320	/* Set default blend mode */
321	c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L0, 0);
322	c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L1, 0);
323	c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L2, 0);
324	c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L3, 0);
325	c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L4, 0);
326	c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L5, 0);
327	c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L6, 0);
328	c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L7, 0);
329
330	/* default transparency mode */
331	c_set_disp_reg(par, CARMINE_DISP_REG_L0_TRANS, 0);
332	c_set_disp_reg(par, CARMINE_DISP_REG_L1_TRANS, 0);
333	c_set_disp_reg(par, CARMINE_DISP_REG_L2_TRANS, 0);
334	c_set_disp_reg(par, CARMINE_DISP_REG_L3_TRANS, 0);
335	c_set_disp_reg(par, CARMINE_DISP_REG_L4_TRANS, 0);
336	c_set_disp_reg(par, CARMINE_DISP_REG_L5_TRANS, 0);
337	c_set_disp_reg(par, CARMINE_DISP_REG_L6_TRANS, 0);
338	c_set_disp_reg(par, CARMINE_DISP_REG_L7_TRANS, 0);
339
340	/* Set default read skip parameter */
341	c_set_disp_reg(par, CARMINE_DISP_REG_L0RM, 0);
342	c_set_disp_reg(par, CARMINE_DISP_REG_L2RM, 0);
343	c_set_disp_reg(par, CARMINE_DISP_REG_L3RM, 0);
344	c_set_disp_reg(par, CARMINE_DISP_REG_L4RM, 0);
345	c_set_disp_reg(par, CARMINE_DISP_REG_L5RM, 0);
346	c_set_disp_reg(par, CARMINE_DISP_REG_L6RM, 0);
347	c_set_disp_reg(par, CARMINE_DISP_REG_L7RM, 0);
348
349	c_set_disp_reg(par, CARMINE_DISP_REG_L0PX, 0);
350	c_set_disp_reg(par, CARMINE_DISP_REG_L2PX, 0);
351	c_set_disp_reg(par, CARMINE_DISP_REG_L3PX, 0);
352	c_set_disp_reg(par, CARMINE_DISP_REG_L4PX, 0);
353	c_set_disp_reg(par, CARMINE_DISP_REG_L5PX, 0);
354	c_set_disp_reg(par, CARMINE_DISP_REG_L6PX, 0);
355	c_set_disp_reg(par, CARMINE_DISP_REG_L7PX, 0);
356
357	c_set_disp_reg(par, CARMINE_DISP_REG_L0PY, 0);
358	c_set_disp_reg(par, CARMINE_DISP_REG_L2PY, 0);
359	c_set_disp_reg(par, CARMINE_DISP_REG_L3PY, 0);
360	c_set_disp_reg(par, CARMINE_DISP_REG_L4PY, 0);
361	c_set_disp_reg(par, CARMINE_DISP_REG_L5PY, 0);
362	c_set_disp_reg(par, CARMINE_DISP_REG_L6PY, 0);
363	c_set_disp_reg(par, CARMINE_DISP_REG_L7PY, 0);
364}
365
366static void set_display_parameters(struct carmine_fb *par)
367{
368	u32 mode;
369	u32 hdp, vdp, htp, hsp, hsw, vtr, vsp, vsw;
370
371	/*
372	 * display timing. Parameters are decreased by one because hardware
373	 * spec is 0 to (n - 1)
374	 * */
375	hdp = par->res->hdp - 1;
376	vdp = par->res->vdp - 1;
377	htp = par->res->htp - 1;
378	hsp = par->res->hsp - 1;
379	hsw = par->res->hsw - 1;
380	vtr = par->res->vtr - 1;
381	vsp = par->res->vsp - 1;
382	vsw = par->res->vsw - 1;
383
384	c_set_disp_reg(par, CARMINE_DISP_REG_H_TOTAL,
385			htp << CARMINE_DISP_HTP_SHIFT);
386	c_set_disp_reg(par, CARMINE_DISP_REG_H_PERIOD,
387			(hdp << CARMINE_DISP_HDB_SHIFT)	| hdp);
388	c_set_disp_reg(par, CARMINE_DISP_REG_V_H_W_H_POS,
389			(vsw << CARMINE_DISP_VSW_SHIFT) |
390			(hsw << CARMINE_DISP_HSW_SHIFT) |
391			(hsp));
392	c_set_disp_reg(par, CARMINE_DISP_REG_V_TOTAL,
393			vtr << CARMINE_DISP_VTR_SHIFT);
394	c_set_disp_reg(par, CARMINE_DISP_REG_V_PERIOD_POS,
395			(vdp << CARMINE_DISP_VDP_SHIFT) | vsp);
396
397	/* clock */
398	mode = c_get_disp_reg(par, CARMINE_DISP_REG_DCM1);
399	mode = (mode & ~CARMINE_DISP_DCM_MASK) |
400		(par->res->disp_mode & CARMINE_DISP_DCM_MASK);
401	/* enable video output and layer 0 */
402	mode |= CARMINE_DEN | CARMINE_L0E;
403	c_set_disp_reg(par, CARMINE_DISP_REG_DCM1, mode);
404}
405
406static int carmine_set_par(struct fb_info *info)
407{
408	struct carmine_fb *par = info->par;
409	int ret;
410
411	ret = carmine_find_mode(&info->var);
412	if (ret < 0)
413		return ret;
414
415	par->new_mode = ret;
416	if (par->cur_mode != par->new_mode) {
417
418		par->cur_mode = par->new_mode;
419		par->res = &car_modes[par->new_mode];
420
421		carmine_init_display_param(par);
422		set_display_parameters(par);
423	}
424
425	info->fix.line_length = info->var.xres * info->var.bits_per_pixel / 8;
426	return 0;
427}
428
429static int init_hardware(struct carmine_hw *hw)
430{
431	u32 flags;
432	u32 loops;
433	u32 ret;
434
435	/* Initialize Carmine */
436	/* Sets internal clock */
437	c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE,
438			CARMINE_DFLT_IP_CLOCK_ENABLE);
439
440	/* Video signal output is turned off */
441	c_set_hw_reg(hw, CARMINE_DISP0_REG + CARMINE_DISP_REG_DCM1, 0);
442	c_set_hw_reg(hw, CARMINE_DISP1_REG + CARMINE_DISP_REG_DCM1, 0);
443
444	/* Software reset */
445	c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_SOFTWARE_RESET, 1);
446	c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_SOFTWARE_RESET, 0);
447
448	/* I/O mode settings */
449	flags = CARMINE_DFLT_IP_DCTL_IO_CONT1 << 16 |
450		CARMINE_DFLT_IP_DCTL_IO_CONT0;
451	c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_IOCONT1_IOCONT0,
452			flags);
453
454	/* DRAM initial sequence */
455	flags = CARMINE_DFLT_IP_DCTL_MODE << 16 | CARMINE_DFLT_IP_DCTL_ADD;
456	c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_MODE_ADD,
457			flags);
458
459	flags = CARMINE_DFLT_IP_DCTL_SET_TIME1 << 16 |
460		CARMINE_DFLT_IP_DCTL_EMODE;
461	c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_SETTIME1_EMODE,
462			flags);
463
464	flags = CARMINE_DFLT_IP_DCTL_REFRESH << 16 |
465		CARMINE_DFLT_IP_DCTL_SET_TIME2;
466	c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_REFRESH_SETTIME2,
467			flags);
468
469	flags = CARMINE_DFLT_IP_DCTL_RESERVE2 << 16 |
470		CARMINE_DFLT_IP_DCTL_FIFO_DEPTH;
471	c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_RSV2_RSV1, flags);
472
473	flags = CARMINE_DFLT_IP_DCTL_DDRIF2 << 16 | CARMINE_DFLT_IP_DCTL_DDRIF1;
474	c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_DDRIF2_DDRIF1,
475			flags);
476
477	flags = CARMINE_DFLT_IP_DCTL_RESERVE0 << 16 |
478		CARMINE_DFLT_IP_DCTL_STATES;
479	c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_RSV0_STATES,
480			flags);
481
482	/* Executes DLL reset */
483	if (CARMINE_DCTL_DLL_RESET) {
484		for (loops = 0; loops < CARMINE_DCTL_INIT_WAIT_LIMIT; loops++) {
485
486			ret = c_get_hw_reg(hw, CARMINE_DCTL_REG +
487					CARMINE_DCTL_REG_RSV0_STATES);
488			ret &= CARMINE_DCTL_REG_STATES_MASK;
489			if (!ret)
490				break;
491
492			mdelay(CARMINE_DCTL_INIT_WAIT_INTERVAL);
493		}
494
495		if (loops >= CARMINE_DCTL_INIT_WAIT_LIMIT) {
496			printk(KERN_ERR "DRAM init failed\n");
497			return -EIO;
498		}
499	}
500
501	flags = CARMINE_DFLT_IP_DCTL_MODE_AFT_RST << 16 |
502		CARMINE_DFLT_IP_DCTL_ADD;
503	c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_MODE_ADD, flags);
504
505	flags = CARMINE_DFLT_IP_DCTL_RESERVE0 << 16 |
506		CARMINE_DFLT_IP_DCTL_STATES_AFT_RST;
507	c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_RSV0_STATES,
508			flags);
509
510	/* Initialize the write back register */
511	c_set_hw_reg(hw, CARMINE_WB_REG + CARMINE_WB_REG_WBM,
512			CARMINE_WB_REG_WBM_DEFAULT);
513
514	/* Initialize the Kottos registers */
515	c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_VRINTM, 0);
516	c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_VRERRM, 0);
517
518	/* Set DC offsets */
519	c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_PX, 0);
520	c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_PY, 0);
521	c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_LX, 0);
522	c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_LY, 0);
523	c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_TX, 0);
524	c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_TY, 0);
525	return 0;
526}
527
528static struct fb_ops carminefb_ops = {
529	.owner		= THIS_MODULE,
530	.fb_fillrect	= cfb_fillrect,
531	.fb_copyarea	= cfb_copyarea,
532	.fb_imageblit	= cfb_imageblit,
533
534	.fb_check_var	= carmine_check_var,
535	.fb_set_par	= carmine_set_par,
536	.fb_setcolreg	= carmine_setcolreg,
537};
538
539static int __devinit alloc_carmine_fb(void __iomem *regs, void __iomem *smem_base,
540		int smem_offset, struct device *device, struct fb_info **rinfo)
541{
542	int ret;
543	struct fb_info *info;
544	struct carmine_fb *par;
545
546	info = framebuffer_alloc(sizeof *par, device);
547	if (!info)
548		return -ENOMEM;
549
550	par = info->par;
551	par->display_reg = regs;
552	par->smem_offset = smem_offset;
553
554	info->screen_base = smem_base + smem_offset;
555	info->screen_size = CARMINE_DISPLAY_MEM;
556	info->fbops = &carminefb_ops;
557
558	info->fix = carminefb_fix;
559	info->pseudo_palette = par->pseudo_palette;
560	info->flags = FBINFO_DEFAULT;
561
562	ret = fb_alloc_cmap(&info->cmap, 256, 1);
563	if (ret < 0)
564		goto err_free_fb;
565
566	if (fb_mode >= ARRAY_SIZE(carmine_modedb))
567		fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
568
569	par->cur_mode = par->new_mode = ~0;
570
571	ret = fb_find_mode(&info->var, info, fb_mode_str, carmine_modedb,
572			ARRAY_SIZE(carmine_modedb),
573			&carmine_modedb[fb_mode], 32);
574	if (!ret || ret == 4) {
575		ret = -EINVAL;
576		goto err_dealloc_cmap;
577	}
578
579	fb_videomode_to_modelist(carmine_modedb, ARRAY_SIZE(carmine_modedb),
580			&info->modelist);
581
582	ret = register_framebuffer(info);
583	if (ret < 0)
584		goto err_dealloc_cmap;
585
586	printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
587			info->fix.id);
588
589	*rinfo = info;
590	return 0;
591
592err_dealloc_cmap:
593	fb_dealloc_cmap(&info->cmap);
594err_free_fb:
595	framebuffer_release(info);
596	return ret;
597}
598
599static void cleanup_fb_device(struct fb_info *info)
600{
601	if (info) {
602		unregister_framebuffer(info);
603		fb_dealloc_cmap(&info->cmap);
604		framebuffer_release(info);
605	}
606}
607
608static int __devinit carminefb_probe(struct pci_dev *dev,
609		const struct pci_device_id *ent)
610{
611	struct carmine_hw *hw;
612	struct device *device = &dev->dev;
613	struct fb_info *info;
614	int ret;
615
616	ret = pci_enable_device(dev);
617	if (ret)
618		return ret;
619
620	ret = -ENOMEM;
621	hw = kzalloc(sizeof *hw, GFP_KERNEL);
622	if (!hw)
623		goto err_enable_pci;
624
625	carminefb_fix.mmio_start = pci_resource_start(dev, CARMINE_CONFIG_BAR);
626	carminefb_fix.mmio_len = pci_resource_len(dev, CARMINE_CONFIG_BAR);
627
628	if (!request_mem_region(carminefb_fix.mmio_start,
629				carminefb_fix.mmio_len,
630				"carminefb regbase")) {
631		printk(KERN_ERR "carminefb: Can't reserve regbase.\n");
632		ret = -EBUSY;
633		goto err_free_hw;
634	}
635	hw->v_regs = ioremap_nocache(carminefb_fix.mmio_start,
636			carminefb_fix.mmio_len);
637	if (!hw->v_regs) {
638		printk(KERN_ERR "carminefb: Can't remap %s register.\n",
639				carminefb_fix.id);
640		goto err_free_reg_mmio;
641	}
642
643	carminefb_fix.smem_start = pci_resource_start(dev, CARMINE_MEMORY_BAR);
644	carminefb_fix.smem_len = pci_resource_len(dev, CARMINE_MEMORY_BAR);
645
646	/* The memory area tends to be very large (256 MiB). Remap only what
647	 * is required for that largest resolution to avoid remaps at run
648	 * time
649	 */
650	if (carminefb_fix.smem_len > CARMINE_TOTAL_DIPLAY_MEM)
651		carminefb_fix.smem_len = CARMINE_TOTAL_DIPLAY_MEM;
652
653	else if (carminefb_fix.smem_len < CARMINE_TOTAL_DIPLAY_MEM) {
654		printk(KERN_ERR "carminefb: Memory bar is only %d bytes, %d "
655				"are required.", carminefb_fix.smem_len,
656				CARMINE_TOTAL_DIPLAY_MEM);
657		goto err_free_reg_mmio;
658	}
659
660	if (!request_mem_region(carminefb_fix.smem_start,
661				carminefb_fix.smem_len,	"carminefb smem")) {
662		printk(KERN_ERR "carminefb: Can't reserve smem.\n");
663		goto err_unmap_vregs;
664	}
665
666	hw->screen_mem = ioremap_nocache(carminefb_fix.smem_start,
667			carminefb_fix.smem_len);
668	if (!hw->screen_mem) {
669		printk(KERN_ERR "carmine: Can't ioremap smem area.\n");
670		release_mem_region(carminefb_fix.smem_start,
671				carminefb_fix.smem_len);
672		goto err_reg_smem;
673	}
674
675	ret = init_hardware(hw);
676	if (ret)
677		goto err_unmap_screen;
678
679	info = NULL;
680	if (fb_displays & CARMINE_USE_DISPLAY0) {
681		ret = alloc_carmine_fb(hw->v_regs + CARMINE_DISP0_REG,
682				hw->screen_mem, CARMINE_DISPLAY_MEM * 0,
683				device, &info);
684		if (ret)
685			goto err_deinit_hw;
686	}
687
688	hw->fb[0] = info;
689
690	info = NULL;
691	if (fb_displays & CARMINE_USE_DISPLAY1) {
692		ret = alloc_carmine_fb(hw->v_regs + CARMINE_DISP1_REG,
693				hw->screen_mem, CARMINE_DISPLAY_MEM * 1,
694				device, &info);
695		if (ret)
696			goto err_cleanup_fb0;
697	}
698
699	hw->fb[1] = info;
700	info = NULL;
701
702	pci_set_drvdata(dev, hw);
703	return 0;
704
705err_cleanup_fb0:
706	cleanup_fb_device(hw->fb[0]);
707err_deinit_hw:
708	/* disable clock, etc */
709	c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE, 0);
710err_unmap_screen:
711	iounmap(hw->screen_mem);
712err_reg_smem:
713	release_mem_region(carminefb_fix.mmio_start, carminefb_fix.mmio_len);
714err_unmap_vregs:
715	iounmap(hw->v_regs);
716err_free_reg_mmio:
717	release_mem_region(carminefb_fix.mmio_start, carminefb_fix.mmio_len);
718err_free_hw:
719	kfree(hw);
720err_enable_pci:
721	pci_disable_device(dev);
722	return ret;
723}
724
725static void __devexit carminefb_remove(struct pci_dev *dev)
726{
727	struct carmine_hw *hw = pci_get_drvdata(dev);
728	struct fb_fix_screeninfo fix;
729	int i;
730
731	/* in case we use only fb1 and not fb1 */
732	if (hw->fb[0])
733		fix = hw->fb[0]->fix;
734	else
735		fix = hw->fb[1]->fix;
736
737	/* deactivate display(s) and switch clocks */
738	c_set_hw_reg(hw, CARMINE_DISP0_REG + CARMINE_DISP_REG_DCM1, 0);
739	c_set_hw_reg(hw, CARMINE_DISP1_REG + CARMINE_DISP_REG_DCM1, 0);
740	c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE, 0);
741
742	for (i = 0; i < MAX_DISPLAY; i++)
743		cleanup_fb_device(hw->fb[i]);
744
745	iounmap(hw->screen_mem);
746	release_mem_region(fix.smem_start, fix.smem_len);
747	iounmap(hw->v_regs);
748	release_mem_region(fix.mmio_start, fix.mmio_len);
749
750	pci_set_drvdata(dev, NULL);
751	pci_disable_device(dev);
752	kfree(hw);
753}
754
755#define PCI_VENDOR_ID_FUJITU_LIMITED 0x10cf
756static struct pci_device_id carmine_devices[] __devinitdata = {
757{
758	PCI_DEVICE(PCI_VENDOR_ID_FUJITU_LIMITED, 0x202b)},
759	{0, 0, 0, 0, 0, 0, 0}
760};
761
762MODULE_DEVICE_TABLE(pci, carmine_devices);
763
764static struct pci_driver carmine_pci_driver = {
765	.name		= "carminefb",
766	.id_table	= carmine_devices,
767	.probe		= carminefb_probe,
768	.remove		= __devexit_p(carminefb_remove),
769};
770
771static int __init carminefb_init(void)
772{
773	if (!(fb_displays &
774		(CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1))) {
775		printk(KERN_ERR "If you disable both displays than you don't "
776				"need the driver at all\n");
777		return -EINVAL;
778	}
779	return pci_register_driver(&carmine_pci_driver);
780}
781module_init(carminefb_init);
782
783static void __exit carminefb_cleanup(void)
784{
785	pci_unregister_driver(&carmine_pci_driver);
786}
787module_exit(carminefb_cleanup);
788
789MODULE_AUTHOR("Sebastian Siewior <bigeasy@linutronix.de>");
790MODULE_DESCRIPTION("Framebuffer driver for Fujitsu Carmine based devices");
791MODULE_LICENSE("GPL v2");
792