diff options
Diffstat (limited to 'drivers/gpu/drm/udl')
| -rw-r--r-- | drivers/gpu/drm/udl/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/udl/udl_connector.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/udl/udl_drv.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/udl/udl_drv.h | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/udl/udl_fb.c | 105 | ||||
| -rw-r--r-- | drivers/gpu/drm/udl/udl_gem.c | 80 | ||||
| -rw-r--r-- | drivers/gpu/drm/udl/udl_main.c | 8 | ||||
| -rw-r--r-- | drivers/gpu/drm/udl/udl_modeset.c | 7 | ||||
| -rw-r--r-- | drivers/gpu/drm/udl/udl_transfer.c | 46 |
9 files changed, 125 insertions, 137 deletions
diff --git a/drivers/gpu/drm/udl/Kconfig b/drivers/gpu/drm/udl/Kconfig index 56e0bf31d42..f02528686cd 100644 --- a/drivers/gpu/drm/udl/Kconfig +++ b/drivers/gpu/drm/udl/Kconfig @@ -1,6 +1,6 @@ config DRM_UDL tristate "DisplayLink" - depends on DRM && EXPERIMENTAL + depends on DRM depends on USB_ARCH_HAS_HCD select DRM_USB select FB_SYS_FILLRECT @@ -8,6 +8,7 @@ config DRM_UDL select FB_SYS_IMAGEBLIT select FB_DEFERRED_IO select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER help This is a KMS driver for the USB displaylink video adapters. Say M/Y to add support for these devices via drm/kms interfaces. diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index fe5cdbcf263..b44d548c56f 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c @@ -61,6 +61,10 @@ static int udl_get_modes(struct drm_connector *connector) int ret; edid = (struct edid *)udl_get_edid(udl); + if (!edid) { + drm_mode_connector_update_edid_property(connector, NULL); + return 0; + } /* * We only read the main block, but if the monitor reports extension diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c index c0770dbba74..3ddd6cd98ac 100644 --- a/drivers/gpu/drm/udl/udl_drv.c +++ b/drivers/gpu/drm/udl/udl_drv.c @@ -65,7 +65,6 @@ static const struct file_operations udl_driver_fops = { .read = drm_read, .unlocked_ioctl = drm_ioctl, .release = drm_release, - .fasync = drm_fasync, #ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, #endif @@ -78,13 +77,12 @@ static struct drm_driver driver = { .unload = udl_driver_unload, /* gem hooks */ - .gem_init_object = udl_gem_init_object, .gem_free_object = udl_gem_free_object, .gem_vm_ops = &udl_gem_vm_ops, .dumb_create = udl_dumb_create, .dumb_map_offset = udl_gem_mmap, - .dumb_destroy = udl_dumb_destroy, + .dumb_destroy = drm_gem_dumb_destroy, .fops = &udl_driver_fops, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index 87aa5f5d3c8..1fbf7b357f1 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -75,6 +75,8 @@ struct udl_framebuffer { struct drm_framebuffer base; struct udl_gem_object *obj; bool active_16; /* active on the 16-bit channel */ + int x1, y1, x2, y2; /* dirty rect */ + spinlock_t dirty_lock; }; #define to_udl_fb(x) container_of(x, struct udl_framebuffer, base) @@ -112,10 +114,7 @@ int udl_dumb_create(struct drm_file *file_priv, struct drm_mode_create_dumb *args); int udl_gem_mmap(struct drm_file *file_priv, struct drm_device *dev, uint32_t handle, uint64_t *offset); -int udl_dumb_destroy(struct drm_file *file_priv, struct drm_device *dev, - uint32_t handle); -int udl_gem_init_object(struct drm_gem_object *obj); void udl_gem_free_object(struct drm_gem_object *gem_obj); struct udl_gem_object *udl_gem_alloc_object(struct drm_device *dev, size_t size); diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index d4ab3beaada..377176372da 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -22,9 +22,9 @@ #include <drm/drm_fb_helper.h> -#define DL_DEFIO_WRITE_DELAY 5 /* fb_deferred_io.delay in jiffies */ +#define DL_DEFIO_WRITE_DELAY (HZ/20) /* fb_deferred_io.delay in jiffies */ -static int fb_defio = 1; /* Optionally enable experimental fb_defio mmap support */ +static int fb_defio = 0; /* Optionally enable experimental fb_defio mmap support */ static int fb_bpp = 16; module_param(fb_bpp, int, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP); @@ -153,6 +153,9 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, struct urb *urb; int aligned_x; int bpp = (fb->base.bits_per_pixel / 8); + int x2, y2; + bool store_for_later = false; + unsigned long flags; if (!fb->active_16) return 0; @@ -169,8 +172,6 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, } } - start_cycles = get_cycles(); - aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long)); width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long)); x = aligned_x; @@ -180,19 +181,53 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, (y + height > fb->base.height)) return -EINVAL; + /* if we are in atomic just store the info + can't test inside spin lock */ + if (in_atomic()) + store_for_later = true; + + x2 = x + width - 1; + y2 = y + height - 1; + + spin_lock_irqsave(&fb->dirty_lock, flags); + + if (fb->y1 < y) + y = fb->y1; + if (fb->y2 > y2) + y2 = fb->y2; + if (fb->x1 < x) + x = fb->x1; + if (fb->x2 > x2) + x2 = fb->x2; + + if (store_for_later) { + fb->x1 = x; + fb->x2 = x2; + fb->y1 = y; + fb->y2 = y2; + spin_unlock_irqrestore(&fb->dirty_lock, flags); + return 0; + } + + fb->x1 = fb->y1 = INT_MAX; + fb->x2 = fb->y2 = 0; + + spin_unlock_irqrestore(&fb->dirty_lock, flags); + start_cycles = get_cycles(); + urb = udl_get_urb(dev); if (!urb) return 0; cmd = urb->transfer_buffer; - for (i = y; i < y + height ; i++) { + for (i = y; i <= y2 ; i++) { const int line_offset = fb->base.pitches[0] * i; const int byte_offset = line_offset + (x * bpp); const int dev_byte_offset = (fb->base.width * bpp * i) + (x * bpp); if (udl_render_hline(dev, bpp, &urb, (char *) fb->obj->vmapping, &cmd, byte_offset, dev_byte_offset, - width * bpp, + (x2 - x + 1) * bpp, &bytes_identical, &bytes_sent)) goto error; } @@ -358,19 +393,6 @@ static struct fb_ops udlfb_ops = { .fb_release = udl_fb_release, }; -static void udl_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, - u16 blue, int regno) -{ -} - -static void udl_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, int regno) -{ - *red = 0; - *green = 0; - *blue = 0; -} - static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb, struct drm_file *file, unsigned flags, unsigned color, @@ -381,15 +403,17 @@ static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb, int i; int ret = 0; + drm_modeset_lock_all(fb->dev); + if (!ufb->active_16) - return 0; + goto unlock; if (ufb->obj->base.import_attach) { ret = dma_buf_begin_cpu_access(ufb->obj->base.import_attach->dmabuf, 0, ufb->obj->base.size, DMA_FROM_DEVICE); if (ret) - return ret; + goto unlock; } for (i = 0; i < num_clips; i++) { @@ -405,6 +429,10 @@ static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb, 0, ufb->obj->base.size, DMA_FROM_DEVICE); } + + unlock: + drm_modeset_unlock_all(fb->dev); + return ret; } @@ -422,7 +450,6 @@ static void udl_user_framebuffer_destroy(struct drm_framebuffer *fb) static const struct drm_framebuffer_funcs udlfb_funcs = { .destroy = udl_user_framebuffer_destroy, .dirty = udl_user_framebuffer_dirty, - .create_handle = NULL, }; @@ -434,19 +461,21 @@ udl_framebuffer_init(struct drm_device *dev, { int ret; + spin_lock_init(&ufb->dirty_lock); ufb->obj = obj; - ret = drm_framebuffer_init(dev, &ufb->base, &udlfb_funcs); drm_helper_mode_fill_fb_struct(&ufb->base, mode_cmd); + ret = drm_framebuffer_init(dev, &ufb->base, &udlfb_funcs); return ret; } -static int udlfb_create(struct udl_fbdev *ufbdev, +static int udlfb_create(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { + struct udl_fbdev *ufbdev = (struct udl_fbdev *)helper; struct drm_device *dev = ufbdev->helper.dev; struct fb_info *info; - struct device *device = &dev->usbdev->dev; + struct device *device = dev->dev; struct drm_framebuffer *fb; struct drm_mode_fb_cmd2 mode_cmd; struct udl_gem_object *obj; @@ -521,27 +550,8 @@ out: return ret; } -static int udl_fb_find_or_create_single(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - struct udl_fbdev *ufbdev = (struct udl_fbdev *)helper; - int new_fb = 0; - int ret; - - if (!helper->fb) { - ret = udlfb_create(ufbdev, sizes); - if (ret) - return ret; - - new_fb = 1; - } - return new_fb; -} - static struct drm_fb_helper_funcs udl_fb_helper_funcs = { - .gamma_set = udl_crtc_fb_gamma_set, - .gamma_get = udl_crtc_fb_gamma_get, - .fb_probe = udl_fb_find_or_create_single, + .fb_probe = udlfb_create, }; static void udl_fbdev_destroy(struct drm_device *dev, @@ -556,6 +566,7 @@ static void udl_fbdev_destroy(struct drm_device *dev, framebuffer_release(info); } drm_fb_helper_fini(&ufbdev->helper); + drm_framebuffer_unregister_private(&ufbdev->ufb.base); drm_framebuffer_cleanup(&ufbdev->ufb.base); drm_gem_object_unreference_unlocked(&ufbdev->ufb.obj->base); } @@ -583,6 +594,10 @@ int udl_fbdev_init(struct drm_device *dev) } drm_fb_helper_single_add_all_connectors(&ufbdev->helper); + + /* disable all the possible outputs/crtcs before entering KMS mode */ + drm_helper_disable_unused_functions(dev); + drm_fb_helper_initial_config(&ufbdev->helper, bpp_sel); return 0; } diff --git a/drivers/gpu/drm/udl/udl_gem.c b/drivers/gpu/drm/udl/udl_gem.c index afd212c9921..c041cd73f39 100644 --- a/drivers/gpu/drm/udl/udl_gem.c +++ b/drivers/gpu/drm/udl/udl_gem.c @@ -60,18 +60,12 @@ int udl_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args) { - args->pitch = args->width * ((args->bpp + 1) / 8); + args->pitch = args->width * DIV_ROUND_UP(args->bpp, 8); args->size = args->pitch * args->height; return udl_gem_create(file, dev, args->size, &args->handle); } -int udl_dumb_destroy(struct drm_file *file, struct drm_device *dev, - uint32_t handle) -{ - return drm_gem_handle_delete(file, handle); -} - int udl_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) { int ret; @@ -103,7 +97,6 @@ int udl_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address, page); switch (ret) { case -EAGAIN: - set_need_resched(); case 0: case -ERESTARTSYS: return VM_FAULT_NOPAGE; @@ -114,64 +107,31 @@ int udl_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) } } -int udl_gem_init_object(struct drm_gem_object *obj) -{ - BUG(); - - return 0; -} - static int udl_gem_get_pages(struct udl_gem_object *obj, gfp_t gfpmask) { - int page_count, i; - struct page *page; - struct inode *inode; - struct address_space *mapping; + struct page **pages; if (obj->pages) return 0; - page_count = obj->base.size / PAGE_SIZE; - BUG_ON(obj->pages != NULL); - obj->pages = drm_malloc_ab(page_count, sizeof(struct page *)); - if (obj->pages == NULL) - return -ENOMEM; - - inode = obj->base.filp->f_path.dentry->d_inode; - mapping = inode->i_mapping; - gfpmask |= mapping_gfp_mask(mapping); + pages = drm_gem_get_pages(&obj->base, gfpmask); + if (IS_ERR(pages)) + return PTR_ERR(pages); - for (i = 0; i < page_count; i++) { - page = shmem_read_mapping_page_gfp(mapping, i, gfpmask); - if (IS_ERR(page)) - goto err_pages; - obj->pages[i] = page; - } + obj->pages = pages; return 0; -err_pages: - while (i--) - page_cache_release(obj->pages[i]); - drm_free_large(obj->pages); - obj->pages = NULL; - return PTR_ERR(page); } static void udl_gem_put_pages(struct udl_gem_object *obj) { - int page_count = obj->base.size / PAGE_SIZE; - int i; - if (obj->base.import_attach) { drm_free_large(obj->pages); obj->pages = NULL; return; } - for (i = 0; i < page_count; i++) - page_cache_release(obj->pages[i]); - - drm_free_large(obj->pages); + drm_gem_put_pages(&obj->base, obj->pages, false, false); obj->pages = NULL; } @@ -217,14 +177,15 @@ void udl_gem_free_object(struct drm_gem_object *gem_obj) if (obj->vmapping) udl_gem_vunmap(obj); - if (gem_obj->import_attach) + if (gem_obj->import_attach) { drm_prime_gem_destroy(gem_obj, obj->sg); + put_device(gem_obj->dev->dev); + } if (obj->pages) udl_gem_put_pages(obj); - if (gem_obj->map_list.map) - drm_gem_free_mmap_offset(gem_obj); + drm_gem_free_mmap_offset(gem_obj); } /* the dumb interface doesn't work with the GEM straight MMAP @@ -247,13 +208,11 @@ int udl_gem_mmap(struct drm_file *file, struct drm_device *dev, ret = udl_gem_get_pages(gobj, GFP_KERNEL); if (ret) goto out; - if (!gobj->base.map_list.map) { - ret = drm_gem_create_mmap_offset(obj); - if (ret) - goto out; - } + ret = drm_gem_create_mmap_offset(obj); + if (ret) + goto out; - *offset = (u64)gobj->base.map_list.hash.key << PAGE_SHIFT; + *offset = drm_vma_node_offset_addr(&gobj->base.vma_node); out: drm_gem_object_unreference(&gobj->base); @@ -299,9 +258,14 @@ struct drm_gem_object *udl_gem_prime_import(struct drm_device *dev, int ret; /* need to attach */ + get_device(dev->dev); attach = dma_buf_attach(dma_buf, dev->dev); - if (IS_ERR(attach)) + if (IS_ERR(attach)) { + put_device(dev->dev); return ERR_CAST(attach); + } + + get_dma_buf(dma_buf); sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); if (IS_ERR(sg)) { @@ -322,5 +286,7 @@ fail_unmap: dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL); fail_detach: dma_buf_detach(dma_buf, attach); + dma_buf_put(dma_buf); + put_device(dev->dev); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index 0ce2d719525..7094b92d1ec 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -41,8 +41,8 @@ static int udl_parse_vendor_descriptor(struct drm_device *dev, total_len = usb_get_descriptor(usbdev, 0x5f, /* vendor specific */ 0, desc, MAX_VENDOR_DESCRIPTOR_SIZE); if (total_len > 5) { - DRM_INFO("vendor descriptor length:%x data:%*ph\n", - total_len, 11, desc); + DRM_INFO("vendor descriptor length:%x data:%11ph\n", + total_len, desc); if ((desc[0] != total_len) || /* descriptor length */ (desc[1] != 0x5f) || /* vendor descriptor type */ @@ -283,7 +283,7 @@ int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len) int udl_driver_load(struct drm_device *dev, unsigned long flags) { struct udl_device *udl; - int ret; + int ret = -ENOMEM; DRM_DEBUG("\n"); udl = kzalloc(sizeof(struct udl_device), GFP_KERNEL); @@ -294,12 +294,12 @@ int udl_driver_load(struct drm_device *dev, unsigned long flags) dev->dev_private = udl; if (!udl_parse_vendor_descriptor(dev, dev->usbdev)) { + ret = -ENODEV; DRM_ERROR("firmware not recognized. Assume incompatible device\n"); goto err; } if (!udl_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) { - ret = -ENOMEM; DRM_ERROR("udl_alloc_urb_list failed\n"); goto err; } diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index e96d2349bd5..cddc4fcf35c 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -310,7 +310,7 @@ static int udl_crtc_mode_set(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; - struct udl_framebuffer *ufb = to_udl_fb(crtc->fb); + struct udl_framebuffer *ufb = to_udl_fb(crtc->primary->fb); struct udl_device *udl = dev->dev_private; char *buf; char *wrptr; @@ -363,10 +363,6 @@ static void udl_crtc_destroy(struct drm_crtc *crtc) kfree(crtc); } -static void udl_load_lut(struct drm_crtc *crtc) -{ -} - static void udl_crtc_prepare(struct drm_crtc *crtc) { } @@ -383,7 +379,6 @@ static struct drm_crtc_helper_funcs udl_helper_funcs = { .prepare = udl_crtc_prepare, .commit = udl_crtc_commit, .disable = udl_crtc_disable, - .load_lut = udl_load_lut, }; static const struct drm_crtc_funcs udl_crtc_funcs = { diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c index 142fee5f983..f343db73e09 100644 --- a/drivers/gpu/drm/udl/udl_transfer.c +++ b/drivers/gpu/drm/udl/udl_transfer.c @@ -75,15 +75,19 @@ static int udl_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes) } #endif -static inline u16 pixel32_to_be16p(const uint8_t *pixel) +static inline u16 pixel32_to_be16(const uint32_t pixel) { - uint32_t pix = *(uint32_t *)pixel; - u16 retval; + return (((pixel >> 3) & 0x001f) | + ((pixel >> 5) & 0x07e0) | + ((pixel >> 8) & 0xf800)); +} - retval = (((pix >> 3) & 0x001f) | - ((pix >> 5) & 0x07e0) | - ((pix >> 8) & 0xf800)); - return retval; +static bool pixel_repeats(const void *pixel, const uint32_t repeat, int bpp) +{ + if (bpp == 2) + return *(const uint16_t *)pixel == repeat; + else + return *(const uint32_t *)pixel == repeat; } /* @@ -152,29 +156,33 @@ static void udl_compress_hline16( prefetch_range((void *) pixel, (cmd_pixel_end - pixel) * bpp); while (pixel < cmd_pixel_end) { - const u8 * const repeating_pixel = pixel; - - if (bpp == 2) - *(uint16_t *)cmd = cpu_to_be16p((uint16_t *)pixel); - else if (bpp == 4) - *(uint16_t *)cmd = cpu_to_be16(pixel32_to_be16p(pixel)); + const u8 *const start = pixel; + u32 repeating_pixel; + + if (bpp == 2) { + repeating_pixel = *(uint16_t *)pixel; + *(uint16_t *)cmd = cpu_to_be16(repeating_pixel); + } else { + repeating_pixel = *(uint32_t *)pixel; + *(uint16_t *)cmd = cpu_to_be16(pixel32_to_be16(repeating_pixel)); + } cmd += 2; pixel += bpp; if (unlikely((pixel < cmd_pixel_end) && - (!memcmp(pixel, repeating_pixel, bpp)))) { + (pixel_repeats(pixel, repeating_pixel, bpp)))) { /* go back and fill in raw pixel count */ - *raw_pixels_count_byte = (((repeating_pixel - + *raw_pixels_count_byte = (((start - raw_pixel_start) / bpp) + 1) & 0xFF; - while ((pixel < cmd_pixel_end) - && (!memcmp(pixel, repeating_pixel, bpp))) { + while ((pixel < cmd_pixel_end) && + (pixel_repeats(pixel, repeating_pixel, bpp))) { pixel += bpp; } /* immediately after raw data is repeat byte */ - *cmd++ = (((pixel - repeating_pixel) / bpp) - 1) & 0xFF; + *cmd++ = (((pixel - start) / bpp) - 1) & 0xFF; /* Then start another raw pixel span */ raw_pixel_start = pixel; @@ -223,6 +231,8 @@ int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr, u8 *cmd = *urb_buf_ptr; u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length; + BUG_ON(!(bpp == 2 || bpp == 4)); + line_start = (u8 *) (front + byte_offset); next_pixel = line_start; line_end = next_pixel + byte_width; |
