diff options
Diffstat (limited to 'drivers/video/fbdev/nvidia/nvidia.c')
| -rw-r--r-- | drivers/video/fbdev/nvidia/nvidia.c | 247 |
1 files changed, 134 insertions, 113 deletions
diff --git a/drivers/video/fbdev/nvidia/nvidia.c b/drivers/video/fbdev/nvidia/nvidia.c index ce7dab7299fe..72b85f475605 100644 --- a/drivers/video/fbdev/nvidia/nvidia.c +++ b/drivers/video/fbdev/nvidia/nvidia.c @@ -9,6 +9,7 @@ * */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -21,6 +22,7 @@ #include <linux/pci.h> #include <linux/console.h> #include <linux/backlight.h> +#include <linux/string_choices.h> #ifdef CONFIG_BOOTX_TEXT #include <asm/btext.h> #endif @@ -55,7 +57,7 @@ /* HW cursor parameters */ #define MAX_CURS 32 -static struct pci_device_id nvidiafb_pci_tbl[] = { +static const struct pci_device_id nvidiafb_pci_tbl[] = { {PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, 0xff0000, 0}, { 0, } @@ -74,11 +76,7 @@ static int vram = 0; static int bpp = 8; static int reverse_i2c; static bool nomtrr = false; -#ifdef CONFIG_PMAC_BACKLIGHT -static int backlight = 1; -#else -static int backlight = 0; -#endif +static int backlight = IS_BUILTIN(CONFIG_PMAC_BACKLIGHT); static char *mode_option = NULL; @@ -168,27 +166,26 @@ static int nvidia_panel_tweak(struct nvidia_par *par, { int tweak = 0; - if (par->paneltweak) { - tweak = par->paneltweak; - } else { - /* begin flat panel hacks */ - /* This is unfortunate, but some chips need this register - tweaked or else you get artifacts where adjacent pixels are - swapped. There are no hard rules for what to set here so all - we can do is experiment and apply hacks. */ - - if(((par->Chipset & 0xffff) == 0x0328) && (state->bpp == 32)) { - /* At least one NV34 laptop needs this workaround. */ - tweak = -1; - } - - if((par->Chipset & 0xfff0) == 0x0310) { - tweak = 1; - } - /* end flat panel hacks */ - } - - return tweak; + if (par->paneltweak) { + tweak = par->paneltweak; + } else { + /* Begin flat panel hacks. + * This is unfortunate, but some chips need this register + * tweaked or else you get artifacts where adjacent pixels are + * swapped. There are no hard rules for what to set here so all + * we can do is experiment and apply hacks. + */ + if (((par->Chipset & 0xffff) == 0x0328) && (state->bpp == 32)) { + /* At least one NV34 laptop needs this workaround. */ + tweak = -1; + } + + if ((par->Chipset & 0xfff0) == 0x0310) + tweak = 1; + /* end flat panel hacks */ + } + + return tweak; } static void nvidia_screen_off(struct nvidia_par *par, int on) @@ -566,7 +563,7 @@ static int nvidiafb_cursor(struct fb_info *info, struct fb_cursor *cursor) u8 *msk = (u8 *) cursor->mask; u8 *src; - src = kmalloc(s_pitch * cursor->image.height, GFP_ATOMIC); + src = kmalloc_array(s_pitch, cursor->image.height, GFP_ATOMIC); if (src) { switch (cursor->rop) { @@ -607,6 +604,8 @@ static int nvidiafb_cursor(struct fb_info *info, struct fb_cursor *cursor) return 0; } +static struct fb_ops nvidia_fb_ops; + static int nvidiafb_set_par(struct fb_info *info) { struct nvidia_par *par = info->par; @@ -624,7 +623,7 @@ static int nvidiafb_set_par(struct fb_info *info) else par->FPDither = !!(NV_RD32(par->PRAMDAC, 0x083C) & 1); printk(KERN_INFO PFX "Flat panel dithering %s\n", - par->FPDither ? "enabled" : "disabled"); + str_enabled_disabled(par->FPDither)); } info->fix.visual = (info->var.bits_per_pixel == 8) ? @@ -660,19 +659,19 @@ static int nvidiafb_set_par(struct fb_info *info) info->fix.line_length = (info->var.xres_virtual * info->var.bits_per_pixel) >> 3; if (info->var.accel_flags) { - info->fbops->fb_imageblit = nvidiafb_imageblit; - info->fbops->fb_fillrect = nvidiafb_fillrect; - info->fbops->fb_copyarea = nvidiafb_copyarea; - info->fbops->fb_sync = nvidiafb_sync; + nvidia_fb_ops.fb_imageblit = nvidiafb_imageblit; + nvidia_fb_ops.fb_fillrect = nvidiafb_fillrect; + nvidia_fb_ops.fb_copyarea = nvidiafb_copyarea; + nvidia_fb_ops.fb_sync = nvidiafb_sync; info->pixmap.scan_align = 4; info->flags &= ~FBINFO_HWACCEL_DISABLED; info->flags |= FBINFO_READS_FAST; NVResetGraphics(info); } else { - info->fbops->fb_imageblit = cfb_imageblit; - info->fbops->fb_fillrect = cfb_fillrect; - info->fbops->fb_copyarea = cfb_copyarea; - info->fbops->fb_sync = NULL; + nvidia_fb_ops.fb_imageblit = cfb_imageblit; + nvidia_fb_ops.fb_fillrect = cfb_fillrect; + nvidia_fb_ops.fb_copyarea = cfb_copyarea; + nvidia_fb_ops.fb_sync = NULL; info->pixmap.scan_align = 1; info->flags |= FBINFO_HWACCEL_DISABLED; info->flags &= ~FBINFO_READS_FAST; @@ -766,6 +765,8 @@ static int nvidiafb_check_var(struct fb_var_screeninfo *var, int pitch, err = 0; NVTRACE_ENTER(); + if (!var->pixclock) + return -EINVAL; var->transp.offset = 0; var->transp.length = 0; @@ -1028,6 +1029,7 @@ static struct fb_ops nvidia_fb_ops = { .owner = THIS_MODULE, .fb_open = nvidiafb_open, .fb_release = nvidiafb_release, + __FB_DEFAULT_IOMEM_OPS_RDWR, .fb_check_var = nvidiafb_check_var, .fb_set_par = nvidiafb_set_par, .fb_setcolreg = nvidiafb_setcolreg, @@ -1038,12 +1040,12 @@ static struct fb_ops nvidia_fb_ops = { .fb_imageblit = nvidiafb_imageblit, .fb_cursor = nvidiafb_cursor, .fb_sync = nvidiafb_sync, + __FB_DEFAULT_IOMEM_OPS_MMAP, }; -#ifdef CONFIG_PM -static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t mesg) +static int nvidiafb_suspend_late(struct device *dev, pm_message_t mesg) { - struct fb_info *info = pci_get_drvdata(dev); + struct fb_info *info = dev_get_drvdata(dev); struct nvidia_par *par = info->par; if (mesg.event == PM_EVENT_PRETHAW) @@ -1055,46 +1057,54 @@ static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t mesg) fb_set_suspend(info, 1); nvidiafb_blank(FB_BLANK_POWERDOWN, info); nvidia_write_regs(par, &par->SavedReg); - pci_save_state(dev); - pci_disable_device(dev); - pci_set_power_state(dev, pci_choose_state(dev, mesg)); } - dev->dev.power.power_state = mesg; + dev->power.power_state = mesg; console_unlock(); return 0; } -static int nvidiafb_resume(struct pci_dev *dev) +static int __maybe_unused nvidiafb_suspend(struct device *dev) { - struct fb_info *info = pci_get_drvdata(dev); - struct nvidia_par *par = info->par; + return nvidiafb_suspend_late(dev, PMSG_SUSPEND); +} - console_lock(); - pci_set_power_state(dev, PCI_D0); +static int __maybe_unused nvidiafb_hibernate(struct device *dev) +{ + return nvidiafb_suspend_late(dev, PMSG_HIBERNATE); +} - if (par->pm_state != PM_EVENT_FREEZE) { - pci_restore_state(dev); +static int __maybe_unused nvidiafb_freeze(struct device *dev) +{ + return nvidiafb_suspend_late(dev, PMSG_FREEZE); +} - if (pci_enable_device(dev)) - goto fail; +static int __maybe_unused nvidiafb_resume(struct device *dev) +{ + struct fb_info *info = dev_get_drvdata(dev); + struct nvidia_par *par = info->par; - pci_set_master(dev); - } + console_lock(); par->pm_state = PM_EVENT_ON; nvidiafb_set_par(info); fb_set_suspend (info, 0); nvidiafb_blank(FB_BLANK_UNBLANK, info); -fail: console_unlock(); return 0; } -#else -#define nvidiafb_suspend NULL -#define nvidiafb_resume NULL -#endif + +static const struct dev_pm_ops nvidiafb_pm_ops = { +#ifdef CONFIG_PM_SLEEP + .suspend = nvidiafb_suspend, + .resume = nvidiafb_resume, + .freeze = nvidiafb_freeze, + .thaw = nvidiafb_resume, + .poweroff = nvidiafb_hibernate, + .restore = nvidiafb_resume, +#endif /* CONFIG_PM_SLEEP */ +}; static int nvidia_set_fbinfo(struct fb_info *info) { @@ -1104,8 +1114,8 @@ static int nvidia_set_fbinfo(struct fb_info *info) int lpitch; NVTRACE_ENTER(); - info->flags = FBINFO_DEFAULT - | FBINFO_HWACCEL_IMAGEBLIT + info->flags = + FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_YPAN; @@ -1165,7 +1175,7 @@ static int nvidia_set_fbinfo(struct fb_info *info) info->pixmap.flags = FB_PIXMAP_SYSTEM; if (!hwcur) - info->fbops->fb_cursor = NULL; + nvidia_fb_ops.fb_cursor = NULL; info->var.accel_flags = (!noaccel); @@ -1192,17 +1202,17 @@ static int nvidia_set_fbinfo(struct fb_info *info) return nvidiafb_check_var(&info->var, info); } -static u32 nvidia_get_chipset(struct fb_info *info) +static u32 nvidia_get_chipset(struct pci_dev *pci_dev, + volatile u32 __iomem *REGS) { - struct nvidia_par *par = info->par; - u32 id = (par->pci_dev->vendor << 16) | par->pci_dev->device; + u32 id = (pci_dev->vendor << 16) | pci_dev->device; printk(KERN_INFO PFX "Device ID: %x \n", id); if ((id & 0xfff0) == 0x00f0 || (id & 0xfff0) == 0x02e0) { /* pci-e */ - id = NV_RD32(par->REGS, 0x1800); + id = NV_RD32(REGS, 0x1800); if ((id & 0x0000ffff) == 0x000010DE) id = 0x10DE0000 | (id >> 16); @@ -1215,12 +1225,11 @@ static u32 nvidia_get_chipset(struct fb_info *info) return id; } -static u32 nvidia_get_arch(struct fb_info *info) +static u32 nvidia_get_arch(u32 Chipset) { - struct nvidia_par *par = info->par; u32 arch = 0; - switch (par->Chipset & 0x0ff0) { + switch (Chipset & 0x0ff0) { case 0x0100: /* GeForce 256 */ case 0x0110: /* GeForce2 MX */ case 0x0150: /* GeForce2 */ @@ -1272,13 +1281,45 @@ static int nvidiafb_probe(struct pci_dev *pd, const struct pci_device_id *ent) struct nvidia_par *par; struct fb_info *info; unsigned short cmd; - + int ret; + volatile u32 __iomem *REGS; + int Chipset; + u32 Architecture; NVTRACE_ENTER(); assert(pd != NULL); - info = framebuffer_alloc(sizeof(struct nvidia_par), &pd->dev); + if (pci_enable_device(pd)) { + printk(KERN_ERR PFX "cannot enable PCI device\n"); + return -ENODEV; + } + + /* enable IO and mem if not already done */ + pci_read_config_word(pd, PCI_COMMAND, &cmd); + cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + pci_write_config_word(pd, PCI_COMMAND, cmd); + + nvidiafb_fix.mmio_start = pci_resource_start(pd, 0); + nvidiafb_fix.mmio_len = pci_resource_len(pd, 0); + + REGS = ioremap(nvidiafb_fix.mmio_start, nvidiafb_fix.mmio_len); + if (!REGS) { + printk(KERN_ERR PFX "cannot ioremap MMIO base\n"); + return -ENODEV; + } + Chipset = nvidia_get_chipset(pd, REGS); + Architecture = nvidia_get_arch(Chipset); + if (Architecture == 0) { + printk(KERN_ERR PFX "unknown NV_ARCH\n"); + goto err_out; + } + + ret = aperture_remove_conflicting_pci_devices(pd, "nvidiafb"); + if (ret) + goto err_out; + + info = framebuffer_alloc(sizeof(struct nvidia_par), &pd->dev); if (!info) goto err_out; @@ -1289,11 +1330,6 @@ static int nvidiafb_probe(struct pci_dev *pd, const struct pci_device_id *ent) if (info->pixmap.addr == NULL) goto err_out_kfree; - if (pci_enable_device(pd)) { - printk(KERN_ERR PFX "cannot enable PCI device\n"); - goto err_out_enable; - } - if (pci_request_regions(pd, "nvidiafb")) { printk(KERN_ERR PFX "cannot request PCI regions\n"); goto err_out_enable; @@ -1309,34 +1345,17 @@ static int nvidiafb_probe(struct pci_dev *pd, const struct pci_device_id *ent) par->paneltweak = paneltweak; par->reverse_i2c = reverse_i2c; - /* enable IO and mem if not already done */ - pci_read_config_word(pd, PCI_COMMAND, &cmd); - cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY); - pci_write_config_word(pd, PCI_COMMAND, cmd); - - nvidiafb_fix.mmio_start = pci_resource_start(pd, 0); nvidiafb_fix.smem_start = pci_resource_start(pd, 1); - nvidiafb_fix.mmio_len = pci_resource_len(pd, 0); - - par->REGS = ioremap(nvidiafb_fix.mmio_start, nvidiafb_fix.mmio_len); - if (!par->REGS) { - printk(KERN_ERR PFX "cannot ioremap MMIO base\n"); - goto err_out_free_base0; - } + par->REGS = REGS; - par->Chipset = nvidia_get_chipset(info); - par->Architecture = nvidia_get_arch(info); - - if (par->Architecture == 0) { - printk(KERN_ERR PFX "unknown NV_ARCH\n"); - goto err_out_arch; - } + par->Chipset = Chipset; + par->Architecture = Architecture; sprintf(nvidiafb_fix.id, "NV%x", (pd->device & 0x0ff0) >> 4); if (NVCommonSetup(info)) - goto err_out_arch; + goto err_out_free_base0; par->FbAddress = nvidiafb_fix.smem_start; par->FbMapSize = par->RamAmountKBytes * 1024; @@ -1384,14 +1403,13 @@ static int nvidiafb_probe(struct pci_dev *pd, const struct pci_device_id *ent) pci_set_drvdata(pd, info); - if (backlight) - nvidia_bl_init(par); - if (register_framebuffer(info) < 0) { printk(KERN_ERR PFX "error registering nVidia framebuffer\n"); goto err_out_iounmap_fb; } + if (backlight) + nvidia_bl_init(par); printk(KERN_INFO PFX "PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n", @@ -1406,15 +1424,14 @@ err_out_iounmap_fb: err_out_free_base1: fb_destroy_modedb(info->monspecs.modedb); nvidia_delete_i2c_busses(par); -err_out_arch: - iounmap(par->REGS); - err_out_free_base0: +err_out_free_base0: pci_release_regions(pd); err_out_enable: kfree(info->pixmap.addr); err_out_kfree: framebuffer_release(info); err_out: + iounmap(REGS); return -ENODEV; } @@ -1425,9 +1442,9 @@ static void nvidiafb_remove(struct pci_dev *pd) NVTRACE_ENTER(); + nvidia_bl_exit(par); unregister_framebuffer(info); - nvidia_bl_exit(par); arch_phys_wc_del(par->wc_cookie); iounmap(info->screen_base); fb_destroy_modedb(info->monspecs.modedb); @@ -1468,7 +1485,7 @@ static int nvidiafb_setup(char *options) flatpanel = 1; } else if (!strncmp(this_opt, "hwcur", 5)) { hwcur = 1; - } else if (!strncmp(this_opt, "noaccel", 6)) { + } else if (!strncmp(this_opt, "noaccel", 7)) { noaccel = 1; } else if (!strncmp(this_opt, "noscale", 7)) { noscale = 1; @@ -1495,12 +1512,11 @@ static int nvidiafb_setup(char *options) #endif /* !MODULE */ static struct pci_driver nvidiafb_driver = { - .name = "nvidiafb", - .id_table = nvidiafb_pci_tbl, - .probe = nvidiafb_probe, - .suspend = nvidiafb_suspend, - .resume = nvidiafb_resume, - .remove = nvidiafb_remove, + .name = "nvidiafb", + .id_table = nvidiafb_pci_tbl, + .probe = nvidiafb_probe, + .driver.pm = &nvidiafb_pm_ops, + .remove = nvidiafb_remove, }; /* ------------------------------------------------------------------------- * @@ -1513,7 +1529,12 @@ static int nvidiafb_init(void) { #ifndef MODULE char *option = NULL; +#endif + if (fb_modesetting_disabled("nvidiafb")) + return -ENODEV; + +#ifndef MODULE if (fb_get_options("nvidiafb", &option)) return -ENODEV; nvidiafb_setup(option); @@ -1548,7 +1569,7 @@ MODULE_PARM_DESC(noaccel, "(default=0)"); module_param(noscale, int, 0); MODULE_PARM_DESC(noscale, - "Disables screen scaleing. (0 or 1=disable) " + "Disables screen scaling. (0 or 1=disable) " "(default=0, do scaling)"); module_param(paneltweak, int, 0); MODULE_PARM_DESC(paneltweak, |
