From a683b14df8f4320d0ef6cac93a6d9806173bf339 Mon Sep 17 00:00:00 2001 From: eric miao Date: Mon, 3 Mar 2008 09:44:25 +0800 Subject: [ARM] pxa: separate GPIOs and their mode definitions to pxa2xx-gpio.h two reasons: 1. GPIO namings and their mode definitions are conceptually not part of the PXA register definitions 2. this is actually a temporary move in the transition of PXA2xx to use MFP-alike APIs (as what PXA3xx is now doing), so that legacy code will still work and new code can be added in step by step Signed-off-by: eric miao Signed-off-by: Russell King --- drivers/video/pxafb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/video') diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 97facb121c7..757651954e6 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3-70-g09d2 From 4ee36dc08e5c4d16d078f59acd6d9d536f9718dd Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 2 Apr 2008 10:54:07 -0700 Subject: xen pvfb: Para-virtual framebuffer, keyboard and pointer driver This is a pair of Xen para-virtual frontend device drivers: drivers/video/xen-fbfront.c provides a framebuffer, and drivers/input/xen-kbdfront provides keyboard and mouse. The backends run in dom0 user space. The two drivers are not in two separate patches, because the intermediate step (one driver, not the other) is somewhat problematic: the backend in dom0 needs both drivers, and will refuse to complete device initialization unless they're both present. Signed-off-by: Markus Armbruster Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- drivers/input/Kconfig | 9 + drivers/input/Makefile | 2 + drivers/input/xen-kbdfront.c | 340 ++++++++++++++++++++++++ drivers/video/Kconfig | 14 + drivers/video/Makefile | 1 + drivers/video/xen-fbfront.c | 550 +++++++++++++++++++++++++++++++++++++++ include/xen/interface/io/fbif.h | 124 +++++++++ include/xen/interface/io/kbdif.h | 114 ++++++++ 8 files changed, 1154 insertions(+) create mode 100644 drivers/input/xen-kbdfront.c create mode 100644 drivers/video/xen-fbfront.c create mode 100644 include/xen/interface/io/fbif.h create mode 100644 include/xen/interface/io/kbdif.h (limited to 'drivers/video') diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 9dea14db724..5f9d860925a 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -149,6 +149,15 @@ config INPUT_APMPOWER To compile this driver as a module, choose M here: the module will be called apm-power. +config XEN_KBDDEV_FRONTEND + tristate "Xen virtual keyboard and mouse support" + depends on XEN_FBDEV_FRONTEND + default y + help + This driver implements the front-end of the Xen virtual + keyboard and mouse device driver. It communicates with a back-end + in another domain. + comment "Input Device Drivers" source "drivers/input/keyboard/Kconfig" diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 2ae87b19caa..98c4f9a7787 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -23,3 +23,5 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ obj-$(CONFIG_INPUT_MISC) += misc/ obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o + +obj-$(CONFIG_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c new file mode 100644 index 00000000000..0f47f4697cd --- /dev/null +++ b/drivers/input/xen-kbdfront.c @@ -0,0 +1,340 @@ +/* + * Xen para-virtual input device + * + * Copyright (C) 2005 Anthony Liguori + * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster + * + * Based on linux/drivers/input/mouse/sermouse.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +/* + * TODO: + * + * Switch to grant tables together with xen-fbfront.c. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct xenkbd_info { + struct input_dev *kbd; + struct input_dev *ptr; + struct xenkbd_page *page; + int irq; + struct xenbus_device *xbdev; + char phys[32]; +}; + +static int xenkbd_remove(struct xenbus_device *); +static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *); +static void xenkbd_disconnect_backend(struct xenkbd_info *); + +/* + * Note: if you need to send out events, see xenfb_do_update() for how + * to do that. + */ + +static irqreturn_t input_handler(int rq, void *dev_id) +{ + struct xenkbd_info *info = dev_id; + struct xenkbd_page *page = info->page; + __u32 cons, prod; + + prod = page->in_prod; + if (prod == page->in_cons) + return IRQ_HANDLED; + rmb(); /* ensure we see ring contents up to prod */ + for (cons = page->in_cons; cons != prod; cons++) { + union xenkbd_in_event *event; + struct input_dev *dev; + event = &XENKBD_IN_RING_REF(page, cons); + + dev = info->ptr; + switch (event->type) { + case XENKBD_TYPE_MOTION: + input_report_rel(dev, REL_X, event->motion.rel_x); + input_report_rel(dev, REL_Y, event->motion.rel_y); + break; + case XENKBD_TYPE_KEY: + dev = NULL; + if (test_bit(event->key.keycode, info->kbd->keybit)) + dev = info->kbd; + if (test_bit(event->key.keycode, info->ptr->keybit)) + dev = info->ptr; + if (dev) + input_report_key(dev, event->key.keycode, + event->key.pressed); + else + printk(KERN_WARNING + "xenkbd: unhandled keycode 0x%x\n", + event->key.keycode); + break; + case XENKBD_TYPE_POS: + input_report_abs(dev, ABS_X, event->pos.abs_x); + input_report_abs(dev, ABS_Y, event->pos.abs_y); + break; + } + if (dev) + input_sync(dev); + } + mb(); /* ensure we got ring contents */ + page->in_cons = cons; + notify_remote_via_irq(info->irq); + + return IRQ_HANDLED; +} + +static int __devinit xenkbd_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + int ret, i; + struct xenkbd_info *info; + struct input_dev *kbd, *ptr; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); + return -ENOMEM; + } + dev->dev.driver_data = info; + info->xbdev = dev; + info->irq = -1; + snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename); + + info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); + if (!info->page) + goto error_nomem; + + /* keyboard */ + kbd = input_allocate_device(); + if (!kbd) + goto error_nomem; + kbd->name = "Xen Virtual Keyboard"; + kbd->phys = info->phys; + kbd->id.bustype = BUS_PCI; + kbd->id.vendor = 0x5853; + kbd->id.product = 0xffff; + kbd->evbit[0] = BIT(EV_KEY); + for (i = KEY_ESC; i < KEY_UNKNOWN; i++) + set_bit(i, kbd->keybit); + for (i = KEY_OK; i < KEY_MAX; i++) + set_bit(i, kbd->keybit); + + ret = input_register_device(kbd); + if (ret) { + input_free_device(kbd); + xenbus_dev_fatal(dev, ret, "input_register_device(kbd)"); + goto error; + } + info->kbd = kbd; + + /* pointing device */ + ptr = input_allocate_device(); + if (!ptr) + goto error_nomem; + ptr->name = "Xen Virtual Pointer"; + ptr->phys = info->phys; + ptr->id.bustype = BUS_PCI; + ptr->id.vendor = 0x5853; + ptr->id.product = 0xfffe; + ptr->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); + for (i = BTN_LEFT; i <= BTN_TASK; i++) + set_bit(i, ptr->keybit); + ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y); + input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0); + input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0); + + ret = input_register_device(ptr); + if (ret) { + input_free_device(ptr); + xenbus_dev_fatal(dev, ret, "input_register_device(ptr)"); + goto error; + } + info->ptr = ptr; + + ret = xenkbd_connect_backend(dev, info); + if (ret < 0) + goto error; + + return 0; + + error_nomem: + ret = -ENOMEM; + xenbus_dev_fatal(dev, ret, "allocating device memory"); + error: + xenkbd_remove(dev); + return ret; +} + +static int xenkbd_resume(struct xenbus_device *dev) +{ + struct xenkbd_info *info = dev->dev.driver_data; + + xenkbd_disconnect_backend(info); + memset(info->page, 0, PAGE_SIZE); + return xenkbd_connect_backend(dev, info); +} + +static int xenkbd_remove(struct xenbus_device *dev) +{ + struct xenkbd_info *info = dev->dev.driver_data; + + xenkbd_disconnect_backend(info); + if (info->kbd) + input_unregister_device(info->kbd); + if (info->ptr) + input_unregister_device(info->ptr); + free_page((unsigned long)info->page); + kfree(info); + return 0; +} + +static int xenkbd_connect_backend(struct xenbus_device *dev, + struct xenkbd_info *info) +{ + int ret, evtchn; + struct xenbus_transaction xbt; + + ret = xenbus_alloc_evtchn(dev, &evtchn); + if (ret) + return ret; + ret = bind_evtchn_to_irqhandler(evtchn, input_handler, + 0, dev->devicetype, info); + if (ret < 0) { + xenbus_free_evtchn(dev, evtchn); + xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); + return ret; + } + info->irq = ret; + + again: + ret = xenbus_transaction_start(&xbt); + if (ret) { + xenbus_dev_fatal(dev, ret, "starting transaction"); + return ret; + } + ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", + virt_to_mfn(info->page)); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", + evtchn); + if (ret) + goto error_xenbus; + ret = xenbus_transaction_end(xbt, 0); + if (ret) { + if (ret == -EAGAIN) + goto again; + xenbus_dev_fatal(dev, ret, "completing transaction"); + return ret; + } + + xenbus_switch_state(dev, XenbusStateInitialised); + return 0; + + error_xenbus: + xenbus_transaction_end(xbt, 1); + xenbus_dev_fatal(dev, ret, "writing xenstore"); + return ret; +} + +static void xenkbd_disconnect_backend(struct xenkbd_info *info) +{ + if (info->irq >= 0) + unbind_from_irqhandler(info->irq, info); + info->irq = -1; +} + +static void xenkbd_backend_changed(struct xenbus_device *dev, + enum xenbus_state backend_state) +{ + struct xenkbd_info *info = dev->dev.driver_data; + int ret, val; + + switch (backend_state) { + case XenbusStateInitialising: + case XenbusStateInitialised: + case XenbusStateUnknown: + case XenbusStateClosed: + break; + + case XenbusStateInitWait: +InitWait: + ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "feature-abs-pointer", "%d", &val); + if (ret < 0) + val = 0; + if (val) { + ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, + "request-abs-pointer", "1"); + if (ret) + printk(KERN_WARNING + "xenkbd: can't request abs-pointer"); + } + xenbus_switch_state(dev, XenbusStateConnected); + break; + + case XenbusStateConnected: + /* + * Work around xenbus race condition: If backend goes + * through InitWait to Connected fast enough, we can + * get Connected twice here. + */ + if (dev->state != XenbusStateConnected) + goto InitWait; /* no InitWait seen yet, fudge it */ + break; + + case XenbusStateClosing: + xenbus_frontend_closed(dev); + break; + } +} + +static struct xenbus_device_id xenkbd_ids[] = { + { "vkbd" }, + { "" } +}; + +static struct xenbus_driver xenkbd = { + .name = "vkbd", + .owner = THIS_MODULE, + .ids = xenkbd_ids, + .probe = xenkbd_probe, + .remove = xenkbd_remove, + .resume = xenkbd_resume, + .otherend_changed = xenkbd_backend_changed, +}; + +static int __init xenkbd_init(void) +{ + if (!is_running_on_xen()) + return -ENODEV; + + /* Nothing to do if running in dom0. */ + if (is_initial_xendomain()) + return -ENODEV; + + return xenbus_register_frontend(&xenkbd); +} + +static void __exit xenkbd_cleanup(void) +{ + xenbus_unregister_driver(&xenkbd); +} + +module_init(xenkbd_init); +module_exit(xenkbd_cleanup); + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 1bd5fb30237..e3dc8f8d0c3 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1930,6 +1930,20 @@ config FB_VIRTUAL If unsure, say N. +config XEN_FBDEV_FRONTEND + tristate "Xen virtual frame buffer support" + depends on FB && XEN + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select FB_SYS_FOPS + select FB_DEFERRED_IO + default y + help + This driver implements the front-end of the Xen virtual + frame buffer driver. It communicates with a back-end + in another domain. + source "drivers/video/omap/Kconfig" source "drivers/video/backlight/Kconfig" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 11c0e5e05f2..f172b9b7331 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -114,6 +114,7 @@ obj-$(CONFIG_FB_PS3) += ps3fb.o obj-$(CONFIG_FB_SM501) += sm501fb.o obj-$(CONFIG_FB_XILINX) += xilinxfb.o obj-$(CONFIG_FB_OMAP) += omap/ +obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o # Platform or fallback drivers go here obj-$(CONFIG_FB_UVESA) += uvesafb.o diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c new file mode 100644 index 00000000000..619a6f8d65a --- /dev/null +++ b/drivers/video/xen-fbfront.c @@ -0,0 +1,550 @@ +/* + * Xen para-virtual frame buffer device + * + * Copyright (C) 2005-2006 Anthony Liguori + * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster + * + * Based on linux/drivers/video/q40fb.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +/* + * TODO: + * + * Switch to grant tables when they become capable of dealing with the + * frame buffer. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct xenfb_info { + unsigned char *fb; + struct fb_info *fb_info; + int x1, y1, x2, y2; /* dirty rectangle, + protected by dirty_lock */ + spinlock_t dirty_lock; + int nr_pages; + int irq; + struct xenfb_page *page; + unsigned long *mfns; + int update_wanted; /* XENFB_TYPE_UPDATE wanted */ + + struct xenbus_device *xbdev; +}; + +static u32 xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8; + +static int xenfb_remove(struct xenbus_device *); +static void xenfb_init_shared_page(struct xenfb_info *); +static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *); +static void xenfb_disconnect_backend(struct xenfb_info *); + +static void xenfb_do_update(struct xenfb_info *info, + int x, int y, int w, int h) +{ + union xenfb_out_event event; + u32 prod; + + event.type = XENFB_TYPE_UPDATE; + event.update.x = x; + event.update.y = y; + event.update.width = w; + event.update.height = h; + + prod = info->page->out_prod; + /* caller ensures !xenfb_queue_full() */ + mb(); /* ensure ring space available */ + XENFB_OUT_RING_REF(info->page, prod) = event; + wmb(); /* ensure ring contents visible */ + info->page->out_prod = prod + 1; + + notify_remote_via_irq(info->irq); +} + +static int xenfb_queue_full(struct xenfb_info *info) +{ + u32 cons, prod; + + prod = info->page->out_prod; + cons = info->page->out_cons; + return prod - cons == XENFB_OUT_RING_LEN; +} + +static void xenfb_refresh(struct xenfb_info *info, + int x1, int y1, int w, int h) +{ + unsigned long flags; + int y2 = y1 + h - 1; + int x2 = x1 + w - 1; + + if (!info->update_wanted) + return; + + spin_lock_irqsave(&info->dirty_lock, flags); + + /* Combine with dirty rectangle: */ + if (info->y1 < y1) + y1 = info->y1; + if (info->y2 > y2) + y2 = info->y2; + if (info->x1 < x1) + x1 = info->x1; + if (info->x2 > x2) + x2 = info->x2; + + if (xenfb_queue_full(info)) { + /* Can't send right now, stash it in the dirty rectangle */ + info->x1 = x1; + info->x2 = x2; + info->y1 = y1; + info->y2 = y2; + spin_unlock_irqrestore(&info->dirty_lock, flags); + return; + } + + /* Clear dirty rectangle: */ + info->x1 = info->y1 = INT_MAX; + info->x2 = info->y2 = 0; + + spin_unlock_irqrestore(&info->dirty_lock, flags); + + if (x1 <= x2 && y1 <= y2) + xenfb_do_update(info, x1, y1, x2 - x1 + 1, y2 - y1 + 1); +} + +static void xenfb_deferred_io(struct fb_info *fb_info, + struct list_head *pagelist) +{ + struct xenfb_info *info = fb_info->par; + struct page *page; + unsigned long beg, end; + int y1, y2, miny, maxy; + + miny = INT_MAX; + maxy = 0; + list_for_each_entry(page, pagelist, lru) { + beg = page->index << PAGE_SHIFT; + end = beg + PAGE_SIZE - 1; + y1 = beg / fb_info->fix.line_length; + y2 = end / fb_info->fix.line_length; + if (y2 >= fb_info->var.yres) + y2 = fb_info->var.yres - 1; + if (miny > y1) + miny = y1; + if (maxy < y2) + maxy = y2; + } + xenfb_refresh(info, 0, miny, fb_info->var.xres, maxy - miny + 1); +} + +static struct fb_deferred_io xenfb_defio = { + .delay = HZ / 20, + .deferred_io = xenfb_deferred_io, +}; + +static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + u32 v; + + if (regno > info->cmap.len) + return 1; + +#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16) + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + transp = CNVT_TOHW(transp, info->var.transp.length); +#undef CNVT_TOHW + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + + switch (info->var.bits_per_pixel) { + case 16: + case 24: + case 32: + ((u32 *)info->pseudo_palette)[regno] = v; + break; + } + + return 0; +} + +static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) +{ + struct xenfb_info *info = p->par; + + sys_fillrect(p, rect); + xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height); +} + +static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image) +{ + struct xenfb_info *info = p->par; + + sys_imageblit(p, image); + xenfb_refresh(info, image->dx, image->dy, image->width, image->height); +} + +static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) +{ + struct xenfb_info *info = p->par; + + sys_copyarea(p, area); + xenfb_refresh(info, area->dx, area->dy, area->width, area->height); +} + +static ssize_t xenfb_write(struct fb_info *p, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct xenfb_info *info = p->par; + ssize_t res; + + res = fb_sys_write(p, buf, count, ppos); + xenfb_refresh(info, 0, 0, info->page->width, info->page->height); + return res; +} + +static struct fb_ops xenfb_fb_ops = { + .owner = THIS_MODULE, + .fb_read = fb_sys_read, + .fb_write = xenfb_write, + .fb_setcolreg = xenfb_setcolreg, + .fb_fillrect = xenfb_fillrect, + .fb_copyarea = xenfb_copyarea, + .fb_imageblit = xenfb_imageblit, +}; + +static irqreturn_t xenfb_event_handler(int rq, void *dev_id) +{ + /* + * No in events recognized, simply ignore them all. + * If you need to recognize some, see xen-kbdfront's + * input_handler() for how to do that. + */ + struct xenfb_info *info = dev_id; + struct xenfb_page *page = info->page; + + if (page->in_cons != page->in_prod) { + info->page->in_cons = info->page->in_prod; + notify_remote_via_irq(info->irq); + } + + /* Flush dirty rectangle: */ + xenfb_refresh(info, INT_MAX, INT_MAX, -INT_MAX, -INT_MAX); + + return IRQ_HANDLED; +} + +static int __devinit xenfb_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + struct xenfb_info *info; + struct fb_info *fb_info; + int ret; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); + return -ENOMEM; + } + dev->dev.driver_data = info; + info->xbdev = dev; + info->irq = -1; + info->x1 = info->y1 = INT_MAX; + spin_lock_init(&info->dirty_lock); + + info->fb = vmalloc(xenfb_mem_len); + if (info->fb == NULL) + goto error_nomem; + memset(info->fb, 0, xenfb_mem_len); + + info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT; + + info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages); + if (!info->mfns) + goto error_nomem; + + /* set up shared page */ + info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); + if (!info->page) + goto error_nomem; + + xenfb_init_shared_page(info); + + /* abusing framebuffer_alloc() to allocate pseudo_palette */ + fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL); + if (fb_info == NULL) + goto error_nomem; + + /* complete the abuse: */ + fb_info->pseudo_palette = fb_info->par; + fb_info->par = info; + + fb_info->screen_base = info->fb; + + fb_info->fbops = &xenfb_fb_ops; + fb_info->var.xres_virtual = fb_info->var.xres = info->page->width; + fb_info->var.yres_virtual = fb_info->var.yres = info->page->height; + fb_info->var.bits_per_pixel = info->page->depth; + + fb_info->var.red = (struct fb_bitfield){16, 8, 0}; + fb_info->var.green = (struct fb_bitfield){8, 8, 0}; + fb_info->var.blue = (struct fb_bitfield){0, 8, 0}; + + fb_info->var.activate = FB_ACTIVATE_NOW; + fb_info->var.height = -1; + fb_info->var.width = -1; + fb_info->var.vmode = FB_VMODE_NONINTERLACED; + + fb_info->fix.visual = FB_VISUAL_TRUECOLOR; + fb_info->fix.line_length = info->page->line_length; + fb_info->fix.smem_start = 0; + fb_info->fix.smem_len = xenfb_mem_len; + strcpy(fb_info->fix.id, "xen"); + fb_info->fix.type = FB_TYPE_PACKED_PIXELS; + fb_info->fix.accel = FB_ACCEL_NONE; + + fb_info->flags = FBINFO_FLAG_DEFAULT; + + ret = fb_alloc_cmap(&fb_info->cmap, 256, 0); + if (ret < 0) { + framebuffer_release(fb_info); + xenbus_dev_fatal(dev, ret, "fb_alloc_cmap"); + goto error; + } + + fb_info->fbdefio = &xenfb_defio; + fb_deferred_io_init(fb_info); + + ret = register_framebuffer(fb_info); + if (ret) { + fb_deferred_io_cleanup(fb_info); + fb_dealloc_cmap(&fb_info->cmap); + framebuffer_release(fb_info); + xenbus_dev_fatal(dev, ret, "register_framebuffer"); + goto error; + } + info->fb_info = fb_info; + + ret = xenfb_connect_backend(dev, info); + if (ret < 0) + goto error; + + return 0; + + error_nomem: + ret = -ENOMEM; + xenbus_dev_fatal(dev, ret, "allocating device memory"); + error: + xenfb_remove(dev); + return ret; +} + +static int xenfb_resume(struct xenbus_device *dev) +{ + struct xenfb_info *info = dev->dev.driver_data; + + xenfb_disconnect_backend(info); + xenfb_init_shared_page(info); + return xenfb_connect_backend(dev, info); +} + +static int xenfb_remove(struct xenbus_device *dev) +{ + struct xenfb_info *info = dev->dev.driver_data; + + xenfb_disconnect_backend(info); + if (info->fb_info) { + fb_deferred_io_cleanup(info->fb_info); + unregister_framebuffer(info->fb_info); + fb_dealloc_cmap(&info->fb_info->cmap); + framebuffer_release(info->fb_info); + } + free_page((unsigned long)info->page); + vfree(info->mfns); + vfree(info->fb); + kfree(info); + + return 0; +} + +static unsigned long vmalloc_to_mfn(void *address) +{ + return pfn_to_mfn(vmalloc_to_pfn(address)); +} + +static void xenfb_init_shared_page(struct xenfb_info *info) +{ + int i; + + for (i = 0; i < info->nr_pages; i++) + info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); + + info->page->pd[0] = vmalloc_to_mfn(info->mfns); + info->page->pd[1] = 0; + info->page->width = XENFB_WIDTH; + info->page->height = XENFB_HEIGHT; + info->page->depth = XENFB_DEPTH; + info->page->line_length = (info->page->depth / 8) * info->page->width; + info->page->mem_length = xenfb_mem_len; + info->page->in_cons = info->page->in_prod = 0; + info->page->out_cons = info->page->out_prod = 0; +} + +static int xenfb_connect_backend(struct xenbus_device *dev, + struct xenfb_info *info) +{ + int ret, evtchn; + struct xenbus_transaction xbt; + + ret = xenbus_alloc_evtchn(dev, &evtchn); + if (ret) + return ret; + ret = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler, + 0, dev->devicetype, info); + if (ret < 0) { + xenbus_free_evtchn(dev, evtchn); + xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); + return ret; + } + info->irq = ret; + + again: + ret = xenbus_transaction_start(&xbt); + if (ret) { + xenbus_dev_fatal(dev, ret, "starting transaction"); + return ret; + } + ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", + virt_to_mfn(info->page)); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", + evtchn); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "protocol", "%s", + XEN_IO_PROTO_ABI_NATIVE); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1"); + if (ret) + goto error_xenbus; + ret = xenbus_transaction_end(xbt, 0); + if (ret) { + if (ret == -EAGAIN) + goto again; + xenbus_dev_fatal(dev, ret, "completing transaction"); + return ret; + } + + xenbus_switch_state(dev, XenbusStateInitialised); + return 0; + + error_xenbus: + xenbus_transaction_end(xbt, 1); + xenbus_dev_fatal(dev, ret, "writing xenstore"); + return ret; +} + +static void xenfb_disconnect_backend(struct xenfb_info *info) +{ + if (info->irq >= 0) + unbind_from_irqhandler(info->irq, info); + info->irq = -1; +} + +static void xenfb_backend_changed(struct xenbus_device *dev, + enum xenbus_state backend_state) +{ + struct xenfb_info *info = dev->dev.driver_data; + int val; + + switch (backend_state) { + case XenbusStateInitialising: + case XenbusStateInitialised: + case XenbusStateUnknown: + case XenbusStateClosed: + break; + + case XenbusStateInitWait: +InitWait: + xenbus_switch_state(dev, XenbusStateConnected); + break; + + case XenbusStateConnected: + /* + * Work around xenbus race condition: If backend goes + * through InitWait to Connected fast enough, we can + * get Connected twice here. + */ + if (dev->state != XenbusStateConnected) + goto InitWait; /* no InitWait seen yet, fudge it */ + + if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "request-update", "%d", &val) < 0) + val = 0; + if (val) + info->update_wanted = 1; + break; + + case XenbusStateClosing: + xenbus_frontend_closed(dev); + break; + } +} + +static struct xenbus_device_id xenfb_ids[] = { + { "vfb" }, + { "" } +}; + +static struct xenbus_driver xenfb = { + .name = "vfb", + .owner = THIS_MODULE, + .ids = xenfb_ids, + .probe = xenfb_probe, + .remove = xenfb_remove, + .resume = xenfb_resume, + .otherend_changed = xenfb_backend_changed, +}; + +static int __init xenfb_init(void) +{ + if (!is_running_on_xen()) + return -ENODEV; + + /* Nothing to do if running in dom0. */ + if (is_initial_xendomain()) + return -ENODEV; + + return xenbus_register_frontend(&xenfb); +} + +static void __exit xenfb_cleanup(void) +{ + xenbus_unregister_driver(&xenfb); +} + +module_init(xenfb_init); +module_exit(xenfb_cleanup); + +MODULE_LICENSE("GPL"); diff --git a/include/xen/interface/io/fbif.h b/include/xen/interface/io/fbif.h new file mode 100644 index 00000000000..5a934dd7796 --- /dev/null +++ b/include/xen/interface/io/fbif.h @@ -0,0 +1,124 @@ +/* + * fbif.h -- Xen virtual frame buffer device + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (C) 2005 Anthony Liguori + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster + */ + +#ifndef __XEN_PUBLIC_IO_FBIF_H__ +#define __XEN_PUBLIC_IO_FBIF_H__ + +/* Out events (frontend -> backend) */ + +/* + * Out events may be sent only when requested by backend, and receipt + * of an unknown out event is an error. + */ + +/* Event type 1 currently not used */ +/* + * Framebuffer update notification event + * Capable frontend sets feature-update in xenstore. + * Backend requests it by setting request-update in xenstore. + */ +#define XENFB_TYPE_UPDATE 2 + +struct xenfb_update { + uint8_t type; /* XENFB_TYPE_UPDATE */ + int32_t x; /* source x */ + int32_t y; /* source y */ + int32_t width; /* rect width */ + int32_t height; /* rect height */ +}; + +#define XENFB_OUT_EVENT_SIZE 40 + +union xenfb_out_event { + uint8_t type; + struct xenfb_update update; + char pad[XENFB_OUT_EVENT_SIZE]; +}; + +/* In events (backend -> frontend) */ + +/* + * Frontends should ignore unknown in events. + * No in events currently defined. + */ + +#define XENFB_IN_EVENT_SIZE 40 + +union xenfb_in_event { + uint8_t type; + char pad[XENFB_IN_EVENT_SIZE]; +}; + +/* shared page */ + +#define XENFB_IN_RING_SIZE 1024 +#define XENFB_IN_RING_LEN (XENFB_IN_RING_SIZE / XENFB_IN_EVENT_SIZE) +#define XENFB_IN_RING_OFFS 1024 +#define XENFB_IN_RING(page) \ + ((union xenfb_in_event *)((char *)(page) + XENFB_IN_RING_OFFS)) +#define XENFB_IN_RING_REF(page, idx) \ + (XENFB_IN_RING((page))[(idx) % XENFB_IN_RING_LEN]) + +#define XENFB_OUT_RING_SIZE 2048 +#define XENFB_OUT_RING_LEN (XENFB_OUT_RING_SIZE / XENFB_OUT_EVENT_SIZE) +#define XENFB_OUT_RING_OFFS (XENFB_IN_RING_OFFS + XENFB_IN_RING_SIZE) +#define XENFB_OUT_RING(page) \ + ((union xenfb_out_event *)((char *)(page) + XENFB_OUT_RING_OFFS)) +#define XENFB_OUT_RING_REF(page, idx) \ + (XENFB_OUT_RING((page))[(idx) % XENFB_OUT_RING_LEN]) + +struct xenfb_page { + uint32_t in_cons, in_prod; + uint32_t out_cons, out_prod; + + int32_t width; /* width of the framebuffer (in pixels) */ + int32_t height; /* height of the framebuffer (in pixels) */ + uint32_t line_length; /* length of a row of pixels (in bytes) */ + uint32_t mem_length; /* length of the framebuffer (in bytes) */ + uint8_t depth; /* depth of a pixel (in bits) */ + + /* + * Framebuffer page directory + * + * Each directory page holds PAGE_SIZE / sizeof(*pd) + * framebuffer pages, and can thus map up to PAGE_SIZE * + * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and + * sizeof(unsigned long) == 4, that's 4 Megs. Two directory + * pages should be enough for a while. + */ + unsigned long pd[2]; +}; + +/* + * Wart: xenkbd needs to know resolution. Put it here until a better + * solution is found, but don't leak it to the backend. + */ +#ifdef __KERNEL__ +#define XENFB_WIDTH 800 +#define XENFB_HEIGHT 600 +#define XENFB_DEPTH 32 +#endif + +#endif diff --git a/include/xen/interface/io/kbdif.h b/include/xen/interface/io/kbdif.h new file mode 100644 index 00000000000..fb97f4284ff --- /dev/null +++ b/include/xen/interface/io/kbdif.h @@ -0,0 +1,114 @@ +/* + * kbdif.h -- Xen virtual keyboard/mouse + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (C) 2005 Anthony Liguori + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster + */ + +#ifndef __XEN_PUBLIC_IO_KBDIF_H__ +#define __XEN_PUBLIC_IO_KBDIF_H__ + +/* In events (backend -> frontend) */ + +/* + * Frontends should ignore unknown in events. + */ + +/* Pointer movement event */ +#define XENKBD_TYPE_MOTION 1 +/* Event type 2 currently not used */ +/* Key event (includes pointer buttons) */ +#define XENKBD_TYPE_KEY 3 +/* + * Pointer position event + * Capable backend sets feature-abs-pointer in xenstore. + * Frontend requests ot instead of XENKBD_TYPE_MOTION by setting + * request-abs-update in xenstore. + */ +#define XENKBD_TYPE_POS 4 + +struct xenkbd_motion { + uint8_t type; /* XENKBD_TYPE_MOTION */ + int32_t rel_x; /* relative X motion */ + int32_t rel_y; /* relative Y motion */ +}; + +struct xenkbd_key { + uint8_t type; /* XENKBD_TYPE_KEY */ + uint8_t pressed; /* 1 if pressed; 0 otherwise */ + uint32_t keycode; /* KEY_* from linux/input.h */ +}; + +struct xenkbd_position { + uint8_t type; /* XENKBD_TYPE_POS */ + int32_t abs_x; /* absolute X position (in FB pixels) */ + int32_t abs_y; /* absolute Y position (in FB pixels) */ +}; + +#define XENKBD_IN_EVENT_SIZE 40 + +union xenkbd_in_event { + uint8_t type; + struct xenkbd_motion motion; + struct xenkbd_key key; + struct xenkbd_position pos; + char pad[XENKBD_IN_EVENT_SIZE]; +}; + +/* Out events (frontend -> backend) */ + +/* + * Out events may be sent only when requested by backend, and receipt + * of an unknown out event is an error. + * No out events currently defined. + */ + +#define XENKBD_OUT_EVENT_SIZE 40 + +union xenkbd_out_event { + uint8_t type; + char pad[XENKBD_OUT_EVENT_SIZE]; +}; + +/* shared page */ + +#define XENKBD_IN_RING_SIZE 2048 +#define XENKBD_IN_RING_LEN (XENKBD_IN_RING_SIZE / XENKBD_IN_EVENT_SIZE) +#define XENKBD_IN_RING_OFFS 1024 +#define XENKBD_IN_RING(page) \ + ((union xenkbd_in_event *)((char *)(page) + XENKBD_IN_RING_OFFS)) +#define XENKBD_IN_RING_REF(page, idx) \ + (XENKBD_IN_RING((page))[(idx) % XENKBD_IN_RING_LEN]) + +#define XENKBD_OUT_RING_SIZE 1024 +#define XENKBD_OUT_RING_LEN (XENKBD_OUT_RING_SIZE / XENKBD_OUT_EVENT_SIZE) +#define XENKBD_OUT_RING_OFFS (XENKBD_IN_RING_OFFS + XENKBD_IN_RING_SIZE) +#define XENKBD_OUT_RING(page) \ + ((union xenkbd_out_event *)((char *)(page) + XENKBD_OUT_RING_OFFS)) +#define XENKBD_OUT_RING_REF(page, idx) \ + (XENKBD_OUT_RING((page))[(idx) % XENKBD_OUT_RING_LEN]) + +struct xenkbd_page { + uint32_t in_cons, in_prod; + uint32_t out_cons, out_prod; +}; + +#endif -- cgit v1.2.3-70-g09d2 From 403ae52ac047eb339f2b7e8cdf93a3b8077914db Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sat, 26 Apr 2008 22:29:43 -0700 Subject: sparc: fix drivers/video/tcx.c warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix compile warning: CC drivers/video/tcx.o drivers/video/tcx.c: In function ‘tcx_init_one’: drivers/video/tcx.c:477: warning: format ‘%lx’ expects type ‘long unsigned int’, but argument 4 has type ‘resource_size_t’ This was the only sparc driver to use the resource directly in the printk so I changed it to physbase like the other drivers. Boot tested on SS4. Signed-off-by: Robert Reif Signed-off-by: David S. Miller --- drivers/video/tcx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index e5a9ddb3c8b..fd94dfbab44 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -419,7 +419,7 @@ static int __devinit tcx_init_one(struct of_device *op) par->mmap_map[6].size = SBUS_MMAP_EMPTY; } - par->physbase = 0; + par->physbase = op->resource[0].start; par->which_io = op->resource[0].flags & IORESOURCE_BITS; for (i = 0; i < TCX_MMAP_ENTRIES; i++) { @@ -473,7 +473,7 @@ static int __devinit tcx_init_one(struct of_device *op) printk("%s: TCX at %lx:%lx, %s\n", dp->full_name, par->which_io, - op->resource[0].start, + par->physbase, par->lowdepth ? "8-bit only" : "24-bit depth"); return 0; -- cgit v1.2.3-70-g09d2 From 2556bf1212c768f567401257582681aa117af4a9 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sun, 27 Apr 2008 15:16:59 -0700 Subject: sparc: bw2.c fix bw2_exit Fix void function bw2_exit returning value. Signed-off-by: Robert Reif Signed-off-by: David S. Miller --- drivers/video/bw2.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index 833b10c8406..bb0bb553284 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -399,10 +399,9 @@ static int __init bw2_init(void) static void __exit bw2_exit(void) { - return of_unregister_driver(&bw2_driver); + of_unregister_driver(&bw2_driver); } - module_init(bw2_init); module_exit(bw2_exit); -- cgit v1.2.3-70-g09d2 From 544330009bc5b879129593236aab29e458ec9fe4 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sun, 27 Apr 2008 15:17:23 -0700 Subject: sparc: cg14.c make cg14_init and cg15_exit static Make cg14_init and cg14_exit static. Signed-off-by: Robert Reif Signed-off-by: David S. Miller --- drivers/video/cg14.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index fdc9f43ec30..359734e9bc1 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -605,7 +605,7 @@ static struct of_platform_driver cg14_driver = { .remove = __devexit_p(cg14_remove), }; -int __init cg14_init(void) +static int __init cg14_init(void) { if (fb_get_options("cg14fb", NULL)) return -ENODEV; @@ -613,7 +613,7 @@ int __init cg14_init(void) return of_register_driver(&cg14_driver, &of_bus_type); } -void __exit cg14_exit(void) +static void __exit cg14_exit(void) { of_unregister_driver(&cg14_driver); } -- cgit v1.2.3-70-g09d2 From a2fb0ce7aeae9c38146df9c2d9b763e5981a0683 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sun, 27 Apr 2008 15:17:49 -0700 Subject: sparc: ffb.c make ffb_init and ffb_exit static Make ffb_init and ffb_exit static. Remove unnecessary function prototype. Signed-off-by: Robert Reif Signed-off-by: David S. Miller --- drivers/video/ffb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c index d7e24889650..02a61147799 100644 --- a/drivers/video/ffb.c +++ b/drivers/video/ffb.c @@ -32,7 +32,6 @@ static int ffb_setcolreg(unsigned, unsigned, unsigned, unsigned, unsigned, struct fb_info *); static int ffb_blank(int, struct fb_info *); -static void ffb_init_fix(struct fb_info *); static void ffb_imageblit(struct fb_info *, const struct fb_image *); static void ffb_fillrect(struct fb_info *, const struct fb_fillrect *); @@ -1062,7 +1061,7 @@ static struct of_platform_driver ffb_driver = { .remove = __devexit_p(ffb_remove), }; -int __init ffb_init(void) +static int __init ffb_init(void) { if (fb_get_options("ffb", NULL)) return -ENODEV; @@ -1070,7 +1069,7 @@ int __init ffb_init(void) return of_register_driver(&ffb_driver, &of_bus_type); } -void __exit ffb_exit(void) +static void __exit ffb_exit(void) { of_unregister_driver(&ffb_driver); } -- cgit v1.2.3-70-g09d2 From f36861d550e6f1a1a7a851b88938f52bdaed7682 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sun, 27 Apr 2008 15:18:12 -0700 Subject: sparc: tcx.c make tcx_init and tcx_exit static Make tcx_init and tcx_exit static. Signed-off-by: Robert Reif Signed-off-by: David S. Miller --- drivers/video/tcx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index fd94dfbab44..7dc33bfe2cb 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -527,7 +527,7 @@ static struct of_platform_driver tcx_driver = { .remove = __devexit_p(tcx_remove), }; -int __init tcx_init(void) +static int __init tcx_init(void) { if (fb_get_options("tcxfb", NULL)) return -ENODEV; @@ -535,7 +535,7 @@ int __init tcx_init(void) return of_register_driver(&tcx_driver, &of_bus_type); } -void __exit tcx_exit(void) +static void __exit tcx_exit(void) { of_unregister_driver(&tcx_driver); } -- cgit v1.2.3-70-g09d2 From 194f1a68b93e959ede6ec363db4714e630bdbb6a Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sun, 27 Apr 2008 15:18:57 -0700 Subject: sparc: video drivers: add facility level Add KERN_ facility level to sparc video drivers. Signed-off-by: Robert Reif Signed-off-by: David S. Miller --- drivers/video/bw2.c | 2 +- drivers/video/cg14.c | 2 +- drivers/video/cg3.c | 2 +- drivers/video/cg6.c | 2 +- drivers/video/ffb.c | 2 +- drivers/video/leo.c | 2 +- drivers/video/p9100.c | 2 +- drivers/video/tcx.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index bb0bb553284..275d9dab0c6 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -339,7 +339,7 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id * dev_set_drvdata(&op->dev, info); - printk("%s: bwtwo at %lx:%lx\n", + printk(KERN_INFO "%s: bwtwo at %lx:%lx\n", dp->full_name, par->which_io, par->physbase); return 0; diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index 359734e9bc1..0db0fecba93 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -556,7 +556,7 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id dev_set_drvdata(&op->dev, info); - printk("%s: cgfourteen at %lx:%lx, %dMB\n", + printk(KERN_INFO "%s: cgfourteen at %lx:%lx, %dMB\n", dp->full_name, par->iospace, par->physbase, par->ramsize >> 20); diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index a5c7fb33152..010ea53978f 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -419,7 +419,7 @@ static int __devinit cg3_probe(struct of_device *op, dev_set_drvdata(&op->dev, info); - printk("%s: cg3 at %lx:%lx\n", + printk(KERN_INFO "%s: cg3 at %lx:%lx\n", dp->full_name, par->which_io, par->physbase); return 0; diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 549891d76ef..fc90db6da65 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -781,7 +781,7 @@ static int __devinit cg6_probe(struct of_device *op, dev_set_drvdata(&op->dev, info); - printk("%s: CGsix [%s] at %lx:%lx\n", + printk(KERN_INFO "%s: CGsix [%s] at %lx:%lx\n", dp->full_name, info->fix.id, par->which_io, par->physbase); diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c index 02a61147799..93dca3e2aa5 100644 --- a/drivers/video/ffb.c +++ b/drivers/video/ffb.c @@ -1000,7 +1000,7 @@ static int __devinit ffb_probe(struct of_device *op, dev_set_drvdata(&op->dev, info); - printk("%s: %s at %016lx, type %d, " + printk(KERN_INFO "%s: %s at %016lx, type %d, " "DAC pnum[%x] rev[%d] manuf_rev[%d]\n", dp->full_name, ((par->flags & FFB_FLAG_AFB) ? "AFB" : "FFB"), diff --git a/drivers/video/leo.c b/drivers/video/leo.c index 45b9a5d55de..f3160fc2979 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c @@ -614,7 +614,7 @@ static int __devinit leo_probe(struct of_device *op, const struct of_device_id * dev_set_drvdata(&op->dev, info); - printk("%s: leo at %lx:%lx\n", + printk(KERN_INFO "%s: leo at %lx:%lx\n", dp->full_name, par->which_io, par->physbase); diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index 58496061142..c95874fe907 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c @@ -310,7 +310,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id dev_set_drvdata(&op->dev, info); - printk("%s: p9100 at %lx:%lx\n", + printk(KERN_INFO "%s: p9100 at %lx:%lx\n", dp->full_name, par->which_io, par->physbase); diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index 7dc33bfe2cb..a7177430577 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -470,7 +470,7 @@ static int __devinit tcx_init_one(struct of_device *op) dev_set_drvdata(&op->dev, info); - printk("%s: TCX at %lx:%lx, %s\n", + printk(KERN_INFO "%s: TCX at %lx:%lx, %s\n", dp->full_name, par->which_io, par->physbase, -- cgit v1.2.3-70-g09d2 From 3c18ddd160d1fcd46d1131d9ad6c594dd8e9af99 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Mon, 28 Apr 2008 02:12:10 -0700 Subject: mm: remove nopage Nothing in the tree uses nopage any more. Remove support for it in the core mm code and documentation (and a few stray references to it in comments). Signed-off-by: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/feature-removal-schedule.txt | 9 --------- Documentation/filesystems/Locking | 3 --- drivers/media/video/vino.c | 2 +- drivers/video/vermilion/vermilion.c | 5 +++-- fs/gfs2/ops_address.c | 2 +- include/linux/mm.h | 8 -------- mm/memory.c | 22 +++++----------------- mm/mincore.c | 2 +- mm/rmap.c | 1 - 9 files changed, 11 insertions(+), 43 deletions(-) (limited to 'drivers/video') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 448729fcaeb..599fe55bf29 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -128,15 +128,6 @@ Who: Arjan van de Ven --------------------------- -What: vm_ops.nopage -When: Soon, provided in-kernel callers have been converted -Why: This interface is replaced by vm_ops.fault, but it has been around - forever, is used by a lot of drivers, and doesn't cost much to - maintain. -Who: Nick Piggin - ---------------------------- - What: PHYSDEVPATH, PHYSDEVBUS, PHYSDEVDRIVER in the uevent environment When: October 2008 Why: The stacking of class devices makes these values misleading and diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 42d4b30b104..c2992bc54f2 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -511,7 +511,6 @@ prototypes: void (*open)(struct vm_area_struct*); void (*close)(struct vm_area_struct*); int (*fault)(struct vm_area_struct*, struct vm_fault *); - struct page *(*nopage)(struct vm_area_struct*, unsigned long, int *); int (*page_mkwrite)(struct vm_area_struct *, struct page *); locking rules: @@ -519,7 +518,6 @@ locking rules: open: no yes close: no yes fault: no yes -nopage: no yes page_mkwrite: no yes no ->page_mkwrite() is called when a previously read-only page is @@ -537,4 +535,3 @@ NULL. ipc/shm.c::shm_delete() - may need BKL. ->read() and ->write() in many drivers are (probably) missing BKL. -drivers/sgi/char/graphics.c::sgi_graphics_nopage() - may need BKL. diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index d545c98dd5e..01ea99c9bc1 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -13,7 +13,7 @@ /* * TODO: * - remove "mark pages reserved-hacks" from memory allocation code - * and implement nopage() + * and implement fault() * - check decimation, calculating and reporting image size when * using decimation * - implement read(), user mode buffers and overlay (?) diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c index 2aa71eb67c2..c18f1884b55 100644 --- a/drivers/video/vermilion/vermilion.c +++ b/drivers/video/vermilion/vermilion.c @@ -112,8 +112,9 @@ static int vmlfb_alloc_vram_area(struct vram_area *va, unsigned max_order, /* * It seems like __get_free_pages only ups the usage count - * of the first page. This doesn't work with nopage mapping, so - * up the usage count once more. + * of the first page. This doesn't work with fault mapping, so + * up the usage count once more (XXX: should use split_page or + * compound page). */ memset((void *)va->logical, 0x00, va->size); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 90a04a6e378..f55394e57cb 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -438,7 +438,7 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) int error; /* - * Due to the order of unstuffing files and ->nopage(), we can be + * Due to the order of unstuffing files and ->fault(), we can be * asked for a zero page in the case of a stuffed file being extended, * so we need to supply one here. It doesn't happen often. */ diff --git a/include/linux/mm.h b/include/linux/mm.h index 286d3152160..ca973359fe5 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -164,8 +164,6 @@ struct vm_operations_struct { void (*open)(struct vm_area_struct * area); void (*close)(struct vm_area_struct * area); int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf); - struct page *(*nopage)(struct vm_area_struct *area, - unsigned long address, int *type); unsigned long (*nopfn)(struct vm_area_struct *area, unsigned long address); @@ -648,12 +646,6 @@ static inline int page_mapped(struct page *page) return atomic_read(&(page)->_mapcount) >= 0; } -/* - * Error return values for the *_nopage functions - */ -#define NOPAGE_SIGBUS (NULL) -#define NOPAGE_OOM ((struct page *) (-1)) - /* * Error return values for the *_nopfn functions */ diff --git a/mm/memory.c b/mm/memory.c index 0d14d1e58a5..46958fb97c2 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1057,8 +1057,7 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, if (pages) foll_flags |= FOLL_GET; if (!write && !(vma->vm_flags & VM_LOCKED) && - (!vma->vm_ops || (!vma->vm_ops->nopage && - !vma->vm_ops->fault))) + (!vma->vm_ops || !vma->vm_ops->fault)) foll_flags |= FOLL_ANON; do { @@ -2199,20 +2198,9 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma, BUG_ON(vma->vm_flags & VM_PFNMAP); - if (likely(vma->vm_ops->fault)) { - ret = vma->vm_ops->fault(vma, &vmf); - if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE))) - return ret; - } else { - /* Legacy ->nopage path */ - ret = 0; - vmf.page = vma->vm_ops->nopage(vma, address & PAGE_MASK, &ret); - /* no page was available -- either SIGBUS or OOM */ - if (unlikely(vmf.page == NOPAGE_SIGBUS)) - return VM_FAULT_SIGBUS; - else if (unlikely(vmf.page == NOPAGE_OOM)) - return VM_FAULT_OOM; - } + ret = vma->vm_ops->fault(vma, &vmf); + if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE))) + return ret; /* * For consistency in subsequent calls, make the faulted page always @@ -2458,7 +2446,7 @@ static inline int handle_pte_fault(struct mm_struct *mm, if (!pte_present(entry)) { if (pte_none(entry)) { if (vma->vm_ops) { - if (vma->vm_ops->fault || vma->vm_ops->nopage) + if (likely(vma->vm_ops->fault)) return do_linear_fault(mm, vma, address, pte, pmd, write_access, entry); if (unlikely(vma->vm_ops->nopfn)) diff --git a/mm/mincore.c b/mm/mincore.c index 5efe0ded69b..5178800bc12 100644 --- a/mm/mincore.c +++ b/mm/mincore.c @@ -33,7 +33,7 @@ static unsigned char mincore_page(struct address_space *mapping, pgoff_t pgoff) * When tmpfs swaps out a page from a file, any process mapping that * file will not get a swp_entry_t in its pte, but rather it is like * any other file mapping (ie. marked !present and faulted in with - * tmpfs's .nopage). So swapped out tmpfs mappings are tested here. + * tmpfs's .fault). So swapped out tmpfs mappings are tested here. * * However when tmpfs moves the page from pagecache and into swapcache, * it is still in core, but the find_get_page below won't find it. diff --git a/mm/rmap.c b/mm/rmap.c index e9bb6b1093f..bf0a5b7cfb8 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -662,7 +662,6 @@ void page_remove_rmap(struct page *page, struct vm_area_struct *vma) printk (KERN_EMERG " page->mapping = %p\n", page->mapping); print_symbol (KERN_EMERG " vma->vm_ops = %s\n", (unsigned long)vma->vm_ops); if (vma->vm_ops) { - print_symbol (KERN_EMERG " vma->vm_ops->nopage = %s\n", (unsigned long)vma->vm_ops->nopage); print_symbol (KERN_EMERG " vma->vm_ops->fault = %s\n", (unsigned long)vma->vm_ops->fault); } if (vma->vm_file && vma->vm_file->f_op) -- cgit v1.2.3-70-g09d2 From 6b745b6fd02213f4b2fef2f2635985929fc5b8cc Mon Sep 17 00:00:00 2001 From: Michal Januszewski Date: Mon, 28 Apr 2008 02:14:48 -0700 Subject: fbdev: make the best-fit section of fb_find_mode return the closest matching mode Currently, if a perfect match in terms of resolution is not found, fb_find_mode() only looks for a best-fit mode among modes with a higher resolution than the one requested. Thus, if the user requests a resolution higher than the largest supported one, they are dropped to the default mode (usually a low resolution one). Change this behaviour so that all valid video modes are considered when looking for a best-fit mode, while still preferring modes with a higher resolution. Signed-off-by: Michal Januszewski Cc: Krzysztof Helt Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/modedb.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 08d07255223..640351c9a9e 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -522,7 +522,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, int res_specified = 0, bpp_specified = 0, refresh_specified = 0; unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0; int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0; - u32 best, diff; + u32 best, diff, tdiff; for (i = namelen-1; i >= 0; i--) { switch (name[i]) { @@ -651,19 +651,27 @@ done: return (refresh_specified) ? 2 : 1; } - diff = xres + yres; + diff = 2 * (xres + yres); best = -1; DPRINTK("Trying best-fit modes\n"); for (i = 0; i < dbsize; i++) { - if (xres <= db[i].xres && yres <= db[i].yres) { DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres); if (!fb_try_mode(var, info, &db[i], bpp)) { - if (diff > (db[i].xres - xres) + (db[i].yres - yres)) { - diff = (db[i].xres - xres) + (db[i].yres - yres); - best = i; - } + tdiff = abs(db[i].xres - xres) + + abs(db[i].yres - yres); + + /* + * Penalize modes with resolutions smaller + * than requested. + */ + if (xres > db[i].xres || yres > db[i].yres) + tdiff += xres + yres; + + if (diff > tdiff) { + diff = tdiff; + best = i; + } } - } } if (best != -1) { fb_try_mode(var, info, &db[best], bpp); -- cgit v1.2.3-70-g09d2 From e4c690e061b909127ab0f12e929f82f3f39ec953 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 28 Apr 2008 02:14:49 -0700 Subject: fb: add support for foreign endianness Add support for the framebuffers with non-native endianness. This is done via FBINFO_FOREIGN_ENDIAN flag that will be used by the drivers. Depending on the host endianness this flag will be overwritten by FBINFO_BE_MATH internal flag, or cleared. Tested to work on MPC8360E-RDK (BE) + Fujitsu MINT framebuffer (LE). Signed-off-by: Anton Vorontsov Cc: "Antonino A. Daplas" Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Cc: Clemens Koller Cc: Krzysztof Helt Cc: Geert Uytterhoeven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/Kconfig | 24 +++++++++++++++++++++ drivers/video/cfbcopyarea.c | 23 +++++++++++--------- drivers/video/cfbfillrect.c | 48 ++++++++++++++++++++++------------------- drivers/video/cfbimgblt.c | 52 ++++++++++++++++++++++----------------------- drivers/video/fb_draw.h | 31 +++++++++++++++------------ drivers/video/fbmem.c | 30 ++++++++++++++++++++++++++ drivers/video/syscopyarea.c | 20 ++++++++--------- drivers/video/sysfillrect.c | 49 +++++++++++++++++++++--------------------- drivers/video/sysimgblt.c | 47 +++++++++++++++++++--------------------- include/linux/fb.h | 44 ++++++++++++++++++++++++++++++-------- 10 files changed, 228 insertions(+), 140 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index e3dc8f8d0c3..da7b9705ca8 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -139,6 +139,30 @@ config FB_SYS_IMAGEBLIT blitting. This is used by drivers that don't provide their own (accelerated) version and the framebuffer is in system RAM. +menuconfig FB_FOREIGN_ENDIAN + bool "Framebuffer foreign endianness support" + depends on FB + ---help--- + This menu will let you enable support for the framebuffers with + non-native endianness (e.g. Little-Endian framebuffer on a + Big-Endian machine). Most probably you don't have such hardware, + so it's safe to say "n" here. + +choice + prompt "Choice endianness support" + depends on FB_FOREIGN_ENDIAN + +config FB_BOTH_ENDIAN + bool "Support for Big- and Little-Endian framebuffers" + +config FB_BIG_ENDIAN + bool "Support for Big-Endian framebuffers only" + +config FB_LITTLE_ENDIAN + bool "Support for Little-Endian framebuffers only" + +endchoice + config FB_SYS_FOPS tristate depends on FB diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c index b07e419b12d..df03f3776dc 100644 --- a/drivers/video/cfbcopyarea.c +++ b/drivers/video/cfbcopyarea.c @@ -44,15 +44,16 @@ */ static void -bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, - int src_idx, int bits, unsigned n, u32 bswapmask) +bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, + const unsigned long __iomem *src, int src_idx, int bits, + unsigned n, u32 bswapmask) { unsigned long first, last; int const shift = dst_idx-src_idx; int left, right; - first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); + first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); if (!shift) { // Same alignment for source and dest @@ -202,8 +203,9 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src */ static void -bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, - int src_idx, int bits, unsigned n, u32 bswapmask) +bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, + const unsigned long __iomem *src, int src_idx, int bits, + unsigned n, u32 bswapmask) { unsigned long first, last; int shift; @@ -221,8 +223,9 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem shift = dst_idx-src_idx; - first = fb_shifted_pixels_mask_long(bits - 1 - dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long(bits - 1 - ((dst_idx-n) % bits), bswapmask); + first = fb_shifted_pixels_mask_long(p, bits - 1 - dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, bits - 1 - ((dst_idx-n) % bits), + bswapmask); if (!shift) { // Same alignment for source and dest @@ -404,7 +407,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) dst_idx &= (bytes - 1); src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); - bitcpy_rev(dst, dst_idx, src, src_idx, bits, + bitcpy_rev(p, dst, dst_idx, src, src_idx, bits, width*p->var.bits_per_pixel, bswapmask); } } else { @@ -413,7 +416,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) dst_idx &= (bytes - 1); src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); - bitcpy(dst, dst_idx, src, src_idx, bits, + bitcpy(p, dst, dst_idx, src, src_idx, bits, width*p->var.bits_per_pixel, bswapmask); dst_idx += bits_per_line; src_idx += bits_per_line; diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c index 23d70a12e4d..64b35766b2a 100644 --- a/drivers/video/cfbfillrect.c +++ b/drivers/video/cfbfillrect.c @@ -36,16 +36,16 @@ */ static void -bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, - unsigned n, int bits, u32 bswapmask) +bitfill_aligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, + unsigned long pat, unsigned n, int bits, u32 bswapmask) { unsigned long first, last; if (!n) return; - first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); + first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); if (dst_idx+n <= bits) { // Single word @@ -93,16 +93,16 @@ bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, */ static void -bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, - int left, int right, unsigned n, int bits) +bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, + unsigned long pat, int left, int right, unsigned n, int bits) { unsigned long first, last; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { // Single word @@ -147,8 +147,9 @@ bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, * Aligned pattern invert using 32/64-bit memory accesses */ static void -bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, - unsigned n, int bits, u32 bswapmask) +bitfill_aligned_rev(struct fb_info *p, unsigned long __iomem *dst, + int dst_idx, unsigned long pat, unsigned n, int bits, + u32 bswapmask) { unsigned long val = pat, dat; unsigned long first, last; @@ -156,8 +157,8 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, if (!n) return; - first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); + first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); if (dst_idx+n <= bits) { // Single word @@ -217,16 +218,17 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, */ static void -bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, - int left, int right, unsigned n, int bits) +bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst, + int dst_idx, unsigned long pat, int left, int right, + unsigned n, int bits) { unsigned long first, last, dat; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { // Single word @@ -306,7 +308,8 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) p->fbops->fb_sync(p); if (!left) { u32 bswapmask = fb_compute_bswapmask(p); - void (*fill_op32)(unsigned long __iomem *dst, int dst_idx, + void (*fill_op32)(struct fb_info *p, + unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits, u32 bswapmask) = NULL; @@ -325,16 +328,17 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) while (height--) { dst += dst_idx >> (ffs(bits) - 1); dst_idx &= (bits - 1); - fill_op32(dst, dst_idx, pat, width*bpp, bits, bswapmask); + fill_op32(p, dst, dst_idx, pat, width*bpp, bits, + bswapmask); dst_idx += p->fix.line_length*8; } } else { int right; int r; int rot = (left-dst_idx) % bpp; - void (*fill_op)(unsigned long __iomem *dst, int dst_idx, - unsigned long pat, int left, int right, - unsigned n, int bits) = NULL; + void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst, + int dst_idx, unsigned long pat, int left, + int right, unsigned n, int bits) = NULL; /* rotate pattern to correct start position */ pat = pat << rot | pat >> (bpp-rot); @@ -355,7 +359,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) while (height--) { dst += dst_idx >> (ffs(bits) - 1); dst_idx &= (bits - 1); - fill_op(dst, dst_idx, pat, left, right, + fill_op(p, dst, dst_idx, pat, left, right, width*bpp, bits); r = (p->fix.line_length*8) % bpp; pat = pat << (bpp-r) | pat >> r; diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c index f598907b42a..ff3136bd464 100644 --- a/drivers/video/cfbimgblt.c +++ b/drivers/video/cfbimgblt.c @@ -43,30 +43,26 @@ #define DPRINTK(fmt, args...) #endif -static const u32 cfb_tab8[] = { -#if defined(__BIG_ENDIAN) +static const u32 cfb_tab8_be[] = { 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff, 0xffff0000,0xffff00ff,0xffffff00,0xffffffff -#elif defined(__LITTLE_ENDIAN) +}; + +static const u32 cfb_tab8_le[] = { 0x00000000,0xff000000,0x00ff0000,0xffff0000, 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00, 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff, 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff -#else -#error FIXME: No endianness?? -#endif }; -static const u32 cfb_tab16[] = { -#if defined(__BIG_ENDIAN) +static const u32 cfb_tab16_be[] = { 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff -#elif defined(__LITTLE_ENDIAN) +}; + +static const u32 cfb_tab16_le[] = { 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff -#else -#error FIXME: No endianness?? -#endif }; static const u32 cfb_tab32[] = { @@ -98,7 +94,8 @@ static inline void color_imageblit(const struct fb_image *image, val = 0; if (start_index) { - u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask); + u32 start_mask = ~fb_shifted_pixels_mask_u32(p, + start_index, bswapmask); val = FB_READL(dst) & start_mask; shift = start_index; } @@ -108,20 +105,21 @@ static inline void color_imageblit(const struct fb_image *image, color = palette[*src]; else color = *src; - color <<= FB_LEFT_POS(bpp); - val |= FB_SHIFT_HIGH(color, shift ^ bswapmask); + color <<= FB_LEFT_POS(p, bpp); + val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask); if (shift >= null_bits) { FB_WRITEL(val, dst++); val = (shift == null_bits) ? 0 : - FB_SHIFT_LOW(color, 32 - shift); + FB_SHIFT_LOW(p, color, 32 - shift); } shift += bpp; shift &= (32 - 1); src++; } if (shift) { - u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask); + u32 end_mask = fb_shifted_pixels_mask_u32(p, shift, + bswapmask); FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); } @@ -152,8 +150,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * u32 bswapmask = fb_compute_bswapmask(p); dst2 = (u32 __iomem *) dst1; - fgcolor <<= FB_LEFT_POS(bpp); - bgcolor <<= FB_LEFT_POS(bpp); + fgcolor <<= FB_LEFT_POS(p, bpp); + bgcolor <<= FB_LEFT_POS(p, bpp); for (i = image->height; i--; ) { shift = val = 0; @@ -164,7 +162,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * /* write leading bits */ if (start_index) { - u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask); + u32 start_mask = ~fb_shifted_pixels_mask_u32(p, + start_index, bswapmask); val = FB_READL(dst) & start_mask; shift = start_index; } @@ -172,13 +171,13 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * while (j--) { l--; color = (*s & (1 << l)) ? fgcolor : bgcolor; - val |= FB_SHIFT_HIGH(color, shift ^ bswapmask); + val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask); /* Did the bitshift spill bits to the next long? */ if (shift >= null_bits) { FB_WRITEL(val, dst++); val = (shift == null_bits) ? 0 : - FB_SHIFT_LOW(color,32 - shift); + FB_SHIFT_LOW(p, color, 32 - shift); } shift += bpp; shift &= (32 - 1); @@ -187,7 +186,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * /* write trailing bits */ if (shift) { - u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask); + u32 end_mask = fb_shifted_pixels_mask_u32(p, shift, + bswapmask); FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); } @@ -223,13 +223,13 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info * u32 __iomem *dst; const u32 *tab = NULL; int i, j, k; - + switch (bpp) { case 8: - tab = cfb_tab8; + tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le; break; case 16: - tab = cfb_tab16; + tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le; break; case 32: default: diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h index a2a0618d86a..1db622192bd 100644 --- a/drivers/video/fb_draw.h +++ b/drivers/video/fb_draw.h @@ -94,41 +94,44 @@ static inline unsigned long fb_rev_pixels_in_long(unsigned long val, return val; } -static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask) +static inline u32 fb_shifted_pixels_mask_u32(struct fb_info *p, u32 index, + u32 bswapmask) { u32 mask; if (!bswapmask) { - mask = FB_SHIFT_HIGH(~(u32)0, index); + mask = FB_SHIFT_HIGH(p, ~(u32)0, index); } else { - mask = 0xff << FB_LEFT_POS(8); - mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask; - mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask)); + mask = 0xff << FB_LEFT_POS(p, 8); + mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask; + mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask)); #if defined(__i386__) || defined(__x86_64__) /* Shift argument is limited to 0 - 31 on x86 based CPU's */ if(index + bswapmask < 32) #endif - mask |= FB_SHIFT_HIGH(~(u32)0, + mask |= FB_SHIFT_HIGH(p, ~(u32)0, (index + bswapmask) & ~(bswapmask)); } return mask; } -static inline unsigned long fb_shifted_pixels_mask_long(u32 index, u32 bswapmask) +static inline unsigned long fb_shifted_pixels_mask_long(struct fb_info *p, + u32 index, + u32 bswapmask) { unsigned long mask; if (!bswapmask) { - mask = FB_SHIFT_HIGH(~0UL, index); + mask = FB_SHIFT_HIGH(p, ~0UL, index); } else { - mask = 0xff << FB_LEFT_POS(8); - mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask; - mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask)); + mask = 0xff << FB_LEFT_POS(p, 8); + mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask; + mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask)); #if defined(__i386__) || defined(__x86_64__) /* Shift argument is limited to 0 - 31 on x86 based CPU's */ if(index + bswapmask < BITS_PER_LONG) #endif - mask |= FB_SHIFT_HIGH(~0UL, + mask |= FB_SHIFT_HIGH(p, ~0UL, (index + bswapmask) & ~(bswapmask)); } return mask; @@ -158,8 +161,8 @@ static inline unsigned long fb_rev_pixels_in_long(unsigned long val, return val; } -#define fb_shifted_pixels_mask_u32(i, b) FB_SHIFT_HIGH(~(u32)0, (i)) -#define fb_shifted_pixels_mask_long(i, b) FB_SHIFT_HIGH(~0UL, (i)) +#define fb_shifted_pixels_mask_u32(p, i, b) FB_SHIFT_HIGH((p), ~(u32)0, (i)) +#define fb_shifted_pixels_mask_long(p, i, b) FB_SHIFT_HIGH((p), ~0UL, (i)) #define fb_compute_bswapmask(...) 0 #endif /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */ diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 01072f4b3e8..279c2dbef8f 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1352,6 +1352,32 @@ static const struct file_operations fb_fops = { struct class *fb_class; EXPORT_SYMBOL(fb_class); + +static int fb_check_foreignness(struct fb_info *fi) +{ + const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN; + + fi->flags &= ~FBINFO_FOREIGN_ENDIAN; + +#ifdef __BIG_ENDIAN + fi->flags |= foreign_endian ? 0 : FBINFO_BE_MATH; +#else + fi->flags |= foreign_endian ? FBINFO_BE_MATH : 0; +#endif /* __BIG_ENDIAN */ + + if (fi->flags & FBINFO_BE_MATH && !fb_be_math(fi)) { + pr_err("%s: enable CONFIG_FB_BIG_ENDIAN to " + "support this framebuffer\n", fi->fix.id); + return -ENOSYS; + } else if (!(fi->flags & FBINFO_BE_MATH) && fb_be_math(fi)) { + pr_err("%s: enable CONFIG_FB_LITTLE_ENDIAN to " + "support this framebuffer\n", fi->fix.id); + return -ENOSYS; + } + + return 0; +} + /** * register_framebuffer - registers a frame buffer device * @fb_info: frame buffer info structure @@ -1371,6 +1397,10 @@ register_framebuffer(struct fb_info *fb_info) if (num_registered_fb == FB_MAX) return -ENXIO; + + if (fb_check_foreignness(fb_info)) + return -ENOSYS; + num_registered_fb++; for (i = 0 ; i < FB_MAX; i++) if (!registered_fb[i]) diff --git a/drivers/video/syscopyarea.c b/drivers/video/syscopyarea.c index 37af10ab8f5..a352d5f46bb 100644 --- a/drivers/video/syscopyarea.c +++ b/drivers/video/syscopyarea.c @@ -26,15 +26,15 @@ */ static void -bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, - int src_idx, int bits, unsigned n) +bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, + const unsigned long *src, int src_idx, int bits, unsigned n) { unsigned long first, last; int const shift = dst_idx-src_idx; int left, right; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (!shift) { /* Same alignment for source and dest */ @@ -167,8 +167,8 @@ bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, */ static void -bitcpy_rev(unsigned long *dst, int dst_idx, const unsigned long *src, - int src_idx, int bits, unsigned n) +bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx, + const unsigned long *src, int src_idx, int bits, unsigned n) { unsigned long first, last; int shift; @@ -186,8 +186,8 @@ bitcpy_rev(unsigned long *dst, int dst_idx, const unsigned long *src, shift = dst_idx-src_idx; - first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx); - last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits))); + first = FB_SHIFT_LOW(p, ~0UL, bits - 1 - dst_idx); + last = ~(FB_SHIFT_LOW(p, ~0UL, bits - 1 - ((dst_idx-n) % bits))); if (!shift) { /* Same alignment for source and dest */ @@ -353,7 +353,7 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area) dst_idx &= (bytes - 1); src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); - bitcpy_rev(dst, dst_idx, src, src_idx, bits, + bitcpy_rev(p, dst, dst_idx, src, src_idx, bits, width*p->var.bits_per_pixel); } } else { @@ -362,7 +362,7 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area) dst_idx &= (bytes - 1); src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); - bitcpy(dst, dst_idx, src, src_idx, bits, + bitcpy(p, dst, dst_idx, src, src_idx, bits, width*p->var.bits_per_pixel); dst_idx += bits_per_line; src_idx += bits_per_line; diff --git a/drivers/video/sysfillrect.c b/drivers/video/sysfillrect.c index a261e9e6a67..f94d6b6e29e 100644 --- a/drivers/video/sysfillrect.c +++ b/drivers/video/sysfillrect.c @@ -22,16 +22,16 @@ */ static void -bitfill_aligned(unsigned long *dst, int dst_idx, unsigned long pat, - unsigned n, int bits) +bitfill_aligned(struct fb_info *p, unsigned long *dst, int dst_idx, + unsigned long pat, unsigned n, int bits) { unsigned long first, last; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { /* Single word */ @@ -78,16 +78,16 @@ bitfill_aligned(unsigned long *dst, int dst_idx, unsigned long pat, */ static void -bitfill_unaligned(unsigned long *dst, int dst_idx, unsigned long pat, - int left, int right, unsigned n, int bits) +bitfill_unaligned(struct fb_info *p, unsigned long *dst, int dst_idx, + unsigned long pat, int left, int right, unsigned n, int bits) { unsigned long first, last; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { /* Single word */ @@ -132,8 +132,8 @@ bitfill_unaligned(unsigned long *dst, int dst_idx, unsigned long pat, * Aligned pattern invert using 32/64-bit memory accesses */ static void -bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat, - unsigned n, int bits) +bitfill_aligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx, + unsigned long pat, unsigned n, int bits) { unsigned long val = pat; unsigned long first, last; @@ -141,8 +141,8 @@ bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat, if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { /* Single word */ @@ -188,16 +188,17 @@ bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat, */ static void -bitfill_unaligned_rev(unsigned long *dst, int dst_idx, unsigned long pat, - int left, int right, unsigned n, int bits) +bitfill_unaligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx, + unsigned long pat, int left, int right, unsigned n, + int bits) { unsigned long first, last; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { /* Single word */ @@ -267,9 +268,9 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect) if (p->fbops->fb_sync) p->fbops->fb_sync(p); if (!left) { - void (*fill_op32)(unsigned long *dst, int dst_idx, - unsigned long pat, unsigned n, int bits) = - NULL; + void (*fill_op32)(struct fb_info *p, unsigned long *dst, + int dst_idx, unsigned long pat, unsigned n, + int bits) = NULL; switch (rect->rop) { case ROP_XOR: @@ -287,16 +288,16 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect) while (height--) { dst += dst_idx >> (ffs(bits) - 1); dst_idx &= (bits - 1); - fill_op32(dst, dst_idx, pat, width*bpp, bits); + fill_op32(p, dst, dst_idx, pat, width*bpp, bits); dst_idx += p->fix.line_length*8; } } else { int right; int r; int rot = (left-dst_idx) % bpp; - void (*fill_op)(unsigned long *dst, int dst_idx, - unsigned long pat, int left, int right, - unsigned n, int bits) = NULL; + void (*fill_op)(struct fb_info *p, unsigned long *dst, + int dst_idx, unsigned long pat, int left, + int right, unsigned n, int bits) = NULL; /* rotate pattern to correct start position */ pat = pat << rot | pat >> (bpp-rot); @@ -318,7 +319,7 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect) while (height--) { dst += dst_idx >> (ffs(bits) - 1); dst_idx &= (bits - 1); - fill_op(dst, dst_idx, pat, left, right, + fill_op(p, dst, dst_idx, pat, left, right, width*bpp, bits); r = (p->fix.line_length*8) % bpp; pat = pat << (bpp-r) | pat >> r; diff --git a/drivers/video/sysimgblt.c b/drivers/video/sysimgblt.c index bd7e7e9d155..88daa9b6f69 100644 --- a/drivers/video/sysimgblt.c +++ b/drivers/video/sysimgblt.c @@ -23,30 +23,26 @@ #define DPRINTK(fmt, args...) #endif -static const u32 cfb_tab8[] = { -#if defined(__BIG_ENDIAN) +static const u32 cfb_tab8_be[] = { 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff, 0xffff0000,0xffff00ff,0xffffff00,0xffffffff -#elif defined(__LITTLE_ENDIAN) +}; + +static const u32 cfb_tab8_le[] = { 0x00000000,0xff000000,0x00ff0000,0xffff0000, 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00, 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff, 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff -#else -#error FIXME: No endianness?? -#endif }; -static const u32 cfb_tab16[] = { -#if defined(__BIG_ENDIAN) +static const u32 cfb_tab16_be[] = { 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff -#elif defined(__LITTLE_ENDIAN) +}; + +static const u32 cfb_tab16_le[] = { 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff -#else -#error FIXME: No endianness?? -#endif }; static const u32 cfb_tab32[] = { @@ -72,7 +68,7 @@ static void color_imageblit(const struct fb_image *image, struct fb_info *p, val = 0; if (start_index) { - u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0, + u32 start_mask = ~(FB_SHIFT_HIGH(p, ~(u32)0, start_index)); val = *dst & start_mask; shift = start_index; @@ -83,20 +79,20 @@ static void color_imageblit(const struct fb_image *image, struct fb_info *p, color = palette[*src]; else color = *src; - color <<= FB_LEFT_POS(bpp); - val |= FB_SHIFT_HIGH(color, shift); + color <<= FB_LEFT_POS(p, bpp); + val |= FB_SHIFT_HIGH(p, color, shift); if (shift >= null_bits) { *dst++ = val; val = (shift == null_bits) ? 0 : - FB_SHIFT_LOW(color, 32 - shift); + FB_SHIFT_LOW(p, color, 32 - shift); } shift += bpp; shift &= (32 - 1); src++; } if (shift) { - u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift); + u32 end_mask = FB_SHIFT_HIGH(p, ~(u32)0, shift); *dst &= end_mask; *dst |= val; @@ -125,8 +121,8 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p, u32 i, j, l; dst2 = dst1; - fgcolor <<= FB_LEFT_POS(bpp); - bgcolor <<= FB_LEFT_POS(bpp); + fgcolor <<= FB_LEFT_POS(p, bpp); + bgcolor <<= FB_LEFT_POS(p, bpp); for (i = image->height; i--; ) { shift = val = 0; @@ -137,7 +133,8 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p, /* write leading bits */ if (start_index) { - u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index)); + u32 start_mask = ~(FB_SHIFT_HIGH(p, ~(u32)0, + start_index)); val = *dst & start_mask; shift = start_index; } @@ -145,13 +142,13 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p, while (j--) { l--; color = (*s & (1 << l)) ? fgcolor : bgcolor; - val |= FB_SHIFT_HIGH(color, shift); + val |= FB_SHIFT_HIGH(p, color, shift); /* Did the bitshift spill bits to the next long? */ if (shift >= null_bits) { *dst++ = val; val = (shift == null_bits) ? 0 : - FB_SHIFT_LOW(color,32 - shift); + FB_SHIFT_LOW(p, color, 32 - shift); } shift += bpp; shift &= (32 - 1); @@ -160,7 +157,7 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p, /* write trailing bits */ if (shift) { - u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift); + u32 end_mask = FB_SHIFT_HIGH(p, ~(u32)0, shift); *dst &= end_mask; *dst |= val; @@ -199,10 +196,10 @@ static void fast_imageblit(const struct fb_image *image, struct fb_info *p, switch (bpp) { case 8: - tab = cfb_tab8; + tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le; break; case 16: - tab = cfb_tab16; + tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le; break; case 32: default: diff --git a/include/linux/fb.h b/include/linux/fb.h index 58c57a33e5d..72295b09922 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -791,6 +791,17 @@ struct fb_tile_ops { */ #define FBINFO_MISC_ALWAYS_SETPAR 0x40000 +/* + * Host and GPU endianness differ. + */ +#define FBINFO_FOREIGN_ENDIAN 0x100000 +/* + * Big endian math. This is the same flags as above, but with different + * meaning, it is set by the fb subsystem depending FOREIGN_ENDIAN flag + * and host endianness. Drivers should not use this flag. + */ +#define FBINFO_BE_MATH 0x100000 + struct fb_info { int node; int flags; @@ -899,15 +910,11 @@ struct fb_info { #endif -#if defined (__BIG_ENDIAN) -#define FB_LEFT_POS(bpp) (32 - bpp) -#define FB_SHIFT_HIGH(val, bits) ((val) >> (bits)) -#define FB_SHIFT_LOW(val, bits) ((val) << (bits)) -#else -#define FB_LEFT_POS(bpp) (0) -#define FB_SHIFT_HIGH(val, bits) ((val) << (bits)) -#define FB_SHIFT_LOW(val, bits) ((val) >> (bits)) -#endif +#define FB_LEFT_POS(p, bpp) (fb_be_math(p) ? (32 - (bpp)) : 0) +#define FB_SHIFT_HIGH(p, val, bits) (fb_be_math(p) ? (val) >> (bits) : \ + (val) << (bits)) +#define FB_SHIFT_LOW(p, val, bits) (fb_be_math(p) ? (val) << (bits) : \ + (val) >> (bits)) /* * `Generic' versions of the frame buffer device operations @@ -970,6 +977,25 @@ extern void fb_deferred_io_cleanup(struct fb_info *info); extern int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync); +static inline bool fb_be_math(struct fb_info *info) +{ +#ifdef CONFIG_FB_FOREIGN_ENDIAN +#if defined(CONFIG_FB_BOTH_ENDIAN) + return info->flags & FBINFO_BE_MATH; +#elif defined(CONFIG_FB_BIG_ENDIAN) + return true; +#elif defined(CONFIG_FB_LITTLE_ENDIAN) + return false; +#endif /* CONFIG_FB_BOTH_ENDIAN */ +#else +#ifdef __BIG_ENDIAN + return true; +#else + return false; +#endif /* __BIG_ENDIAN */ +#endif /* CONFIG_FB_FOREIGN_ENDIAN */ +} + /* drivers/video/fbsysfs.c */ extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev); extern void framebuffer_release(struct fb_info *info); -- cgit v1.2.3-70-g09d2 From 7f29b87a7779505288a31df16ba84a85fc1ae93c Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 28 Apr 2008 02:14:50 -0700 Subject: powerpc: offb: add support for foreign endianness Signed-off-by: Anton Vorontsov Cc: "Antonino A. Daplas" Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/offb.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 452433d4697..d7b3dcc0dc4 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -248,7 +248,7 @@ static void __iomem *offb_map_reg(struct device_node *np, int index, static void __init offb_init_fb(const char *name, const char *full_name, int width, int height, int depth, int pitch, unsigned long address, - struct device_node *dp) + int foreign_endian, struct device_node *dp) { unsigned long res_size = pitch * height * (depth + 7) / 8; struct offb_par *par = &default_par; @@ -397,7 +397,7 @@ static void __init offb_init_fb(const char *name, const char *full_name, info->screen_base = ioremap(address, fix->smem_len); info->par = par; info->pseudo_palette = (void *) (info + 1); - info->flags = FBINFO_DEFAULT; + info->flags = FBINFO_DEFAULT | foreign_endian; fb_alloc_cmap(&info->cmap, 256, 0); @@ -424,6 +424,15 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node) u64 rstart, address = OF_BAD_ADDR; const u32 *pp, *addrp, *up; u64 asize; + int foreign_endian = 0; + +#ifdef __BIG_ENDIAN + if (of_get_property(dp, "little-endian", NULL)) + foreign_endian = FBINFO_FOREIGN_ENDIAN; +#else + if (of_get_property(dp, "big-endian", NULL)) + foreign_endian = FBINFO_FOREIGN_ENDIAN; +#endif pp = of_get_property(dp, "linux,bootx-depth", &len); if (pp == NULL) @@ -509,7 +518,7 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node) offb_init_fb(no_real_node ? "bootx" : dp->name, no_real_node ? "display" : dp->full_name, width, height, depth, pitch, address, - no_real_node ? NULL : dp); + foreign_endian, no_real_node ? NULL : dp); } } -- cgit v1.2.3-70-g09d2 From 416e74ea7813597b586eafc24f67779eeb86e12f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 28 Apr 2008 02:14:51 -0700 Subject: fbdev: use DIV_ROUND_UP or roundup The kernel.h macro DIV_ROUND_UP performs the computation (((n) + (d) - 1) / (d)) but is perhaps more readable. An extract of the semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @haskernel@ @@ #include @depends on haskernel@ expression n,d; @@ ( - (n + d - 1) / d + DIV_ROUND_UP(n,d) | - (n + (d - 1)) / d + DIV_ROUND_UP(n,d) ) @depends on haskernel@ expression n,d; @@ - DIV_ROUND_UP((n),d) + DIV_ROUND_UP(n,d) @depends on haskernel@ expression n,d; @@ - DIV_ROUND_UP(n,(d)) + DIV_ROUND_UP(n,d) // Signed-off-by: Julia Lawall Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/atafb.c | 2 +- drivers/video/cirrusfb.c | 2 +- drivers/video/console/fbcon.c | 3 +-- drivers/video/gxt4500.c | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index 5d4fbaa53a6..dff35474b85 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -1270,7 +1270,7 @@ again: gstart = (prescale / 2 + plen * left_margin) / prescale; /* gend1 is for hde (gend-gstart multiple of align), shifter's xres */ - gend1 = gstart + ((xres + align - 1) / align) * align * plen / prescale; + gend1 = gstart + roundup(xres, align) * plen / prescale; /* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */ gend2 = gstart + xres * plen / prescale; par->HHT = plen * (left_margin + xres + right_margin) / diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index f7e2d5add83..ccfbdc5a40d 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c @@ -3117,7 +3117,7 @@ static void bestclock(long freq, long *best, long *nom, } } } - d = ((143181 * n) + f - 1) / f; + d = DIV_ROUND_UP(143181 * n, f); if ((d >= 7) && (d <= 63)) { if (d > 31) d = (d / 2) * 2; diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 022282494d3..025d4f5e1f6 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -620,8 +620,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, if (fb_get_color_depth(&info->var, &info->fix) == 1) erase &= ~0x400; logo_height = fb_prepare_logo(info, ops->rotate); - logo_lines = (logo_height + vc->vc_font.height - 1) / - vc->vc_font.height; + logo_lines = DIV_ROUND_UP(logo_height, vc->vc_font.height); q = (unsigned short *) (vc->vc_origin + vc->vc_size_row * rows); step = logo_lines * cols; diff --git a/drivers/video/gxt4500.c b/drivers/video/gxt4500.c index e92337bef50..564557792be 100644 --- a/drivers/video/gxt4500.c +++ b/drivers/video/gxt4500.c @@ -238,7 +238,7 @@ static int calc_pll(int period_ps, struct gxt4500_par *par) for (pdiv1 = 1; pdiv1 <= 8; ++pdiv1) { for (pdiv2 = 1; pdiv2 <= pdiv1; ++pdiv2) { postdiv = pdiv1 * pdiv2; - pll_period = (period_ps + postdiv - 1) / postdiv; + pll_period = DIV_ROUND_UP(period_ps, postdiv); /* keep pll in range 350..600 MHz */ if (pll_period < 1666 || pll_period > 2857) continue; -- cgit v1.2.3-70-g09d2 From 2ae09f0da1cd0c8c646edea2e68356e76789461c Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Mon, 28 Apr 2008 02:14:51 -0700 Subject: pm2fb: correct error values returned from probe function Fix error values returned in some code branches in the pm2fb_probe() function. Signed-off-by: Krzysztof Helt Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/pm2fb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index 30181b59382..82aa8242f44 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -1687,10 +1687,12 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, if (!err || err == 4) info->var = pm2fb_var; - if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) + retval = fb_alloc_cmap(&info->cmap, 256, 0); + if (retval < 0) goto err_exit_both; - if (register_framebuffer(info) < 0) + retval = register_framebuffer(info); + if (retval < 0) goto err_exit_all; printk(KERN_INFO "fb%d: %s frame buffer device, memory = %dK.\n", -- cgit v1.2.3-70-g09d2 From 22af89aa0c0b4012a7431114a340efd3665a7617 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Mon, 28 Apr 2008 02:14:53 -0700 Subject: fbcon: replace mono_col macro with static inline Use __u32 for max_len to match the declaration of length in the struct fb_bitfield. Suppresses sparse shadowed variable warnings from the nested max() macros: drivers/video/console/fbcon.h:130:8: warning: symbol '_x' shadows an earlier one drivers/video/console/fbcon.h:130:8: originally declared here drivers/video/console/fbcon.h:130:8: warning: symbol '_x' shadows an earlier one drivers/video/console/fbcon.h:130:8: originally declared here drivers/video/console/fbcon.h:130:8: warning: symbol '_y' shadows an earlier one drivers/video/console/fbcon.h:130:8: originally declared here [akpm@linux-foundation.org: fix constness] Signed-off-by: Harvey Harrison Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/console/fbcon.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index 3706307e70e..0135e039545 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h @@ -104,10 +104,14 @@ struct fbcon_ops { #define attr_blink(s) \ ((s) & 0x8000) -#define mono_col(info) \ - (~(0xfff << (max((info)->var.green.length, \ - max((info)->var.red.length, \ - (info)->var.blue.length)))) & 0xff) + +static inline int mono_col(const struct fb_info *info) +{ + __u32 max_len; + max_len = max(info->var.green.length, info->var.red.length); + max_len = max(info->var.blue.length, max_len); + return ~(0xfff << (max_len & 0xff)); +} static inline int attr_col_ec(int shift, struct vc_data *vc, struct fb_info *info, int is_fg) -- cgit v1.2.3-70-g09d2 From 32bf87e3697cf2f730b8fbf47cad903ceef718a2 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Mon, 28 Apr 2008 02:14:53 -0700 Subject: x86: geode: MSR cleanup This cleans up a few MSR-using drivers in the following manner: - Ensures MSRs are all defined in asm/geode.h, rather than in misc places - Makes the naming consistent; cs553[56] ones begin with MSR_, GX-specific ones start with MSR_GX_, and LX-specific ones start with MSR_LX_. Also, make the names match the data sheet. - Use MSR names rather than numbers in source code - Document the fact that the LX's MSR_PADSEL has the wrong value in the data sheet. That's, uh, good to note. Signed-off-by: Andres Salomon Acked-by: Jordan Crouse Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86/kernel/mfgpt_32.c | 8 ++++---- drivers/video/geode/display_gx.h | 1 - drivers/video/geode/gxfb_core.c | 3 ++- drivers/video/geode/lxfb.h | 8 -------- drivers/video/geode/lxfb_ops.c | 19 ++++++++++--------- drivers/video/geode/video_gx.c | 5 +++-- drivers/video/geode/video_gx.h | 3 --- include/asm-x86/geode.h | 16 +++++++++++++--- 8 files changed, 32 insertions(+), 31 deletions(-) (limited to 'drivers/video') diff --git a/arch/x86/kernel/mfgpt_32.c b/arch/x86/kernel/mfgpt_32.c index cfc2648d25f..3cad17fe026 100644 --- a/arch/x86/kernel/mfgpt_32.c +++ b/arch/x86/kernel/mfgpt_32.c @@ -63,7 +63,7 @@ static int __init mfgpt_fix(char *s) /* The following udocumented bit resets the MFGPT timers */ val = 0xFF; dummy = 0; - wrmsr(0x5140002B, val, dummy); + wrmsr(MSR_MFGPT_SETUP, val, dummy); return 1; } __setup("mfgptfix", mfgpt_fix); @@ -127,17 +127,17 @@ int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable) * 6; that is, resets for 7 and 8 will be ignored. Is this * a problem? -dilinger */ - msr = MFGPT_NR_MSR; + msr = MSR_MFGPT_NR; mask = 1 << (timer + 24); break; case MFGPT_EVENT_NMI: - msr = MFGPT_NR_MSR; + msr = MSR_MFGPT_NR; mask = 1 << (timer + shift); break; case MFGPT_EVENT_IRQ: - msr = MFGPT_IRQ_MSR; + msr = MSR_MFGPT_IRQ; mask = 1 << (timer + shift); break; diff --git a/drivers/video/geode/display_gx.h b/drivers/video/geode/display_gx.h index 0af33f329e8..df94e4fc662 100644 --- a/drivers/video/geode/display_gx.h +++ b/drivers/video/geode/display_gx.h @@ -17,7 +17,6 @@ int gx_line_delta(int xres, int bpp); extern struct geode_dc_ops gx_dc_ops; /* MSR that tells us if a TFT or CRT is attached */ -#define GLD_MSR_CONFIG 0xC0002001 #define GLD_MSR_CONFIG_DM_FP 0x40 /* Display controller registers */ diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c index cf841efa229..4e22ee0377e 100644 --- a/drivers/video/geode/gxfb_core.c +++ b/drivers/video/geode/gxfb_core.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "geodefb.h" #include "display_gx.h" @@ -326,7 +327,7 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i /* Figure out if this is a TFT or CRT part */ - rdmsrl(GLD_MSR_CONFIG, val); + rdmsrl(MSR_GX_GLD_MSR_CONFIG, val); if ((val & GLD_MSR_CONFIG_DM_FP) == GLD_MSR_CONFIG_DM_FP) par->enable_crt = 0; diff --git a/drivers/video/geode/lxfb.h b/drivers/video/geode/lxfb.h index ca13c48d19b..8c83a1b4439 100644 --- a/drivers/video/geode/lxfb.h +++ b/drivers/video/geode/lxfb.h @@ -31,14 +31,6 @@ void lx_set_palette_reg(struct fb_info *, unsigned int, unsigned int, /* MSRS */ -#define MSR_LX_GLD_CONFIG 0x48002001 -#define MSR_LX_GLCP_DOTPLL 0x4c000015 -#define MSR_LX_DF_PADSEL 0x48002011 -#define MSR_LX_DC_SPARE 0x80000011 -#define MSR_LX_DF_GLCONFIG 0x48002001 - -#define MSR_LX_GLIU0_P2D_RO0 0x10000029 - #define GLCP_DOTPLL_RESET (1 << 0) #define GLCP_DOTPLL_BYPASS (1 << 15) #define GLCP_DOTPLL_HALFPIX (1 << 24) diff --git a/drivers/video/geode/lxfb_ops.c b/drivers/video/geode/lxfb_ops.c index 4fbc99be96e..a52c180062c 100644 --- a/drivers/video/geode/lxfb_ops.c +++ b/drivers/video/geode/lxfb_ops.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "lxfb.h" @@ -101,7 +102,7 @@ static void lx_set_dotpll(u32 pllval) u32 dotpll_lo, dotpll_hi; int i; - rdmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + rdmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); if ((dotpll_lo & GLCP_DOTPLL_LOCK) && (dotpll_hi == pllval)) return; @@ -110,7 +111,7 @@ static void lx_set_dotpll(u32 pllval) dotpll_lo &= ~(GLCP_DOTPLL_BYPASS | GLCP_DOTPLL_HALFPIX); dotpll_lo |= GLCP_DOTPLL_RESET; - wrmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); /* Wait 100us for the PLL to lock */ @@ -119,7 +120,7 @@ static void lx_set_dotpll(u32 pllval) /* Now, loop for the lock bit */ for (i = 0; i < 1000; i++) { - rdmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + rdmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); if (dotpll_lo & GLCP_DOTPLL_LOCK) break; } @@ -127,7 +128,7 @@ static void lx_set_dotpll(u32 pllval) /* Clear the reset bit */ dotpll_lo &= ~GLCP_DOTPLL_RESET; - wrmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); } /* Set the clock based on the frequency specified by the current mode */ @@ -255,7 +256,7 @@ static void lx_graphics_enable(struct fb_info *info) msrlo = DF_DEFAULT_TFT_PAD_SEL_LOW; msrhi = DF_DEFAULT_TFT_PAD_SEL_HIGH; - wrmsr(MSR_LX_DF_PADSEL, msrlo, msrhi); + wrmsr(MSR_LX_MSR_PADSEL, msrlo, msrhi); } if (par->output & OUTPUT_CRT) { @@ -321,7 +322,7 @@ void lx_set_mode(struct fb_info *info) /* Set output mode */ - rdmsrl(MSR_LX_DF_GLCONFIG, msrval); + rdmsrl(MSR_LX_GLD_MSR_CONFIG, msrval); msrval &= ~DF_CONFIG_OUTPUT_MASK; if (par->output & OUTPUT_PANEL) { @@ -335,7 +336,7 @@ void lx_set_mode(struct fb_info *info) msrval |= DF_OUTPUT_CRT; } - wrmsrl(MSR_LX_DF_GLCONFIG, msrval); + wrmsrl(MSR_LX_GLD_MSR_CONFIG, msrval); /* Clear the various buffers */ /* FIXME: Adjust for panning here */ @@ -383,13 +384,13 @@ void lx_set_mode(struct fb_info *info) /* Set default watermark values */ - rdmsrl(MSR_LX_DC_SPARE, msrval); + rdmsrl(MSR_LX_SPARE_MSR, msrval); msrval &= ~(DC_SPARE_DISABLE_CFIFO_HGO | DC_SPARE_VFIFO_ARB_SELECT | DC_SPARE_LOAD_WM_LPEN_MASK | DC_SPARE_WM_LPEN_OVRD | DC_SPARE_DISABLE_INIT_VID_PRI | DC_SPARE_DISABLE_VFIFO_WM); msrval |= DC_SPARE_DISABLE_VFIFO_WM | DC_SPARE_DISABLE_INIT_VID_PRI; - wrmsrl(MSR_LX_DC_SPARE, msrval); + wrmsrl(MSR_LX_SPARE_MSR, msrval); gcfg = DC_GCFG_DFLE; /* Display fifo enable */ gcfg |= 0xB600; /* Set default priority */ diff --git a/drivers/video/geode/video_gx.c b/drivers/video/geode/video_gx.c index febf09c6349..d0885370675 100644 --- a/drivers/video/geode/video_gx.c +++ b/drivers/video/geode/video_gx.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "geodefb.h" #include "video_gx.h" @@ -184,10 +185,10 @@ gx_configure_tft(struct fb_info *info) /* Set up the DF pad select MSR */ - rdmsrl(GX_VP_MSR_PAD_SELECT, val); + rdmsrl(MSR_GX_MSR_PADSEL, val); val &= ~GX_VP_PAD_SELECT_MASK; val |= GX_VP_PAD_SELECT_TFT; - wrmsrl(GX_VP_MSR_PAD_SELECT, val); + wrmsrl(MSR_GX_MSR_PADSEL, val); /* Turn off the panel */ diff --git a/drivers/video/geode/video_gx.h b/drivers/video/geode/video_gx.h index ce28d8f382d..d21bca02059 100644 --- a/drivers/video/geode/video_gx.h +++ b/drivers/video/geode/video_gx.h @@ -14,7 +14,6 @@ extern struct geode_vid_ops gx_vid_ops; /* GX Flatpanel control MSR */ -#define GX_VP_MSR_PAD_SELECT 0xC0002011 #define GX_VP_PAD_SELECT_MASK 0x3FFFFFFF #define GX_VP_PAD_SELECT_TFT 0x1FFFFFFF @@ -59,12 +58,10 @@ extern struct geode_vid_ops gx_vid_ops; /* Geode GX clock control MSRs */ -#define MSR_GLCP_SYS_RSTPLL 0x4c000014 # define MSR_GLCP_SYS_RSTPLL_DOTPREDIV2 (0x0000000000000002ull) # define MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 (0x0000000000000004ull) # define MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 (0x0000000000000008ull) -#define MSR_GLCP_DOTPLL 0x4c000015 # define MSR_GLCP_DOTPLL_DOTRESET (0x0000000000000001ull) # define MSR_GLCP_DOTPLL_BYPASS (0x0000000000008000ull) # define MSR_GLCP_DOTPLL_LOCK (0x0000000002000000ull) diff --git a/include/asm-x86/geode.h b/include/asm-x86/geode.h index 9870cc1f2f8..b1bdf637856 100644 --- a/include/asm-x86/geode.h +++ b/include/asm-x86/geode.h @@ -30,7 +30,11 @@ extern int geode_get_dev_base(unsigned int dev); /* MSRS */ -#define GX_GLCP_SYS_RSTPLL 0x4C000014 +#define MSR_LX_GLD_MSR_CONFIG 0x48002001 +#define MSR_LX_MSR_PADSEL 0x48002011 /* NOT 0x48000011; the data + * sheet has the wrong value */ +#define MSR_GLCP_SYS_RSTPLL 0x4C000014 +#define MSR_GLCP_DOTPLL 0x4C000015 #define MSR_LBAR_SMB 0x5140000B #define MSR_LBAR_GPIO 0x5140000C @@ -45,8 +49,14 @@ extern int geode_get_dev_base(unsigned int dev); #define MSR_PIC_ZSEL_LOW 0x51400022 #define MSR_PIC_ZSEL_HIGH 0x51400023 -#define MFGPT_IRQ_MSR 0x51400028 -#define MFGPT_NR_MSR 0x51400029 +#define MSR_MFGPT_IRQ 0x51400028 +#define MSR_MFGPT_NR 0x51400029 +#define MSR_MFGPT_SETUP 0x5140002B + +#define MSR_LX_SPARE_MSR 0x80000011 /* DC-specific */ + +#define MSR_GX_GLD_MSR_CONFIG 0xC0002001 +#define MSR_GX_MSR_PADSEL 0xC0002011 /* Resource Sizes */ -- cgit v1.2.3-70-g09d2 From f0a0c1f20f837221c0d990a54ae5426acf039036 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Mon, 28 Apr 2008 02:14:55 -0700 Subject: gxfb: set the right registers to tweak the sync polarity While running in flatpanel mode it is important to change the FP sync bits (VG register 0x408) rather then the CRT sync bits (VG register 0x008). This patch keeps the CRT sync bits at default when a flatpanel exists. Note that this also fixes inverted logic; we want CRT_VSYNC_POL to be set (ie, vsync is normally high) when FB_SYNC_VERT_HIGH_ACT is unset. Signed-off-by: Jordan Crouse Signed-off-by: Andres Salomon Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/geode/video_gx.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/geode/video_gx.c b/drivers/video/geode/video_gx.c index d0885370675..06245a8400c 100644 --- a/drivers/video/geode/video_gx.c +++ b/drivers/video/geode/video_gx.c @@ -208,7 +208,7 @@ gx_configure_tft(struct fb_info *info) fp = 0x0F100000; - /* Add sync polarity */ + /* Configure sync polarity */ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) fp |= GX_FP_PT2_VSP; @@ -269,11 +269,15 @@ static void gx_configure_display(struct fb_info *info) /* Enable hsync and vsync. */ dcfg |= GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN; - /* Sync polarities. */ - if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) - dcfg |= GX_DCFG_CRT_HSYNC_POL; - if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) - dcfg |= GX_DCFG_CRT_VSYNC_POL; + /* Only change the sync polarities if we are running + * in CRT mode. The FP polarities will be handled in + * gxfb_configure_tft */ + if (par->enable_crt) { + if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) + dcfg |= GX_DCFG_CRT_HSYNC_POL; + if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) + dcfg |= GX_DCFG_CRT_VSYNC_POL; + } /* Enable the display logic */ /* Set up the DACS to blank normally */ -- cgit v1.2.3-70-g09d2 From e2b118090969f153f134647acbcbbf01a9005e64 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Mon, 28 Apr 2008 02:14:56 -0700 Subject: gxfb: don't enable the CRT DACs when we are in flatpanel mode When the FP strap is enabled, don't turn on the CRT DACs - that will save about 35 mA of power. Updated/cleaned up by Andres Salomon. Signed-off-by: Andres Salomon Signed-off-by: Jordan Crouse Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/geode/video_gx.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/geode/video_gx.c b/drivers/video/geode/video_gx.c index 06245a8400c..cfe2c80b025 100644 --- a/drivers/video/geode/video_gx.c +++ b/drivers/video/geode/video_gx.c @@ -239,18 +239,6 @@ static void gx_configure_display(struct fb_info *info) struct geodefb_par *par = info->par; u32 dcfg, misc; - /* Set up the MISC register */ - - misc = readl(par->vid_regs + GX_MISC); - - /* Power up the DAC */ - misc &= ~(GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN); - - /* Disable gamma correction */ - misc |= GX_MISC_GAM_EN; - - writel(misc, par->vid_regs + GX_MISC); - /* Write the display configuration */ dcfg = readl(par->vid_regs + GX_DCFG); @@ -269,14 +257,28 @@ static void gx_configure_display(struct fb_info *info) /* Enable hsync and vsync. */ dcfg |= GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN; - /* Only change the sync polarities if we are running - * in CRT mode. The FP polarities will be handled in - * gxfb_configure_tft */ + misc = readl(par->vid_regs + GX_MISC); + + /* Disable gamma correction */ + misc |= GX_MISC_GAM_EN; + if (par->enable_crt) { + + /* Power up the CRT DACs */ + misc &= ~(GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN); + writel(misc, par->vid_regs + GX_MISC); + + /* Only change the sync polarities if we are running + * in CRT mode. The FP polarities will be handled in + * gxfb_configure_tft */ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) dcfg |= GX_DCFG_CRT_HSYNC_POL; if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) dcfg |= GX_DCFG_CRT_VSYNC_POL; + } else { + /* Power down the CRT DACs if in FP mode */ + misc |= (GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN); + writel(misc, par->vid_regs + GX_MISC); } /* Enable the display logic */ -- cgit v1.2.3-70-g09d2 From 0a5e79098799a4bead070a9bd7f1a2213ba5eef5 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Mon, 28 Apr 2008 02:14:57 -0700 Subject: gxfb: use PCI_DEVICE() for gxfb's pci device table Drop the class/class_mask stuff; it's unnecessary as long as the vendor and device IDs match. Signed-off-by: Andres Salomon Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/geode/gxfb_core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c index 4e22ee0377e..546e53038fa 100644 --- a/drivers/video/geode/gxfb_core.c +++ b/drivers/video/geode/gxfb_core.c @@ -398,9 +398,7 @@ static void gxfb_remove(struct pci_dev *pdev) } static struct pci_device_id gxfb_id_table[] = { - { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO, - PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, - 0xff0000, 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO) }, { 0, } }; -- cgit v1.2.3-70-g09d2 From fa20c8a6e520d9ccd68c8101155ffdbc19c977c3 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Mon, 28 Apr 2008 02:14:57 -0700 Subject: gxfb: replace FBSIZE config option with a module parameter Use a command line option (vram) rather than hardcoding the vram size. LxFB already does this; it's useful for machines that can't query the BIOS for fb size. This patch originated from David Woodhouse, was modified by Jordan Crouse, and was then modified further by me. This also adds some gxfb documentation in Documentation/fb. Signed-off-by: Andres Salomon Cc: Jordan Crouse Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/fb/gxfb.txt | 51 ++++++++++++++++++++++++++++++++++++++++ drivers/video/geode/Kconfig | 20 ---------------- drivers/video/geode/display_gx.c | 7 ------ drivers/video/geode/gxfb_core.c | 14 ++++++----- 4 files changed, 59 insertions(+), 33 deletions(-) create mode 100644 Documentation/fb/gxfb.txt (limited to 'drivers/video') diff --git a/Documentation/fb/gxfb.txt b/Documentation/fb/gxfb.txt new file mode 100644 index 00000000000..b5609614201 --- /dev/null +++ b/Documentation/fb/gxfb.txt @@ -0,0 +1,51 @@ +[This file is cloned from VesaFB/aty128fb] + +What is gxfb? +================= + +This is a graphics framebuffer driver for AMD Geode GX2 based processors. + +Advantages: + + * No need to use AMD's VSA code (or other VESA emulation layer) in the + BIOS. + * It provides a nice large console (128 cols + 48 lines with 1024x768) + without using tiny, unreadable fonts. + * You can run XF68_FBDev on top of /dev/fb0 + * Most important: boot logo :-) + +Disadvantages: + + * graphic mode is slower than text mode... + + +How to use it? +============== + +Switching modes is done using gxfb.mode_option=... boot +parameter or using `fbset' program. + +See Documentation/fb/modedb.txt for more information on modedb +resolutions. + + +X11 +=== + +XF68_FBDev should generally work fine, but it is non-accelerated. + + +Configuration +============= + +You can pass kernel command line options to gxfb with gxfb.