^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * linux/drivers/video/ps3fb.c -- PS3 GPU frame buffer device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2006 Sony Computer Entertainment Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright 2006, 2007 Sony Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * This file is based on :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * linux/drivers/video/vfb.c -- Virtual frame buffer device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Copyright (C) 2002 James Simmons
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Copyright (C) 1997 Geert Uytterhoeven
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * License. See the file COPYING in the main directory of this archive for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/ioctl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/kthread.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/freezer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/fbcon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <asm/cell-regs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <asm/lv1call.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <asm/ps3av.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <asm/ps3fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <asm/ps3.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <asm/ps3gpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define DEVICE_NAME "ps3fb"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define GPU_CMD_BUF_SIZE (2 * 1024 * 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define GPU_FB_START (64 * 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define GPU_IOIF (0x0d000000UL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define GPU_ALIGN_UP(x) ALIGN((x), 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define GPU_MAX_LINE_LENGTH (65536 - 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define GPU_INTR_STATUS_VSYNC_0 0 /* vsync on head A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define GPU_INTR_STATUS_VSYNC_1 1 /* vsync on head B */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define GPU_INTR_STATUS_FLIP_0 3 /* flip head A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define GPU_INTR_STATUS_FLIP_1 4 /* flip head B */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define GPU_INTR_STATUS_QUEUE_0 5 /* queue head A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define GPU_INTR_STATUS_QUEUE_1 6 /* queue head B */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define GPU_DRIVER_INFO_VERSION 0x211
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) /* gpu internals */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct display_head {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) u64 be_time_stamp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) u32 status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) u32 offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) u32 res1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) u32 res2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) u32 field;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) u32 reserved1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) u64 res3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) u32 raster;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) u64 vblank_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) u32 field_vsync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) u32 reserved2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) struct gpu_irq {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) u32 irq_outlet;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) u32 status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) u32 mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) u32 video_cause;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) u32 graph_cause;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) u32 user_cause;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) u32 res1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) u64 res2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) u32 reserved[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct gpu_driver_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) u32 version_driver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) u32 version_gpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) u32 memory_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) u32 hardware_channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) u32 nvcore_frequency;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) u32 memory_frequency;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) u32 reserved[1063];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct display_head display_head[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct gpu_irq irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) struct ps3fb_priv {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) unsigned int irq_no;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) u64 context_handle, memory_handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct gpu_driver_info *dinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) u64 vblank_count; /* frame count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) wait_queue_head_t wait_vsync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) atomic_t ext_flip; /* on/off flip with vsync */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) atomic_t f_count; /* fb_open count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) int is_blanked;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) int is_kicked;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) struct task_struct *task;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static struct ps3fb_priv ps3fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) struct ps3fb_par {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) u32 pseudo_palette[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) int mode_id, new_mode_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) unsigned int num_frames; /* num of frame buffers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) unsigned int width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) unsigned int height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) unsigned int ddr_line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) unsigned int ddr_frame_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) unsigned int xdr_frame_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) unsigned int full_offset; /* start of fullscreen DDR fb */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) unsigned int fb_offset; /* start of actual DDR fb */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) unsigned int pan_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) #define FIRST_NATIVE_MODE_INDEX 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static const struct fb_videomode ps3fb_modedb[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) /* 60 Hz broadcast modes (modes "1" to "5") */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) /* 480i */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) "480i", 60, 576, 384, 74074, 130, 89, 78, 57, 63, 6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) /* 480p */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) "480p", 60, 576, 384, 37037, 130, 89, 78, 57, 63, 6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /* 720p */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) "720p", 60, 1124, 644, 13481, 298, 148, 57, 44, 80, 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) /* 1080i */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) "1080i", 60, 1688, 964, 13481, 264, 160, 94, 62, 88, 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) /* 1080p */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) "1080p", 60, 1688, 964, 6741, 264, 160, 94, 62, 88, 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) /* 50 Hz broadcast modes (modes "6" to "10") */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) /* 576i */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) "576i", 50, 576, 460, 74074, 142, 83, 97, 63, 63, 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) /* 576p */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) "576p", 50, 576, 460, 37037, 142, 83, 97, 63, 63, 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) /* 720p */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) "720p", 50, 1124, 644, 13468, 298, 478, 57, 44, 80, 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /* 1080i */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) "1080i", 50, 1688, 964, 13468, 264, 600, 94, 62, 88, 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) /* 1080p */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) "1080p", 50, 1688, 964, 6734, 264, 600, 94, 62, 88, 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) [FIRST_NATIVE_MODE_INDEX] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) /* 60 Hz broadcast modes (full resolution versions of modes "1" to "5") */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) /* 480if */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) "480if", 60, 720, 480, 74074, 58, 17, 30, 9, 63, 6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) /* 480pf */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) "480pf", 60, 720, 480, 37037, 58, 17, 30, 9, 63, 6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) /* 720pf */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) "720pf", 60, 1280, 720, 13481, 220, 70, 19, 6, 80, 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) /* 1080if */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) "1080if", 60, 1920, 1080, 13481, 148, 44, 36, 4, 88, 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) /* 1080pf */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) "1080pf", 60, 1920, 1080, 6741, 148, 44, 36, 4, 88, 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) /* 50 Hz broadcast modes (full resolution versions of modes "6" to "10") */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) /* 576if */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) "576if", 50, 720, 576, 74074, 70, 11, 39, 5, 63, 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) /* 576pf */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) "576pf", 50, 720, 576, 37037, 70, 11, 39, 5, 63, 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) /* 720pf */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) "720pf", 50, 1280, 720, 13468, 220, 400, 19, 6, 80, 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) /* 1080if */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) "1080if", 50, 1920, 1080, 13468, 148, 484, 36, 4, 88, 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) /* 1080pf */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) "1080pf", 50, 1920, 1080, 6734, 148, 484, 36, 4, 88, 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) /* VESA modes (modes "11" to "13") */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) /* WXGA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 0, FB_VMODE_NONINTERLACED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) FB_MODE_IS_VESA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) /* SXGA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) FB_MODE_IS_VESA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) /* WUXGA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) FB_MODE_IS_VESA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) #define HEAD_A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) #define HEAD_B
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) #define BPP 4 /* number of bytes per pixel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) static int ps3fb_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) module_param(ps3fb_mode, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) static char *mode_option;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) static int ps3fb_cmp_mode(const struct fb_videomode *vmode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) const struct fb_var_screeninfo *var)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) long xres, yres, left_margin, right_margin, upper_margin, lower_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) long dx, dy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) /* maximum values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (var->xres > vmode->xres || var->yres > vmode->yres ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) var->pixclock > vmode->pixclock ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) var->hsync_len > vmode->hsync_len ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) var->vsync_len > vmode->vsync_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) /* progressive/interlaced must match */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) if ((var->vmode & FB_VMODE_MASK) != vmode->vmode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) /* minimum resolution */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) xres = max(var->xres, 1U);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) yres = max(var->yres, 1U);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) /* minimum margins */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) left_margin = max(var->left_margin, vmode->left_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) right_margin = max(var->right_margin, vmode->right_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) upper_margin = max(var->upper_margin, vmode->upper_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) lower_margin = max(var->lower_margin, vmode->lower_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) /* resolution + margins may not exceed native parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) dx = ((long)vmode->left_margin + (long)vmode->xres +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) (long)vmode->right_margin) -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) (left_margin + xres + right_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if (dx < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) dy = ((long)vmode->upper_margin + (long)vmode->yres +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) (long)vmode->lower_margin) -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) (upper_margin + yres + lower_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) if (dy < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) /* exact match */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if (!dx && !dy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) /* resolution difference */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) return (vmode->xres - xres) * (vmode->yres - yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) static const struct fb_videomode *ps3fb_native_vmode(enum ps3av_mode_num id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) return &ps3fb_modedb[FIRST_NATIVE_MODE_INDEX + id - 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) static const struct fb_videomode *ps3fb_vmode(int id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) u32 mode = id & PS3AV_MODE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) if (mode < PS3AV_MODE_480I || mode > PS3AV_MODE_WUXGA)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (mode <= PS3AV_MODE_1080P50 && !(id & PS3AV_MODE_FULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) /* Non-fullscreen broadcast mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) return &ps3fb_modedb[mode - 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) return ps3fb_native_vmode(mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) static unsigned int ps3fb_find_mode(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) u32 *ddr_line_length, u32 *xdr_line_length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) unsigned int id, best_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) int diff, best_diff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) const struct fb_videomode *vmode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) long gap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) best_id = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) best_diff = INT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) pr_debug("%s: wanted %u [%u] %u x %u [%u] %u\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) var->left_margin, var->xres, var->right_margin,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) var->upper_margin, var->yres, var->lower_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) for (id = PS3AV_MODE_480I; id <= PS3AV_MODE_WUXGA; id++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) vmode = ps3fb_native_vmode(id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) diff = ps3fb_cmp_mode(vmode, var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) pr_debug("%s: mode %u: %u [%u] %u x %u [%u] %u: diff = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) __func__, id, vmode->left_margin, vmode->xres,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) vmode->right_margin, vmode->upper_margin,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) vmode->yres, vmode->lower_margin, diff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (diff < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) if (diff < best_diff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) best_id = id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) if (!diff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) best_diff = diff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) if (!best_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) pr_debug("%s: no suitable mode found\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) id = best_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) vmode = ps3fb_native_vmode(id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) *ddr_line_length = vmode->xres * BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) /* minimum resolution */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) if (!var->xres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) var->xres = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) if (!var->yres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) var->yres = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) /* minimum virtual resolution */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) if (var->xres_virtual < var->xres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) var->xres_virtual = var->xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if (var->yres_virtual < var->yres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) var->yres_virtual = var->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) /* minimum margins */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) if (var->left_margin < vmode->left_margin)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) var->left_margin = vmode->left_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) if (var->right_margin < vmode->right_margin)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) var->right_margin = vmode->right_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) if (var->upper_margin < vmode->upper_margin)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) var->upper_margin = vmode->upper_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) if (var->lower_margin < vmode->lower_margin)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) var->lower_margin = vmode->lower_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) /* extra margins */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) gap = ((long)vmode->left_margin + (long)vmode->xres +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) (long)vmode->right_margin) -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) ((long)var->left_margin + (long)var->xres +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) (long)var->right_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) if (gap > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) var->left_margin += gap/2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) var->right_margin += (gap+1)/2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) pr_debug("%s: rounded up H to %u [%u] %u\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) var->left_margin, var->xres, var->right_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) gap = ((long)vmode->upper_margin + (long)vmode->yres +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) (long)vmode->lower_margin) -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) ((long)var->upper_margin + (long)var->yres +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) (long)var->lower_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) if (gap > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) var->upper_margin += gap/2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) var->lower_margin += (gap+1)/2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) pr_debug("%s: rounded up V to %u [%u] %u\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) var->upper_margin, var->yres, var->lower_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) /* fixed fields */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) var->pixclock = vmode->pixclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) var->hsync_len = vmode->hsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) var->vsync_len = vmode->vsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) var->sync = vmode->sync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) if (ps3_compare_firmware_version(1, 9, 0) >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) *xdr_line_length = GPU_ALIGN_UP(var->xres_virtual * BPP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) if (*xdr_line_length > GPU_MAX_LINE_LENGTH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) *xdr_line_length = GPU_MAX_LINE_LENGTH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) *xdr_line_length = *ddr_line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) if (vmode->sync & FB_SYNC_BROADCAST) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) /* Full broadcast modes have the full mode bit set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) if (vmode->xres == var->xres && vmode->yres == var->yres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) id |= PS3AV_MODE_FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) pr_debug("%s: mode %u\n", __func__, id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) return id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) u64 dst_offset, u64 src_offset, u32 width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) u32 height, u32 dst_line_length,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) u32 src_line_length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) u64 line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) line_length = dst_line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) if (src_line_length != dst_line_length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) line_length |= (u64)src_line_length << 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) src_offset += GPU_FB_START;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) mutex_lock(&ps3_gpu_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) status = lv1_gpu_fb_blit(ps3fb.context_handle, dst_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) GPU_IOIF + src_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) (width << 16) | height,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) line_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) mutex_unlock(&ps3_gpu_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) if (status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) dev_err(dev, "%s: lv1_gpu_fb_blit failed: %d\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) #ifdef HEAD_A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) status = lv1_gpu_display_flip(ps3fb.context_handle, 0, frame_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) if (status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) #ifdef HEAD_B
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) status = lv1_gpu_display_flip(ps3fb.context_handle, 1, frame_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) if (status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) static int ps3fb_sync(struct fb_info *info, u32 frame)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) struct ps3fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) int error = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) u64 ddr_base, xdr_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) if (frame > par->num_frames - 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) dev_dbg(info->device, "%s: invalid frame number (%u)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) __func__, frame);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) error = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) xdr_base = frame * par->xdr_frame_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) ddr_base = frame * par->ddr_frame_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) ps3fb_sync_image(info->device, ddr_base + par->full_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) ddr_base + par->fb_offset, xdr_base + par->pan_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) par->width, par->height, par->ddr_line_length,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) info->fix.line_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) static int ps3fb_open(struct fb_info *info, int user)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) atomic_inc(&ps3fb.f_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) static int ps3fb_release(struct fb_info *info, int user)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) if (atomic_dec_and_test(&ps3fb.f_count)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) if (atomic_read(&ps3fb.ext_flip)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) atomic_set(&ps3fb.ext_flip, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) if (console_trylock()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) ps3fb_sync(info, 0); /* single buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) * Setting the video mode has been split into two parts.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) * First part, xxxfb_check_var, must not write anything
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) * to hardware, it should only verify and adjust var.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) * This means it doesn't alter par but it does use hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) * data from it to check this var.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) u32 xdr_line_length, ddr_line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) int mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) mode = ps3fb_find_mode(var, &ddr_line_length, &xdr_line_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) if (!mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) /* Virtual screen */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) if (var->xres_virtual > xdr_line_length / BPP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) dev_dbg(info->device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) "Horizontal virtual screen size too large\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) if (var->xoffset + var->xres > var->xres_virtual ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) var->yoffset + var->yres > var->yres_virtual) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) dev_dbg(info->device, "panning out-of-range\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) /* We support ARGB8888 only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) if (var->bits_per_pixel > 32 || var->grayscale ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) var->red.offset > 16 || var->green.offset > 8 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) var->blue.offset > 0 || var->transp.offset > 24 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) var->red.length > 8 || var->green.length > 8 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) var->blue.length > 8 || var->transp.length > 8 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) var->red.msb_right || var->green.msb_right ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) var->blue.msb_right || var->transp.msb_right || var->nonstd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) dev_dbg(info->device, "We support ARGB8888 only\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) var->bits_per_pixel = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) var->red.offset = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) var->green.offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) var->transp.offset = 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) var->transp.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) var->red.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) var->green.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) var->blue.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) var->transp.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) /* Rotation is not supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) if (var->rotate) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) dev_dbg(info->device, "Rotation is not supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) /* Memory limit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) if (var->yres_virtual * xdr_line_length > info->fix.smem_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) dev_dbg(info->device, "Not enough memory\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) var->height = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) var->width = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) * This routine actually sets the video mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) static int ps3fb_set_par(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) struct ps3fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) unsigned int mode, ddr_line_length, xdr_line_length, lines, maxlines;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) unsigned int ddr_xoff, ddr_yoff, offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) const struct fb_videomode *vmode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) u64 dst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) mode = ps3fb_find_mode(&info->var, &ddr_line_length, &xdr_line_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) if (!mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) vmode = ps3fb_native_vmode(mode & PS3AV_MODE_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) info->fix.line_length = xdr_line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) par->ddr_line_length = ddr_line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) par->ddr_frame_size = vmode->yres * ddr_line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) par->xdr_frame_size = info->var.yres_virtual * xdr_line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) par->num_frames = info->fix.smem_len /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) max(par->ddr_frame_size, par->xdr_frame_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) /* Keep the special bits we cannot set using fb_var_screeninfo */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) par->width = info->var.xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) par->height = info->var.yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) /* Start of the virtual frame buffer (relative to fullscreen) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) ddr_xoff = info->var.left_margin - vmode->left_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) ddr_yoff = info->var.upper_margin - vmode->upper_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) offset = ddr_yoff * ddr_line_length + ddr_xoff * BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) par->fb_offset = GPU_ALIGN_UP(offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) par->full_offset = par->fb_offset - offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) par->pan_offset = info->var.yoffset * xdr_line_length +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) info->var.xoffset * BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) if (par->new_mode_id != par->mode_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) if (ps3av_set_video_mode(par->new_mode_id)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) par->new_mode_id = par->mode_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) par->mode_id = par->new_mode_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) /* Clear XDR frame buffer memory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) memset((void __force *)info->screen_base, 0, info->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) /* Clear DDR frame buffer memory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) lines = vmode->yres * par->num_frames;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) if (par->full_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) lines++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) maxlines = info->fix.smem_len / ddr_line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) for (dst = 0; lines; dst += maxlines * ddr_line_length) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) unsigned int l = min(lines, maxlines);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) ps3fb_sync_image(info->device, 0, dst, 0, vmode->xres, l,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) ddr_line_length, ddr_line_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) lines -= l;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) * Set a single color register. The values supplied are already
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) * rounded down to the hardware's capabilities (according to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) * entries in the var structure). Return != 0 for invalid regno.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) static int ps3fb_setcolreg(unsigned int regno, unsigned int red,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) unsigned int green, unsigned int blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) unsigned int transp, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) if (regno >= 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) red >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) green >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) blue >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) transp >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) ((u32 *)info->pseudo_palette)[regno] = transp << 24 | red << 16 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) green << 8 | blue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) static int ps3fb_pan_display(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) struct ps3fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) par->pan_offset = var->yoffset * info->fix.line_length +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) var->xoffset * BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) * As we have a virtual frame buffer, we need our own mmap function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) static int ps3fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) r = vm_iomap_memory(vma, info->fix.smem_start, info->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) dev_dbg(info->device, "ps3fb: mmap framebuffer P(%lx)->V(%lx)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) info->fix.smem_start + (vma->vm_pgoff << PAGE_SHIFT),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) vma->vm_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) * Blank the display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) static int ps3fb_blank(int blank, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) dev_dbg(info->device, "%s: blank:%d\n", __func__, blank);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) switch (blank) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) case FB_BLANK_POWERDOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) case FB_BLANK_HSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) case FB_BLANK_VSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) case FB_BLANK_NORMAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) retval = ps3av_video_mute(1); /* mute on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) if (!retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) ps3fb.is_blanked = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) default: /* unblank */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) retval = ps3av_video_mute(0); /* mute off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) if (!retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) ps3fb.is_blanked = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) static int ps3fb_get_vblank(struct fb_vblank *vblank)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) memset(vblank, 0, sizeof(*vblank));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) vblank->flags = FB_VBLANK_HAVE_VSYNC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) static int ps3fb_wait_for_vsync(u32 crtc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) u64 count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) count = ps3fb.vblank_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) ret = wait_event_interruptible_timeout(ps3fb.wait_vsync,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) count != ps3fb.vblank_count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) HZ / 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) * ioctl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) void __user *argp = (void __user *)arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) int retval = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) case FBIOGET_VBLANK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) struct fb_vblank vblank;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) dev_dbg(info->device, "FBIOGET_VBLANK:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) retval = ps3fb_get_vblank(&vblank);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) if (copy_to_user(argp, &vblank, sizeof(vblank)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) retval = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) case FBIO_WAITFORVSYNC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) u32 crt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) dev_dbg(info->device, "FBIO_WAITFORVSYNC:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) if (get_user(crt, (u32 __user *) arg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) retval = ps3fb_wait_for_vsync(crt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) case PS3FB_IOCTL_SETMODE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) struct ps3fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) const struct fb_videomode *vmode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) struct fb_var_screeninfo var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) if (copy_from_user(&val, argp, sizeof(val)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) if (!(val & PS3AV_MODE_MASK)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) u32 id = ps3av_get_auto_mode();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) if (id > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) val = (val & ~PS3AV_MODE_MASK) | id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) retval = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) vmode = ps3fb_vmode(val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) if (vmode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) var = info->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) fb_videomode_to_var(&var, vmode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) console_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) /* Force, in case only special bits changed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) var.activate |= FB_ACTIVATE_FORCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) par->new_mode_id = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) retval = fb_set_var(info, &var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) if (!retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) fbcon_update_vcs(info, var.activate & FB_ACTIVATE_ALL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) case PS3FB_IOCTL_GETMODE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) val = ps3av_get_mode();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) dev_dbg(info->device, "PS3FB_IOCTL_GETMODE:%x\n", val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) if (!copy_to_user(argp, &val, sizeof(val)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) case PS3FB_IOCTL_SCREENINFO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) struct ps3fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) struct ps3fb_ioctl_res res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) dev_dbg(info->device, "PS3FB_IOCTL_SCREENINFO:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) res.xres = info->fix.line_length / BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) res.yres = info->var.yres_virtual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) res.xoff = (res.xres - info->var.xres) / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) res.yoff = (res.yres - info->var.yres) / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) res.num_frames = par->num_frames;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) if (!copy_to_user(argp, &res, sizeof(res)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) case PS3FB_IOCTL_ON:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) dev_dbg(info->device, "PS3FB_IOCTL_ON:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) atomic_inc(&ps3fb.ext_flip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) case PS3FB_IOCTL_OFF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) dev_dbg(info->device, "PS3FB_IOCTL_OFF:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) atomic_dec_if_positive(&ps3fb.ext_flip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) case PS3FB_IOCTL_FSEL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) if (copy_from_user(&val, argp, sizeof(val)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) dev_dbg(info->device, "PS3FB_IOCTL_FSEL:%d\n", val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) console_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) retval = ps3fb_sync(info, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) retval = -ENOIOCTLCMD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) static int ps3fbd(void *arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) struct fb_info *info = arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) set_freezable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) while (!kthread_should_stop()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) try_to_freeze();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) set_current_state(TASK_INTERRUPTIBLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) if (ps3fb.is_kicked) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) ps3fb.is_kicked = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) console_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) ps3fb_sync(info, 0); /* single buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) schedule();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) struct device *dev = ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) u64 v1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) struct display_head *head = &ps3fb.dinfo->display_head[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) status = lv1_gpu_context_intr(ps3fb.context_handle, &v1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) if (status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) dev_err(dev, "%s: lv1_gpu_context_intr failed: %d\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) if (v1 & (1 << GPU_INTR_STATUS_VSYNC_1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) /* VSYNC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) ps3fb.vblank_count = head->vblank_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) if (ps3fb.task && !ps3fb.is_blanked &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) !atomic_read(&ps3fb.ext_flip)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) ps3fb.is_kicked = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) wake_up_process(ps3fb.task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) wake_up_interruptible(&ps3fb.wait_vsync);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) static const struct fb_ops ps3fb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) .fb_open = ps3fb_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) .fb_release = ps3fb_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) .fb_read = fb_sys_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) .fb_write = fb_sys_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) .fb_check_var = ps3fb_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) .fb_set_par = ps3fb_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) .fb_setcolreg = ps3fb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) .fb_pan_display = ps3fb_pan_display,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) .fb_fillrect = sys_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) .fb_copyarea = sys_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) .fb_imageblit = sys_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) .fb_mmap = ps3fb_mmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) .fb_blank = ps3fb_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) .fb_ioctl = ps3fb_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) .fb_compat_ioctl = ps3fb_ioctl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) static const struct fb_fix_screeninfo ps3fb_fix = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) .id = DEVICE_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) .type = FB_TYPE_PACKED_PIXELS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) .visual = FB_VISUAL_TRUECOLOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) .accel = FB_ACCEL_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) static int ps3fb_probe(struct ps3_system_bus_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) struct ps3fb_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) u64 ddr_lpar = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) u64 lpar_dma_control = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) u64 lpar_driver_info = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) u64 lpar_reports = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) u64 lpar_reports_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) u64 xdr_lpar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) struct gpu_driver_info *dinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) void *fb_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) struct task_struct *task;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) unsigned long max_ps3fb_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) if (ps3fb_videomemory.size < GPU_CMD_BUF_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) dev_err(&dev->core, "%s: Not enough video memory\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) retval = ps3_open_hv_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) dev_err(&dev->core, "%s: ps3_open_hv_device failed\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) if (!ps3fb_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) ps3fb_mode = ps3av_get_mode();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) dev_dbg(&dev->core, "ps3fb_mode: %d\n", ps3fb_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) init_waitqueue_head(&ps3fb.wait_vsync);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) #ifdef HEAD_A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) status = lv1_gpu_display_sync(0x0, 0, L1GPU_DISPLAY_SYNC_VSYNC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) if (status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) __func__, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) retval = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) goto err_close_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) #ifdef HEAD_B
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) status = lv1_gpu_display_sync(0x0, 1, L1GPU_DISPLAY_SYNC_VSYNC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) if (status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) __func__, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) retval = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) goto err_close_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) max_ps3fb_size = ALIGN(GPU_IOIF, 256*1024*1024) - GPU_IOIF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) if (ps3fb_videomemory.size > max_ps3fb_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) dev_info(&dev->core, "Limiting ps3fb mem size to %lu bytes\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) max_ps3fb_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) ps3fb_videomemory.size = max_ps3fb_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) /* get gpu context handle */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) status = lv1_gpu_memory_allocate(ps3fb_videomemory.size, 0, 0, 0, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) &ps3fb.memory_handle, &ddr_lpar);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) if (status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) __func__, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) goto err_close_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) dev_dbg(&dev->core, "ddr:lpar:0x%llx\n", ddr_lpar);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) status = lv1_gpu_context_allocate(ps3fb.memory_handle, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) &ps3fb.context_handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) &lpar_dma_control, &lpar_driver_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) &lpar_reports, &lpar_reports_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) if (status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) dev_err(&dev->core,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) "%s: lv1_gpu_context_allocate failed: %d\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) goto err_gpu_memory_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) /* vsync interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) if (!dinfo) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) dev_err(&dev->core, "%s: ioremap failed\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) goto err_gpu_context_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) ps3fb.dinfo = dinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) dev_dbg(&dev->core, "version_driver:%x\n", dinfo->version_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) dev_dbg(&dev->core, "irq outlet:%x\n", dinfo->irq.irq_outlet);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) dev_dbg(&dev->core, "version_gpu: %x memory_size: %x ch: %x "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) "core_freq: %d mem_freq:%d\n", dinfo->version_gpu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) dinfo->memory_size, dinfo->hardware_channel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) dinfo->nvcore_frequency/1000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) dinfo->memory_frequency/1000000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) dev_err(&dev->core, "%s: version_driver err:%x\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) dinfo->version_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) retval = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) goto err_iounmap_dinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) retval = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) &ps3fb.irq_no);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) dev_err(&dev->core, "%s: ps3_alloc_irq failed %d\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) retval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) goto err_iounmap_dinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) retval = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) 0, DEVICE_NAME, &dev->core);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) dev_err(&dev->core, "%s: request_irq failed %d\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) retval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) goto err_destroy_plug;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) (1 << GPU_INTR_STATUS_FLIP_1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) /* Clear memory to prevent kernel info leakage into userspace */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) xdr_lpar, ps3fb_videomemory.size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) CBE_IOPTE_PP_W | CBE_IOPTE_PP_R |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) CBE_IOPTE_M);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) if (status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) dev_err(&dev->core, "%s: lv1_gpu_context_iomap failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) __func__, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) retval = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) goto err_free_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) dev_dbg(&dev->core, "video:%p ioif:%lx lpar:%llx size:%lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) ps3fb_videomemory.address, GPU_IOIF, xdr_lpar,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) ps3fb_videomemory.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) status = lv1_gpu_fb_setup(ps3fb.context_handle, xdr_lpar,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) GPU_CMD_BUF_SIZE, GPU_IOIF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) if (status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) dev_err(&dev->core, "%s: lv1_gpu_fb_setup failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) __func__, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) retval = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) goto err_context_unmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) if (!info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) goto err_context_fb_close;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) par->new_mode_id = ps3fb_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) par->num_frames = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) info->fbops = &ps3fb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) info->fix = ps3fb_fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) * The GPU command buffer is at the start of video memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) * As we don't use the full command buffer, we can put the actual
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) * frame buffer at offset GPU_FB_START and save some precious XDR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) * memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) fb_start = ps3fb_videomemory.address + GPU_FB_START;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) info->screen_base = (char __force __iomem *)fb_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) info->fix.smem_start = __pa(fb_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) info->fix.smem_len = ps3fb_videomemory.size - GPU_FB_START;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) info->pseudo_palette = par->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) retval = fb_alloc_cmap(&info->cmap, 256, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) if (retval < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) goto err_framebuffer_release;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) ARRAY_SIZE(ps3fb_modedb),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) ps3fb_vmode(par->new_mode_id), 32)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) retval = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) goto err_fb_dealloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) fb_videomode_to_modelist(ps3fb_modedb, ARRAY_SIZE(ps3fb_modedb),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) &info->modelist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) retval = register_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) if (retval < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) goto err_fb_dealloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) ps3_system_bus_set_drvdata(dev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) dev_info(info->device, "%s %s, using %u KiB of video memory\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) dev_driver_string(info->dev), dev_name(info->dev),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) info->fix.smem_len >> 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) task = kthread_run(ps3fbd, info, DEVICE_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) if (IS_ERR(task)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) retval = PTR_ERR(task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) goto err_unregister_framebuffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) ps3fb.task = task;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) err_unregister_framebuffer:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) unregister_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) err_fb_dealloc:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) err_framebuffer_release:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) err_context_fb_close:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) lv1_gpu_fb_close(ps3fb.context_handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) err_context_unmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) ps3fb_videomemory.size, CBE_IOPTE_M);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) err_free_irq:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) free_irq(ps3fb.irq_no, &dev->core);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) err_destroy_plug:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) ps3_irq_plug_destroy(ps3fb.irq_no);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) err_iounmap_dinfo:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) iounmap((u8 __force __iomem *)ps3fb.dinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) err_gpu_context_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) lv1_gpu_context_free(ps3fb.context_handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) err_gpu_memory_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) lv1_gpu_memory_free(ps3fb.memory_handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) err_close_device:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) ps3_close_hv_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) struct fb_info *info = ps3_system_bus_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) u64 xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) atomic_inc(&ps3fb.ext_flip); /* flip off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) ps3fb.dinfo->irq.mask = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) if (ps3fb.task) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) struct task_struct *task = ps3fb.task;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) ps3fb.task = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) kthread_stop(task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) if (ps3fb.irq_no) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) free_irq(ps3fb.irq_no, &dev->core);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) ps3_irq_plug_destroy(ps3fb.irq_no);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) if (info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) unregister_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) ps3_system_bus_set_drvdata(dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) iounmap((u8 __force __iomem *)ps3fb.dinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) lv1_gpu_fb_close(ps3fb.context_handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) ps3fb_videomemory.size, CBE_IOPTE_M);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) lv1_gpu_context_free(ps3fb.context_handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) lv1_gpu_memory_free(ps3fb.memory_handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) ps3_close_hv_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) static struct ps3_system_bus_driver ps3fb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) .match_id = PS3_MATCH_ID_GPU,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) .match_sub_id = PS3_MATCH_SUB_ID_GPU_FB,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) .core.name = DEVICE_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) .core.owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) .probe = ps3fb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) .remove = ps3fb_shutdown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) .shutdown = ps3fb_shutdown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) static int __init ps3fb_setup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) char *options;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) #ifdef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) if (fb_get_options(DEVICE_NAME, &options))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) if (!options || !*options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) char *this_opt = strsep(&options, ",");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) if (!this_opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) if (!*this_opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) if (!strncmp(this_opt, "mode:", 5))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) ps3fb_mode = simple_strtoul(this_opt + 5, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) mode_option = this_opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) static int __init ps3fb_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) if (!ps3fb_videomemory.address || ps3fb_setup())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) return ps3_system_bus_driver_register(&ps3fb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) static void __exit ps3fb_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) pr_debug(" -> %s:%d\n", __func__, __LINE__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) ps3_system_bus_driver_unregister(&ps3fb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) pr_debug(" <- %s:%d\n", __func__, __LINE__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) module_init(ps3fb_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) module_exit(ps3fb_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) MODULE_DESCRIPTION("PS3 GPU Frame Buffer Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) MODULE_AUTHOR("Sony Computer Entertainment Inc.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) MODULE_ALIAS(PS3_MODULE_ALIAS_GPU_FB);