Lynx framebuffers multidomain implementation.
[linux/elbrus.git] / drivers / video / mgam83 / sbus_mgam83fb_base.c
blobf916eadda060ec34e7813295b14aa1df9099cc24
1 /* MGA-M83 framebuffer driver
2 * make -C ../linux-2.6.14 SUBDIRS=$PWD modules
4 * Copyright (C) 2005-2006, Alexander Shmelev <ashmelev@task.sun.mcst.ru>
6 * To specify a video mode at bootup, use the following boot options:
7 * video=mgam83fb:<xres>x<yres>[-<bpp>][@refresh]
8 *
9 * Supported resolutions:
10 * 640x480, 800x600, 1024x768, 1280x1024, 1600x1200
11 * Supported depths:
12 * 8bpp, 16bpp, 24bpp, 32bpp
14 * Details about modes can be found in Linux/Documentation/fb/modedb.txt
16 * History:
17 * 1.1 SBUS model support added
18 * 2.0 Linux-2.6 version
21 #include <linux/module.h>
22 #include <linux/kernel.h>
23 #include <linux/errno.h>
24 #include <linux/string.h>
25 #include <linux/mm.h>
26 #include <linux/tty.h>
27 #include <linux/slab.h>
28 #include <linux/delay.h>
29 #include <linux/fb.h>
30 #include <linux/init.h>
31 #include <linux/proc_fs.h>
32 #include <asm/uaccess.h>
33 #include <linux/dma-mapping.h>
34 #include <linux/of_device.h>
36 #if defined(CONFIG_SBUS)
37 #define mga_ioremap of_ioremap
38 #elif defined(CONFIG_PCI2SBUS_MODULE)
39 #include <linux/mcst/p2ssbus.h>
40 #endif
42 #include "sbus_mgam83fb.h"
44 static char* mode_option = NULL;
45 static int next_index = 0;
47 /*******************************************************************************
48 * Structures
49 *******************************************************************************
51 struct mgam83fb_par {
52 int bus_type; // 0 - PCI, 1 - SBUS
53 int index; // MGAM index
55 struct {
56 #ifdef __sparc__
57 int iospace; // iospace
58 #endif
59 unsigned long base; // phys address
60 uint8_t* vbase; // virtual address
61 unsigned int len;
62 } mem;
63 struct {
64 unsigned long base; // phys address
65 uint8_t* vbase; // virtual address
66 unsigned int len;
67 } mmio;
68 struct {
69 unsigned long base; // phys address
70 uint8_t* vbase; // virtual address
71 unsigned int len;
72 } i2c;
73 struct {
74 unsigned long kvaddr;
75 unsigned long ioaddr;
76 unsigned int size;
77 } video_buf;
79 struct of_device *mgaop;
80 struct fb_info* info;
82 /* Current videomode **************************************************/
83 __u32 xres; // visible resolution
84 __u32 yres;
85 __u32 xres_virtual; // virtual resolution
86 __u32 yres_virtual;
87 __u32 xoffset; // offset from virtual to visible
88 __u32 yoffset; // resolution
90 __u32 bits_per_pixel; // Bits per pixel
92 __u32 pixclock; // pixel clock in ps (pico seconds)
93 __u32 left_margin; // time from sync to picture
94 __u32 right_margin; // time from picture to sync
95 __u32 upper_margin; // time from sync to picture
96 __u32 lower_margin;
97 __u32 hsync_len; // length of horizontal sync
98 __u32 vsync_len; // length of vertical sync
100 __u32 sync;
102 u32 pseudo_palette[16];
107 /*******************************************************************************
108 * Prototypes
109 *******************************************************************************
111 /* Framebuffer entry points */
112 static int mgam83fb_check_var(struct fb_var_screeninfo* var, struct fb_info* info);
113 static int mgam83fb_set_par(struct fb_info* info);
114 static int mgam83fb_setcolreg(unsigned regno, unsigned red, unsigned green,
115 unsigned blue, unsigned transp,
116 struct fb_info *info);
117 static int mgam83fb_mmap(struct fb_info *info, struct vm_area_struct *vma);
118 void __proc_init( struct mgam83fb_par* p );
119 int mgafb_proc_write(struct file *file, const char *buffer, unsigned long count, void *data);
120 int mgafb_proc_read(char *buf, char **start, off_t off, int count, int *eof, void *data);
121 void __fb_fill ( struct mgam83fb_par* p );
122 void __dump_var( const struct fb_var_screeninfo* var );
123 void __dump_par( const struct mgam83fb_par* p );
124 void __dump_mmio( struct mgam83fb_par* p );
126 #undef MGAM_TRACE_FUNC
127 #ifdef MGAM_TRACE_FUNC
128 extern void mgam_trace_func(unsigned int i);
129 #define trace_func(x) mgam_trace_func(x)
130 #else
131 #define trace_func(x)
132 #endif
133 /*******************************************************************************
134 * MMIO Registers
135 *******************************************************************************
137 static void MMIO_WRITE( struct mgam83fb_par* p, unsigned long reg, uint32_t val )
139 TRACE_MSG( "MMIO[0x%03lx] <= 0x%08x\n", reg, val );
141 switch( p->bus_type ) {
142 #if defined(CONFIG_SBUS) || defined(CONFIG_PCI2SBUS_MODULE)
143 case BUS_TYPE_SBUS :
144 // registers are little-endian like in PCI model
145 writel( val, (void*)((unsigned long)p->mmio.vbase + reg) );
146 break;
147 #endif /* CONFIG_SBUS || CONFIG_PCI2SBUS_MODULE */
148 default :
149 printk( KERN_WARNING "Cannot write to mmio: unsupported MGA/M video card model!\n" );
152 TRACE_MSG( "Sleeping 10 msecs...\n" );
155 static uint32_t MMIO_READ( struct mgam83fb_par* p, unsigned long reg )
157 uint32_t result;
159 switch( p->bus_type ) {
160 #if defined(CONFIG_SBUS) || defined(CONFIG_PCI2SBUS_MODULE)
161 case BUS_TYPE_SBUS :
162 // registers are little-endian like in PCI model
163 result = readl( (void*)((unsigned long) p->mmio.vbase + reg) );
166 break;
167 #endif /* CONFIG_SBUS || CONFIG_PCI2SBUS_MODULE */
168 default :
169 result = ~(uint32_t)0;
170 printk( KERN_WARNING "Cannot write to mmio: unsupported MGA/M video card model!\n" );
172 TRACE_MSG( "MMIO[0x%03lx] => 0x%08x\n", reg, result );
173 return result;
176 /*******************************************************************************
177 * External entry points
178 *******************************************************************************
180 static struct { struct fb_bitfield transp, red, green, blue; } colors[] = {
181 { { 0, 0, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0} }, // 8bpp
182 { { 0, 0, 0}, { 11, 5, 0}, { 5, 6, 0}, { 0, 5, 0} }, // 16bpp
183 { { 0, 0, 0}, { 0, 8, 0}, { 8, 8, 0}, {16, 8, 0} }, // 24bpp
184 { { 24, 8, 0}, { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0} }, // 32bpp
187 static int mgam83fb_check_var(struct fb_var_screeninfo* var, struct fb_info* info)
189 struct mgam83fb_par* p = (struct mgam83fb_par*)info->par;
190 int colors_index = (var->bits_per_pixel>>3) - 1; // Index in colors table
192 DEBUG_MSG("mgam83fb: mgam83fb_check_var start\n");
193 if ( (var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED ) {
194 INFO_MSG( "mode %dx%dx%d rejected, interlaced not supported\n",
195 var->xres, var->yres, var->bits_per_pixel);
196 return -EINVAL;
199 if ( var->bits_per_pixel != 8 &&
200 var->bits_per_pixel != 16 &&
201 var->bits_per_pixel != 24 &&
202 var->bits_per_pixel != 32 )
204 INFO_MSG( "mode %dx%dx%d rejected, color depth invalid\n",
205 var->xres, var->yres, var->bits_per_pixel);
206 printk("mgam83fb: mgam83fb_check_var finish with error\n");
207 return -EINVAL;
210 if (var->xres_virtual * var->yres_virtual * ( var->bits_per_pixel >> 3) > p->mem.len) {
211 INFO_MSG( "mode %dx%dx%d rejected, not enough memory\n",
212 var->xres, var->yres, var->bits_per_pixel);
213 printk("mgam83fb: mgam83fb_check_var finish with error\n");
214 return -EINVAL;
217 var->red = colors[colors_index].red;
218 var->green = colors[colors_index].green;
219 var->blue = colors[colors_index].blue;
220 var->transp = colors[colors_index].transp;
221 DEBUG_MSG("mgam83fb: mgam83fb_check_var finish\n");
223 return 0;
227 static int __set_mode( struct mgam83fb_par* p )
229 int hsync = p->hsync_len; // The Horizontal Syncronization Time (Sync Pulse )
230 int hgdel = p->left_margin; // The Horizontal Gate Delay Time (Back Porch)
231 int hgate = p->xres; // The Horizontal Gate Time (Active Time)
232 int hlen = hsync + hgdel + hgate + p->right_margin; // The Horizontal Length Time (Line Total)
233 int vsync = p->vsync_len; // The Vertical Syncronization Time (Sync Pulse )
234 int vgdel = p->upper_margin; // The Vertical Gate Delay Time (Back Porch)
235 int vgate = p->yres; // The Vertical Gate Time (Active Time)
236 int vlen = vsync + vgdel + vgate + p->lower_margin; // The Vertical Length Time (Frame total)
237 int vbl = CTRL_VBL1024; // Video Memory Burst Length
238 int ctrl = CTRL_BL_NEG | vbl;
241 CHECKPOINT_ENTER;
243 switch( p->bits_per_pixel ) {
244 case 8 :
245 ctrl |= CTRL_CD_8BPP | CTRL_PC_PSEUDO;
246 break;
247 case 16 :
248 ctrl |= CTRL_CD_16BPP;
249 break;
250 case 24 :
251 ctrl |= CTRL_CD_24BPP;
252 break;
253 case 32 :
254 ctrl |= CTRL_CD_32BPP;
255 break;
256 default:
257 ERROR_MSG( "Invalid color depth: %s %s %d\n", __FILE__, __FUNCTION__, __LINE__ );
258 CHECKPOINT_LEAVE;
259 return -EINVAL;
262 ctrl |= ( p->sync & FB_SYNC_COMP_HIGH_ACT ) ? CTRL_CSYNC_HIGH : CTRL_CSYNC_LOW;
263 ctrl |= ( p->sync & FB_SYNC_VERT_HIGH_ACT ) ? CTRL_VSYNC_HIGH : CTRL_VSYNC_LOW;
264 ctrl |= ( p->sync & FB_SYNC_HOR_HIGH_ACT ) ? CTRL_HSYNC_HIGH : CTRL_HSYNC_LOW;
266 hsync--, hgdel--, hgate--, vsync--, vgdel--, vgate--, hlen--, vlen--;
267 trace_func(18);
268 MMIO_WRITE( p, REG_CTRL, ctrl );
269 trace_func(19);
270 MMIO_WRITE( p, REG_HTIM, hsync << 24 | hgdel << 16 | hgate );
271 trace_func(20);
272 MMIO_WRITE( p, REG_VTIM, vsync << 24 | vgdel << 16 | vgate );
273 trace_func(21);
274 MMIO_WRITE( p, REG_HVLEN, hlen << 16 | vlen );
275 trace_func(22);
276 MMIO_WRITE( p, REG_VBARa, 0x0 );
277 MMIO_WRITE(p, REG_BUGFIX, 0);
279 DEBUG_MSG( "hsync: %d hgdel: %d hgate %d\n", hsync, hgdel, hgate );
280 DEBUG_MSG( "vsync: %d vgdel: %d vgate %d\n", vsync, vgdel, vgate );
281 DEBUG_MSG( "hlen: %d vlen: %d\n", hlen, vlen );
282 trace_func(23);
283 MMIO_WRITE( p, REG_CTRL, MMIO_READ( p, REG_CTRL ) | CTRL_VEN );
284 // MMIO_WRITE( p, REG_CTRL, ctrl | CTRL_VEN );
286 CHECKPOINT_LEAVE;
287 return 0;
290 #define DEBUG_MSG_SET_PAR_MODE 0
291 #define DEBUG_MSG_SET_PAR if (DEBUG_MSG_SET_PAR_MODE) printk
292 static int mgam83fb_set_par(struct fb_info* info)
294 struct fb_var_screeninfo* mode = &info->var;
295 struct mgam83fb_par* p = (struct mgam83fb_par*)info->par;
297 CHECKPOINT_ENTER;
299 DEBUG_MSG_SET_PAR("mgam83fb_set_par: start\n");
300 /* Update fix */
301 info->fix.visual = (mode->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
302 info->fix.line_length = mode->xres_virtual * (mode->bits_per_pixel >> 3) ;
304 /* Update par */
305 p->xres = mode->xres;
306 DEBUG_MSG_SET_PAR("mgam83fb_set_par: p->xres = 0x%x\n", p->xres);
307 p->yres = mode->yres;
308 DEBUG_MSG_SET_PAR("mgam83fb_set_par: p->yres = 0x%x\n", p->yres);
309 p->xres_virtual = mode->xres_virtual;
310 DEBUG_MSG_SET_PAR("mgam83fb_set_par: p->xres_virtual = 0x%x\n", p->xres_virtual);
311 p->yres_virtual = mode->yres_virtual;
312 DEBUG_MSG_SET_PAR("mgam83fb_set_par: p->yres_virtual = 0x%x\n", p->yres_virtual);
313 p->xoffset = mode->xoffset;
314 DEBUG_MSG_SET_PAR("mgam83fb_set_par: p->xoffset = 0x%x\n", p->xoffset);
315 p->yoffset = mode->yoffset;
316 DEBUG_MSG_SET_PAR("mgam83fb_set_par: p->yoffset = 0x%x\n", p->yoffset);
317 p->left_margin = mode->left_margin;
318 DEBUG_MSG_SET_PAR("mgam83fb_set_par: p->left_margin = 0x%x\n", p->left_margin);
319 p->right_margin = mode->right_margin;
320 DEBUG_MSG_SET_PAR("mgam83fb_set_par: p->right_margin = 0x%x\n", p->right_margin);
321 p->hsync_len = mode->hsync_len;
322 DEBUG_MSG_SET_PAR("mgam83fb_set_par: p->hsync_len = 0x%x\n", p->hsync_len);
323 p->upper_margin = mode->upper_margin;
324 DEBUG_MSG_SET_PAR("mgam83fb_set_par: p->upper_margin = 0x%x\n", p->upper_margin);
325 p->lower_margin = mode->lower_margin;
326 DEBUG_MSG_SET_PAR("mgam83fb_set_par: p->lower_margin = 0x%x\n", p->lower_margin );
327 p->vsync_len = mode->vsync_len;
328 DEBUG_MSG_SET_PAR("mgam83fb_set_par: p->vsync_len = 0x%x\n", p->vsync_len);
329 p->bits_per_pixel = mode->bits_per_pixel;
330 DEBUG_MSG_SET_PAR("mgam83fb_set_par: p->bits_per_pixel = 0x%x\n", p->bits_per_pixel);
331 p->pixclock = mode->pixclock;
332 DEBUG_MSG_SET_PAR("mgam83fb_set_par: p->pixclock = 0x%x\n", p->pixclock);
333 DEBUG_MSG_SET_PAR("mgam83fb_set_par: p->sync = 0x%x\n", p->sync);
335 #ifdef MGA_DEBUG
336 __dump_par( p );
337 #endif
338 DEBUG_MSG_SET_PAR( KERN_DEBUG " xres:%d yres:%d xvirt:%d yvirt:%d bpp:%d\n",
339 p->xres, p->yres,
340 p->xres_virtual, p->yres_virtual, p->bits_per_pixel);
341 DEBUG_MSG_SET_PAR( KERN_DEBUG " pixclock:%d left:%d right:%d upper:%d "
342 "lower:%d hslen:%d vslen:%d\n",
343 p->pixclock, p->left_margin, p->right_margin,
344 p->upper_margin, p->lower_margin,
345 p->hsync_len, p->vsync_len);
347 trace_func(3);
348 __sbus_set_pixclock( p->bus_type, (unsigned long)p->i2c.vbase, p->pixclock );
349 trace_func(17);
350 __set_mode( p );
351 trace_func(24);
353 #ifdef MGA_DEBUG
354 __dump_mmio( p );
355 #endif
356 DEBUG_MSG_SET_PAR("mgam83fb_set_par finish\n");
357 return 0;
361 static int mgam83_get_cmap_len(int bpp)
363 switch(bpp) {
364 case 8: return 256; /* pseudocolor... 256 entries HW palette */
365 case 16:
366 case 24:
367 case 32: return 16; /* directcolor... 16 entries SW palette */
368 default: return 0;
372 static int mgam83fb_setcolreg(unsigned regno, unsigned red, unsigned green,
373 unsigned blue, unsigned transp,
374 struct fb_info *info)
376 struct mgam83fb_par* p = (struct mgam83fb_par*)info->par;
378 trace_func(25);
379 DEBUG_MSG("mgam83fb_setcolreg start\n");
380 if (regno >= mgam83_get_cmap_len(p->bits_per_pixel)){ /* no. of hw registers */
381 DEBUG_MSG("mgam83fb: mgam83fb_setcolreg finish with error\n");
382 return -EINVAL;
384 /* grayscale works only partially under directcolor */
385 if (info->var.grayscale) {
386 /* grayscale = 0.30*R + 0.59*G + 0.11*B */
387 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
390 red >>= (16 - info->var.red.length);
391 green >>= (16 - info->var.green.length);
392 blue >>= (16 - info->var.blue.length);
393 transp >>= (16 - info->var.transp.length);
395 if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
396 uint32_t val = (red << 16) | (green << 8) | blue;
397 // using CLUT0
398 trace_func(26);
399 MMIO_WRITE( p, 0x800 + regno * 4, val );
402 /* Truecolor has hardware independent palette */
403 if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
404 u32 v;
406 if (regno >= 16){
407 printk("mgam83fb: mgam83fb_setcolreg finish with error, regno = 0x%x\n", regno);
408 return -EINVAL;
411 v = (red << info->var.red.offset) |
412 (green << info->var.green.offset) |
413 (blue << info->var.blue.offset) |
414 (transp << info->var.transp.offset);
416 // 16bpp, 24bpp or 32bpp
417 trace_func(27);
418 ((u32*)(info->pseudo_palette))[regno] = v;
420 trace_func(28);
421 DEBUG_MSG("mgam83fb_setcolreg finish\n");
422 return 0;
425 struct dma_mem {
426 unsigned long phys_addr; /* dma addr */
427 size_t size;
430 struct ker_dma_mem {
431 unsigned long phys_addr; /* dma addr */
432 unsigned long kvaddr;
433 size_t size;
434 struct ker_dma_mem *next;
437 static struct ker_dma_mem *dma_mem_list = NULL;
439 #define FBIOALLOC_DMA_MEM 0x4631
440 #define FBIOFREE_ALL_DMA_MEMS 0x4632
442 #define DEBUG_IOCTL_MSG_ON 0
443 #define DEBUG_IOCTL_MSG if (DEBUG_IOCTL_MSG_ON) printk
445 static int
446 mgam83fb_ioctl(struct fb_info *info, unsigned int cmd,
447 unsigned long arg)
449 unsigned long kvaddr;
450 struct dma_mem dmem;
451 int order;
452 struct page *map, *mapend;
453 struct mgam83fb_par* par = (struct mgam83fb_par*)info->par;
454 void __user *argp = (void __user *)arg;
456 switch (cmd) {
457 case FBIOALLOC_DMA_MEM:
458 if (!par->video_buf.ioaddr) {
459 if (copy_from_user(&dmem, argp, sizeof(dmem))) {
460 return -EFAULT;
462 DEBUG_IOCTL_MSG("mgam83fb_ioctl: Ask to alloc 0x%lx bytes\n",
463 (unsigned long)dmem.size);
464 order = get_order(dmem.size);
465 kvaddr = __get_free_pages(GFP_KERNEL | GFP_DMA, order);
467 if (!kvaddr){
468 DEBUG_IOCTL_MSG("mgam83fb_ioctl: failed to alloc dma buffer\n");
469 return -ENOMEM;
471 mapend = virt_to_page (kvaddr + (PAGE_SIZE << order) - 1);
472 for (map = virt_to_page(kvaddr); map <= mapend; map++) {
473 SetPageReserved(map);
475 par->video_buf.ioaddr = dma_map_single(&par->mgaop->dev, (void *)kvaddr, dmem.size,
476 DMA_BIDIRECTIONAL);
477 par->video_buf.kvaddr = kvaddr;
478 par->video_buf.size = dmem.size;
480 dmem.phys_addr = par->video_buf.ioaddr;
481 DEBUG_IOCTL_MSG("FBIOALLOC_DMA_MEM: kvaddr = 0x%08lx; dmem.phys_addr = 0x%08lx\n", kvaddr, dmem.phys_addr);
483 if (copy_to_user(argp, &dmem, sizeof(dmem))){
484 DEBUG_IOCTL_MSG("mgam83fb_ioctl: failed to copy_to_user\n");
485 return -EFAULT;
487 return 0;
488 default:
489 return -EINVAL;
493 #define DEBUG_MMAP_MSG_ON 0
494 #define DEBUG_MMAP_MSG if (DEBUG_MMAP_MSG_ON) printk
496 static struct ker_dma_mem *lookup_trough_dma_list(unsigned long off)
498 struct ker_dma_mem *tmp_list = dma_mem_list;
499 while (tmp_list){
500 if ((off >= tmp_list->phys_addr) &&
501 (off < (tmp_list->phys_addr + tmp_list->size)))
502 return tmp_list;
503 tmp_list = dma_mem_list->next;
505 return NULL;
508 static int mgam83fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
510 unsigned long off;
511 unsigned long start;
512 struct ker_dma_mem *tmp_list = NULL;
513 u32 len;
514 struct mgam83fb_par* p = (struct mgam83fb_par*)info->par;
516 off = vma->vm_pgoff << PAGE_SHIFT;
518 /* frame buffer memory */
519 start = info->fix.smem_start;
520 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
521 DEBUG_MMAP_MSG("mgam83fb_mmap: start = 0x%lx, off = 0x%lx, len = 0x%x\n",
522 start, off, len);
523 /* off that's in range of 0..."fb len" corresponds to framebuffer */
524 /* off that's in range of "fb len"..."io len" corresponds to mmio */
525 if (off < len){
526 DEBUG_MMAP_MSG("mgam83fb_mmap: given off corresponds to fbmem\n");
527 #ifdef CONFIG_E2K
528 vma->vm_page_prot = (cpu_has(CPU_HAS_WC_PCI_PREFETCH)) ?
529 pgprot_writecombine(vma->vm_page_prot) :
530 pgprot_noncached(vma->vm_page_prot);
531 #endif
534 if ((off >= len) && (off < 0x80000000)) {
535 /* memory mapped io */
536 DEBUG_MMAP_MSG("mgam83fb_mmap: given off corresponds to mmio\n");
537 off -= len;
538 start = info->fix.mmio_start;
539 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
540 #ifdef CONFIG_E2K
541 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
542 #endif
545 /* off that's more then 0x80000000 corresponds to allocated dma buffers */
546 if (off >= 0x80000000){
547 DEBUG_MMAP_MSG("mgam83fb_mmap: given off corresponds to dma mem\n");
548 off = off - 0x80000000;
549 DEBUG_MMAP_MSG("mgam83fb_mmap: corrected off: 0x%lx\n", off);
550 tmp_list = lookup_trough_dma_list(off);
551 if (!tmp_list){
552 DEBUG_MMAP_MSG("mgam83fb_mmap: relevant dma buffer isn't found\n");
553 return -EINVAL;
555 DEBUG_MMAP_MSG("mgam83fb_mmap: found dma buffer, the \"off\" corresponds to\n");
556 DEBUG_MMAP_MSG("mgam83fb_mmap: dma buf parms: paddr 0x%lx, size 0x%x\n",
557 tmp_list->phys_addr, tmp_list->size);
558 DEBUG_MMAP_MSG("mgam83fb_mmap: We desire to map the range from 0x%lx to 0x%lx\n",
559 off, (off + vma->vm_end - vma->vm_start));
560 if (((off - tmp_list->phys_addr) +
561 (vma->vm_end - vma->vm_start)) > tmp_list->size){
562 DEBUG_MMAP_MSG("mgam83fb_mmap: too much size was given to map in:\n");
563 DEBUG_MMAP_MSG("mgam83fb_mmap: off: 0x%lx given size: 0x%lx, "
564 "found dma buffer size: 0x%x\n", (off - tmp_list->phys_addr),
565 (vma->vm_end - vma->vm_start), tmp_list->size);
566 return -EINVAL;
569 vma->vm_pgoff = off >> PAGE_SHIFT;
570 vma->vm_flags |= VM_IO | VM_RESERVED;
571 #if defined(__e2k__)
572 if (vma->vm_flags & VM_WRITECOMBINED)
573 vma->vm_page_prot =
574 pgprot_writecombine(vma->vm_page_prot);
575 #endif
577 #if defined (__sparc__)
578 if (remap_pfn_range(vma, vma->vm_start,
579 MK_IOSPACE_PFN(p->mem.iospace, (off >> PAGE_SHIFT)),
580 vma->vm_end - vma->vm_start, vma->vm_page_prot))
581 return -EAGAIN;
582 #else
583 if (remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
584 vma->vm_end - vma->vm_start, vma->vm_page_prot))
585 return -EAGAIN;
586 #endif
587 DEBUG_MMAP_MSG("mgam83fb_mmap: mapping done successfully\n");
588 return 0;
591 start &= PAGE_MASK;
592 if ((off + vma->vm_end - vma->vm_start) > len)
593 return -EINVAL;
595 off += start;
596 vma->vm_pgoff = off >> PAGE_SHIFT;
597 /* This is an IO map - tell maydump to skip this VMA */
598 vma->vm_flags |= VM_IO | VM_RESERVED;
600 #if !defined(__e2k__)
601 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
602 #endif
604 #if defined (__sparc__)
605 if (io_remap_pfn_range(vma, vma->vm_start,
606 MK_IOSPACE_PFN(p->mem.iospace, (off >> PAGE_SHIFT)),
607 vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
608 return -EAGAIN;
610 #else
611 if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
612 vma->vm_end - vma->vm_start, vma->vm_page_prot))
613 return -EAGAIN;
614 #endif
616 return 0;
619 #if 0
620 extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor);
621 extern void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect);
622 #endif
624 #ifdef MGA_DEBUG
625 static struct fb_copyarea last_area[10];
626 static int area_count = 0;
627 static struct fb_copyarea *curr_area = NULL;
628 static struct fb_info *last_info[10];
629 #endif
631 static inline u32 flip_32 (u32 l)
633 return ((l&0xff)<<24) | (((l>>8)&0xff)<<16) |
634 (((l>>16)&0xff)<<8)| ((l>>24)&0xff);
637 static inline u32 bitflip_32 (u32 l)
639 return ((l&0x1)<<31) | (((l>>1)&0x1)<<30) |
640 (((l>>2)&0x1)<<29) | (((l>>3)&0x1)<<28) |
641 (((l>>4)&0x1)<<27) | (((l>>5)&0x1)<<26) |
642 (((l>>6)&0x1)<<25) | (((l>>7)&0x1)<<24) |
643 (((l>>8)&0x1)<<23) | (((l>>9)&0x1)<<22) |
644 (((l>>10)&0x1)<<21)| (((l>>11)&0x1)<<20)|
645 (((l>>12)&0x1)<<19)| (((l>>13)&0x1)<<18)|
646 (((l>>14)&0x1)<<17)| (((l>>15)&0x1)<<16)|
647 (((l>>16)&0x1)<<15)| (((l>>17)&0x1)<<14)|
648 (((l>>18)&0x1)<<13)| (((l>>19)&0x1)<<12)|
649 (((l>>20)&0x1)<<11)| (((l>>21)&0x1)<<10)|
650 (((l>>22)&0x1)<<9) | (((l>>23)&0x1)<<8) |
651 (((l>>24)&0x1)<<7) | (((l>>25)&0x1)<<6) |
652 (((l>>26)&0x1)<<5) | (((l>>27)&0x1)<<4) |
653 (((l>>28)&0x1)<<3) | (((l>>29)&0x1)<<2) |
654 (((l>>30)&0x1)<<1) | ((l>>31)&0x1);
657 #if 0
658 struct dma_image {
659 unsigned long virt_addr;
660 dma_addr_t dma_addr;
661 size_t size;
664 static struct dma_image d_image;
665 #endif
667 #define FB_WRITEL fb_writel
668 #define FB_READL fb_readl
670 #undef DMA_DEBUG
672 #ifdef CONFIG_SBUS_MGA_HWCOPYAREA
673 static void mgam83fb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
675 struct mgam83fb_par* p = (struct mgam83fb_par*)info->par;
676 unsigned int line_length = info->var.xres_virtual * (info->var.bits_per_pixel >> 3); /* Bytes */
677 unsigned int command = 0;
678 struct fb_copyarea modded;
679 u32 dx = region->dx, dy = region->dy;
680 u32 sx = region->sx, sy = region->sy;
681 int dst_idx = 0, src_idx = 0;
682 u32 spitch = line_length;
683 u32 dpitch = line_length;
684 u32 width = 0;
685 u32 height = 0;
686 u32 vxres, vyres;
688 modded.width = region->width;
689 modded.height = region->height;
691 #ifdef MGA_DEBUG
692 #if 1
693 if (area_count == 10)
694 area_count = 0;
695 last_area[area_count].width = modded.width;
696 last_area[area_count].height = modded.height;
697 last_area[area_count].dx = dx;
698 last_area[area_count].dy = dy;
699 last_area[area_count].sx = sx;
700 last_area[area_count].sy = sy;
701 last_info[area_count] = info;
702 area_count++;
703 #endif
704 #endif
706 if ((info->flags & FBINFO_HWACCEL_DISABLED)) {
707 cfb_copyarea(info, region);
708 return;
711 vxres = info->var.xres_virtual;
712 vyres = info->var.yres_virtual;
714 if(!region->width || !region->height ||
715 sx >= vxres || sy >= vyres ||
716 dx >= vxres || dy >= vyres)
717 return;
719 if(sx + modded.width > vxres) modded.width = vxres - sx;
720 if(dx + modded.width > vxres) modded.width = vxres - dx;
721 if(sy + modded.height > vyres) modded.height = vyres - sy;
722 if(dy + modded.height > vyres) modded.height = vyres - dy;
724 width = ((modded.width)*(info->var.bits_per_pixel >> 3)); /* window lenght in bytes */
725 height = modded.height; /* number of lines */
727 // Waiting for BitBLT is not full
729 while (MMIO_READ(p, BBR0) & PROCESS){
732 /* FIXME: should be investigated */
733 if (info->fbops->fb_sync)
734 info->fbops->fb_sync(info);
736 if (sy < dy){
737 sy = sy + height;
738 dy = dy + height;
740 dst_idx = dy*line_length + dx*(info->var.bits_per_pixel >> 3); /* Bytes */
741 src_idx = sy*line_length + sx*(info->var.bits_per_pixel >> 3); /* Bytes */
742 #ifdef MGA_DEBUG
743 #if 1
744 if (area_count == 10)
745 area_count = 0;
746 last_area[area_count].width = modded.width;
747 last_area[area_count].height = modded.height;
748 last_area[area_count].dx = dx;
749 last_area[area_count].dy = dy;
750 last_area[area_count].sx = sx;
751 last_area[area_count].sy = sy;
752 last_info[area_count] = info;
753 area_count++;
754 #endif
755 #endif
756 MMIO_WRITE(p, BBR1, ((height << 16) | width));
757 MMIO_WRITE(p, BBR2, src_idx);
758 MMIO_WRITE(p, BBR3, dst_idx);
759 MMIO_WRITE(p, BBR4, ((dpitch << 16) | spitch));
761 command |= (ROP_05 | START);
762 if (sy < dy){
763 command |= VDIR;
766 MMIO_WRITE(p, BBR0, command);
768 while ( MMIO_READ(p, BBR0) & PROCESS) {
771 #endif
774 * Driver initialization
777 extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor);
779 static struct fb_ops mgam83fb_ops = {
780 .owner = THIS_MODULE,
782 .fb_check_var = mgam83fb_check_var,
783 .fb_set_par = mgam83fb_set_par,
784 .fb_setcolreg = mgam83fb_setcolreg,
785 .fb_ioctl = mgam83fb_ioctl,
786 .fb_mmap = mgam83fb_mmap,
787 .fb_fillrect = cfb_fillrect, // Generic function
788 #ifdef CONFIG_SBUS_MGA_HWCOPYAREA
789 .fb_copyarea = mgam83fb_copyarea, // HW function
790 #else
791 .fb_copyarea = cfb_copyarea, // Generic function
792 #endif
793 .fb_imageblit = cfb_imageblit,
795 .fb_cursor = soft_cursor
798 static int __fb_init( struct fb_info* info )
800 struct mgam83fb_par* p = (struct mgam83fb_par*)info->par;
801 #if 0
802 int regno = 0;
803 #endif
804 int retval;
806 printk( KERN_INFO "MEM : base 0x%08lx vbase 0x%08lx len 0x%lx\n",
807 (unsigned long)p->mem.base, (unsigned long)p->mem.vbase,
808 (unsigned long)p->mem.len );
809 printk( KERN_INFO "MMIO: base 0x%08lx vbase 0x%08lx len 0x%lx\n",
810 (unsigned long)p->mmio.base, (unsigned long)p->mmio.vbase,
811 (unsigned long)p->mmio.len );
812 printk( KERN_INFO "I2C : base 0x%08lx vbase 0x%08lx len 0x%lx\n",
813 (unsigned long)p->i2c.base, (unsigned long)p->i2c.vbase,
814 (unsigned long)p->i2c.len );
817 * Here we set the screen_base to the virtual memory address
818 * for the framebuffer.
820 info->screen_base = p->mem.vbase; // Framebuffer virtual memory
821 info->fbops = &mgam83fb_ops;
823 strncpy( info->fix.id, "mcst_mga", 8 );
824 info->fix.smem_start = p->mem.base;
825 info->fix.smem_len = p->mem.len;
826 info->fix.type = FB_TYPE_PACKED_PIXELS;
827 info->fix.type_aux = 0;
828 info->fix.xpanstep = 0;
829 info->fix.ypanstep = 0;
830 info->fix.ywrapstep = 0;
831 info->fix.mmio_start = p->mmio.base;
832 info->fix.mmio_len = p->mmio.len;
833 info->fix.accel = 0;
835 info->pseudo_palette = p->pseudo_palette; /* The pseudopalette is an
836 * 16-member array
838 /* Set up flags to indicate what sort of acceleration driver can provide */
840 info->flags = FBINFO_DEFAULT
841 #ifdef CONFIG_SBUS_MGA_HWCOPYAREA
842 | FBINFO_HWACCEL_COPYAREA
843 #endif
846 * This should give a reasonable default video mode. The following is
847 * done when we can set a video mode.
849 if (!mode_option)
850 mode_option = "640x480@60";
851 // mode_option = "1024x768@60";
853 retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
854 if (!retval || retval == 4) {
855 ERROR_MSG( "fb_find_mode() failed\n");
856 return -EINVAL;
858 printk(KERN_INFO "MGA/M-83: default bits_per_pixel: %d\n", info->var.bits_per_pixel);
860 /* úÄÅÓØ ÉÎÉÃÉÁÌÉÚÉÒÕÅÔÓÑ ÓÔÒÕËÔÕÒÁ cmap É ÚÁÐÏÌÎÑÅÔÓÑ Ã×ÅÔÁÍÉ ÐÏ default
861 îÁ ÒÅÇÉÓÔÒÙ ÒÁÓËÌÁÄËÁ ÌÏÖÉÔÓÑ Æ-ÅÊ fb_set_cmap -> fb_setcolreg ÉÌÉ ÐÏ default
862 ÉÌÉ ÐÏÌØÚÏ×ÁÔÅÌØÓËÁÑ ÉÓÐÏÌØÚÕÑ FBIOPUTCMAP */
863 retval = fb_alloc_cmap(&info->cmap, 256, 0);
864 if (retval) {
865 ERROR_MSG( "unable to allocate colormap\n" );
866 return -ENOMEM;
870 * For drivers that can...
872 /* ÚÄÅÓØ ÉÎÉÃÉÁÌÉÚÉÒÕÅÔÓÑ ÍÁÓÓÉ× fb_bitfield ÄÌÑ Ã×ÅÔÏ× */
873 DEBUG_MSG("__fb_init: fb_bitfield initialization\n");
874 if (mgam83fb_check_var(&info->var, info)) {
875 ERROR_MSG( "unable to validate variable\n" );
876 return -EINVAL;
879 if (p->bus_type == BUS_TYPE_SBUS){
880 DEBUG_MSG("mgam83fb: __init_pixclock - only SBUS\n");
881 __sbus_init_pixclock(p->bus_type, (unsigned long)p->i2c.vbase);
883 /* ÚÄÅÓØ ÉÎÉÃÉÁÌÉÚÉÒÕÅÔÓÑ ×ÙÓÏÔÁ, ÛÉÒÉÎÁ, ÒÁÚÒÅÛÅÎÉÅ É Ô.Ä */
884 mgam83fb_set_par(info);
887 if (register_framebuffer(info) < 0) {
888 ERROR_MSG( "register_framebuffer() failed\n" );
889 fb_dealloc_cmap(&info->cmap);
890 return -EINVAL;
892 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id);
893 p->index = next_index++;
894 #ifdef MGA_DEBUG
895 __proc_init( p );
896 #endif
898 return 0;
901 #if defined(CONFIG_SBUS) || defined(CONFIG_PCI2SBUS_MODULE)
902 static int mga_sbus_probe(struct of_device* op, const struct of_device_id *match)
904 struct fb_info* info;
905 struct mgam83fb_par* p;
906 int ret = -EINVAL;
907 unsigned long length = 0;
910 * Dynamically allocate info and par
912 DEBUG_MSG("mgam83fb: sbus driver init\n");
913 info = framebuffer_alloc(sizeof(struct mgam83fb_par), NULL );
914 if (!info) {
915 printk( KERN_ERR "mgam83: failed to allocate fb_info instance!\n");
916 ret = -ENOMEM;
917 goto fail;
919 p = info->par;
920 p->bus_type = BUS_TYPE_SBUS;
921 p->mgaop = op;
922 p->info = info;
923 dev_set_drvdata(&op->dev, p);
924 // Framebuffer memory
925 #ifdef __sparc__
926 p->mem.iospace = op->resource[SBUS_MEM_BAR].flags & IORESOURCE_BITS;
927 #endif
928 p->mem.base = op->resource[SBUS_MEM_BAR].start;
929 p->mem.len = op->resource[SBUS_MEM_BAR].end - op->resource[SBUS_MEM_BAR].start + 1;
930 p->mem.vbase = (uint8_t*)of_ioremap(&op->resource[SBUS_MEM_BAR], 0, p->mem.len, "mga_mem");
931 if (!p->mem.vbase) {
932 ERROR_MSG( "Cannot ioremap MEM (0x%08lx:0x%x)\n", p->mem.base, p->mem.len );
933 ret = -ENOMEM;
934 goto fail_mem_ioremap;
937 // Video card registers
938 p->mmio.base = op->resource[SBUS_MMIO_BAR].start;
939 p->mmio.len = op->resource[SBUS_MMIO_BAR].end - op->resource[SBUS_MMIO_BAR].start + 1;
940 p->mmio.vbase = (uint8_t*)of_ioremap(&op->resource[SBUS_MMIO_BAR], 0, p->mmio.len, "mga_mmio");
941 if ( !p->mmio.vbase )
943 ERROR_MSG( "Cannot ioremap MMIO (0x%08lx:0x%x)\n", p->mmio.base, p->mmio.len );
944 ret = -ENOMEM;
945 goto fail_mmio_ioremap;
948 // I2C bus registers
949 p->i2c.base = op->resource[SBUS_I2C_BAR].start;
950 p->i2c.len = op->resource[SBUS_I2C_BAR].end - op->resource[SBUS_I2C_BAR].start + 1;
951 p->i2c.vbase = (uint8_t*)of_ioremap(&op->resource[SBUS_I2C_BAR], 0, p->i2c.len, "mga_i2c");
952 if ( !p->i2c.vbase )
954 ERROR_MSG("Cannot ioremap I2C (0x%08lx:0x%x)\n", p->i2c.base, p->i2c.len);
955 ret = -ENOMEM;
956 goto fail_i2c_ioremap;
960 // Filling info, selecting mode and initializating framebuffer
961 DEBUG_MSG("mgam83fb: framerbuffer init...\n");
962 if ( (ret = __fb_init( info )) )
963 goto fail_register_fb;
965 printk("SBUS MGA video card %d:%d\n", op->slot, op->portid);
966 return 0;
968 fail_register_fb:
969 length = p->i2c.len;
970 #ifdef CONFIG_SBUS
971 of_iounmap(&op->resource[SBUS_I2C_BAR], p->i2c.vbase, length);
972 #else
973 sbus_iounmap((unsigned long)p->i2c.vbase, length );
974 #endif
975 fail_i2c_ioremap:
976 length = p->mmio.len;
977 #ifdef CONFIG_SBUS
978 of_iounmap(&op->resource[SBUS_MMIO_BAR], p->mmio.vbase, length);
979 #else
980 sbus_iounmap((unsigned long)p->mmio.vbase, length );
981 #endif
982 fail_mmio_ioremap:
983 length = p->mem.len;
984 #ifdef CONFIG_SBUS
985 of_iounmap(&op->resource[SBUS_MEM_BAR], p->mem.vbase, length);
986 #else
987 sbus_iounmap((unsigned long)p->mem.vbase, length );
988 #endif
989 fail_mem_ioremap:
990 framebuffer_release(info);
991 fail:
992 return ret;
996 static int mga_sbus_remove(struct of_device *op)
998 struct mgam83fb_par* p = dev_get_drvdata(&op->dev);
999 struct fb_info* info = p->info;
1000 /* or dev_get_drv_data(device); */
1001 unsigned long length = 0;
1003 if (p->video_buf.ioaddr) {
1004 struct page *map, *mapend;
1005 dma_unmap_single(&p->mgaop->dev, p->video_buf.ioaddr,
1006 p->video_buf.size, DMA_BIDIRECTIONAL);
1007 mapend = virt_to_page(p->video_buf.kvaddr + p->video_buf.size -1);
1008 for (map = virt_to_page(p->video_buf.kvaddr); map <= mapend; map++) {
1009 ClearPageReserved(map);
1011 free_pages(p->video_buf.kvaddr, get_order(p->video_buf.size));
1012 p->video_buf.ioaddr = 0;
1013 p->video_buf.kvaddr = 0;
1014 p->video_buf.size = 0;
1017 if (info) {
1018 // Turn of display
1019 MMIO_WRITE(p, REG_CTRL, MMIO_READ( p, REG_CTRL) & ~CTRL_VEN);
1021 unregister_framebuffer(info);
1022 fb_dealloc_cmap(&info->cmap);
1023 length = p->i2c.len;
1024 #ifdef CONFIG_SBUS
1025 of_iounmap(&op->resource[SBUS_I2C_BAR], p->i2c.vbase, length);
1026 #else
1027 sbus_iounmap((unsigned long)p->i2c.vbase, length );
1028 #endif
1029 length = p->mmio.len;
1030 #ifdef CONFIG_SBUS
1031 of_iounmap(&op->resource[SBUS_MMIO_BAR], p->mmio.vbase, length);
1032 #else
1033 sbus_iounmap((unsigned long)p->mmio.vbase, length);
1034 #endif
1035 length = p->mem.len;
1036 #ifdef CONFIG_SBUS
1037 of_iounmap(&op->resource[SBUS_MEM_BAR], p->mem.vbase, length);
1038 #else
1039 sbus_iounmap((unsigned long)p->mem.vbase, length);
1040 #endif
1041 framebuffer_release(info);
1043 return 0;
1045 #endif
1050 static const struct of_device_id mgam_sbus_match[] = {
1052 .name = "mgam",
1055 .name = "mga",
1058 .name = " MGA/M",
1063 MODULE_DEVICE_TABLE(of, mgam_sbus_match);
1065 static struct of_platform_driver mga_sbus_driver = {
1066 .name = "mgam83fb",
1067 .match_table = mgam_sbus_match,
1068 .probe = mga_sbus_probe,
1069 .remove = mga_sbus_remove,
1075 ////////////////////////////////////////////////////////////////////////////////
1076 // Modularization
1077 ////////////////////////////////////////////////////////////////////////////////
1078 static int __init mga_sbus_init(void)
1080 printk("SBUS MGA video card driver loaded\n");
1081 #ifndef MODULE
1082 char *option = NULL;
1083 if (fb_get_options("mgam83fb", &option)) {
1084 return -ENODEV;
1086 mode_option = option;
1087 #endif
1088 return of_register_driver(&mga_sbus_driver, &of_bus_type);
1091 static void __exit mga_sbus_exit(void)
1093 of_unregister_driver(&mga_sbus_driver);
1096 module_init(mga_sbus_init);
1097 module_exit(mga_sbus_exit);
1099 MODULE_LICENSE("GPL");