drm/udl: Convert to drm_atomic_helper_dirtyfb()
[linux-2.6-block.git] / drivers / gpu / drm / udl / udl_fb.c
CommitLineData
12eb90f1 1// SPDX-License-Identifier: GPL-2.0-only
5320918b
DA
2/*
3 * Copyright (C) 2012 Red Hat
4 *
5 * based in parts on udlfb.c:
6 * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
7 * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
8 * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
5320918b 9 */
a9dcf380
SR
10
11#include <linux/moduleparam.h>
32ecd242 12#include <linux/dma-buf.h>
5320918b 13
a9dcf380 14#include <drm/drm_fourcc.h>
08b22f65 15#include <drm/drm_gem_shmem_helper.h>
a9dcf380
SR
16
17#include "udl_drv.h"
5320918b 18
5320918b
DA
19/** Read the red component (0..255) of a 32 bpp colour. */
20#define DLO_RGB_GETRED(col) (uint8_t)((col) & 0xFF)
21
22/** Read the green component (0..255) of a 32 bpp colour. */
23#define DLO_RGB_GETGRN(col) (uint8_t)(((col) >> 8) & 0xFF)
24
25/** Read the blue component (0..255) of a 32 bpp colour. */
26#define DLO_RGB_GETBLU(col) (uint8_t)(((col) >> 16) & 0xFF)
27
28/** Return red/green component of a 16 bpp colour number. */
29#define DLO_RG16(red, grn) (uint8_t)((((red) & 0xF8) | ((grn) >> 5)) & 0xFF)
30
31/** Return green/blue component of a 16 bpp colour number. */
32#define DLO_GB16(grn, blu) (uint8_t)(((((grn) & 0x1C) << 3) | ((blu) >> 3)) & 0xFF)
33
34/** Return 8 bpp colour number from red, green and blue components. */
35#define DLO_RGB8(red, grn, blu) ((((red) << 5) | (((grn) & 3) << 3) | ((blu) & 7)) & 0xFF)
36
37#if 0
38static uint8_t rgb8(uint32_t col)
39{
40 uint8_t red = DLO_RGB_GETRED(col);
41 uint8_t grn = DLO_RGB_GETGRN(col);
42 uint8_t blu = DLO_RGB_GETBLU(col);
43
44 return DLO_RGB8(red, grn, blu);
45}
46
47static uint16_t rgb16(uint32_t col)
48{
49 uint8_t red = DLO_RGB_GETRED(col);
50 uint8_t grn = DLO_RGB_GETGRN(col);
51 uint8_t blu = DLO_RGB_GETBLU(col);
52
53 return (DLO_RG16(red, grn) << 8) + DLO_GB16(grn, blu);
54}
55#endif
56
cd45e30a
TZ
57static long udl_log_cpp(unsigned int cpp)
58{
59 if (WARN_ON(!is_power_of_2(cpp)))
60 return -EINVAL;
61 return __ffs(cpp);
62}
63
ffc90486
TZ
64static int udl_aligned_damage_clip(struct drm_rect *clip, int x, int y,
65 int width, int height)
66{
67 int x1, x2;
68
69 if (WARN_ON_ONCE(x < 0) ||
70 WARN_ON_ONCE(y < 0) ||
71 WARN_ON_ONCE(width < 0) ||
72 WARN_ON_ONCE(height < 0))
73 return -EINVAL;
74
75 x1 = ALIGN_DOWN(x, sizeof(unsigned long));
76 x2 = ALIGN(width + (x - x1), sizeof(unsigned long)) + x1;
77
78 clip->x1 = x1;
79 clip->y1 = y;
80 clip->x2 = x2;
81 clip->y2 = y + height;
82
83 return 0;
84}
85
83446035 86int udl_handle_damage(struct drm_framebuffer *fb, int x, int y,
5320918b
DA
87 int width, int height)
88{
83446035 89 struct drm_device *dev = fb->dev;
fd96e0db 90 struct udl_device *udl = to_udl(dev);
798ce3fe
TZ
91 struct dma_buf_attachment *import_attach = fb->obj[0]->import_attach;
92 int i, ret, tmp_ret;
5320918b 93 char *cmd;
5320918b 94 struct urb *urb;
ffc90486 95 struct drm_rect clip;
91ba11fb 96 int log_bpp;
6c44e30a 97 void *vaddr;
91ba11fb 98
ba59b015 99 spin_lock(&udl->active_fb_16_lock);
83446035 100 if (udl->active_fb_16 != fb) {
ba59b015 101 spin_unlock(&udl->active_fb_16_lock);
5320918b 102 return 0;
ba59b015
TZ
103 }
104 spin_unlock(&udl->active_fb_16_lock);
5320918b 105
cd45e30a
TZ
106 ret = udl_log_cpp(fb->format->cpp[0]);
107 if (ret < 0)
108 return ret;
109 log_bpp = ret;
110
ffc90486
TZ
111 ret = udl_aligned_damage_clip(&clip, x, y, width, height);
112 if (ret)
113 return ret;
114 else if ((clip.x2 > fb->width) || (clip.y2 > fb->height))
2d2bebb8 115 return -EINVAL;
2d2bebb8 116
798ce3fe
TZ
117 if (import_attach) {
118 ret = dma_buf_begin_cpu_access(import_attach->dmabuf,
119 DMA_FROM_DEVICE);
120 if (ret)
121 return ret;
122 }
123
2d2bebb8
TZ
124 vaddr = drm_gem_shmem_vmap(fb->obj[0]);
125 if (IS_ERR(vaddr)) {
126 DRM_ERROR("failed to vmap fb\n");
798ce3fe 127 goto out_dma_buf_end_cpu_access;
6c44e30a 128 }
5320918b
DA
129
130 urb = udl_get_urb(dev);
131 if (!urb)
798ce3fe 132 goto out_drm_gem_shmem_vunmap;
5320918b
DA
133 cmd = urb->transfer_buffer;
134
ffc90486 135 for (i = clip.y1; i < clip.y2; i++) {
83446035 136 const int line_offset = fb->pitches[0] * i;
ffc90486
TZ
137 const int byte_offset = line_offset + (clip.x1 << log_bpp);
138 const int dev_byte_offset = (fb->width * i + clip.x1) << log_bpp;
139 const int byte_width = (clip.x2 - clip.x1) << log_bpp;
1ca3fd96
TZ
140 ret = udl_render_hline(dev, log_bpp, &urb, (char *)vaddr,
141 &cmd, byte_offset, dev_byte_offset,
142 byte_width);
143 if (ret)
798ce3fe 144 goto out_drm_gem_shmem_vunmap;
5320918b
DA
145 }
146
147 if (cmd > (char *) urb->transfer_buffer) {
148 /* Send partial buffer remaining before exiting */
99ec9e77
MP
149 int len;
150 if (cmd < (char *) urb->transfer_buffer + urb->transfer_buffer_length)
151 *cmd++ = 0xAF;
152 len = cmd - (char *) urb->transfer_buffer;
5320918b 153 ret = udl_submit_urb(dev, urb, len);
5320918b
DA
154 } else
155 udl_urb_completion(urb);
156
798ce3fe
TZ
157 ret = 0;
158
159out_drm_gem_shmem_vunmap:
83446035 160 drm_gem_shmem_vunmap(fb->obj[0], vaddr);
798ce3fe
TZ
161out_dma_buf_end_cpu_access:
162 if (import_attach) {
163 tmp_ret = dma_buf_end_cpu_access(import_attach->dmabuf,
164 DMA_FROM_DEVICE);
165 if (tmp_ret && !ret)
166 ret = tmp_ret; /* only update ret if not set yet */
167 }
6c44e30a 168
798ce3fe 169 return ret;
5320918b 170}