Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Alan Hourihane and committed by
Linus Torvalds
dbe7e429 249bdbbf

+1981
+16
drivers/video/Kconfig
··· 882 882 select FB_DDC 883 883 help 884 884 885 + config FB_LE80578 886 + tristate "Intel LE80578 (Vermilion) support" 887 + depends on FB && PCI && X86 888 + select FB_MODE_HELPERS 889 + select FB_CFB_FILLRECT 890 + select FB_CFB_COPYAREA 891 + select FB_CFB_IMAGEBLIT 892 + help 893 + This driver supports the LE80578 (Vermilion Range) chipset 894 + 895 + config FB_CARILLO_RANCH 896 + tristate "Intel Carillo Ranch support" 897 + depends on FB_LE80578 && FB && PCI && X86 898 + help 899 + This driver supports the LE80578 (Carillo Ranch) board 900 + 885 901 config FB_INTEL 886 902 tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G support (EXPERIMENTAL)" 887 903 depends on FB && EXPERIMENTAL && PCI && X86
+1
drivers/video/Makefile
··· 56 56 obj-$(CONFIG_FB_FM2) += fm2fb.o 57 57 obj-$(CONFIG_FB_CYBLA) += cyblafb.o 58 58 obj-$(CONFIG_FB_TRIDENT) += tridentfb.o 59 + obj-$(CONFIG_FB_LE80578) += vermilion/ 59 60 obj-$(CONFIG_FB_S3) += s3fb.o 60 61 obj-$(CONFIG_FB_STI) += stifb.o 61 62 obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o
+8
drivers/video/backlight/Kconfig
··· 63 63 help 64 64 If you have a Frontpath ProGear say Y to enable the 65 65 backlight driver. 66 + 67 + config BACKLIGHT_CARILLO_RANCH 68 + tristate "Intel Carillo Ranch Backlight Driver" 69 + depends on BACKLIGHT_CLASS_DEVICE && LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578 70 + default n 71 + help 72 + If you have a Intel LE80578 (Carillo Ranch) say Y to enable the 73 + backlight driver.
+1
drivers/video/backlight/Makefile
··· 6 6 obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o 7 7 obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o 8 8 obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o 9 + obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o
+287
drivers/video/backlight/cr_bllcd.c
··· 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/init.h> 33 + #include <linux/platform_device.h> 34 + #include <linux/mutex.h> 35 + #include <linux/fb.h> 36 + #include <linux/backlight.h> 37 + #include <linux/lcd.h> 38 + #include <linux/pci.h> 39 + #include <asm/uaccess.h> 40 + 41 + /* The LVDS- and panel power controls sits on the 42 + * GPIO port of the ISA bridge. 43 + */ 44 + 45 + #define CRVML_DEVICE_LPC 0x27B8 46 + #define CRVML_REG_GPIOBAR 0x48 47 + #define CRVML_REG_GPIOEN 0x4C 48 + #define CRVML_GPIOEN_BIT (1 << 4) 49 + #define CRVML_PANEL_PORT 0x38 50 + #define CRVML_LVDS_ON 0x00000001 51 + #define CRVML_PANEL_ON 0x00000002 52 + #define CRVML_BACKLIGHT_OFF 0x00000004 53 + 54 + /* The PLL Clock register sits on Host bridge */ 55 + #define CRVML_DEVICE_MCH 0x5001 56 + #define CRVML_REG_MCHBAR 0x44 57 + #define CRVML_REG_MCHEN 0x54 58 + #define CRVML_MCHEN_BIT (1 << 28) 59 + #define CRVML_MCHMAP_SIZE 4096 60 + #define CRVML_REG_CLOCK 0xc3c 61 + #define CRVML_CLOCK_SHIFT 8 62 + #define CRVML_CLOCK_MASK 0x00000f00 63 + 64 + static struct pci_dev *lpc_dev; 65 + static u32 gpio_bar; 66 + 67 + struct cr_panel { 68 + struct backlight_device *cr_backlight_device; 69 + struct lcd_device *cr_lcd_device; 70 + }; 71 + 72 + static int cr_backlight_set_intensity(struct backlight_device *bd) 73 + { 74 + int intensity = bd->props.brightness; 75 + u32 addr = gpio_bar + CRVML_PANEL_PORT; 76 + u32 cur = inl(addr); 77 + 78 + if (bd->props.power == FB_BLANK_UNBLANK) 79 + intensity = FB_BLANK_UNBLANK; 80 + if (bd->props.fb_blank == FB_BLANK_UNBLANK) 81 + intensity = FB_BLANK_UNBLANK; 82 + if (bd->props.power == FB_BLANK_POWERDOWN) 83 + intensity = FB_BLANK_POWERDOWN; 84 + if (bd->props.fb_blank == FB_BLANK_POWERDOWN) 85 + intensity = FB_BLANK_POWERDOWN; 86 + 87 + if (intensity == FB_BLANK_UNBLANK) { /* FULL ON */ 88 + cur &= ~CRVML_BACKLIGHT_OFF; 89 + outl(cur, addr); 90 + } else if (intensity == FB_BLANK_POWERDOWN) { /* OFF */ 91 + cur |= CRVML_BACKLIGHT_OFF; 92 + outl(cur, addr); 93 + } /* anything else, don't bother */ 94 + 95 + return 0; 96 + } 97 + 98 + static int cr_backlight_get_intensity(struct backlight_device *bd) 99 + { 100 + u32 addr = gpio_bar + CRVML_PANEL_PORT; 101 + u32 cur = inl(addr); 102 + u8 intensity; 103 + 104 + if (cur & CRVML_BACKLIGHT_OFF) 105 + intensity = FB_BLANK_POWERDOWN; 106 + else 107 + intensity = FB_BLANK_UNBLANK; 108 + 109 + return intensity; 110 + } 111 + 112 + static struct backlight_ops cr_backlight_ops = { 113 + .get_brightness = cr_backlight_get_intensity, 114 + .update_status = cr_backlight_set_intensity, 115 + }; 116 + 117 + static void cr_panel_on(void) 118 + { 119 + u32 addr = gpio_bar + CRVML_PANEL_PORT; 120 + u32 cur = inl(addr); 121 + 122 + if (!(cur & CRVML_PANEL_ON)) { 123 + /* Make sure LVDS controller is down. */ 124 + if (cur & 0x00000001) { 125 + cur &= ~CRVML_LVDS_ON; 126 + outl(cur, addr); 127 + } 128 + /* Power up Panel */ 129 + schedule_timeout(HZ / 10); 130 + cur |= CRVML_PANEL_ON; 131 + outl(cur, addr); 132 + } 133 + 134 + /* Power up LVDS controller */ 135 + 136 + if (!(cur & CRVML_LVDS_ON)) { 137 + schedule_timeout(HZ / 10); 138 + outl(cur | CRVML_LVDS_ON, addr); 139 + } 140 + } 141 + 142 + static void cr_panel_off(void) 143 + { 144 + u32 addr = gpio_bar + CRVML_PANEL_PORT; 145 + u32 cur = inl(addr); 146 + 147 + /* Power down LVDS controller first to avoid high currents */ 148 + if (cur & CRVML_LVDS_ON) { 149 + cur &= ~CRVML_LVDS_ON; 150 + outl(cur, addr); 151 + } 152 + if (cur & CRVML_PANEL_ON) { 153 + schedule_timeout(HZ / 10); 154 + outl(cur & ~CRVML_PANEL_ON, addr); 155 + } 156 + } 157 + 158 + static int cr_lcd_set_power(struct lcd_device *ld, int power) 159 + { 160 + if (power == FB_BLANK_UNBLANK) 161 + cr_panel_on(); 162 + if (power == FB_BLANK_POWERDOWN) 163 + cr_panel_off(); 164 + 165 + return 0; 166 + } 167 + 168 + static struct lcd_ops cr_lcd_ops = { 169 + .set_power = cr_lcd_set_power, 170 + }; 171 + 172 + static int cr_backlight_probe(struct platform_device *pdev) 173 + { 174 + struct cr_panel *crp; 175 + u8 dev_en; 176 + 177 + crp = kzalloc(sizeof(crp), GFP_KERNEL); 178 + if (crp == NULL) 179 + return -ENOMEM; 180 + 181 + lpc_dev = pci_get_device(PCI_VENDOR_ID_INTEL, 182 + CRVML_DEVICE_LPC, NULL); 183 + if (!lpc_dev) { 184 + printk("INTEL CARILLO RANCH LPC not found.\n"); 185 + return -ENODEV; 186 + } 187 + 188 + pci_read_config_byte(lpc_dev, CRVML_REG_GPIOEN, &dev_en); 189 + if (!(dev_en & CRVML_GPIOEN_BIT)) { 190 + printk(KERN_ERR 191 + "Carillo Ranch GPIO device was not enabled.\n"); 192 + pci_dev_put(lpc_dev); 193 + return -ENODEV; 194 + } 195 + 196 + crp->cr_backlight_device = backlight_device_register("cr-backlight", 197 + &pdev->dev, NULL, 198 + &cr_backlight_ops); 199 + if (IS_ERR(crp->cr_backlight_device)) { 200 + pci_dev_put(lpc_dev); 201 + return PTR_ERR(crp->cr_backlight_device); 202 + } 203 + 204 + crp->cr_lcd_device = lcd_device_register("cr-lcd", 205 + &pdev->dev, 206 + &cr_lcd_ops); 207 + 208 + if (IS_ERR(crp->cr_lcd_device)) { 209 + pci_dev_put(lpc_dev); 210 + return PTR_ERR(crp->cr_backlight_device); 211 + } 212 + 213 + pci_read_config_dword(lpc_dev, CRVML_REG_GPIOBAR, 214 + &gpio_bar); 215 + gpio_bar &= ~0x3F; 216 + 217 + crp->cr_backlight_device->props.power = FB_BLANK_UNBLANK; 218 + crp->cr_backlight_device->props.brightness = 0; 219 + crp->cr_backlight_device->props.max_brightness = 0; 220 + cr_backlight_set_intensity(crp->cr_backlight_device); 221 + 222 + cr_lcd_set_power(crp->cr_lcd_device, FB_BLANK_UNBLANK); 223 + 224 + platform_set_drvdata(pdev, crp); 225 + 226 + return 0; 227 + } 228 + 229 + static int cr_backlight_remove(struct platform_device *pdev) 230 + { 231 + struct cr_panel *crp = platform_get_drvdata(pdev); 232 + crp->cr_backlight_device->props.power = FB_BLANK_POWERDOWN; 233 + crp->cr_backlight_device->props.brightness = 0; 234 + crp->cr_backlight_device->props.max_brightness = 0; 235 + cr_backlight_set_intensity(crp->cr_backlight_device); 236 + cr_lcd_set_power(crp->cr_lcd_device, FB_BLANK_POWERDOWN); 237 + backlight_device_unregister(crp->cr_backlight_device); 238 + lcd_device_unregister(crp->cr_lcd_device); 239 + pci_dev_put(lpc_dev); 240 + 241 + return 0; 242 + } 243 + 244 + static struct platform_driver cr_backlight_driver = { 245 + .probe = cr_backlight_probe, 246 + .remove = cr_backlight_remove, 247 + .driver = { 248 + .name = "cr_backlight", 249 + }, 250 + }; 251 + 252 + static struct platform_device *crp; 253 + 254 + static int __init cr_backlight_init(void) 255 + { 256 + int ret = platform_driver_register(&cr_backlight_driver); 257 + 258 + if (!ret) { 259 + crp = platform_device_alloc("cr_backlight", -1); 260 + if (!crp) 261 + return -ENOMEM; 262 + 263 + ret = platform_device_add(crp); 264 + 265 + if (ret) { 266 + platform_device_put(crp); 267 + platform_driver_unregister(&cr_backlight_driver); 268 + } 269 + } 270 + 271 + printk("Carillo Ranch Backlight Driver Initialized.\n"); 272 + 273 + return ret; 274 + } 275 + 276 + static void __exit cr_backlight_exit(void) 277 + { 278 + platform_device_unregister(crp); 279 + platform_driver_unregister(&cr_backlight_driver); 280 + } 281 + 282 + module_init(cr_backlight_init); 283 + module_exit(cr_backlight_exit); 284 + 285 + MODULE_AUTHOR("Tungsten Graphics Inc."); 286 + MODULE_DESCRIPTION("Carillo Ranch Backlight Driver"); 287 + MODULE_LICENSE("GPL");
+5
drivers/video/vermilion/Makefile
··· 1 + obj-$(CONFIG_FB_LE80578) += vmlfb.o 2 + obj-$(CONFIG_FB_CARILLO_RANCH) += crvml.o 3 + 4 + vmlfb-objs := vermilion.o 5 + crvml-objs := cr_pll.o
+208
drivers/video/vermilion/cr_pll.c
··· 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 + 47 + static struct pci_dev *mch_dev; 48 + static u32 mch_bar; 49 + static void __iomem *mch_regs_base; 50 + static u32 saved_clock; 51 + 52 + static 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 + 67 + static 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 + 79 + static const unsigned crvml_num_clocks = ARRAY_SIZE(crvml_clocks); 80 + 81 + static 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 + 91 + static 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 + 100 + static 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 + 120 + static int crvml_nearest_clock(const struct vml_sys *sys, int clock) 121 + { 122 + return crvml_clocks[crvml_nearest_index(sys, clock)]; 123 + } 124 + 125 + static 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 + 144 + static 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 + 152 + static 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 + 195 + static 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 + 203 + module_init(cr_pll_init); 204 + module_exit(cr_pll_exit); 205 + 206 + MODULE_AUTHOR("Tungsten Graphics Inc."); 207 + MODULE_DESCRIPTION("Carillo Ranch PLL Driver"); 208 + MODULE_LICENSE("GPL");
+1195
drivers/video/vermilion/vermilion.c
··· 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 + 52 + static struct mutex vml_mutex; 53 + static struct list_head global_no_mode; 54 + static struct list_head global_has_mode; 55 + static struct fb_ops vmlfb_ops; 56 + static struct vml_sys *subsys = NULL; 57 + static char *vml_default_mode = "1024x768@60"; 58 + static struct fb_videomode defaultmode = { 59 + NULL, 60, 1024, 768, 12896, 144, 24, 29, 3, 136, 6, 60 + 0, FB_VMODE_NONINTERLACED 61 + }; 62 + 63 + static u32 vml_mem_requested = (10 * 1024 * 1024); 64 + static u32 vml_mem_contig = (4 * 1024 * 1024); 65 + static u32 vml_mem_min = (4 * 1024 * 1024); 66 + 67 + static 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 + 80 + static 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 + 87 + static 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 + 151 + static 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 + 188 + static 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 + 205 + static 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 + 289 + static 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 + */ 311 + static 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 + 331 + static 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 + 366 + out_err_2: 367 + release_mem_region(par->gpu_mem_base, par->gpu_mem_size); 368 + out_err_1: 369 + iounmap(par->vdc_mem); 370 + out_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 + 379 + static 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 + 391 + static 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 + 404 + static 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 + 426 + static 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 + 463 + static 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 + 554 + out_err_5: 555 + fb_dealloc_cmap(&info->cmap); 556 + out_err_4: 557 + vmlfb_free_vram(vinfo); 558 + out_err_3: 559 + vmlfb_disable_mmio(par); 560 + out_err_2: 561 + vmlfb_release_devices(par); 562 + out_err_1: 563 + kfree(vinfo); 564 + out_err_0: 565 + kfree(par); 566 + return err; 567 + } 568 + 569 + static int vmlfb_open(struct fb_info *info, int user) 570 + { 571 + /* 572 + * Save registers here? 573 + */ 574 + return 0; 575 + } 576 + 577 + static int vmlfb_release(struct fb_info *info, int user) 578 + { 579 + /* 580 + * Restore registers here. 581 + */ 582 + 583 + return 0; 584 + } 585 + 586 + static 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 + 608 + static 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 + 703 + static 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 + 715 + static 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 + 721 + static 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 744 + static 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 + 787 + static 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 + 897 + static 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 + 911 + static 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 + 949 + static 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 + 961 + static 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 + 977 + static 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 + 1014 + static 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 + 1038 + static int vmlfb_sync(struct fb_info *info) 1039 + { 1040 + return 0; 1041 + } 1042 + 1043 + static int vmlfb_cursor(struct fb_info *info, struct fb_cursor *cursor) 1044 + { 1045 + return -EINVAL; /* just to force soft_cursor() call */ 1046 + } 1047 + 1048 + static 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 + 1065 + static struct pci_device_id vml_ids[] = { 1066 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, VML_DEVICE_VDC)}, 1067 + {0} 1068 + }; 1069 + 1070 + static 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 + 1077 + static void __exit vmlfb_cleanup(void) 1078 + { 1079 + pci_unregister_driver(&vmlfb_pci_driver); 1080 + } 1081 + 1082 + static 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 + 1100 + int 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 + 1165 + EXPORT_SYMBOL_GPL(vmlfb_register_subsys); 1166 + 1167 + void 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 + 1187 + EXPORT_SYMBOL_GPL(vmlfb_unregister_subsys); 1188 + 1189 + module_init(vmlfb_init); 1190 + module_exit(vmlfb_cleanup); 1191 + 1192 + MODULE_AUTHOR("Tungsten Graphics"); 1193 + MODULE_DESCRIPTION("Initialization of the Vermilion display devices"); 1194 + MODULE_VERSION("1.0.0"); 1195 + MODULE_LICENSE("GPL");
+260
drivers/video/vermilion/vermilion.h
··· 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 + 192 + struct 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 + 206 + struct vram_area { 207 + unsigned long logical; 208 + unsigned long phys; 209 + unsigned long size; 210 + unsigned order; 211 + }; 212 + 213 + struct 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 + 234 + struct 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 + 252 + extern int vmlfb_register_subsys(struct vml_sys *sys); 253 + extern 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