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