Commit | Line | Data |
---|---|---|
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 | |
38 | static 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 | ||
47 | static 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 |
57 | static 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 |
64 | static 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 | 86 | int 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 | ||
159 | out_drm_gem_shmem_vunmap: | |
83446035 | 160 | drm_gem_shmem_vunmap(fb->obj[0], vaddr); |
798ce3fe TZ |
161 | out_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 | } |