initial import
[ps3linux_kernel_patches_319.git] / 0020-ps3fb-use-fifo.patch
blob39f405d47a1b05b3a2d77460a59f260576e840b7
1 --- a/arch/powerpc/include/asm/ps3gpu.h 2012-01-03 19:41:27.000000000 +0100
2 +++ b/arch/powerpc/include/asm/ps3gpu.h 2012-01-05 23:17:51.200679863 +0100
3 @@ -25,6 +25,10 @@
4 #include <asm/lv1call.h>
7 +#define L1GPU_CONTEXT_ATTRIBUTE_FIFO_SETUP 0x1
8 +#define L1GPU_CONTEXT_ATTRIBUTE_FIFO_PAUSE 0x2
9 +#define L1GPU_CONTEXT_ATTRIBUTE_FIFO_RESUME 0x3
11 #define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC 0x101
12 #define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP 0x102
14 @@ -44,11 +48,11 @@
17 static inline int lv1_gpu_display_sync(u64 context_handle, u64 head,
18 - u64 ddr_offset)
19 + u64 sync_mode)
21 return lv1_gpu_context_attribute(context_handle,
22 L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
23 - head, ddr_offset, 0, 0);
24 + head, sync_mode, 0, 0);
27 static inline int lv1_gpu_display_flip(u64 context_handle, u64 head,
28 --- a/drivers/video/fbdev/ps3fb.c 2012-01-03 19:41:27.000000000 +0100
29 +++ b/drivers/video/fbdev/ps3fb.c 2012-01-05 23:17:32.550387632 +0100
30 @@ -50,6 +50,7 @@
32 #define GPU_INTR_STATUS_VSYNC_0 0 /* vsync on head A */
33 #define GPU_INTR_STATUS_VSYNC_1 1 /* vsync on head B */
34 +#define GPU_INTR_STATUS_GRAPH_EXCEPTION 2 /* graphics exception */
35 #define GPU_INTR_STATUS_FLIP_0 3 /* flip head A */
36 #define GPU_INTR_STATUS_FLIP_1 4 /* flip head B */
37 #define GPU_INTR_STATUS_QUEUE_0 5 /* queue head A */
38 @@ -75,6 +76,22 @@
39 u32 reserved2;
42 +struct gpu_graph_exception_info {
43 + u32 channel_id;
44 + u32 cause;
45 + u32 res1[8];
46 + u32 dma_put;
47 + u32 dma_get;
48 + u32 call;
49 + u32 jump;
50 + u32 res2;
51 + u32 fifo_put;
52 + u32 fifo_get;
53 + u32 fifo_ref;
54 + u32 fifo_cache[512];
55 + u32 graph_fifo[512];
56 +};
58 struct gpu_irq {
59 u32 irq_outlet;
60 u32 status;
61 @@ -82,11 +99,8 @@
62 u32 video_cause;
63 u32 graph_cause;
64 u32 user_cause;
66 - u32 res1;
67 - u64 res2;
69 - u32 reserved[4];
70 + u32 res[8];
71 + struct gpu_graph_exception_info graph_exception_info;
74 struct gpu_driver_info {
75 @@ -103,11 +117,27 @@
76 struct gpu_irq irq;
79 +struct gpu_fifo_ctrl {
80 + u8 res[64];
81 + u32 put;
82 + u32 get;
83 + u32 ref;
84 +};
86 +struct gpu_fifo {
87 + volatile struct gpu_fifo_ctrl *ctrl;
88 + u32 *start;
89 + u32 *curr;
90 + unsigned int len;
91 + u32 ioif;
92 +};
94 struct ps3fb_priv {
95 unsigned int irq_no;
97 u64 context_handle, memory_handle;
98 struct gpu_driver_info *dinfo;
99 + struct gpu_fifo fifo;
101 u64 vblank_count; /* frame count */
102 wait_queue_head_t wait_vsync;
103 @@ -260,8 +290,267 @@
104 static int ps3fb_mode;
105 module_param(ps3fb_mode, int, 0);
107 +static unsigned long ps3fb_gpu_ctx_flags = 0x820;
108 +module_param(ps3fb_gpu_ctx_flags, ulong, 0);
110 +static unsigned long ps3fb_gpu_mem_size[4];
111 +static int ps3fb_gpu_mem_size_count;
112 +module_param_array(ps3fb_gpu_mem_size, ulong, &ps3fb_gpu_mem_size_count, 0);
114 static char *mode_option;
116 +static int ps3fb_fb_setup(struct device *dev,
117 + u64 context_handle,
118 + struct gpu_fifo *fifo)
120 + /* FIFO program for L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP from LV1 */
121 + const static u32 fifo_setup_program[] = {
122 + 0x00042000,
123 + 0x31337303,
125 + 0x00042180,
126 + 0x66604200,
128 + 0x00082184,
129 + 0xFEED0001,
130 + 0xFEED0000,
132 + 0x00044000,
133 + 0x3137C0DE,
135 + 0x00044180,
136 + 0x66604200,
138 + 0x00084184,
139 + 0xFEED0000,
140 + 0xFEED0001,
142 + 0x00046000,
143 + 0x313371C3,
145 + 0x00046180,
146 + 0x66604200,
148 + 0x00046184,
149 + 0xFEED0000,
151 + 0x00046188,
152 + 0xFEED0000,
154 + 0x0004A000,
155 + 0x31337808,
157 + 0x0020A180,
158 + 0x66604200,
159 + 0x00000000,
160 + 0x00000000,
161 + 0x00000000,
162 + 0x00000000,
163 + 0x00000000,
164 + 0x00000000,
165 + 0x313371C3,
167 + 0x0008A2FC,
168 + 0x00000003,
169 + 0x00000004,
171 + 0x00048000,
172 + 0x31337A73,
174 + 0x00048180,
175 + 0x66604200,
177 + 0x00048184,
178 + 0xFEED0000,
180 + 0x0004C000,
181 + 0x3137AF00,
183 + 0x0004C180,
184 + 0x66604200,
186 + 0x00000000,
187 + };
188 + int retval = 0;
189 + int status;
190 + volatile struct gpu_fifo_ctrl *fifo_ctrl = fifo->ctrl;
191 + u32 *fifo_prev = fifo->curr;
192 + unsigned int timeout;
194 + pr_debug("%s: enter\n", __func__);
196 + /* copy setup program to FIFO */
197 + memcpy(fifo->curr, fifo_setup_program, sizeof(fifo_setup_program));
198 + fifo->curr += sizeof(fifo_setup_program) / sizeof(u32);
200 + /* set PUT and GET registers */
201 + status = lv1_gpu_context_attribute(context_handle,
202 + L1GPU_CONTEXT_ATTRIBUTE_FIFO_SETUP,
203 + fifo->ioif, /* PUT */
204 + fifo->ioif, /* GET */
205 + 0, /* REF */
206 + 0);
207 + if (status) {
208 + dev_err(dev, "%s: lv1_gpu_context_attribute failed (%d)\n",
209 + __func__, status);
210 + retval = -ENXIO;
211 + goto done;
214 + /* kick FIFO */
215 + fifo_ctrl->put += (fifo->curr - fifo_prev) * sizeof(u32);
217 + /* wait until FIFO is done */
218 + timeout = 100000;
219 + while (timeout--) {
220 + if (fifo_ctrl->put == fifo_ctrl->get)
221 + break;
224 + if (fifo_ctrl->put != fifo_ctrl->get)
225 + retval = -ETIMEDOUT;
227 +done:
229 + pr_debug("%s: leave (%d)\n", __func__, retval);
231 + return (retval);
234 +static int ps3fb_fb_blit(struct gpu_fifo *fifo,
235 + u64 dst_offset, u64 src_offset,
236 + u32 width, u32 height,
237 + u32 dst_pitch, u32 src_pitch,
238 + u64 flags)
240 +#define BLEN 0x400UL
242 + int retval = 0;
243 + volatile struct gpu_fifo_ctrl *fifo_ctrl = fifo->ctrl;
244 + u32 *fifo_prev = fifo->curr;
245 + unsigned int timeout;
246 + u32 h, w, x, y, dx, dy;
248 + pr_debug("%s: enter\n", __func__);
250 + /* check if there is enough free space in FIFO */
251 + if ((fifo->len - ((fifo->curr - fifo->start) * sizeof(u32))) < 0x1000) {
252 + /* no, jump back to FIFO start */
254 + pr_debug("%s: not enough free space left in FIFO put (0x%08x) get (0x%08x)\n",
255 + __func__, fifo_ctrl->put, fifo_ctrl->get);
257 + *fifo->curr++ = 0x20000000 /* JMP */ | fifo->ioif;
259 + /* kick FIFO */
260 + fifo_ctrl->put = fifo->ioif;
262 + /* wait until FIFO is done */
263 + timeout = 100000;
264 + while (timeout--) {
265 + if (fifo_ctrl->put == fifo_ctrl->get)
266 + break;
269 + if (fifo_ctrl->put != fifo_ctrl->get) {
270 + retval = -ETIMEDOUT;
271 + goto done;
274 + fifo->curr = fifo->start;
275 + fifo_prev = fifo->curr;
278 + /* FIFO program for L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT from LV1 (transfer image) */
280 + /* set source location */
281 + *fifo->curr++ = 0x0004C184;
282 + *fifo->curr++ = 0xFEED0001; /* GART memory */
284 + *fifo->curr++ = 0x0004C198;
285 + *fifo->curr++ = 0x313371C3;
287 + *fifo->curr++ = 0x00046300;
288 + *fifo->curr++ = 0x0000000A; /* 4 bytes per pixel */
290 + /*
291 + * Transfer data in a block-wise fashion with block size 1024x1024x4 bytes
292 + * by using RSX DMA controller. Go from top to bottom and from left to right.
293 + */
295 + h = height;
296 + y = 0;
298 + while (h) {
299 + dy = (h <= BLEN) ? h : BLEN;
301 + w = width;
302 + x = 0;
304 + while (w) {
305 + dx = (w <= BLEN) ? w : BLEN;
307 + *fifo->curr++ = 0x0004630C;
308 + *fifo->curr++ = dst_offset + (y & ~(BLEN - 1)) * dst_pitch + (x & ~(BLEN - 1)) * BPP; /* destination */
310 + *fifo->curr++ = 0x00046304;
311 + *fifo->curr++ = (dst_pitch << 16) | dst_pitch;
313 + *fifo->curr++ = 0x0024C2FC;
314 + *fifo->curr++ = 0x00000001;
315 + *fifo->curr++ = 0x00000003; /* 4 bytes per pixel */
316 + *fifo->curr++ = 0x00000003;
317 + *fifo->curr++ = ((x & (BLEN - 1)) << 16) | (y & (BLEN - 1));
318 + *fifo->curr++ = (dy << 16) | dx;
319 + *fifo->curr++ = ((x & (BLEN - 1)) << 16) | (y & (BLEN - 1));
320 + *fifo->curr++ = (dy << 16) | dx;
321 + *fifo->curr++ = 0x00100000;
322 + *fifo->curr++ = 0x00100000;
324 + *fifo->curr++ = 0x0010C400;
325 + *fifo->curr++ = (dy << 16) | ((dx < 0x10) ? 0x10 : (dx + 1) & ~0x1);
326 + *fifo->curr++ = 0x00020000 | src_pitch;
327 + *fifo->curr++ = src_offset + y * src_pitch + x * BPP; /* source */
328 + *fifo->curr++ = 0x00000000;
330 + w -= dx;
331 + x += dx;
334 + h -= dy;
335 + y += dy;
338 +#if 0
339 + /* wait for idle */
340 + *fifo->curr++ = 0x00040110;
341 + *fifo->curr++ = 0x00000000;
342 +#endif
344 + /* kick FIFO */
345 + fifo_ctrl->put += (fifo->curr - fifo_prev) * sizeof(u32);
347 + /* wait until FIFO is done */
348 + if (flags & L1GPU_FB_BLIT_WAIT_FOR_COMPLETION) {
349 + timeout = 100000;
350 + while (timeout--) {
351 + if (fifo_ctrl->put == fifo_ctrl->get)
352 + break;
355 + if (fifo_ctrl->put != fifo_ctrl->get)
356 + retval = -ETIMEDOUT;
359 +done:
361 + pr_debug("%s: leave (%d)\n", __func__, retval);
363 + return (retval);
365 +#undef BLEN
368 static int ps3fb_cmp_mode(const struct fb_videomode *vmode,
369 const struct fb_var_screeninfo *var)
371 @@ -444,24 +733,20 @@
372 u32 src_line_length)
374 int status;
375 - u64 line_length;
377 - line_length = dst_line_length;
378 - if (src_line_length != dst_line_length)
379 - line_length |= (u64)src_line_length << 32;
381 src_offset += GPU_FB_START;
383 mutex_lock(&ps3_gpu_mutex);
384 - status = lv1_gpu_fb_blit(ps3fb.context_handle, dst_offset,
385 - GPU_IOIF + src_offset,
386 - L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
387 - (width << 16) | height,
388 - line_length);
389 + status = ps3fb_fb_blit(&ps3fb.fifo,
390 + dst_offset,
391 + GPU_IOIF + src_offset,
392 + width, height,
393 + dst_line_length, src_line_length,
394 + L1GPU_FB_BLIT_WAIT_FOR_COMPLETION);
395 mutex_unlock(&ps3_gpu_mutex);
397 if (status)
398 - dev_err(dev, "%s: lv1_gpu_fb_blit failed: %d\n", __func__,
399 + dev_err(dev, "%s: ps3fb_fb_blit failed: %d\n", __func__,
400 status);
401 #ifdef HEAD_A
402 status = lv1_gpu_display_flip(ps3fb.context_handle, 0, frame_offset);
403 @@ -912,6 +1197,34 @@
404 return 0;
407 +static void ps3fb_print_graph_exception_info(struct device *dev,
408 + struct gpu_graph_exception_info *info)
410 + int i;
412 + dev_err(dev, "channel id 0x%08x cause 0x%08x\n", info->channel_id, info->cause);
414 + /* print FIFO info */
416 + dev_err(dev, "fifo:\n");
417 + dev_err(dev, "\tdma get 0x%08x dma put 0x%08x\n",
418 + info->dma_get, info->dma_put);
419 + dev_err(dev, "\tcall 0x%08x jump 0x%08x\n", info->call, info->jump);
420 + dev_err(dev, "\tget 0x%08x put 0x%08x ref 0x%08x\n",
421 + info->fifo_get, info->fifo_put, info->fifo_ref);
423 + for (i = 0; i < 512; i += 4) {
424 + dev_err(dev, "\t%s %s [%03x] %08x:%08x %08x:%08x %08x:%08x %08x:%08x\n",
425 + (((info->fifo_put & ~0x3) == i) ? "P" : " "),
426 + (((info->fifo_get & ~0x3) == i) ? "G" : " "),
427 + i,
428 + info->fifo_cache[i * 4 + 0], info->graph_fifo[i * 4 + 0],
429 + info->fifo_cache[i * 4 + 1], info->graph_fifo[i * 4 + 1],
430 + info->fifo_cache[i * 4 + 2], info->graph_fifo[i * 4 + 2],
431 + info->fifo_cache[i * 4 + 3], info->graph_fifo[i * 4 + 3]);
435 static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr)
437 struct device *dev = ptr;
438 @@ -926,6 +1239,11 @@
439 return IRQ_NONE;
442 + if (v1 & (1 << GPU_INTR_STATUS_GRAPH_EXCEPTION)) {
443 + dev_err(dev, "%s: graphics exception\n", __func__);
444 + ps3fb_print_graph_exception_info(dev, &ps3fb.dinfo->irq.graph_exception_info);
447 if (v1 & (1 << GPU_INTR_STATUS_VSYNC_1)) {
448 /* VSYNC */
449 ps3fb.vblank_count = head->vblank_count;
450 @@ -1030,8 +1348,9 @@
453 /* get gpu context handle */
454 - status = lv1_gpu_memory_allocate(ps3fb_videomemory.size, 0, 0, 0, 0,
455 - &ps3fb.memory_handle, &ddr_lpar);
456 + status = lv1_gpu_memory_allocate(ps3fb_videomemory.size, ps3fb_gpu_mem_size[0],
457 + ps3fb_gpu_mem_size[1], ps3fb_gpu_mem_size[2], ps3fb_gpu_mem_size[3],
458 + &ps3fb.memory_handle, &ddr_lpar);
459 if (status) {
460 dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n",
461 __func__, status);
462 @@ -1039,7 +1358,7 @@
464 dev_dbg(&dev->core, "ddr:lpar:0x%llx\n", ddr_lpar);
466 - status = lv1_gpu_context_allocate(ps3fb.memory_handle, 0,
467 + status = lv1_gpu_context_allocate(ps3fb.memory_handle, ps3fb_gpu_ctx_flags,
468 &ps3fb.context_handle,
469 &lpar_dma_control, &lpar_driver_info,
470 &lpar_reports, &lpar_reports_size);
471 @@ -1089,7 +1408,8 @@
472 goto err_destroy_plug;
475 - dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) |
476 + dinfo->irq.mask = (1 << GPU_INTR_STATUS_GRAPH_EXCEPTION) |
477 + (1 << GPU_INTR_STATUS_VSYNC_1) |
478 (1 << GPU_INTR_STATUS_FLIP_1);
480 /* Clear memory to prevent kernel info leakage into userspace */
481 @@ -1434,19 +1434,30 @@
482 ps3fb_videomemory.address, GPU_IOIF, xdr_lpar,
483 ps3fb_videomemory.size);
485 - status = lv1_gpu_fb_setup(ps3fb.context_handle, xdr_lpar,
486 - GPU_CMD_BUF_SIZE, GPU_IOIF);
487 + /* FIFO control */
488 + ps3fb.fifo.ctrl = (void __force *)ioremap_nocache(lpar_dma_control, PAGE_SIZE);
489 + if (!ps3fb.fifo.ctrl) {
490 + dev_err(&dev->core, "%s: ioremap_nocache failed\n", __func__);
491 + goto err_context_unmap;
494 + ps3fb.fifo.start = ps3fb_videomemory.address;
495 + ps3fb.fifo.curr = ps3fb.fifo.start;
496 + ps3fb.fifo.len = GPU_FB_START;
497 + ps3fb.fifo.ioif = GPU_IOIF;
499 + status = ps3fb_fb_setup(&dev->core, ps3fb.context_handle, &ps3fb.fifo);
500 if (status) {
501 - dev_err(&dev->core, "%s: lv1_gpu_fb_setup failed: %d\n",
502 + dev_err(&dev->core, "%s: ps3fb_fb_setup failed: %d\n",
503 __func__, status);
504 - retval = -ENXIO;
505 - goto err_context_unmap;
506 + retval = status;
507 + goto err_iounmap_fifo_ctrl;
510 info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core);
511 if (!info) {
512 retval = -ENOMEM;
513 - goto err_context_fb_close;
514 + goto err_iounmap_fifo_ctrl;
517 par = info->par;
518 @@ -1188,8 +1519,8 @@
519 fb_dealloc_cmap(&info->cmap);
520 err_framebuffer_release:
521 framebuffer_release(info);
522 -err_context_fb_close:
523 - lv1_gpu_fb_close(ps3fb.context_handle);
524 +err_iounmap_fifo_ctrl:
525 + iounmap((u8 __force __iomem *)ps3fb.fifo.ctrl);
526 err_context_unmap:
527 lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar,
528 ps3fb_videomemory.size, CBE_IOPTE_M);
529 @@ -1235,7 +1566,7 @@
530 ps3_system_bus_set_drvdata(dev, NULL);
532 iounmap((u8 __force __iomem *)ps3fb.dinfo);
533 - lv1_gpu_fb_close(ps3fb.context_handle);
534 + iounmap((u8 __force __iomem *)ps3fb.fifo.ctrl);
535 lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar,
536 ps3fb_videomemory.size, CBE_IOPTE_M);
537 lv1_gpu_context_free(ps3fb.context_handle);