treewide: remove duplicate includes
[firefly-linux-kernel-4.4.55.git] / drivers / staging / gma500 / psb_2d.c
1 /**************************************************************************
2  * Copyright (c) 2007, Intel Corporation.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
19  * develop this driver.
20  *
21  **************************************************************************/
22
23 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/errno.h>
26 #include <linux/string.h>
27 #include <linux/mm.h>
28 #include <linux/tty.h>
29 #include <linux/slab.h>
30 #include <linux/delay.h>
31 #include <linux/fb.h>
32 #include <linux/init.h>
33 #include <linux/console.h>
34
35 #include <drm/drmP.h>
36 #include <drm/drm.h>
37 #include <drm/drm_crtc.h>
38
39 #include "psb_drv.h"
40 #include "psb_reg.h"
41 #include "psb_fb.h"
42
43 void psb_spank(struct drm_psb_private *dev_priv)
44 {
45         PSB_WSGX32(_PSB_CS_RESET_BIF_RESET | _PSB_CS_RESET_DPM_RESET |
46                 _PSB_CS_RESET_TA_RESET | _PSB_CS_RESET_USE_RESET |
47                 _PSB_CS_RESET_ISP_RESET | _PSB_CS_RESET_TSP_RESET |
48                 _PSB_CS_RESET_TWOD_RESET, PSB_CR_SOFT_RESET);
49         (void) PSB_RSGX32(PSB_CR_SOFT_RESET);
50
51         msleep(1);
52
53         PSB_WSGX32(0, PSB_CR_SOFT_RESET);
54         wmb();
55         PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) | _PSB_CB_CTRL_CLEAR_FAULT,
56                    PSB_CR_BIF_CTRL);
57         wmb();
58         (void) PSB_RSGX32(PSB_CR_BIF_CTRL);
59
60         msleep(1);
61         PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) & ~_PSB_CB_CTRL_CLEAR_FAULT,
62                    PSB_CR_BIF_CTRL);
63         (void) PSB_RSGX32(PSB_CR_BIF_CTRL);
64         PSB_WSGX32(dev_priv->pg->gatt_start, PSB_CR_BIF_TWOD_REQ_BASE);
65 }
66
67 static int psb_2d_wait_available(struct drm_psb_private *dev_priv,
68                           unsigned size)
69 {
70         uint32_t avail = PSB_RSGX32(PSB_CR_2D_SOCIF);
71         unsigned long t = jiffies + HZ;
72
73         while(avail < size) {
74                 avail = PSB_RSGX32(PSB_CR_2D_SOCIF);
75                 if (time_after(jiffies, t)) {
76                         psb_spank(dev_priv);
77                         return -EIO;
78                 }
79         }
80         return 0;
81 }
82
83 /* FIXME: Remember if we expose the 2D engine to the DRM we need to serialize
84    it with console use */
85
86 int psbfb_2d_submit(struct drm_psb_private *dev_priv, uint32_t *cmdbuf,
87                            unsigned size)
88 {
89         int ret = 0;
90         int i;
91         unsigned submit_size;
92
93         while (size > 0) {
94                 submit_size = (size < 0x60) ? size : 0x60;
95                 size -= submit_size;
96                 ret = psb_2d_wait_available(dev_priv, submit_size);
97                 if (ret)
98                         return ret;
99
100                 submit_size <<= 2;
101                 for (i = 0; i < submit_size; i += 4) {
102                         PSB_WSGX32(*cmdbuf++, PSB_SGX_2D_SLAVE_PORT + i);
103                 }
104                 (void)PSB_RSGX32(PSB_SGX_2D_SLAVE_PORT + i - 4);
105         }
106         return 0;
107 }
108
109 static int psb_accel_2d_fillrect(struct drm_psb_private *dev_priv,
110                                  uint32_t dst_offset, uint32_t dst_stride,
111                                  uint32_t dst_format, uint16_t dst_x,
112                                  uint16_t dst_y, uint16_t size_x,
113                                  uint16_t size_y, uint32_t fill)
114 {
115         uint32_t buffer[10];
116         uint32_t *buf;
117
118         buf = buffer;
119
120         *buf++ = PSB_2D_FENCE_BH;
121
122         *buf++ =
123             PSB_2D_DST_SURF_BH | dst_format | (dst_stride <<
124                                                PSB_2D_DST_STRIDE_SHIFT);
125         *buf++ = dst_offset;
126
127         *buf++ =
128             PSB_2D_BLIT_BH |
129             PSB_2D_ROT_NONE |
130             PSB_2D_COPYORDER_TL2BR |
131             PSB_2D_DSTCK_DISABLE |
132             PSB_2D_SRCCK_DISABLE | PSB_2D_USE_FILL | PSB_2D_ROP3_PATCOPY;
133
134         *buf++ = fill << PSB_2D_FILLCOLOUR_SHIFT;
135         *buf++ =
136             (dst_x << PSB_2D_DST_XSTART_SHIFT) | (dst_y <<
137                                                   PSB_2D_DST_YSTART_SHIFT);
138         *buf++ =
139             (size_x << PSB_2D_DST_XSIZE_SHIFT) | (size_y <<
140                                                   PSB_2D_DST_YSIZE_SHIFT);
141         *buf++ = PSB_2D_FLUSH_BH;
142
143         return psbfb_2d_submit(dev_priv, buffer, buf - buffer);
144 }
145
146 static void psbfb_fillrect_accel(struct fb_info *info,
147                                  const struct fb_fillrect *r)
148 {
149         struct psb_fbdev *fbdev = info->par;
150         struct psb_framebuffer *psbfb = fbdev->pfb;
151         struct drm_device *dev = psbfb->base.dev;
152         struct drm_framebuffer *fb = fbdev->psb_fb_helper.fb;
153         struct drm_psb_private *dev_priv = dev->dev_private;
154
155         uint32_t offset;
156         uint32_t stride;
157         uint32_t format;
158
159         if (!fb)
160                 return;
161
162         offset = psbfb->gtt->offset;
163         stride = fb->pitch;
164
165         switch (fb->depth) {
166         case 8:
167                 format = PSB_2D_DST_332RGB;
168                 break;
169         case 15:
170                 format = PSB_2D_DST_555RGB;
171                 break;
172         case 16:
173                 format = PSB_2D_DST_565RGB;
174                 break;
175         case 24:
176         case 32:
177                 /* this is wrong but since we don't do blending its okay */
178                 format = PSB_2D_DST_8888ARGB;
179                 break;
180         default:
181                 /* software fallback */
182                 cfb_fillrect(info, r);
183                 return;
184         }
185
186         psb_accel_2d_fillrect(dev_priv,
187                               offset, stride, format,
188                               r->dx, r->dy, r->width, r->height, r->color);
189 }
190
191 void psbfb_fillrect(struct fb_info *info,
192                            const struct fb_fillrect *rect)
193 {
194         if (unlikely(info->state != FBINFO_STATE_RUNNING))
195                 return;
196
197         if (1 || (info->flags & FBINFO_HWACCEL_DISABLED))
198                 return cfb_fillrect(info, rect);
199
200         /*psb_check_power_state(dev, PSB_DEVICE_SGX); */
201         psbfb_fillrect_accel(info, rect);
202         /* Drop power again here on MRST FIXMEAC */
203 }
204
205 static u32 psb_accel_2d_copy_direction(int xdir, int ydir)
206 {
207         if (xdir < 0)
208                 return (ydir < 0) ? PSB_2D_COPYORDER_BR2TL :
209                                         PSB_2D_COPYORDER_TR2BL;
210         else
211                 return (ydir < 0) ? PSB_2D_COPYORDER_BL2TR :
212                                         PSB_2D_COPYORDER_TL2BR;
213 }
214
215 /*
216  * @src_offset in bytes
217  * @src_stride in bytes
218  * @src_format psb 2D format defines
219  * @dst_offset in bytes
220  * @dst_stride in bytes
221  * @dst_format psb 2D format defines
222  * @src_x offset in pixels
223  * @src_y offset in pixels
224  * @dst_x offset in pixels
225  * @dst_y offset in pixels
226  * @size_x of the copied area
227  * @size_y of the copied area
228  */
229 static int psb_accel_2d_copy(struct drm_psb_private *dev_priv,
230                              uint32_t src_offset, uint32_t src_stride,
231                              uint32_t src_format, uint32_t dst_offset,
232                              uint32_t dst_stride, uint32_t dst_format,
233                              uint16_t src_x, uint16_t src_y,
234                              uint16_t dst_x, uint16_t dst_y,
235                              uint16_t size_x, uint16_t size_y)
236 {
237         uint32_t blit_cmd;
238         uint32_t buffer[10];
239         uint32_t *buf;
240         uint32_t direction;
241
242         buf = buffer;
243
244         direction =
245             psb_accel_2d_copy_direction(src_x - dst_x, src_y - dst_y);
246
247         if (direction == PSB_2D_COPYORDER_BR2TL ||
248             direction == PSB_2D_COPYORDER_TR2BL) {
249                 src_x += size_x - 1;
250                 dst_x += size_x - 1;
251         }
252         if (direction == PSB_2D_COPYORDER_BR2TL ||
253             direction == PSB_2D_COPYORDER_BL2TR) {
254                 src_y += size_y - 1;
255                 dst_y += size_y - 1;
256         }
257
258         blit_cmd =
259             PSB_2D_BLIT_BH |
260             PSB_2D_ROT_NONE |
261             PSB_2D_DSTCK_DISABLE |
262             PSB_2D_SRCCK_DISABLE |
263             PSB_2D_USE_PAT | PSB_2D_ROP3_SRCCOPY | direction;
264
265         *buf++ = PSB_2D_FENCE_BH;
266         *buf++ =
267             PSB_2D_DST_SURF_BH | dst_format | (dst_stride <<
268                                                PSB_2D_DST_STRIDE_SHIFT);
269         *buf++ = dst_offset;
270         *buf++ =
271             PSB_2D_SRC_SURF_BH | src_format | (src_stride <<
272                                                PSB_2D_SRC_STRIDE_SHIFT);
273         *buf++ = src_offset;
274         *buf++ =
275             PSB_2D_SRC_OFF_BH | (src_x << PSB_2D_SRCOFF_XSTART_SHIFT) |
276             (src_y << PSB_2D_SRCOFF_YSTART_SHIFT);
277         *buf++ = blit_cmd;
278         *buf++ =
279             (dst_x << PSB_2D_DST_XSTART_SHIFT) | (dst_y <<
280                                                   PSB_2D_DST_YSTART_SHIFT);
281         *buf++ =
282             (size_x << PSB_2D_DST_XSIZE_SHIFT) | (size_y <<
283                                                   PSB_2D_DST_YSIZE_SHIFT);
284         *buf++ = PSB_2D_FLUSH_BH;
285
286         return psbfb_2d_submit(dev_priv, buffer, buf - buffer);
287 }
288
289 static void psbfb_copyarea_accel(struct fb_info *info,
290                                  const struct fb_copyarea *a)
291 {
292         struct psb_fbdev *fbdev = info->par;
293         struct psb_framebuffer *psbfb = fbdev->pfb;
294         struct drm_device *dev = psbfb->base.dev;
295         struct drm_framebuffer *fb = fbdev->psb_fb_helper.fb;
296         struct drm_psb_private *dev_priv = dev->dev_private;
297         uint32_t offset;
298         uint32_t stride;
299         uint32_t src_format;
300         uint32_t dst_format;
301
302         if (!fb)
303                 return;
304
305         offset = psbfb->gtt->offset;
306         stride = fb->pitch;
307
308         switch (fb->depth) {
309         case 8:
310                 src_format = PSB_2D_SRC_332RGB;
311                 dst_format = PSB_2D_DST_332RGB;
312                 break;
313         case 15:
314                 src_format = PSB_2D_SRC_555RGB;
315                 dst_format = PSB_2D_DST_555RGB;
316                 break;
317         case 16:
318                 src_format = PSB_2D_SRC_565RGB;
319                 dst_format = PSB_2D_DST_565RGB;
320                 break;
321         case 24:
322         case 32:
323                 /* this is wrong but since we don't do blending its okay */
324                 src_format = PSB_2D_SRC_8888ARGB;
325                 dst_format = PSB_2D_DST_8888ARGB;
326                 break;
327         default:
328                 /* software fallback */
329                 cfb_copyarea(info, a);
330                 return;
331         }
332
333         psb_accel_2d_copy(dev_priv,
334                           offset, stride, src_format,
335                           offset, stride, dst_format,
336                           a->sx, a->sy, a->dx, a->dy, a->width, a->height);
337 }
338
339 void psbfb_copyarea(struct fb_info *info,
340                            const struct fb_copyarea *region)
341 {
342         if (unlikely(info->state != FBINFO_STATE_RUNNING))
343                 return;
344
345         if (info->flags & FBINFO_HWACCEL_DISABLED)
346                 return cfb_copyarea(info, region);
347
348         /* psb_check_power_state(dev, PSB_DEVICE_SGX); */
349         psbfb_copyarea_accel(info, region);
350         /* Need to power back off here for MRST FIXMEAC */
351 }
352
353 void psbfb_imageblit(struct fb_info *info, const struct fb_image *image)
354 {
355         /* For now */
356         cfb_imageblit(info, image);
357 }
358
359 int psbfb_sync(struct fb_info *info)
360 {
361         struct psb_fbdev *fbdev = info->par;
362         struct psb_framebuffer *psbfb = fbdev->pfb;
363         struct drm_device *dev = psbfb->base.dev;
364         struct drm_psb_private *dev_priv = dev->dev_private;
365         unsigned long _end = jiffies + DRM_HZ;
366         int busy = 0;
367
368 #if 0
369         /* Just a way to quickly test if cmd issue explodes */
370         u32 test[2] = {
371                 PSB_2D_FENCE_BH,
372         };
373         psbfb_2d_submit(dev_priv, test, 1);
374 #endif  
375         /*
376          * First idle the 2D engine.
377          */
378
379         if ((PSB_RSGX32(PSB_CR_2D_SOCIF) == _PSB_C2_SOCIF_EMPTY) &&
380             ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & _PSB_C2B_STATUS_BUSY) == 0))
381                 goto out;
382
383         do {
384                 busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY);
385                 cpu_relax();
386         } while (busy && !time_after_eq(jiffies, _end));
387
388         if (busy)
389                 busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY);
390         if (busy)
391                 goto out;
392
393         do {
394                 busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) &
395                                                 _PSB_C2B_STATUS_BUSY) != 0);
396                 cpu_relax();
397         } while (busy && !time_after_eq(jiffies, _end));
398         if (busy)
399                 busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) &
400                                         _PSB_C2B_STATUS_BUSY) != 0);
401
402 out:
403         return (busy) ? -EBUSY : 0;
404 }
405
406 /*
407         info->fix.accel = FB_ACCEL_I830;
408         info->flags = FBINFO_DEFAULT;
409 */