/*
* PS3 AV backend support.
*
* Copyright (C) 2007 Sony Computer Entertainment Inc.
* Copyright 2007 Sony Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/notifier.h>
#include <linux/ioctl.h>
#include <linux/fb.h>
#include <asm/firmware.h>
#include <asm/ps3av.h>
#include <asm/ps3.h>
#include "vuart.h"
#define BUFSIZE 4096 /* vuart buf size */
#define PS3AV_BUF_SIZE 512 /* max packet size */
static int safe_mode;
static int timeout = 5000; /* in msec ( 5 sec ) */
module_param(timeout, int, 0644);
static struct ps3av {
struct mutex mutex;
struct work_struct work;
struct completion done;
struct workqueue_struct *wq;
int open_count;
struct ps3_system_bus_device *dev;
int region;
struct ps3av_pkt_av_get_hw_conf av_hw_conf;
u32 av_port[PS3AV_AV_PORT_MAX + PS3AV_OPT_PORT_MAX];
u32 opt_port[PS3AV_OPT_PORT_MAX];
u32 head[PS3AV_HEAD_MAX];
u32 audio_port;
int ps3av_mode;
int ps3av_mode_old;
union {
struct ps3av_reply_hdr reply_hdr;
u8 raw[PS3AV_BUF_SIZE];
} recv_buf;
} *ps3av;
/* color space */
#define YUV444 PS3AV_CMD_VIDEO_CS_YUV444_8
#define RGB8 PS3AV_CMD_VIDEO_CS_RGB_8
/* format */
#define XRGB PS3AV_CMD_VIDEO_FMT_X8R8G8B8
/* aspect */
#define A_N PS3AV_CMD_AV_ASPECT_4_3
#define A_W PS3AV_CMD_AV_ASPECT_16_9
static const struct avset_video_mode {
u32 cs;
u32 fmt;
u32 vid;
u32 aspect;
u32 x;
u32 y;
} video_mode_table[] = {
{ 0, }, /* auto */
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_N, 1280, 720},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_N, 1280, 720},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080},
{ RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768},
{ RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA, A_N, 1280, 1024},
{ RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA, A_W, 1920, 1200},
};
/* supported CIDs */
static u32 cmd_table[] = {
/* init */
PS3AV_CID_AV_INIT,
PS3AV_CID_AV_FIN,
PS3AV_CID_VIDEO_INIT,
PS3AV_CID_AUDIO_INIT,
/* set */
PS3AV_CID_AV_ENABLE_EVENT,
PS3AV_CID_AV_DISABLE_EVENT,
PS3AV_CID_AV_VIDEO_CS,
PS3AV_CID_AV_VIDEO_MUTE,
PS3AV_CID_AV_VIDEO_DISABLE_SIG,
PS3AV_CID_AV_AUDIO_PARAM,
PS3AV_CID_AV_AUDIO_MUTE,
PS3AV_CID_AV_HDMI_MODE,
PS3AV_CID_AV_TV_MUTE,
PS3AV_CID_VIDEO_MODE,
PS3AV_CID_VIDEO_FORMAT,
PS3AV_CID_VIDEO_PITCH,
PS3AV_CID_AUDIO_MODE,
PS3AV_CID_AUDIO_MUTE,
PS3AV_CID_AUDIO_ACTIVE,
PS3AV_CID_AUDIO_INACTIVE,
PS3AV_CID_AVB_PARAM,
/* get */
PS3AV_CID_AV_GET_HW_CONF,
PS3AV_CID_AV_GET_MONITOR_INFO,
/* event */
PS3AV_CID_EVENT_UNPLUGGED,
PS3AV_CID_EVENT_PLUGGED,
PS3AV_CID_EVENT_HDCP_DONE,
PS3AV_CID_EVENT_HDCP_FAIL,
PS3AV_CID_EVENT_HDCP_AUTH,
PS3AV_CID_EVENT_HDCP_ERROR,
0
};
#define PS3AV_EVENT_CMD_MASK 0x10000000
#define PS3AV_EVENT_ID_MASK 0x0000ffff
#define PS3AV_CID_MASK 0xffffffff
#define PS3AV_REPLY_BIT 0x80000000
#define ps3av_event_get_port_id(cid) ((cid >> 16) & 0xff)
static u32 *ps3av_search_cmd_table(u32 cid, u32 mask)
{
u32 *table;
int i;
table = cmd_table;
for