1 /***************************************************************************
2 * Silicon Motion VoyagerGX framebuffer driver
4 * ported to 2.6 by Embedded Alley Solutions, Inc
5 * Copyright (C) 2005 Embedded Alley Solutions, Inc
8 copyright : (C) 2001 by Szu-Tao Huang
9 email : johuang@siliconmotion.com
10 Updated to SM501 by Eric.Devolder@amd.com and dan@embeddededge.com
11 for the AMD Mirage Portable Tablet. 20 Oct 2003
12 ***************************************************************************/
14 /***************************************************************************
16 * This program is free software; you can redistribute it and/or modify *
17 * it under the terms of the GNU General Public License as published by *
18 * the Free Software Foundation; either version 2 of the License, or *
19 * (at your option) any later version. *
21 ***************************************************************************/
23 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/errno.h>
26 #include <linux/string.h>
28 #include <linux/tty.h>
29 #include <linux/slab.h>
30 #include <linux/delay.h>
32 #include <linux/pci.h>
33 #include <linux/init.h>
37 #include <asm/pgtable.h>
38 #include <asm/system.h>
39 #include <asm/uaccess.h>
41 static char __iomem
*SMIRegs
; // point to virtual Memory Map IO starting address
42 static char __iomem
*SMILFB
; // point to virtual video memory starting address
44 static struct fb_fix_screeninfo smifb_fix __devinitdata
= {
46 .type
= FB_TYPE_PACKED_PIXELS
,
47 .visual
= FB_VISUAL_TRUECOLOR
,
49 .line_length
= 1024 * 2, /* (bbp * xres)/8 */
50 .accel
= FB_ACCEL_NONE
,
53 static struct fb_var_screeninfo smifb_var __devinitdata
= {
62 .activate
= FB_ACTIVATE_NOW
,
65 .vmode
= FB_VMODE_NONINTERLACED
,
69 static struct fb_info info
;
71 #define smi_mmiowb(dat,reg) writeb(dat, (SMIRegs + reg))
72 #define smi_mmioww(dat,reg) writew(dat, (SMIRegs + reg))
73 #define smi_mmiowl(dat,reg) writel(dat, (SMIRegs + reg))
75 #define smi_mmiorb(reg) readb(SMIRegs + reg)
76 #define smi_mmiorw(reg) readw(SMIRegs + reg)
77 #define smi_mmiorl(reg) readl(SMIRegs + reg)
79 /* Address space offsets for various control/status registers.
81 #define MISC_CTRL 0x000004
82 #define GPIO_LO_CTRL 0x000008
83 #define GPIO_HI_CTRL 0x00000c
84 #define DRAM_CTRL 0x000010
85 #define CURRENT_POWER_GATE 0x000038
86 #define CURRENT_POWER_CLOCK 0x00003C
87 #define POWER_MODE1_GATE 0x000048
88 #define POWER_MODE1_CLOCK 0x00004C
89 #define POWER_MODE_CTRL 0x000054
91 #define GPIO_DATA_LO 0x010000
92 #define GPIO_DATA_HI 0x010004
93 #define GPIO_DATA_DIR_LO 0x010008
94 #define GPIO_DATA_DIR_HI 0x01000c
95 #define I2C_BYTE_COUNT 0x010040
96 #define I2C_CONTROL 0x010041
97 #define I2C_STATUS_RESET 0x010042
98 #define I2C_SLAVE_ADDRESS 0x010043
99 #define I2C_DATA 0x010044
101 #define DE_COLOR_COMPARE 0x100020
102 #define DE_COLOR_COMPARE_MASK 0x100024
103 #define DE_MASKS 0x100028
104 #define DE_WRAP 0x10004C
106 #define PANEL_DISPLAY_CTRL 0x080000
107 #define PANEL_PAN_CTRL 0x080004
108 #define PANEL_COLOR_KEY 0x080008
109 #define PANEL_FB_ADDRESS 0x08000C
110 #define PANEL_FB_WIDTH 0x080010
111 #define PANEL_WINDOW_WIDTH 0x080014
112 #define PANEL_WINDOW_HEIGHT 0x080018
113 #define PANEL_PLANE_TL 0x08001C
114 #define PANEL_PLANE_BR 0x080020
115 #define PANEL_HORIZONTAL_TOTAL 0x080024
116 #define PANEL_HORIZONTAL_SYNC 0x080028
117 #define PANEL_VERTICAL_TOTAL 0x08002C
118 #define PANEL_VERTICAL_SYNC 0x080030
119 #define PANEL_CURRENT_LINE 0x080034
120 #define VIDEO_DISPLAY_CTRL 0x080040
121 #define VIDEO_DISPLAY_FB0 0x080044
122 #define VIDEO_DISPLAY_FBWIDTH 0x080048
123 #define VIDEO_DISPLAY_FB0LAST 0x08004C
124 #define VIDEO_DISPLAY_TL 0x080050
125 #define VIDEO_DISPLAY_BR 0x080054
126 #define VIDEO_SCALE 0x080058
127 #define VIDEO_INITIAL_SCALE 0x08005C
128 #define VIDEO_YUV_CONSTANTS 0x080060
129 #define VIDEO_DISPLAY_FB1 0x080064
130 #define VIDEO_DISPLAY_FB1LAST 0x080068
131 #define VIDEO_ALPHA_CTRL 0x080080
132 #define PANEL_HWC_ADDRESS 0x0800F0
133 #define CRT_DISPLAY_CTRL 0x080200
134 #define CRT_FB_ADDRESS 0x080204
135 #define CRT_FB_WIDTH 0x080208
136 #define CRT_HORIZONTAL_TOTAL 0x08020c
137 #define CRT_HORIZONTAL_SYNC 0x080210
138 #define CRT_VERTICAL_TOTAL 0x080214
139 #define CRT_VERTICAL_SYNC 0x080218
140 #define CRT_HWC_ADDRESS 0x080230
141 #define CRT_HWC_LOCATION 0x080234
143 #define ZV_CAPTURE_CTRL 0x090000
144 #define ZV_CAPTURE_CLIP 0x090004
145 #define ZV_CAPTURE_SIZE 0x090008
146 #define ZV_CAPTURE_BUF0 0x09000c
147 #define ZV_CAPTURE_BUF1 0x090010
148 #define ZV_CAPTURE_OFFSET 0x090014
149 #define ZV_FIFO_CTRL 0x090018
151 #define waitforvsync() udelay(400)
153 static int initdone
= 0;
154 static int crt_out
= 1;
158 smi_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
159 unsigned blue
, unsigned transp
,
160 struct fb_info
*info
)
165 ((u32
*)(info
->pseudo_palette
))[regno
] =
166 ((red
& 0xf800) >> 0) |
167 ((green
& 0xfc00) >> 5) |
168 ((blue
& 0xf800) >> 11);
173 /* This function still needs lots of work to generically support
174 * different output devices (CRT or LCD) and resolutions.
175 * Currently hard-coded for 1024x768 LCD panel.
177 static void smi_setmode(void)
184 /* Just blast in some control values based upon the chip
185 * documentation. We use the internal memory, I don't know
186 * how to determine the amount available yet.
188 smi_mmiowl(0x07F127C2, DRAM_CTRL
);
189 smi_mmiowl(0x02000020, PANEL_HWC_ADDRESS
);
190 smi_mmiowl(0x007FF800, PANEL_HWC_ADDRESS
);
191 smi_mmiowl(0x00021827, POWER_MODE1_GATE
);
192 smi_mmiowl(0x011A0A09, POWER_MODE1_CLOCK
);
193 smi_mmiowl(0x00000001, POWER_MODE_CTRL
);
194 smi_mmiowl(0x80000000, PANEL_FB_ADDRESS
);
195 smi_mmiowl(0x08000800, PANEL_FB_WIDTH
);
196 smi_mmiowl(0x04000000, PANEL_WINDOW_WIDTH
);
197 smi_mmiowl(0x03000000, PANEL_WINDOW_HEIGHT
);
198 smi_mmiowl(0x00000000, PANEL_PLANE_TL
);
199 smi_mmiowl(0x02FF03FF, PANEL_PLANE_BR
);
200 smi_mmiowl(0x05D003FF, PANEL_HORIZONTAL_TOTAL
);
201 smi_mmiowl(0x00C80424, PANEL_HORIZONTAL_SYNC
);
202 smi_mmiowl(0x032502FF, PANEL_VERTICAL_TOTAL
);
203 smi_mmiowl(0x00060302, PANEL_VERTICAL_SYNC
);
204 smi_mmiowl(0x00013905, PANEL_DISPLAY_CTRL
);
205 smi_mmiowl(0x01013105, PANEL_DISPLAY_CTRL
);
207 smi_mmiowl(0x03013905, PANEL_DISPLAY_CTRL
);
209 smi_mmiowl(0x07013905, PANEL_DISPLAY_CTRL
);
211 smi_mmiowl(0x0F013905, PANEL_DISPLAY_CTRL
);
212 smi_mmiowl(0x0002187F, POWER_MODE1_GATE
);
213 smi_mmiowl(0x01011801, POWER_MODE1_CLOCK
);
214 smi_mmiowl(0x00000001, POWER_MODE_CTRL
);
216 smi_mmiowl(0x80000000, PANEL_FB_ADDRESS
);
217 smi_mmiowl(0x00000000, PANEL_PAN_CTRL
);
218 smi_mmiowl(0x00000000, PANEL_COLOR_KEY
);
221 /* Just sent the panel out to the CRT for now.
223 smi_mmiowl(0x80000000, CRT_FB_ADDRESS
);
224 smi_mmiowl(0x08000800, CRT_FB_WIDTH
);
225 smi_mmiowl(0x05D003FF, CRT_HORIZONTAL_TOTAL
);
226 smi_mmiowl(0x00C80424, CRT_HORIZONTAL_SYNC
);
227 smi_mmiowl(0x032502FF, CRT_VERTICAL_TOTAL
);
228 smi_mmiowl(0x00060302, CRT_VERTICAL_SYNC
);
229 smi_mmiowl(0x007FF800, CRT_HWC_ADDRESS
);
230 smi_mmiowl(0x00010305, CRT_DISPLAY_CTRL
);
231 smi_mmiowl(0x00000001, MISC_CTRL
);
236 * Unmap in the memory mapped IO registers
240 static void __devinit
smi_unmap_mmio(void)
250 * Unmap in the screen memory
253 static void __devinit
smi_unmap_smem(void)
261 static void vgxfb_setup(char *options
)
264 if (!options
|| !*options
)
267 /* The only thing I'm looking for right now is to disable a
268 * CRT output that mirrors the panel display.
270 if (strcmp(options
, "no_crt") == 0)
276 static struct fb_ops smifb_ops
= {
277 .owner
= THIS_MODULE
,
278 .fb_setcolreg
= smi_setcolreg
,
279 .fb_fillrect
= cfb_fillrect
,
280 .fb_copyarea
= cfb_copyarea
,
281 .fb_imageblit
= cfb_imageblit
,
284 static int __devinit
vgx_pci_probe(struct pci_dev
*dev
, const struct pci_device_id
*id
)
290 err
= pci_enable_device(dev
);
295 /* Set up MMIO space.
297 smifb_fix
.mmio_start
= pci_resource_start(dev
,1);
298 smifb_fix
.mmio_len
= 0x00200000;
299 SMIRegs
= ioremap(smifb_fix
.mmio_start
, smifb_fix
.mmio_len
);
301 /* Set up framebuffer. It's a 64M space, various amount of
302 * internal memory. I don't know how to determine the real
303 * amount of memory (yet).
305 smifb_fix
.smem_start
= pci_resource_start(dev
,0);
306 smifb_fix
.smem_len
= 0x00800000;
307 SMILFB
= ioremap(smifb_fix
.smem_start
, smifb_fix
.smem_len
);
309 memset_io(SMILFB
, 0, smifb_fix
.smem_len
);
311 info
.screen_base
= SMILFB
;
312 info
.fbops
= &smifb_ops
;
313 info
.fix
= smifb_fix
;
315 info
.flags
= FBINFO_FLAG_DEFAULT
;
317 info
.pseudo_palette
= kmalloc(sizeof(u32
) * 16, GFP_KERNEL
);
318 if (!info
.pseudo_palette
) {
321 memset(info
.pseudo_palette
, 0, sizeof(u32
) *16);
323 fb_alloc_cmap(&info
.cmap
,256,0);
327 info
.var
= smifb_var
;
329 if (register_framebuffer(&info
) < 0)
341 static void __devexit
vgx_pci_remove(struct pci_dev
*dev
)
343 unregister_framebuffer(&info
);
348 static struct pci_device_id vgx_devices
[] = {
349 {PCI_VENDOR_ID_SILICON_MOTION
, PCI_DEVICE_ID_SM501_VOYAGER_GX_REV_AA
,
350 PCI_ANY_ID
, PCI_ANY_ID
},
351 {PCI_VENDOR_ID_SILICON_MOTION
, PCI_DEVICE_ID_SM501_VOYAGER_GX_REV_B
,
352 PCI_ANY_ID
, PCI_ANY_ID
},
356 MODULE_DEVICE_TABLE(pci
, vgx_devices
);
358 static struct pci_driver vgxfb_pci_driver
= {
360 .id_table
= vgx_devices
,
361 .probe
= vgx_pci_probe
,
362 .remove
= __devexit_p(vgx_pci_remove
),
365 static int __init
vgxfb_init(void)
369 if (fb_get_options("vgxfb", &option
))
373 printk("Silicon Motion Inc. VOYAGER Init complete.\n");
374 return pci_module_init(&vgxfb_pci_driver
);
377 static void __exit
vgxfb_exit(void)
379 pci_unregister_driver(&vgxfb_pci_driver
);
382 module_init(vgxfb_init
);
383 module_exit(vgxfb_exit
);
386 MODULE_DESCRIPTION("Framebuffer driver for SMI Voyager");
387 MODULE_LICENSE("GPL");