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
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
17 static inline int lv1_gpu_display_sync(u64 context_handle, u64 head,
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
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 */
42 +struct gpu_graph_exception_info {
54 + u32 fifo_cache[512];
55 + u32 graph_fifo[512];
71 + struct gpu_graph_exception_info graph_exception_info;
74 struct gpu_driver_info {
79 +struct gpu_fifo_ctrl {
87 + volatile struct gpu_fifo_ctrl *ctrl;
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[] = {
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 */
208 + dev_err(dev, "%s: lv1_gpu_context_attribute failed (%d)\n",
215 + fifo_ctrl->put += (fifo->curr - fifo_prev) * sizeof(u32);
217 + /* wait until FIFO is done */
219 + while (timeout--) {
220 + if (fifo_ctrl->put == fifo_ctrl->get)
224 + if (fifo_ctrl->put != fifo_ctrl->get)
225 + retval = -ETIMEDOUT;
229 + pr_debug("%s: leave (%d)\n", __func__, 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,
240 +#define BLEN 0x400UL
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;
260 + fifo_ctrl->put = fifo->ioif;
262 + /* wait until FIFO is done */
264 + while (timeout--) {
265 + if (fifo_ctrl->put == fifo_ctrl->get)
269 + if (fifo_ctrl->put != fifo_ctrl->get) {
270 + retval = -ETIMEDOUT;
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 */
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.
299 + dy = (h <= BLEN) ? h : BLEN;
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;
339 + /* wait for idle */
340 + *fifo->curr++ = 0x00040110;
341 + *fifo->curr++ = 0x00000000;
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) {
350 + while (timeout--) {
351 + if (fifo_ctrl->put == fifo_ctrl->get)
355 + if (fifo_ctrl->put != fifo_ctrl->get)
356 + retval = -ETIMEDOUT;
361 + pr_debug("%s: leave (%d)\n", __func__, retval);
368 static int ps3fb_cmp_mode(const struct fb_videomode *vmode,
369 const struct fb_var_screeninfo *var)
371 @@ -444,24 +733,20 @@
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,
389 + status = ps3fb_fb_blit(&ps3fb.fifo,
391 + GPU_IOIF + src_offset,
393 + dst_line_length, src_line_length,
394 + L1GPU_FB_BLIT_WAIT_FOR_COMPLETION);
395 mutex_unlock(&ps3_gpu_mutex);
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__,
402 status = lv1_gpu_display_flip(ps3fb.context_handle, 0, frame_offset);
403 @@ -912,6 +1197,34 @@
407 +static void ps3fb_print_graph_exception_info(struct device *dev,
408 + struct gpu_graph_exception_info *info)
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" : " "),
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 @@
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)) {
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);
460 dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n",
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);
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);
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",
505 - goto err_context_unmap;
507 + goto err_iounmap_fifo_ctrl;
510 info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core);
513 - goto err_context_fb_close;
514 + goto err_iounmap_fifo_ctrl;
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);
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);