LUT updates
[platform/upstream/libdrm.git] / shared-core / amd_legacy_cbuffer.c
1 /*
2  * Copyright 2008 Jérôme Glisse
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Jerome Glisse <glisse@freedesktop.org>
26  */
27 #include "radeon_ms.h"
28 #include "amd.h"
29
30 #define RADEON_DST_Y_X                      0x1438
31 #define RADEON_SRC_Y_X                      0x1434
32 #define RADEON_DP_CNTL                      0x16c0
33 #define RADEON_DP_GUI_MASTER_CNTL           0x146c
34 #define RADEON_DP_BRUSH_BKGD_CLR            0x1478
35 #define RADEON_DP_BRUSH_FRGD_CLR            0x147c
36 #define RADEON_DP_WRITE_MASK                0x16cc
37 #define RADEON_DST_PITCH_OFFSET             0x142c
38 #define RADEON_SRC_PITCH_OFFSET             0x1428
39 #define RADEON_DST_HEIGHT_WIDTH             0x143c
40
41 struct legacy_check
42 {
43         /* for 2D operations */
44         uint32_t                dp_gui_master_cntl;
45         uint32_t                dst_offset;
46         uint32_t                dst_pitch;
47         struct amd_cmd_bo       *dst;
48         uint32_t                dst_x;
49         uint32_t                dst_y;
50         uint32_t                dst_h;
51         uint32_t                dst_w;
52         struct amd_cmd_bo       *src;
53         uint32_t                src_pitch;
54         uint32_t                src_x;
55         uint32_t                src_y;
56 };
57
58 static int check_blit(struct drm_device *dev, struct amd_cmd *cmd)
59 {
60         struct legacy_check *legacy_check;
61         long bpp, start, end;
62         
63         legacy_check = (struct legacy_check *)cmd->driver;
64         /* check that gui master cntl have been set */
65         if (legacy_check->dp_gui_master_cntl == 0xffffffff) {
66                 return -EINVAL;
67         }
68         switch ((legacy_check->dp_gui_master_cntl >> 8) & 0xf) {
69         case 2:
70                 bpp = 1;
71                 break;
72         case 3:
73         case 4:
74                 bpp = 2;
75                 break;
76         case 6:
77                 bpp = 4;
78                 break;
79         default:
80                 return -EINVAL;
81         }
82         /* check that a destination have been set */
83         if (legacy_check->dst == (void *)-1) {
84                 return -EINVAL;
85         }
86         if (legacy_check->dst_pitch == 0xffffffff) {
87                 return -EINVAL;
88         }
89         if (legacy_check->dst_x == 0xffffffff) {
90                 return -EINVAL;
91         }
92         if (legacy_check->dst_y == 0xffffffff) {
93                 return -EINVAL;
94         }
95         if (legacy_check->dst_w == 0xffffffff) {
96                 return -EINVAL;
97         }
98         if (legacy_check->dst_h == 0xffffffff) {
99                 return -EINVAL;
100         }
101         /* compute start offset of blit */
102         start = legacy_check->dst_pitch * legacy_check->dst_y +
103                 legacy_check->dst_x * bpp;
104         /* compute end offset of blit */
105         end = legacy_check->dst_pitch * legacy_check->dst_h +
106               legacy_check->dst_w * bpp;
107         /* FIXME: check that end offset is inside dst bo */
108
109         /* check that a destination have been set */
110         if (legacy_check->dp_gui_master_cntl & 1) {
111                 if (legacy_check->src == (void *)-1) {
112                         return -EINVAL;
113                 }
114                 if (legacy_check->src_pitch == 0xffffffff) {
115                         return -EINVAL;
116                 }
117                 if (legacy_check->src_x == 0xffffffff) {
118                         return -EINVAL;
119                 }
120                 if (legacy_check->src_y == 0xffffffff) {
121                         return -EINVAL;
122                 }
123                 /* compute start offset of blit */
124                 start = legacy_check->src_pitch * legacy_check->src_y +
125                         legacy_check->src_x * bpp;
126                 /* compute end offset of blit */
127                 end = legacy_check->src_pitch * legacy_check->dst_h +
128                       legacy_check->dst_w * bpp + start;
129                 /* FIXME: check that end offset is inside src bo */
130         }
131         return 0;
132 }
133
134 static int p0_dp_gui_master_cntl(struct drm_device *dev,
135                                  struct amd_cmd *cmd,
136                                  int cdw_id, int reg)
137 {
138         struct legacy_check *legacy_check;
139         
140         legacy_check = (struct legacy_check *)cmd->driver;
141         legacy_check->dp_gui_master_cntl = cmd->cdw[cdw_id];
142         /* we only accept src data type to be same as dst */
143         if (((legacy_check->dp_gui_master_cntl >> 12) & 0x3) != 3) {
144                 return -EINVAL;
145         }
146         return 0;
147 }
148
149 static int p0_dst_pitch_offset(struct drm_device *dev,
150                                struct amd_cmd *cmd,
151                                int cdw_id, int reg)
152 {
153         struct legacy_check *legacy_check;
154         uint32_t tmp;
155         int ret;
156         
157         legacy_check = (struct legacy_check *)cmd->driver;
158         legacy_check->dst_pitch = ((cmd->cdw[cdw_id] >> 22) & 0xff) << 6;
159         tmp = cmd->cdw[cdw_id] & 0x003fffff;
160         legacy_check->dst = amd_cmd_get_bo(cmd, tmp);
161         if (legacy_check->dst == NULL) {
162                 DRM_ERROR("invalid bo (%d) for DST_PITCH_OFFSET register.\n",
163                           tmp);
164                 return -EINVAL;
165         }
166         ret = radeon_ms_bo_get_gpu_addr(dev, &legacy_check->dst->bo->mem, &tmp);
167         if (ret) {
168                 DRM_ERROR("failed to get GPU offset for bo 0x%x.\n",
169                           legacy_check->dst->handle);
170                 return -EINVAL;
171         }
172         if (tmp & 0x3fff) {
173                 DRM_ERROR("bo 0x%x offset doesn't meet alignement 0x%x.\n",
174                           legacy_check->dst->handle, tmp);
175         }
176         cmd->cdw[cdw_id] &= 0xffc00000;
177         cmd->cdw[cdw_id] |= (tmp >> 10);
178         return 0;
179 }
180
181 static int p0_src_pitch_offset(struct drm_device *dev,
182                                struct amd_cmd *cmd,
183                                int cdw_id, int reg)
184 {
185         struct legacy_check *legacy_check;
186         uint32_t tmp;
187         int ret;
188         
189         legacy_check = (struct legacy_check *)cmd->driver;
190         legacy_check->src_pitch = ((cmd->cdw[cdw_id] >> 22) & 0xff) << 6;
191         tmp = cmd->cdw[cdw_id] & 0x003fffff;
192         legacy_check->src = amd_cmd_get_bo(cmd, tmp);
193         if (legacy_check->src == NULL) {
194                 DRM_ERROR("invalid bo (%d) for SRC_PITCH_OFFSET register.\n",
195                           tmp);
196                 return -EINVAL;
197         }
198         ret = radeon_ms_bo_get_gpu_addr(dev, &legacy_check->src->bo->mem, &tmp);
199         if (ret) {
200                 DRM_ERROR("failed to get GPU offset for bo 0x%x.\n",
201                           legacy_check->src->handle);
202                 return -EINVAL;
203         }
204         if (tmp & 0x3fff) {
205                 DRM_ERROR("bo 0x%x offset doesn't meet alignement 0x%x.\n",
206                           legacy_check->src->handle, tmp);
207         }
208         cmd->cdw[cdw_id] &= 0xffc00000;
209         cmd->cdw[cdw_id] |= (tmp >> 10);
210         return 0;
211 }
212
213 static int p0_dst_y_x(struct drm_device *dev,
214                       struct amd_cmd *cmd,
215                       int cdw_id, int reg)
216 {
217         struct legacy_check *legacy_check;
218         
219         legacy_check = (struct legacy_check *)cmd->driver;
220         legacy_check->dst_x = cmd->cdw[cdw_id] & 0xffff;
221         legacy_check->dst_y = (cmd->cdw[cdw_id] >> 16) & 0xffff;
222         return 0;
223 }
224
225 static int p0_src_y_x(struct drm_device *dev,
226                       struct amd_cmd *cmd,
227                       int cdw_id, int reg)
228 {
229         struct legacy_check *legacy_check;
230         
231         legacy_check = (struct legacy_check *)cmd->driver;
232         legacy_check->src_x = cmd->cdw[cdw_id] & 0xffff;
233         legacy_check->src_y = (cmd->cdw[cdw_id] >> 16) & 0xffff;
234         return 0;
235 }
236
237 static int p0_dst_h_w(struct drm_device *dev,
238                       struct amd_cmd *cmd,
239                       int cdw_id, int reg)
240 {
241         struct legacy_check *legacy_check;
242         
243         legacy_check = (struct legacy_check *)cmd->driver;
244         legacy_check->dst_w = cmd->cdw[cdw_id] & 0xffff;
245         legacy_check->dst_h = (cmd->cdw[cdw_id] >> 16) & 0xffff;
246         return check_blit(dev, cmd);
247 }
248
249 static int legacy_cmd_check(struct drm_device *dev,
250                                 struct amd_cmd *cmd)
251 {
252         struct legacy_check legacy_check;
253
254         memset(&legacy_check, 0xff, sizeof(struct legacy_check));
255         cmd->driver = &legacy_check;
256         return amd_cmd_check(dev, cmd);
257 }
258
259 int amd_legacy_cmd_module_destroy(struct drm_device *dev)
260 {
261         struct drm_radeon_private *dev_priv = dev->dev_private;
262
263         dev_priv->cmd_module.check = NULL;
264         if (dev_priv->cmd_module.numof_p0_checkers) {
265                 drm_free(dev_priv->cmd_module.check_p0,
266                          dev_priv->cmd_module.numof_p0_checkers *
267                          sizeof(void*), DRM_MEM_DRIVER);
268                 dev_priv->cmd_module.numof_p0_checkers = 0;
269         }
270         if (dev_priv->cmd_module.numof_p3_checkers) {
271                 drm_free(dev_priv->cmd_module.check_p3,
272                          dev_priv->cmd_module.numof_p3_checkers *
273                          sizeof(void*), DRM_MEM_DRIVER);
274                 dev_priv->cmd_module.numof_p3_checkers = 0;
275         }
276         return 0;
277 }
278
279 int amd_legacy_cmd_module_initialize(struct drm_device *dev)
280 {
281         struct drm_radeon_private *dev_priv = dev->dev_private;
282         struct amd_cmd_module *checker = &dev_priv->cmd_module;
283         long size;
284
285         /* packet 0 */
286         checker->numof_p0_checkers = 0x5000 >> 2;
287         size = checker->numof_p0_checkers * sizeof(void*);
288         checker->check_p0 = drm_alloc(size, DRM_MEM_DRIVER);
289         if (checker->check_p0 == NULL) {
290                 amd_legacy_cmd_module_destroy(dev);
291                 return -ENOMEM;
292         }
293         /* initialize to -1 */
294         memset(checker->check_p0, 0xff, size);
295
296         /* packet 3 */
297         checker->numof_p3_checkers = 20;
298         size = checker->numof_p3_checkers * sizeof(void*);
299         checker->check_p3 = drm_alloc(size, DRM_MEM_DRIVER);
300         if (checker->check_p3 == NULL) {
301                 amd_legacy_cmd_module_destroy(dev);
302                 return -ENOMEM;
303         }
304         /* initialize to -1 */
305         memset(checker->check_p3, 0xff, size);
306
307         /* initialize packet0 checker */
308         checker->check_p0[RADEON_DST_Y_X >> 2] = p0_dst_y_x;
309         checker->check_p0[RADEON_SRC_Y_X >> 2] = p0_src_y_x;
310         checker->check_p0[RADEON_DST_HEIGHT_WIDTH >> 2] = p0_dst_h_w;
311         checker->check_p0[RADEON_DST_PITCH_OFFSET >> 2] = p0_dst_pitch_offset;
312         checker->check_p0[RADEON_SRC_PITCH_OFFSET >> 2] = p0_src_pitch_offset;
313         checker->check_p0[RADEON_DP_GUI_MASTER_CNTL>>2] = p0_dp_gui_master_cntl;
314         checker->check_p0[RADEON_DP_BRUSH_FRGD_CLR >> 2] = NULL;
315         checker->check_p0[RADEON_DP_WRITE_MASK >> 2] = NULL;
316         checker->check_p0[RADEON_DP_CNTL >> 2] = NULL;
317
318         checker->check = legacy_cmd_check;
319         return 0;
320 }