aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/vermilion
diff options
context:
space:
mode:
authorAlan Hourihane <alanh@fairlite.demon.co.uk>2007-05-08 03:39:25 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-08 14:15:32 -0400
commitdbe7e429fedb3fbc93b496cc1c3eb4fc28333ac0 (patch)
tree9f88a999af677f65beb7041604c3a5d63bfc58db /drivers/video/vermilion
parent249bdbbf0dbab5554a4bfe55639e324d4758da96 (diff)
vmlfb: framebuffer driver for Intel Vermilion Range
Add the Intel Vermilion Range framebuffer support. Signed-off-by: Alan Hourihane <alanh@tungstengraphics.com> Signed-off-by: Antonino Daplas <adaplas@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/vermilion')
-rw-r--r--drivers/video/vermilion/Makefile5
-rw-r--r--drivers/video/vermilion/cr_pll.c208
-rw-r--r--drivers/video/vermilion/vermilion.c1195
-rw-r--r--drivers/video/vermilion/vermilion.h260
4 files changed, 1668 insertions, 0 deletions
diff --git a/drivers/video/vermilion/Makefile b/drivers/video/vermilion/Makefile
new file mode 100644
index 000000000000..cc21a656153d
--- /dev/null
+++ b/drivers/video/vermilion/Makefile
@@ -0,0 +1,5 @@
1obj-$(CONFIG_FB_LE80578) += vmlfb.o
2obj-$(CONFIG_FB_CARILLO_RANCH) += crvml.o
3
4vmlfb-objs := vermilion.o
5crvml-objs := cr_pll.o
diff --git a/drivers/video/vermilion/cr_pll.c b/drivers/video/vermilion/cr_pll.c
new file mode 100644
index 000000000000..ebc6e6e0dd0f
--- /dev/null
+++ b/drivers/video/vermilion/cr_pll.c
@@ -0,0 +1,208 @@
1/*
2 * Copyright (c) Intel Corp. 2007.
3 * All Rights Reserved.
4 *
5 * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
6 * develop this driver.
7 *
8 * This file is part of the Carillo Ranch video subsystem driver.
9 * The Carillo Ranch video subsystem driver is free software;
10 * you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * The Carillo Ranch video subsystem driver is distributed
16 * in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this driver; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 *
25 * Authors:
26 * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
27 * Alan Hourihane <alanh-at-tungstengraphics-dot-com>
28 */
29
30#include <linux/module.h>
31#include <linux/kernel.h>
32#include <linux/pci.h>
33#include <linux/errno.h>
34#include <linux/fb.h>
35#include "vermilion.h"
36
37/* The PLL Clock register sits on Host bridge */
38#define CRVML_DEVICE_MCH 0x5001
39#define CRVML_REG_MCHBAR 0x44
40#define CRVML_REG_MCHEN 0x54
41#define CRVML_MCHEN_BIT (1 << 28)
42#define CRVML_MCHMAP_SIZE 4096
43#define CRVML_REG_CLOCK 0xc3c
44#define CRVML_CLOCK_SHIFT 8
45#define CRVML_CLOCK_MASK 0x00000f00
46
47static struct pci_dev *mch_dev;
48static u32 mch_bar;
49static void __iomem *mch_regs_base;
50static u32 saved_clock;
51
52static const unsigned crvml_clocks[] = {
53 6750,
54 13500,
55 27000,
56 29700,
57 37125,
58 54000,
59 59400,
60 74250,
61 120000
62 /*
63 * There are more clocks, but they are disabled on the CR board.
64 */
65};
66
67static const u32 crvml_clock_bits[] = {
68 0x0a,
69 0x09,
70 0x08,
71 0x07,
72 0x06,
73 0x05,
74 0x04,
75 0x03,
76 0x0b
77};
78
79static const unsigned crvml_num_clocks = ARRAY_SIZE(crvml_clocks);
80
81static int crvml_sys_restore(struct vml_sys *sys)
82{
83 void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
84
85 iowrite32(saved_clock, clock_reg);
86 ioread32(clock_reg);
87
88 return 0;
89}
90
91static int crvml_sys_save(struct vml_sys *sys)
92{
93 void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
94
95 saved_clock = ioread32(clock_reg);
96
97 return 0;
98}
99
100static int crvml_nearest_index(const struct vml_sys *sys, int clock)
101{
102 int i;
103 int cur_index = 0;
104 int cur_diff;
105 int diff;
106
107 cur_diff = clock - crvml_clocks[0];
108 cur_diff = (cur_diff < 0) ? -cur_diff : cur_diff;
109 for (i = 1; i < crvml_num_clocks; ++i) {
110 diff = clock - crvml_clocks[i];
111 diff = (diff < 0) ? -diff : diff;
112 if (diff < cur_diff) {
113 cur_index = i;
114 cur_diff = diff;
115 }
116 }
117 return cur_index;
118}
119
120static int crvml_nearest_clock(const struct vml_sys *sys, int clock)
121{
122 return crvml_clocks[crvml_nearest_index(sys, clock)];
123}
124
125static int crvml_set_clock(struct vml_sys *sys, int clock)
126{
127 void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
128 int index;
129 u32 clock_val;
130
131 index = crvml_nearest_index(sys, clock);
132
133 if (crvml_clocks[index] != clock)
134 return -EINVAL;
135
136 clock_val = ioread32(clock_reg) & ~CRVML_CLOCK_MASK;
137 clock_val = crvml_clock_bits[index] << CRVML_CLOCK_SHIFT;
138 iowrite32(clock_val, clock_reg);
139 ioread32(clock_reg);
140
141 return 0;
142}
143
144static struct vml_sys cr_pll_ops = {
145 .name = "Carillo Ranch",
146 .save = crvml_sys_save,
147 .restore = crvml_sys_restore,
148 .set_clock = crvml_set_clock,
149 .nearest_clock = crvml_nearest_clock,
150};
151
152static int __init cr_pll_init(void)
153{
154 int err;
155 u32 dev_en;
156
157 mch_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
158 CRVML_DEVICE_MCH, NULL);
159 if (!mch_dev) {
160 printk(KERN_ERR
161 "Could not find Carillo Ranch MCH device.\n");
162 return -ENODEV;
163 }
164
165 pci_read_config_dword(mch_dev, CRVML_REG_MCHEN, &dev_en);
166 if (!(dev_en & CRVML_MCHEN_BIT)) {
167 printk(KERN_ERR
168 "Carillo Ranch MCH device was not enabled.\n");
169 pci_dev_put(mch_dev);
170 return -ENODEV;
171 }
172
173 pci_read_config_dword(mch_dev, CRVML_REG_MCHBAR,
174 &mch_bar);
175 mch_regs_base =
176 ioremap_nocache(mch_bar, CRVML_MCHMAP_SIZE);
177 if (!mch_regs_base) {
178 printk(KERN_ERR
179 "Carillo Ranch MCH device was not enabled.\n");
180 pci_dev_put(mch_dev);
181 return -ENODEV;
182 }
183
184 err = vmlfb_register_subsys(&cr_pll_ops);
185 if (err) {
186 printk(KERN_ERR
187 "Carillo Ranch failed to initialize vml_sys.\n");
188 pci_dev_put(mch_dev);
189 return err;
190 }
191
192 return 0;
193}
194
195static void __exit cr_pll_exit(void)
196{
197 vmlfb_unregister_subsys(&cr_pll_ops);
198
199 iounmap(mch_regs_base);
200 pci_dev_put(mch_dev);
201}
202
203module_init(cr_pll_init);
204module_exit(cr_pll_exit);
205
206MODULE_AUTHOR("Tungsten Graphics Inc.");
207MODULE_DESCRIPTION("Carillo Ranch PLL Driver");
208MODULE_LICENSE("GPL");
diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c
new file mode 100644
index 000000000000..de531c907718
--- /dev/null
+++ b/drivers/video/vermilion/vermilion.c
@@ -0,0 +1,1195 @@
1/*
2 * Copyright (c) Intel Corp. 2007.
3 * All Rights Reserved.
4 *
5 * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
6 * develop this driver.
7 *
8 * This file is part of the Vermilion Range fb driver.
9 * The Vermilion Range fb driver is free software;
10 * you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * The Vermilion Range fb driver is distributed
16 * in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this driver; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 *
25 * Authors:
26 * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
27 * Michel Dänzer <michel-at-tungstengraphics-dot-com>
28 * Alan Hourihane <alanh-at-tungstengraphics-dot-com>
29 */
30
31#include <linux/module.h>
32#include <linux/kernel.h>
33#include <linux/errno.h>
34#include <linux/string.h>
35#include <linux/delay.h>
36#include <linux/mm.h>
37#include <linux/fb.h>
38#include <linux/pci.h>
39#include <asm/cacheflush.h>
40#include <asm/tlbflush.h>
41#include <linux/mmzone.h>
42#include <asm/uaccess.h>
43
44/* #define VERMILION_DEBUG */
45
46#include "vermilion.h"
47
48#define MODULE_NAME "vmlfb"
49
50#define VML_TOHW(_val, _width) ((((_val) << (_width)) + 0x7FFF - (_val)) >> 16)
51
52static struct mutex vml_mutex;
53static struct list_head global_no_mode;
54static struct list_head global_has_mode;
55static struct fb_ops vmlfb_ops;
56static struct vml_sys *subsys = NULL;
57static char *vml_default_mode = "1024x768@60";
58static struct fb_videomode defaultmode = {
59 NULL, 60, 1024, 768, 12896, 144, 24, 29, 3, 136, 6,
60 0, FB_VMODE_NONINTERLACED
61};
62
63static u32 vml_mem_requested = (10 * 1024 * 1024);
64static u32 vml_mem_contig = (4 * 1024 * 1024);
65static u32 vml_mem_min = (4 * 1024 * 1024);
66
67static u32 vml_clocks[] = {
68 6750,
69 13500,
70 27000,
71 29700,
72 37125,
73 54000,
74 59400,
75 74250,
76 120000,
77 148500
78};
79
80static u32 vml_num_clocks = ARRAY_SIZE(vml_clocks);
81
82/*
83 * Allocate a contiguous vram area and make its linear kernel map
84 * uncached.
85 */
86
87static int vmlfb_alloc_vram_area(struct vram_area *va, unsigned max_order,
88 unsigned min_order)
89{
90 gfp_t flags;
91 unsigned long i;
92 pgprot_t wc_pageprot;
93
94 wc_pageprot = PAGE_KERNEL_NOCACHE;
95 max_order++;
96 do {
97 /*
98 * Really try hard to get the needed memory.
99 * We need memory below the first 32MB, so we
100 * add the __GFP_DMA flag that guarantees that we are
101 * below the first 16MB.
102 */
103
104 flags = __GFP_DMA | __GFP_HIGH;
105 va->logical =
106 __get_free_pages(flags, --max_order);
107 } while (va->logical == 0 && max_order > min_order);
108
109 if (!va->logical)
110 return -ENOMEM;
111
112 va->phys = virt_to_phys((void *)va->logical);
113 va->size = PAGE_SIZE << max_order;
114 va->order = max_order;
115
116 /*
117 * It seems like __get_free_pages only ups the usage count
118 * of the first page. This doesn't work with nopage mapping, so
119 * up the usage count once more.
120 */
121
122 memset((void *)va->logical, 0x00, va->size);
123 for (i = va->logical; i < va->logical + va->size; i += PAGE_SIZE) {
124 get_page(virt_to_page(i));
125 }
126
127 /*
128 * Change caching policy of the linear kernel map to avoid
129 * mapping type conflicts with user-space mappings.
130 * The first global_flush_tlb() is really only there to do a global
131 * wbinvd().
132 */
133
134 global_flush_tlb();
135 change_page_attr(virt_to_page(va->logical), va->size >> PAGE_SHIFT,
136 wc_pageprot);
137 global_flush_tlb();
138
139 printk(KERN_DEBUG MODULE_NAME
140 ": Allocated %ld bytes vram area at 0x%08lx\n",
141 va->size, va->phys);
142
143 return 0;
144}
145
146/*
147 * Free a contiguous vram area and reset its linear kernel map
148 * mapping type.
149 */
150
151static void vmlfb_free_vram_area(struct vram_area *va)
152{
153 unsigned long j;
154
155 if (va->logical) {
156
157 /*
158 * Reset the linear kernel map caching policy.
159 */
160
161 change_page_attr(virt_to_page(va->logical),
162 va->size >> PAGE_SHIFT, PAGE_KERNEL);
163 global_flush_tlb();
164
165 /*
166 * Decrease the usage count on the pages we've used
167 * to compensate for upping when allocating.
168 */
169
170 for (j = va->logical; j < va->logical + va->size;
171 j += PAGE_SIZE) {
172 (void)put_page_testzero(virt_to_page(j));
173 }
174
175 printk(KERN_DEBUG MODULE_NAME
176 ": Freeing %ld bytes vram area at 0x%08lx\n",
177 va->size, va->phys);
178 free_pages(va->logical, va->order);
179
180 va->logical = 0;
181 }
182}
183
184/*
185 * Free allocated vram.
186 */
187
188static void vmlfb_free_vram(struct vml_info *vinfo)
189{
190 int i;
191
192 for (i = 0; i < vinfo->num_areas; ++i) {
193 vmlfb_free_vram_area(&vinfo->vram[i]);
194 }
195 vinfo->num_areas = 0;
196}
197
198/*
199 * Allocate vram. Currently we try to allocate contiguous areas from the
200 * __GFP_DMA zone and puzzle them together. A better approach would be to
201 * allocate one contiguous area for scanout and use one-page allocations for
202 * offscreen areas. This requires user-space and GPU virtual mappings.
203 */
204
205static int vmlfb_alloc_vram(struct vml_info *vinfo,
206 size_t requested,
207 size_t min_total, size_t min_contig)
208{
209 int i, j;
210 int order;
211 int contiguous;
212 int err;
213 struct vram_area *va;
214 struct vram_area *va2;
215
216 vinfo->num_areas = 0;
217 for (i = 0; i < VML_VRAM_AREAS; ++i) {
218 va = &vinfo->vram[i];
219 order = 0;
220
221 while (requested > (PAGE_SIZE << order) && order < MAX_ORDER)
222 order++;
223
224 err = vmlfb_alloc_vram_area(va, order, 0);
225
226 if (err)
227 break;
228
229 if (i == 0) {
230 vinfo->vram_start = va->phys;
231 vinfo->vram_logical = (void __iomem *) va->logical;
232 vinfo->vram_contig_size = va->size;
233 vinfo->num_areas = 1;
234 } else {
235 contiguous = 0;
236
237 for (j = 0; j < i; ++j) {
238 va2 = &vinfo->vram[j];
239 if (va->phys + va->size == va2->phys ||
240 va2->phys + va2->size == va->phys) {
241 contiguous = 1;
242 break;
243 }
244 }
245
246 if (contiguous) {
247 vinfo->num_areas++;
248 if (va->phys < vinfo->vram_start) {
249 vinfo->vram_start = va->phys;
250 vinfo->vram_logical =
251 (void __iomem *)va->logical;
252 }
253 vinfo->vram_contig_size += va->size;
254 } else {
255 vmlfb_free_vram_area(va);
256 break;
257 }
258 }
259
260 if (requested < va->size)
261 break;
262 else
263 requested -= va->size;
264 }
265
266 if (vinfo->vram_contig_size > min_total &&
267 vinfo->vram_contig_size > min_contig) {
268
269 printk(KERN_DEBUG MODULE_NAME
270 ": Contiguous vram: %ld bytes at physical 0x%08lx.\n",
271 (unsigned long)vinfo->vram_contig_size,
272 (unsigned long)vinfo->vram_start);
273
274 return 0;
275 }
276
277 printk(KERN_ERR MODULE_NAME
278 ": Could not allocate requested minimal amount of vram.\n");
279
280 vmlfb_free_vram(vinfo);
281
282 return -ENOMEM;
283}
284
285/*
286 * Find the GPU to use with our display controller.
287 */
288
289static int vmlfb_get_gpu(struct vml_par *par)
290{
291 mutex_lock(&vml_mutex);
292
293 par->gpu = pci_get_device(PCI_VENDOR_ID_INTEL, VML_DEVICE_GPU, NULL);
294
295 if (!par->gpu) {
296 mutex_unlock(&vml_mutex);
297 return -ENODEV;
298 }
299
300 mutex_unlock(&vml_mutex);
301
302 if (pci_enable_device(par->gpu) < 0)
303 return -ENODEV;
304
305 return 0;
306}
307
308/*
309 * Find a contiguous vram area that contains a given offset from vram start.
310 */
311static int vmlfb_vram_offset(struct vml_info *vinfo, unsigned long offset)
312{
313 unsigned long aoffset;
314 unsigned i;
315
316 for (i = 0; i < vinfo->num_areas; ++i) {
317 aoffset = offset - (vinfo->vram[i].phys - vinfo->vram_start);
318
319 if (aoffset < vinfo->vram[i].size) {
320 return 0;
321 }
322 }
323
324 return -EINVAL;
325}
326
327/*
328 * Remap the MMIO register spaces of the VDC and the GPU.
329 */
330
331static int vmlfb_enable_mmio(struct vml_par *par)
332{
333 int err;
334
335 par->vdc_mem_base = pci_resource_start(par->vdc, 0);
336 par->vdc_mem_size = pci_resource_len(par->vdc, 0);
337 if (!request_mem_region(par->vdc_mem_base, par->vdc_mem_size, "vmlfb")) {
338 printk(KERN_ERR MODULE_NAME
339 ": Could not claim display controller MMIO.\n");
340 return -EBUSY;
341 }
342 par->vdc_mem = ioremap_nocache(par->vdc_mem_base, par->vdc_mem_size);
343 if (par->vdc_mem == NULL) {
344 printk(KERN_ERR MODULE_NAME
345 ": Could not map display controller MMIO.\n");
346 err = -ENOMEM;
347 goto out_err_0;
348 }
349
350 par->gpu_mem_base = pci_resource_start(par->gpu, 0);
351 par->gpu_mem_size = pci_resource_len(par->gpu, 0);
352 if (!request_mem_region(par->gpu_mem_base, par->gpu_mem_size, "vmlfb")) {
353 printk(KERN_ERR MODULE_NAME ": Could not claim GPU MMIO.\n");
354 err = -EBUSY;
355 goto out_err_1;
356 }
357 par->gpu_mem = ioremap_nocache(par->gpu_mem_base, par->gpu_mem_size);
358 if (par->gpu_mem == NULL) {
359 printk(KERN_ERR MODULE_NAME ": Could not map GPU MMIO.\n");
360 err = -ENOMEM;
361 goto out_err_2;
362 }
363
364 return 0;
365
366out_err_2:
367 release_mem_region(par->gpu_mem_base, par->gpu_mem_size);
368out_err_1:
369 iounmap(par->vdc_mem);
370out_err_0:
371 release_mem_region(par->vdc_mem_base, par->vdc_mem_size);
372 return err;
373}
374
375/*
376 * Unmap the VDC and GPU register spaces.
377 */
378
379static void vmlfb_disable_mmio(struct vml_par *par)
380{
381 iounmap(par->gpu_mem);
382 release_mem_region(par->gpu_mem_base, par->gpu_mem_size);
383 iounmap(par->vdc_mem);
384 release_mem_region(par->vdc_mem_base, par->vdc_mem_size);
385}
386
387/*
388 * Release and uninit the VDC and GPU.
389 */
390
391static void vmlfb_release_devices(struct vml_par *par)
392{
393 if (atomic_dec_and_test(&par->refcount)) {
394 pci_set_drvdata(par->vdc, NULL);
395 pci_disable_device(par->gpu);
396 pci_disable_device(par->vdc);
397 }
398}
399
400/*
401 * Free up allocated resources for a device.
402 */
403
404static void __devexit vml_pci_remove(struct pci_dev *dev)
405{
406 struct fb_info *info;
407 struct vml_info *vinfo;
408 struct vml_par *par;
409
410 info = pci_get_drvdata(dev);
411 if (info) {
412 vinfo = container_of(info, struct vml_info, info);
413 par = vinfo->par;
414 mutex_lock(&vml_mutex);
415 unregister_framebuffer(info);
416 fb_dealloc_cmap(&info->cmap);
417 vmlfb_free_vram(vinfo);
418 vmlfb_disable_mmio(par);
419 vmlfb_release_devices(par);
420 kfree(vinfo);
421 kfree(par);
422 mutex_unlock(&vml_mutex);
423 }
424}
425
426static void vmlfb_set_pref_pixel_format(struct fb_var_screeninfo *var)
427{
428 switch (var->bits_per_pixel) {
429 case 16:
430 var->blue.offset = 0;
431 var->blue.length = 5;
432 var->green.offset = 5;
433 var->green.length = 5;
434 var->red.offset = 10;
435 var->red.length = 5;
436 var->transp.offset = 15;
437 var->transp.length = 1;
438 break;
439 case 32:
440 var->blue.offset = 0;
441 var->blue.length = 8;
442 var->green.offset = 8;
443 var->green.length = 8;
444 var->red.offset = 16;
445 var->red.length = 8;
446 var->transp.offset = 24;
447 var->transp.length = 0;
448 break;
449 default:
450 break;
451 }
452
453 var->blue.msb_right = var->green.msb_right =
454 var->red.msb_right = var->transp.msb_right = 0;
455}
456
457/*
458 * Device initialization.
459 * We initialize one vml_par struct per device and one vml_info
460 * struct per pipe. Currently we have only one pipe.
461 */
462
463static int __devinit vml_pci_probe(struct pci_dev *dev,
464 const struct pci_device_id *id)
465{
466 struct vml_info *vinfo;
467 struct fb_info *info;
468 struct vml_par *par;
469 int err = 0;
470
471 par = kzalloc(sizeof(*par), GFP_KERNEL);
472 if (par == NULL)
473 return -ENOMEM;
474
475 vinfo = kzalloc(sizeof(*vinfo), GFP_KERNEL);
476 if (vinfo == NULL) {
477 err = -ENOMEM;
478 goto out_err_0;
479 }
480
481 vinfo->par = par;
482 par->vdc = dev;
483 atomic_set(&par->refcount, 1);
484
485 switch (id->device) {
486 case VML_DEVICE_VDC:
487 if ((err = vmlfb_get_gpu(par)))
488 goto out_err_1;
489 pci_set_drvdata(dev, &vinfo->info);
490 break;
491 default:
492 err = -ENODEV;
493 goto out_err_1;
494 break;
495 }
496
497 info = &vinfo->info;
498 info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK;
499
500 err = vmlfb_enable_mmio(par);
501 if (err)
502 goto out_err_2;
503
504 err = vmlfb_alloc_vram(vinfo, vml_mem_requested,
505 vml_mem_contig, vml_mem_min);
506 if (err)
507 goto out_err_3;
508
509 strcpy(info->fix.id, "Vermilion Range");
510 info->fix.mmio_start = 0;
511 info->fix.mmio_len = 0;
512 info->fix.smem_start = vinfo->vram_start;
513 info->fix.smem_len = vinfo->vram_contig_size;
514 info->fix.type = FB_TYPE_PACKED_PIXELS;
515 info->fix.visual = FB_VISUAL_TRUECOLOR;
516 info->fix.ypanstep = 1;
517 info->fix.xpanstep = 1;
518 info->fix.ywrapstep = 0;
519 info->fix.accel = FB_ACCEL_NONE;
520 info->screen_base = vinfo->vram_logical;
521 info->pseudo_palette = vinfo->pseudo_palette;
522 info->par = par;
523 info->fbops = &vmlfb_ops;
524 info->device = &dev->dev;
525
526 INIT_LIST_HEAD(&vinfo->head);
527 vinfo->pipe_disabled = 1;
528 vinfo->cur_blank_mode = FB_BLANK_UNBLANK;
529
530 info->var.grayscale = 0;
531 info->var.bits_per_pixel = 16;
532 vmlfb_set_pref_pixel_format(&info->var);
533
534 if (!fb_find_mode
535 (&info->var, info, vml_default_mode, NULL, 0, &defaultmode, 16)) {
536 printk(KERN_ERR MODULE_NAME ": Could not find initial mode\n");
537 }
538
539 if (fb_alloc_cmap(&info->cmap, 256, 1) < 0) {
540 err = -ENOMEM;
541 goto out_err_4;
542 }
543
544 err = register_framebuffer(info);
545 if (err) {
546 printk(KERN_ERR MODULE_NAME ": Register framebuffer error.\n");
547 goto out_err_5;
548 }
549
550 printk("Initialized vmlfb\n");
551
552 return 0;
553
554out_err_5:
555 fb_dealloc_cmap(&info->cmap);
556out_err_4:
557 vmlfb_free_vram(vinfo);
558out_err_3:
559 vmlfb_disable_mmio(par);
560out_err_2:
561 vmlfb_release_devices(par);
562out_err_1:
563 kfree(vinfo);
564out_err_0:
565 kfree(par);
566 return err;
567}
568
569static int vmlfb_open(struct fb_info *info, int user)
570{
571 /*
572 * Save registers here?
573 */
574 return 0;
575}
576
577static int vmlfb_release(struct fb_info *info, int user)
578{
579 /*
580 * Restore registers here.
581 */
582
583 return 0;
584}
585
586static int vml_nearest_clock(int clock)
587{
588
589 int i;
590 int cur_index;
591 int cur_diff;
592 int diff;
593
594 cur_index = 0;
595 cur_diff = clock - vml_clocks[0];
596 cur_diff = (cur_diff < 0) ? -cur_diff : cur_diff;
597 for (i = 1; i < vml_num_clocks; ++i) {
598 diff = clock - vml_clocks[i];
599 diff = (diff < 0) ? -diff : diff;
600 if (diff < cur_diff) {
601 cur_index = i;
602 cur_diff = diff;
603 }
604 }
605 return vml_clocks[cur_index];
606}
607
608static int vmlfb_check_var_locked(struct fb_var_screeninfo *var,
609 struct vml_info *vinfo)
610{
611 u32 pitch;
612 u64 mem;
613 int nearest_clock;
614 int clock;
615 int clock_diff;
616 struct fb_var_screeninfo v;
617
618 v = *var;
619 clock = PICOS2KHZ(var->pixclock);
620
621 if (subsys && subsys->nearest_clock) {
622 nearest_clock = subsys->nearest_clock(subsys, clock);
623 } else {
624 nearest_clock = vml_nearest_clock(clock);
625 }
626
627 /*
628 * Accept a 20% diff.
629 */
630
631 clock_diff = nearest_clock - clock;
632 clock_diff = (clock_diff < 0) ? -clock_diff : clock_diff;
633 if (clock_diff > clock / 5) {
634#if 0
635 printk(KERN_DEBUG MODULE_NAME ": Diff failure. %d %d\n",clock_diff,clock);
636#endif
637 return -EINVAL;
638 }
639
640 v.pixclock = KHZ2PICOS(nearest_clock);
641
642 if (var->xres > VML_MAX_XRES || var->yres > VML_MAX_YRES) {
643 printk(KERN_DEBUG MODULE_NAME ": Resolution failure.\n");
644 return -EINVAL;
645 }
646 if (var->xres_virtual > VML_MAX_XRES_VIRTUAL) {
647 printk(KERN_DEBUG MODULE_NAME
648 ": Virtual resolution failure.\n");
649 return -EINVAL;
650 }
651 switch (v.bits_per_pixel) {
652 case 0 ... 16:
653 v.bits_per_pixel = 16;
654 break;
655 case 17 ... 32:
656 v.bits_per_pixel = 32;
657 break;
658 default:
659 printk(KERN_DEBUG MODULE_NAME ": Invalid bpp: %d.\n",
660 var->bits_per_pixel);
661 return -EINVAL;
662 }
663
664 pitch = __ALIGN_MASK((var->xres * var->bits_per_pixel) >> 3, 0x3F);
665 mem = pitch * var->yres_virtual;
666 if (mem > vinfo->vram_contig_size) {
667 return -ENOMEM;
668 }
669
670 switch (v.bits_per_pixel) {
671 case 16:
672 if (var->blue.offset != 0 ||
673 var->blue.length != 5 ||
674 var->green.offset != 5 ||
675 var->green.length != 5 ||
676 var->red.offset != 10 ||
677 var->red.length != 5 ||
678 var->transp.offset != 15 || var->transp.length != 1) {
679 vmlfb_set_pref_pixel_format(&v);
680 }
681 break;
682 case 32:
683 if (var->blue.offset != 0 ||
684 var->blue.length != 8 ||
685 var->green.offset != 8 ||
686 var->green.length != 8 ||
687 var->red.offset != 16 ||
688 var->red.length != 8 ||
689 (var->transp.length != 0 && var->transp.length != 8) ||
690 (var->transp.length == 8 && var->transp.offset != 24)) {
691 vmlfb_set_pref_pixel_format(&v);
692 }
693 break;
694 default:
695 return -EINVAL;
696 }
697
698 *var = v;
699
700 return 0;
701}
702
703static int vmlfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
704{
705 struct vml_info *vinfo = container_of(info, struct vml_info, info);
706 int ret;
707
708 mutex_lock(&vml_mutex);
709 ret = vmlfb_check_var_locked(var, vinfo);
710 mutex_unlock(&vml_mutex);
711
712 return ret;
713}
714
715static void vml_wait_vblank(struct vml_info *vinfo)
716{
717 /* Wait for vblank. For now, just wait for a 50Hz cycle (20ms)) */
718 mdelay(20);
719}
720
721static void vmlfb_disable_pipe(struct vml_info *vinfo)
722{
723 struct vml_par *par = vinfo->par;
724
725 /* Disable the MDVO pad */
726 VML_WRITE32(par, VML_RCOMPSTAT, 0);
727 while (!(VML_READ32(par, VML_RCOMPSTAT) & VML_MDVO_VDC_I_RCOMP)) ;
728
729 /* Disable display planes */
730 VML_WRITE32(par, VML_DSPCCNTR,
731 VML_READ32(par, VML_DSPCCNTR) & ~VML_GFX_ENABLE);
732 (void)VML_READ32(par, VML_DSPCCNTR);
733 /* Wait for vblank for the disable to take effect */
734 vml_wait_vblank(vinfo);
735
736 /* Next, disable display pipes */
737 VML_WRITE32(par, VML_PIPEACONF, 0);
738 (void)VML_READ32(par, VML_PIPEACONF);
739
740 vinfo->pipe_disabled = 1;
741}
742
743#ifdef VERMILION_DEBUG
744static void vml_dump_regs(struct vml_info *vinfo)
745{
746 struct vml_par *par = vinfo->par;
747
748 printk(KERN_DEBUG MODULE_NAME ": Modesetting register dump:\n");
749 printk(KERN_DEBUG MODULE_NAME ": \tHTOTAL_A : 0x%08x\n",
750 (unsigned)VML_READ32(par, VML_HTOTAL_A));
751 printk(KERN_DEBUG MODULE_NAME ": \tHBLANK_A : 0x%08x\n",
752 (unsigned)VML_READ32(par, VML_HBLANK_A));
753 printk(KERN_DEBUG MODULE_NAME ": \tHSYNC_A : 0x%08x\n",
754 (unsigned)VML_READ32(par, VML_HSYNC_A));
755 printk(KERN_DEBUG MODULE_NAME ": \tVTOTAL_A : 0x%08x\n",
756 (unsigned)VML_READ32(par, VML_VTOTAL_A));
757 printk(KERN_DEBUG MODULE_NAME ": \tVBLANK_A : 0x%08x\n",
758 (unsigned)VML_READ32(par, VML_VBLANK_A));
759 printk(KERN_DEBUG MODULE_NAME ": \tVSYNC_A : 0x%08x\n",
760 (unsigned)VML_READ32(par, VML_VSYNC_A));
761 printk(KERN_DEBUG MODULE_NAME ": \tDSPCSTRIDE : 0x%08x\n",
762 (unsigned)VML_READ32(par, VML_DSPCSTRIDE));
763 printk(KERN_DEBUG MODULE_NAME ": \tDSPCSIZE : 0x%08x\n",
764 (unsigned)VML_READ32(par, VML_DSPCSIZE));
765 printk(KERN_DEBUG MODULE_NAME ": \tDSPCPOS : 0x%08x\n",
766 (unsigned)VML_READ32(par, VML_DSPCPOS));
767 printk(KERN_DEBUG MODULE_NAME ": \tDSPARB : 0x%08x\n",
768 (unsigned)VML_READ32(par, VML_DSPARB));
769 printk(KERN_DEBUG MODULE_NAME ": \tDSPCADDR : 0x%08x\n",
770 (unsigned)VML_READ32(par, VML_DSPCADDR));
771 printk(KERN_DEBUG MODULE_NAME ": \tBCLRPAT_A : 0x%08x\n",
772 (unsigned)VML_READ32(par, VML_BCLRPAT_A));
773 printk(KERN_DEBUG MODULE_NAME ": \tCANVSCLR_A : 0x%08x\n",
774 (unsigned)VML_READ32(par, VML_CANVSCLR_A));
775 printk(KERN_DEBUG MODULE_NAME ": \tPIPEASRC : 0x%08x\n",
776 (unsigned)VML_READ32(par, VML_PIPEASRC));
777 printk(KERN_DEBUG MODULE_NAME ": \tPIPEACONF : 0x%08x\n",
778 (unsigned)VML_READ32(par, VML_PIPEACONF));
779 printk(KERN_DEBUG MODULE_NAME ": \tDSPCCNTR : 0x%08x\n",
780 (unsigned)VML_READ32(par, VML_DSPCCNTR));
781 printk(KERN_DEBUG MODULE_NAME ": \tRCOMPSTAT : 0x%08x\n",
782 (unsigned)VML_READ32(par, VML_RCOMPSTAT));
783 printk(KERN_DEBUG MODULE_NAME ": End of modesetting register dump.\n");
784}
785#endif
786
787static int vmlfb_set_par_locked(struct vml_info *vinfo)
788{
789 struct vml_par *par = vinfo->par;
790 struct fb_info *info = &vinfo->info;
791 struct fb_var_screeninfo *var = &info->var;
792 u32 htotal, hactive, hblank_start, hblank_end, hsync_start, hsync_end;
793 u32 vtotal, vactive, vblank_start, vblank_end, vsync_start, vsync_end;
794 u32 dspcntr;
795 int clock;
796
797 vinfo->bytes_per_pixel = var->bits_per_pixel >> 3;
798 vinfo->stride =
799 __ALIGN_MASK(var->xres_virtual * vinfo->bytes_per_pixel, 0x3F);
800 info->fix.line_length = vinfo->stride;
801
802 if (!subsys)
803 return 0;
804
805 htotal =
806 var->xres + var->right_margin + var->hsync_len + var->left_margin;
807 hactive = var->xres;
808 hblank_start = var->xres;
809 hblank_end = htotal;
810 hsync_start = hactive + var->right_margin;
811 hsync_end = hsync_start + var->hsync_len;
812
813 vtotal =
814 var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
815 vactive = var->yres;
816 vblank_start = var->yres;
817 vblank_end = vtotal;
818 vsync_start = vactive + var->lower_margin;
819 vsync_end = vsync_start + var->vsync_len;
820
821 dspcntr = VML_GFX_ENABLE | VML_GFX_GAMMABYPASS;
822 clock = PICOS2KHZ(var->pixclock);
823
824 if (subsys->nearest_clock) {
825 clock = subsys->nearest_clock(subsys, clock);
826 } else {
827 clock = vml_nearest_clock(clock);
828 }
829 printk(KERN_DEBUG MODULE_NAME
830 ": Set mode Hfreq : %d kHz, Vfreq : %d Hz.\n", clock / htotal,
831 ((clock / htotal) * 1000) / vtotal);
832
833 switch (var->bits_per_pixel) {
834 case 16:
835 dspcntr |= VML_GFX_ARGB1555;
836 break;
837 case 32:
838 if (var->transp.length == 8)
839 dspcntr |= VML_GFX_ARGB8888 | VML_GFX_ALPHAMULT;
840 else
841 dspcntr |= VML_GFX_RGB0888;
842 break;
843 default:
844 return -EINVAL;
845 }
846
847 vmlfb_disable_pipe(vinfo);
848 mb();
849
850 if (subsys->set_clock)
851 subsys->set_clock(subsys, clock);
852 else
853 return -EINVAL;
854
855 VML_WRITE32(par, VML_HTOTAL_A, ((htotal - 1) << 16) | (hactive - 1));
856 VML_WRITE32(par, VML_HBLANK_A,
857 ((hblank_end - 1) << 16) | (hblank_start - 1));
858 VML_WRITE32(par, VML_HSYNC_A,
859 ((hsync_end - 1) << 16) | (hsync_start - 1));
860 VML_WRITE32(par, VML_VTOTAL_A, ((vtotal - 1) << 16) | (vactive - 1));
861 VML_WRITE32(par, VML_VBLANK_A,
862 ((vblank_end - 1) << 16) | (vblank_start - 1));
863 VML_WRITE32(par, VML_VSYNC_A,
864 ((vsync_end - 1) << 16) | (vsync_start - 1));
865 VML_WRITE32(par, VML_DSPCSTRIDE, vinfo->stride);
866 VML_WRITE32(par, VML_DSPCSIZE,
867 ((var->yres - 1) << 16) | (var->xres - 1));
868 VML_WRITE32(par, VML_DSPCPOS, 0x00000000);
869 VML_WRITE32(par, VML_DSPARB, VML_FIFO_DEFAULT);
870 VML_WRITE32(par, VML_BCLRPAT_A, 0x00000000);
871 VML_WRITE32(par, VML_CANVSCLR_A, 0x00000000);
872 VML_WRITE32(par, VML_PIPEASRC,
873 ((var->xres - 1) << 16) | (var->yres - 1));
874
875 wmb();
876 VML_WRITE32(par, VML_PIPEACONF, VML_PIPE_ENABLE);
877 wmb();
878 VML_WRITE32(par, VML_DSPCCNTR, dspcntr);
879 wmb();
880 VML_WRITE32(par, VML_DSPCADDR, (u32) vinfo->vram_start +
881 var->yoffset * vinfo->stride +
882 var->xoffset * vinfo->bytes_per_pixel);
883
884 VML_WRITE32(par, VML_RCOMPSTAT, VML_MDVO_PAD_ENABLE);
885
886 while (!(VML_READ32(par, VML_RCOMPSTAT) &
887 (VML_MDVO_VDC_I_RCOMP | VML_MDVO_PAD_ENABLE))) ;
888
889 vinfo->pipe_disabled = 0;
890#ifdef VERMILION_DEBUG
891 vml_dump_regs(vinfo);
892#endif
893
894 return 0;
895}
896
897static int vmlfb_set_par(struct fb_info *info)
898{
899 struct vml_info *vinfo = container_of(info, struct vml_info, info);
900 int ret;
901
902 mutex_lock(&vml_mutex);
903 list_del(&vinfo->head);
904 list_add(&vinfo->head, (subsys) ? &global_has_mode : &global_no_mode);
905 ret = vmlfb_set_par_locked(vinfo);
906
907 mutex_unlock(&vml_mutex);
908 return ret;
909}
910
911static int vmlfb_blank_locked(struct vml_info *vinfo)
912{
913 struct vml_par *par = vinfo->par;
914 u32 cur = VML_READ32(par, VML_PIPEACONF);
915
916 switch (vinfo->cur_blank_mode) {
917 case FB_BLANK_UNBLANK:
918 if (vinfo->pipe_disabled) {
919 vmlfb_set_par_locked(vinfo);
920 }
921 VML_WRITE32(par, VML_PIPEACONF, cur & ~VML_PIPE_FORCE_BORDER);
922 (void)VML_READ32(par, VML_PIPEACONF);
923 break;
924 case FB_BLANK_NORMAL:
925 if (vinfo->pipe_disabled) {
926 vmlfb_set_par_locked(vinfo);
927 }
928 VML_WRITE32(par, VML_PIPEACONF, cur | VML_PIPE_FORCE_BORDER);
929 (void)VML_READ32(par, VML_PIPEACONF);
930 break;
931 case FB_BLANK_VSYNC_SUSPEND:
932 case FB_BLANK_HSYNC_SUSPEND:
933 if (!vinfo->pipe_disabled) {
934 vmlfb_disable_pipe(vinfo);
935 }
936 break;
937 case FB_BLANK_POWERDOWN:
938 if (!vinfo->pipe_disabled) {
939 vmlfb_disable_pipe(vinfo);
940 }
941 break;
942 default:
943 return -EINVAL;
944 }
945
946 return 0;
947}
948
949static int vmlfb_blank(int blank_mode, struct fb_info *info)
950{
951 struct vml_info *vinfo = container_of(info, struct vml_info, info);
952 int ret;
953
954 mutex_lock(&vml_mutex);
955 vinfo->cur_blank_mode = blank_mode;
956 ret = vmlfb_blank_locked(vinfo);
957 mutex_unlock(&vml_mutex);
958 return ret;
959}
960
961static int vmlfb_pan_display(struct fb_var_screeninfo *var,
962 struct fb_info *info)
963{
964 struct vml_info *vinfo = container_of(info, struct vml_info, info);
965 struct vml_par *par = vinfo->par;
966
967 mutex_lock(&vml_mutex);
968 VML_WRITE32(par, VML_DSPCADDR, (u32) vinfo->vram_start +
969 var->yoffset * vinfo->stride +
970 var->xoffset * vinfo->bytes_per_pixel);
971 (void)VML_READ32(par, VML_DSPCADDR);
972 mutex_unlock(&vml_mutex);
973
974 return 0;
975}
976
977static int vmlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
978 u_int transp, struct fb_info *info)
979{
980 u32 v;
981
982 if (regno >= 16)
983 return -EINVAL;
984
985 if (info->var.grayscale) {
986 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
987 }
988
989 if (info->fix.visual != FB_VISUAL_TRUECOLOR)
990 return -EINVAL;
991
992 red = VML_TOHW(red, info->var.red.length);
993 blue = VML_TOHW(blue, info->var.blue.length);
994 green = VML_TOHW(green, info->var.green.length);
995 transp = VML_TOHW(transp, info->var.transp.length);
996
997 v = (red << info->var.red.offset) |
998 (green << info->var.green.offset) |
999 (blue << info->var.blue.offset) |
1000 (transp << info->var.transp.offset);
1001
1002 switch (info->var.bits_per_pixel) {
1003 case 16:
1004 ((u32 *) info->pseudo_palette)[regno] = v;
1005 break;
1006 case 24:
1007 case 32:
1008 ((u32 *) info->pseudo_palette)[regno] = v;
1009 break;
1010 }
1011 return 0;
1012}
1013
1014static int vmlfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
1015{
1016 struct vml_info *vinfo = container_of(info, struct vml_info, info);
1017 unsigned long size = vma->vm_end - vma->vm_start;
1018 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
1019 int ret;
1020
1021 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1022 return -EINVAL;
1023 if (offset + size > vinfo->vram_contig_size)
1024 return -EINVAL;
1025 ret = vmlfb_vram_offset(vinfo, offset);
1026 if (ret)
1027 return -EINVAL;
1028 offset += vinfo->vram_start;
1029 pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
1030 pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
1031 vma->vm_flags |= VM_RESERVED | VM_IO;
1032 if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
1033 size, vma->vm_page_prot))
1034 return -EAGAIN;
1035 return 0;
1036}
1037
1038static int vmlfb_sync(struct fb_info *info)
1039{
1040 return 0;
1041}
1042
1043static int vmlfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
1044{
1045 return -EINVAL; /* just to force soft_cursor() call */
1046}
1047
1048static struct fb_ops vmlfb_ops = {
1049 .owner = THIS_MODULE,
1050 .fb_open = vmlfb_open,
1051 .fb_release = vmlfb_release,
1052 .fb_check_var = vmlfb_check_var,
1053 .fb_set_par = vmlfb_set_par,
1054 .fb_blank = vmlfb_blank,
1055 .fb_pan_display = vmlfb_pan_display,
1056 .fb_fillrect = cfb_fillrect,
1057 .fb_copyarea = cfb_copyarea,
1058 .fb_imageblit = cfb_imageblit,
1059 .fb_cursor = vmlfb_cursor,
1060 .fb_sync = vmlfb_sync,
1061 .fb_mmap = vmlfb_mmap,
1062 .fb_setcolreg = vmlfb_setcolreg
1063};
1064
1065static struct pci_device_id vml_ids[] = {
1066 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, VML_DEVICE_VDC)},
1067 {0}
1068};
1069
1070static struct pci_driver vmlfb_pci_driver = {
1071 .name = "vmlfb",
1072 .id_table = vml_ids,
1073 .probe = vml_pci_probe,
1074 .remove = __devexit_p(vml_pci_remove)
1075};
1076
1077static void __exit vmlfb_cleanup(void)
1078{
1079 pci_unregister_driver(&vmlfb_pci_driver);
1080}
1081
1082static int __init vmlfb_init(void)
1083{
1084
1085#ifndef MODULE
1086 char *option = NULL;
1087
1088 if (fb_get_options(MODULE_NAME, &option))
1089 return -ENODEV;
1090#endif
1091
1092 printk(KERN_DEBUG MODULE_NAME ": initializing\n");
1093 mutex_init(&vml_mutex);
1094 INIT_LIST_HEAD(&global_no_mode);
1095 INIT_LIST_HEAD(&global_has_mode);
1096
1097 return pci_register_driver(&vmlfb_pci_driver);
1098}
1099
1100int vmlfb_register_subsys(struct vml_sys *sys)
1101{
1102 struct vml_info *entry;
1103 struct list_head *list;
1104 u32 save_activate;
1105
1106 mutex_lock(&vml_mutex);
1107 if (subsys != NULL) {
1108 subsys->restore(subsys);
1109 }
1110 subsys = sys;
1111 subsys->save(subsys);
1112
1113 /*
1114 * We need to restart list traversal for each item, since we
1115 * release the list mutex in the loop.
1116 */
1117
1118 list = global_no_mode.next;
1119 while (list != &global_no_mode) {
1120 list_del_init(list);
1121 entry = list_entry(list, struct vml_info, head);
1122
1123 /*
1124 * First, try the current mode which might not be
1125 * completely validated with respect to the pixel clock.
1126 */
1127
1128 if (!vmlfb_check_var_locked(&entry->info.var, entry)) {
1129 vmlfb_set_par_locked(entry);
1130 list_add_tail(list, &global_has_mode);
1131 } else {
1132
1133 /*
1134 * Didn't work. Try to find another mode,
1135 * that matches this subsys.
1136 */
1137
1138 mutex_unlock(&vml_mutex);
1139 save_activate = entry->info.var.activate;
1140 entry->info.var.bits_per_pixel = 16;
1141 vmlfb_set_pref_pixel_format(&entry->info.var);
1142 if (fb_find_mode(&entry->info.var,
1143 &entry->info,
1144 vml_default_mode, NULL, 0, NULL, 16)) {
1145 entry->info.var.activate |=
1146 FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
1147 fb_set_var(&entry->info, &entry->info.var);
1148 } else {
1149 printk(KERN_ERR MODULE_NAME
1150 ": Sorry. no mode found for this subsys.\n");
1151 }
1152 entry->info.var.activate = save_activate;
1153 mutex_lock(&vml_mutex);
1154 }
1155 vmlfb_blank_locked(entry);
1156 list = global_no_mode.next;
1157 }
1158 mutex_unlock(&vml_mutex);
1159
1160 printk(KERN_DEBUG MODULE_NAME ": Registered %s subsystem.\n",
1161 subsys->name ? subsys->name : "unknown");
1162 return 0;
1163}
1164
1165EXPORT_SYMBOL_GPL(vmlfb_register_subsys);
1166
1167void vmlfb_unregister_subsys(struct vml_sys *sys)
1168{
1169 struct vml_info *entry, *next;
1170
1171 mutex_lock(&vml_mutex);
1172 if (subsys != sys) {
1173 mutex_unlock(&vml_mutex);
1174 return;
1175 }
1176 subsys->restore(subsys);
1177 subsys = NULL;
1178 list_for_each_entry_safe(entry, next, &global_has_mode, head) {
1179 printk(KERN_DEBUG MODULE_NAME ": subsys disable pipe\n");
1180 vmlfb_disable_pipe(entry);
1181 list_del(&entry->head);
1182 list_add_tail(&entry->head, &global_no_mode);
1183 }
1184 mutex_unlock(&vml_mutex);
1185}
1186
1187EXPORT_SYMBOL_GPL(vmlfb_unregister_subsys);
1188
1189module_init(vmlfb_init);
1190module_exit(vmlfb_cleanup);
1191
1192MODULE_AUTHOR("Tungsten Graphics");
1193MODULE_DESCRIPTION("Initialization of the Vermilion display devices");
1194MODULE_VERSION("1.0.0");
1195MODULE_LICENSE("GPL");
diff --git a/drivers/video/vermilion/vermilion.h b/drivers/video/vermilion/vermilion.h
new file mode 100644
index 000000000000..1fc6695a49d2
--- /dev/null
+++ b/drivers/video/vermilion/vermilion.h
@@ -0,0 +1,260 @@
1/*
2 * Copyright (c) Intel Corp. 2007.
3 * All Rights Reserved.
4 *
5 * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
6 * develop this driver.
7 *
8 * This file is part of the Vermilion Range fb driver.
9 * The Vermilion Range fb driver is free software;
10 * you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * The Vermilion Range fb driver is distributed
16 * in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this driver; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 *
25 * Authors:
26 * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
27 */
28
29#ifndef _VERMILION_H_
30#define _VERMILION_H_
31
32#include <linux/kernel.h>
33#include <linux/version.h>
34#include <linux/pci.h>
35#include <asm/atomic.h>
36#include <linux/mutex.h>
37
38#define VML_DEVICE_GPU 0x5002
39#define VML_DEVICE_VDC 0x5009
40
41#define VML_VRAM_AREAS 3
42#define VML_MAX_XRES 1024
43#define VML_MAX_YRES 768
44#define VML_MAX_XRES_VIRTUAL 1040
45
46/*
47 * Display controller registers:
48 */
49
50/* Display controller 10-bit color representation */
51
52#define VML_R_MASK 0x3FF00000
53#define VML_R_SHIFT 20
54#define VML_G_MASK 0x000FFC00
55#define VML_G_SHIFT 10
56#define VML_B_MASK 0x000003FF
57#define VML_B_SHIFT 0
58
59/* Graphics plane control */
60#define VML_DSPCCNTR 0x00072180
61#define VML_GFX_ENABLE 0x80000000
62#define VML_GFX_GAMMABYPASS 0x40000000
63#define VML_GFX_ARGB1555 0x0C000000
64#define VML_GFX_RGB0888 0x18000000
65#define VML_GFX_ARGB8888 0x1C000000
66#define VML_GFX_ALPHACONST 0x02000000
67#define VML_GFX_ALPHAMULT 0x01000000
68#define VML_GFX_CONST_ALPHA 0x000000FF
69
70/* Graphics plane start address. Pixel aligned. */
71#define VML_DSPCADDR 0x00072184
72
73/* Graphics plane stride register. */
74#define VML_DSPCSTRIDE 0x00072188
75
76/* Graphics plane position register. */
77#define VML_DSPCPOS 0x0007218C
78#define VML_POS_YMASK 0x0FFF0000
79#define VML_POS_YSHIFT 16
80#define VML_POS_XMASK 0x00000FFF
81#define VML_POS_XSHIFT 0
82
83/* Graphics plane height and width */
84#define VML_DSPCSIZE 0x00072190
85#define VML_SIZE_HMASK 0x0FFF0000
86#define VML_SIZE_HSHIFT 16
87#define VML_SISE_WMASK 0x00000FFF
88#define VML_SIZE_WSHIFT 0
89
90/* Graphics plane gamma correction lookup table registers (129 * 32 bits) */
91#define VML_DSPCGAMLUT 0x00072200
92
93/* Pixel video output configuration register */
94#define VML_PVOCONFIG 0x00061140
95#define VML_CONFIG_BASE 0x80000000
96#define VML_CONFIG_PIXEL_SWAP 0x04000000
97#define VML_CONFIG_DE_INV 0x01000000
98#define VML_CONFIG_HREF_INV 0x00400000
99#define VML_CONFIG_VREF_INV 0x00100000
100#define VML_CONFIG_CLK_INV 0x00040000
101#define VML_CONFIG_CLK_DIV2 0x00010000
102#define VML_CONFIG_ESTRB_INV 0x00008000
103
104/* Pipe A Horizontal total register */
105#define VML_HTOTAL_A 0x00060000
106#define VML_HTOTAL_MASK 0x1FFF0000
107#define VML_HTOTAL_SHIFT 16
108#define VML_HTOTAL_VAL 8192
109#define VML_HACTIVE_MASK 0x000007FF
110#define VML_HACTIVE_SHIFT 0
111#define VML_HACTIVE_VAL 4096
112
113/* Pipe A Horizontal Blank register */
114#define VML_HBLANK_A 0x00060004
115#define VML_HBLANK_END_MASK 0x1FFF0000
116#define VML_HBLANK_END_SHIFT 16
117#define VML_HBLANK_END_VAL 8192
118#define VML_HBLANK_START_MASK 0x00001FFF
119#define VML_HBLANK_START_SHIFT 0
120#define VML_HBLANK_START_VAL 8192
121
122/* Pipe A Horizontal Sync register */
123#define VML_HSYNC_A 0x00060008
124#define VML_HSYNC_END_MASK 0x1FFF0000
125#define VML_HSYNC_END_SHIFT 16
126#define VML_HSYNC_END_VAL 8192
127#define VML_HSYNC_START_MASK 0x00001FFF
128#define VML_HSYNC_START_SHIFT 0
129#define VML_HSYNC_START_VAL 8192
130
131/* Pipe A Vertical total register */
132#define VML_VTOTAL_A 0x0006000C
133#define VML_VTOTAL_MASK 0x1FFF0000
134#define VML_VTOTAL_SHIFT 16
135#define VML_VTOTAL_VAL 8192
136#define VML_VACTIVE_MASK 0x000007FF
137#define VML_VACTIVE_SHIFT 0
138#define VML_VACTIVE_VAL 4096
139
140/* Pipe A Vertical Blank register */
141#define VML_VBLANK_A 0x00060010
142#define VML_VBLANK_END_MASK 0x1FFF0000
143#define VML_VBLANK_END_SHIFT 16
144#define VML_VBLANK_END_VAL 8192
145#define VML_VBLANK_START_MASK 0x00001FFF
146#define VML_VBLANK_START_SHIFT 0
147#define VML_VBLANK_START_VAL 8192
148
149/* Pipe A Vertical Sync register */
150#define VML_VSYNC_A 0x00060014
151#define VML_VSYNC_END_MASK 0x1FFF0000
152#define VML_VSYNC_END_SHIFT 16
153#define VML_VSYNC_END_VAL 8192
154#define VML_VSYNC_START_MASK 0x00001FFF
155#define VML_VSYNC_START_SHIFT 0
156#define VML_VSYNC_START_VAL 8192
157
158/* Pipe A Source Image size (minus one - equal to active size)
159 * Programmable while pipe is enabled.
160 */
161#define VML_PIPEASRC 0x0006001C
162#define VML_PIPEASRC_HMASK 0x0FFF0000
163#define VML_PIPEASRC_HSHIFT 16
164#define VML_PIPEASRC_VMASK 0x00000FFF
165#define VML_PIPEASRC_VSHIFT 0
166
167/* Pipe A Border Color Pattern register (10 bit color) */
168#define VML_BCLRPAT_A 0x00060020
169
170/* Pipe A Canvas Color register (10 bit color) */
171#define VML_CANVSCLR_A 0x00060024
172
173/* Pipe A Configuration register */
174#define VML_PIPEACONF 0x00070008
175#define VML_PIPE_BASE 0x00000000
176#define VML_PIPE_ENABLE 0x80000000
177#define VML_PIPE_FORCE_BORDER 0x02000000
178#define VML_PIPE_PLANES_OFF 0x00080000
179#define VML_PIPE_ARGB_OUTPUT_MODE 0x00040000
180
181/* Pipe A FIFO setting */
182#define VML_DSPARB 0x00070030
183#define VML_FIFO_DEFAULT 0x00001D9C
184
185/* MDVO rcomp status & pads control register */
186#define VML_RCOMPSTAT 0x00070048
187#define VML_MDVO_VDC_I_RCOMP 0x80000000
188#define VML_MDVO_POWERSAVE_OFF 0x00000008
189#define VML_MDVO_PAD_ENABLE 0x00000004
190#define VML_MDVO_PULLDOWN_ENABLE 0x00000001
191
192struct vml_par {
193 struct pci_dev *vdc;
194 u64 vdc_mem_base;
195 u64 vdc_mem_size;
196 char __iomem *vdc_mem;
197
198 struct pci_dev *gpu;
199 u64 gpu_mem_base;
200 u64 gpu_mem_size;
201 char __iomem *gpu_mem;
202
203 atomic_t refcount;
204};
205
206struct vram_area {
207 unsigned long logical;
208 unsigned long phys;
209 unsigned long size;
210 unsigned order;
211};
212
213struct vml_info {
214 struct fb_info info;
215 struct vml_par *par;
216 struct list_head head;
217 struct vram_area vram[VML_VRAM_AREAS];
218 u64 vram_start;
219 u64 vram_contig_size;
220 u32 num_areas;
221 void __iomem *vram_logical;
222 u32 pseudo_palette[16];
223 u32 stride;
224 u32 bytes_per_pixel;
225 atomic_t vmas;
226 int cur_blank_mode;
227 int pipe_disabled;
228};
229
230/*
231 * Subsystem
232 */
233
234struct vml_sys {
235 char *name;
236
237 /*
238 * Save / Restore;
239 */
240
241 int (*save) (struct vml_sys * sys);
242 int (*restore) (struct vml_sys * sys);
243
244 /*
245 * PLL programming;
246 */
247
248 int (*set_clock) (struct vml_sys * sys, int clock);
249 int (*nearest_clock) (const struct vml_sys * sys, int clock);
250};
251
252extern int vmlfb_register_subsys(struct vml_sys *sys);
253extern void vmlfb_unregister_subsys(struct vml_sys *sys);
254
255#define VML_READ32(_par, _offset) \
256 (ioread32((_par)->vdc_mem + (_offset)))
257#define VML_WRITE32(_par, _offset, _value) \
258 iowrite32(_value, (_par)->vdc_mem + (_offset))
259
260#endif