111227fd1SGeert Uytterhoeven /* 213a5e30cSGeoff Levand * PS3 AV backend support. 311227fd1SGeert Uytterhoeven * 413a5e30cSGeoff Levand * Copyright (C) 2007 Sony Computer Entertainment Inc. 513a5e30cSGeoff Levand * Copyright 2007 Sony Corp. 611227fd1SGeert Uytterhoeven * 713a5e30cSGeoff Levand * This program is free software; you can redistribute it and/or modify 813a5e30cSGeoff Levand * it under the terms of the GNU General Public License as published by 913a5e30cSGeoff Levand * the Free Software Foundation; version 2 of the License. 1011227fd1SGeert Uytterhoeven * 1113a5e30cSGeoff Levand * This program is distributed in the hope that it will be useful, 1213a5e30cSGeoff Levand * but WITHOUT ANY WARRANTY; without even the implied warranty of 1313a5e30cSGeoff Levand * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1413a5e30cSGeoff Levand * GNU General Public License for more details. 1511227fd1SGeert Uytterhoeven * 1613a5e30cSGeoff Levand * You should have received a copy of the GNU General Public License 1713a5e30cSGeoff Levand * along with this program; if not, write to the Free Software 1813a5e30cSGeoff Levand * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1911227fd1SGeert Uytterhoeven */ 2011227fd1SGeert Uytterhoeven 2113a5e30cSGeoff Levand #include <linux/kernel.h> 2211227fd1SGeert Uytterhoeven #include <linux/module.h> 2311227fd1SGeert Uytterhoeven #include <linux/delay.h> 2411227fd1SGeert Uytterhoeven #include <linux/notifier.h> 2511227fd1SGeert Uytterhoeven #include <linux/ioctl.h> 26ef596c69SGeert Uytterhoeven 27ef596c69SGeert Uytterhoeven #include <asm/firmware.h> 2811227fd1SGeert Uytterhoeven #include <asm/ps3av.h> 2911227fd1SGeert Uytterhoeven #include <asm/ps3.h> 3011227fd1SGeert Uytterhoeven 3111227fd1SGeert Uytterhoeven #include "vuart.h" 3211227fd1SGeert Uytterhoeven 3311227fd1SGeert Uytterhoeven #define BUFSIZE 4096 /* vuart buf size */ 3411227fd1SGeert Uytterhoeven #define PS3AV_BUF_SIZE 512 /* max packet size */ 3511227fd1SGeert Uytterhoeven 3611227fd1SGeert Uytterhoeven static int timeout = 5000; /* in msec ( 5 sec ) */ 3711227fd1SGeert Uytterhoeven module_param(timeout, int, 0644); 3811227fd1SGeert Uytterhoeven 39fffe52e8SGeert Uytterhoeven static struct ps3av { 40fffe52e8SGeert Uytterhoeven struct mutex mutex; 41fffe52e8SGeert Uytterhoeven struct work_struct work; 42fffe52e8SGeert Uytterhoeven struct completion done; 43fffe52e8SGeert Uytterhoeven struct workqueue_struct *wq; 44fffe52e8SGeert Uytterhoeven int open_count; 4513a5e30cSGeoff Levand struct ps3_system_bus_device *dev; 46fffe52e8SGeert Uytterhoeven 47fffe52e8SGeert Uytterhoeven int region; 48fffe52e8SGeert Uytterhoeven struct ps3av_pkt_av_get_hw_conf av_hw_conf; 49fffe52e8SGeert Uytterhoeven u32 av_port[PS3AV_AV_PORT_MAX + PS3AV_OPT_PORT_MAX]; 50fffe52e8SGeert Uytterhoeven u32 opt_port[PS3AV_OPT_PORT_MAX]; 51fffe52e8SGeert Uytterhoeven u32 head[PS3AV_HEAD_MAX]; 52fffe52e8SGeert Uytterhoeven u32 audio_port; 53fffe52e8SGeert Uytterhoeven int ps3av_mode; 54fffe52e8SGeert Uytterhoeven int ps3av_mode_old; 5513a5e30cSGeoff Levand union { 5613a5e30cSGeoff Levand struct ps3av_reply_hdr reply_hdr; 5713a5e30cSGeoff Levand u8 raw[PS3AV_BUF_SIZE]; 5813a5e30cSGeoff Levand } recv_buf; 5913a5e30cSGeoff Levand void (*flip_ctl)(int on, void *data); 6013a5e30cSGeoff Levand void *flip_data; 6113a5e30cSGeoff Levand } *ps3av; 6211227fd1SGeert Uytterhoeven 6311227fd1SGeert Uytterhoeven /* color space */ 6411227fd1SGeert Uytterhoeven #define YUV444 PS3AV_CMD_VIDEO_CS_YUV444_8 6511227fd1SGeert Uytterhoeven #define RGB8 PS3AV_CMD_VIDEO_CS_RGB_8 6611227fd1SGeert Uytterhoeven /* format */ 6711227fd1SGeert Uytterhoeven #define XRGB PS3AV_CMD_VIDEO_FMT_X8R8G8B8 6811227fd1SGeert Uytterhoeven /* aspect */ 6911227fd1SGeert Uytterhoeven #define A_N PS3AV_CMD_AV_ASPECT_4_3 7011227fd1SGeert Uytterhoeven #define A_W PS3AV_CMD_AV_ASPECT_16_9 7111227fd1SGeert Uytterhoeven static const struct avset_video_mode { 7211227fd1SGeert Uytterhoeven u32 cs; 7311227fd1SGeert Uytterhoeven u32 fmt; 7411227fd1SGeert Uytterhoeven u32 vid; 7511227fd1SGeert Uytterhoeven u32 aspect; 7611227fd1SGeert Uytterhoeven u32 x; 7711227fd1SGeert Uytterhoeven u32 y; 7811227fd1SGeert Uytterhoeven u32 interlace; 7911227fd1SGeert Uytterhoeven u32 freq; 8011227fd1SGeert Uytterhoeven } video_mode_table[] = { 8111227fd1SGeert Uytterhoeven { 0, }, /* auto */ 8211227fd1SGeert Uytterhoeven {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480, 1, 60}, 8311227fd1SGeert Uytterhoeven {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480, 0, 60}, 8411227fd1SGeert Uytterhoeven {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_N, 1280, 720, 0, 60}, 8511227fd1SGeert Uytterhoeven {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080, 1, 60}, 8611227fd1SGeert Uytterhoeven {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080, 0, 60}, 8711227fd1SGeert Uytterhoeven {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576, 1, 50}, 8811227fd1SGeert Uytterhoeven {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576, 0, 50}, 8911227fd1SGeert Uytterhoeven {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_N, 1280, 720, 0, 50}, 9011227fd1SGeert Uytterhoeven {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080, 1, 50}, 9111227fd1SGeert Uytterhoeven {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080, 0, 50}, 9211227fd1SGeert Uytterhoeven { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768, 0, 60}, 9311227fd1SGeert Uytterhoeven { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA, A_N, 1280, 1024, 0, 60}, 9411227fd1SGeert Uytterhoeven { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA, A_W, 1920, 1200, 0, 60}, 9511227fd1SGeert Uytterhoeven }; 9611227fd1SGeert Uytterhoeven 9711227fd1SGeert Uytterhoeven /* supported CIDs */ 9811227fd1SGeert Uytterhoeven static u32 cmd_table[] = { 9911227fd1SGeert Uytterhoeven /* init */ 10011227fd1SGeert Uytterhoeven PS3AV_CID_AV_INIT, 10111227fd1SGeert Uytterhoeven PS3AV_CID_AV_FIN, 10211227fd1SGeert Uytterhoeven PS3AV_CID_VIDEO_INIT, 10311227fd1SGeert Uytterhoeven PS3AV_CID_AUDIO_INIT, 10411227fd1SGeert Uytterhoeven 10511227fd1SGeert Uytterhoeven /* set */ 10611227fd1SGeert Uytterhoeven PS3AV_CID_AV_ENABLE_EVENT, 10711227fd1SGeert Uytterhoeven PS3AV_CID_AV_DISABLE_EVENT, 10811227fd1SGeert Uytterhoeven 10911227fd1SGeert Uytterhoeven PS3AV_CID_AV_VIDEO_CS, 11011227fd1SGeert Uytterhoeven PS3AV_CID_AV_VIDEO_MUTE, 11111227fd1SGeert Uytterhoeven PS3AV_CID_AV_VIDEO_DISABLE_SIG, 11211227fd1SGeert Uytterhoeven PS3AV_CID_AV_AUDIO_PARAM, 11311227fd1SGeert Uytterhoeven PS3AV_CID_AV_AUDIO_MUTE, 11411227fd1SGeert Uytterhoeven PS3AV_CID_AV_HDMI_MODE, 11511227fd1SGeert Uytterhoeven PS3AV_CID_AV_TV_MUTE, 11611227fd1SGeert Uytterhoeven 11711227fd1SGeert Uytterhoeven PS3AV_CID_VIDEO_MODE, 11811227fd1SGeert Uytterhoeven PS3AV_CID_VIDEO_FORMAT, 11911227fd1SGeert Uytterhoeven PS3AV_CID_VIDEO_PITCH, 12011227fd1SGeert Uytterhoeven 12111227fd1SGeert Uytterhoeven PS3AV_CID_AUDIO_MODE, 12211227fd1SGeert Uytterhoeven PS3AV_CID_AUDIO_MUTE, 12311227fd1SGeert Uytterhoeven PS3AV_CID_AUDIO_ACTIVE, 12411227fd1SGeert Uytterhoeven PS3AV_CID_AUDIO_INACTIVE, 12511227fd1SGeert Uytterhoeven PS3AV_CID_AVB_PARAM, 12611227fd1SGeert Uytterhoeven 12711227fd1SGeert Uytterhoeven /* get */ 12811227fd1SGeert Uytterhoeven PS3AV_CID_AV_GET_HW_CONF, 12911227fd1SGeert Uytterhoeven PS3AV_CID_AV_GET_MONITOR_INFO, 13011227fd1SGeert Uytterhoeven 13111227fd1SGeert Uytterhoeven /* event */ 13211227fd1SGeert Uytterhoeven PS3AV_CID_EVENT_UNPLUGGED, 13311227fd1SGeert Uytterhoeven PS3AV_CID_EVENT_PLUGGED, 13411227fd1SGeert Uytterhoeven PS3AV_CID_EVENT_HDCP_DONE, 13511227fd1SGeert Uytterhoeven PS3AV_CID_EVENT_HDCP_FAIL, 13611227fd1SGeert Uytterhoeven PS3AV_CID_EVENT_HDCP_AUTH, 13711227fd1SGeert Uytterhoeven PS3AV_CID_EVENT_HDCP_ERROR, 13811227fd1SGeert Uytterhoeven 13911227fd1SGeert Uytterhoeven 0 14011227fd1SGeert Uytterhoeven }; 14111227fd1SGeert Uytterhoeven 14211227fd1SGeert Uytterhoeven #define PS3AV_EVENT_CMD_MASK 0x10000000 14311227fd1SGeert Uytterhoeven #define PS3AV_EVENT_ID_MASK 0x0000ffff 14411227fd1SGeert Uytterhoeven #define PS3AV_CID_MASK 0xffffffff 14511227fd1SGeert Uytterhoeven #define PS3AV_REPLY_BIT 0x80000000 14611227fd1SGeert Uytterhoeven 14711227fd1SGeert Uytterhoeven #define ps3av_event_get_port_id(cid) ((cid >> 16) & 0xff) 14811227fd1SGeert Uytterhoeven 14911227fd1SGeert Uytterhoeven static u32 *ps3av_search_cmd_table(u32 cid, u32 mask) 15011227fd1SGeert Uytterhoeven { 15111227fd1SGeert Uytterhoeven u32 *table; 15211227fd1SGeert Uytterhoeven int i; 15311227fd1SGeert Uytterhoeven 15411227fd1SGeert Uytterhoeven table = cmd_table; 15511227fd1SGeert Uytterhoeven for (i = 0;; table++, i++) { 15611227fd1SGeert Uytterhoeven if ((*table & mask) == (cid & mask)) 15711227fd1SGeert Uytterhoeven break; 15811227fd1SGeert Uytterhoeven if (*table == 0) 15911227fd1SGeert Uytterhoeven return NULL; 16011227fd1SGeert Uytterhoeven } 16111227fd1SGeert Uytterhoeven return table; 16211227fd1SGeert Uytterhoeven } 16311227fd1SGeert Uytterhoeven 16411227fd1SGeert Uytterhoeven static int ps3av_parse_event_packet(const struct ps3av_reply_hdr *hdr) 16511227fd1SGeert Uytterhoeven { 16611227fd1SGeert Uytterhoeven u32 *table; 16711227fd1SGeert Uytterhoeven 16811227fd1SGeert Uytterhoeven if (hdr->cid & PS3AV_EVENT_CMD_MASK) { 16911227fd1SGeert Uytterhoeven table = ps3av_search_cmd_table(hdr->cid, PS3AV_EVENT_CMD_MASK); 17011227fd1SGeert Uytterhoeven if (table) 17113a5e30cSGeoff Levand dev_dbg(&ps3av->dev->core, 17211227fd1SGeert Uytterhoeven "recv event packet cid:%08x port:0x%x size:%d\n", 17311227fd1SGeert Uytterhoeven hdr->cid, ps3av_event_get_port_id(hdr->cid), 17411227fd1SGeert Uytterhoeven hdr->size); 17511227fd1SGeert Uytterhoeven else 17611227fd1SGeert Uytterhoeven printk(KERN_ERR 17711227fd1SGeert Uytterhoeven "%s: failed event packet, cid:%08x size:%d\n", 178253f04e7SGeert Uytterhoeven __func__, hdr->cid, hdr->size); 17911227fd1SGeert Uytterhoeven return 1; /* receive event packet */ 18011227fd1SGeert Uytterhoeven } 18111227fd1SGeert Uytterhoeven return 0; 18211227fd1SGeert Uytterhoeven } 18311227fd1SGeert Uytterhoeven 18413a5e30cSGeoff Levand 18513a5e30cSGeoff Levand #define POLLING_INTERVAL 25 /* in msec */ 18613a5e30cSGeoff Levand 18713a5e30cSGeoff Levand static int ps3av_vuart_write(struct ps3_system_bus_device *dev, 18813a5e30cSGeoff Levand const void *buf, unsigned long size) 18913a5e30cSGeoff Levand { 19013a5e30cSGeoff Levand int error; 19113a5e30cSGeoff Levand dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); 19213a5e30cSGeoff Levand error = ps3_vuart_write(dev, buf, size); 19313a5e30cSGeoff Levand dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); 19413a5e30cSGeoff Levand return error ? error : size; 19513a5e30cSGeoff Levand } 19613a5e30cSGeoff Levand 19713a5e30cSGeoff Levand static int ps3av_vuart_read(struct ps3_system_bus_device *dev, void *buf, 19813a5e30cSGeoff Levand unsigned long size, int timeout) 19913a5e30cSGeoff Levand { 20013a5e30cSGeoff Levand int error; 20113a5e30cSGeoff Levand int loopcnt = 0; 20213a5e30cSGeoff Levand 20313a5e30cSGeoff Levand dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); 20413a5e30cSGeoff Levand timeout = (timeout + POLLING_INTERVAL - 1) / POLLING_INTERVAL; 20513a5e30cSGeoff Levand while (loopcnt++ <= timeout) { 20613a5e30cSGeoff Levand error = ps3_vuart_read(dev, buf, size); 20713a5e30cSGeoff Levand if (!error) 20813a5e30cSGeoff Levand return size; 20913a5e30cSGeoff Levand if (error != -EAGAIN) { 21013a5e30cSGeoff Levand printk(KERN_ERR "%s: ps3_vuart_read failed %d\n", 21113a5e30cSGeoff Levand __func__, error); 21213a5e30cSGeoff Levand return error; 21313a5e30cSGeoff Levand } 21413a5e30cSGeoff Levand msleep(POLLING_INTERVAL); 21513a5e30cSGeoff Levand } 21613a5e30cSGeoff Levand return -EWOULDBLOCK; 21713a5e30cSGeoff Levand } 21813a5e30cSGeoff Levand 21911227fd1SGeert Uytterhoeven static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf, 22011227fd1SGeert Uytterhoeven struct ps3av_reply_hdr *recv_buf, int write_len, 22111227fd1SGeert Uytterhoeven int read_len) 22211227fd1SGeert Uytterhoeven { 22311227fd1SGeert Uytterhoeven int res; 22411227fd1SGeert Uytterhoeven u32 cmd; 22511227fd1SGeert Uytterhoeven int event; 22611227fd1SGeert Uytterhoeven 22713a5e30cSGeoff Levand if (!ps3av) 22811227fd1SGeert Uytterhoeven return -ENODEV; 22911227fd1SGeert Uytterhoeven 23011227fd1SGeert Uytterhoeven /* send pkt */ 23113a5e30cSGeoff Levand res = ps3av_vuart_write(ps3av->dev, send_buf, write_len); 23211227fd1SGeert Uytterhoeven if (res < 0) { 23313a5e30cSGeoff Levand dev_dbg(&ps3av->dev->core, 23411227fd1SGeert Uytterhoeven "%s: ps3av_vuart_write() failed (result=%d)\n", 235253f04e7SGeert Uytterhoeven __func__, res); 23611227fd1SGeert Uytterhoeven return res; 23711227fd1SGeert Uytterhoeven } 23811227fd1SGeert Uytterhoeven 23911227fd1SGeert Uytterhoeven /* recv pkt */ 24011227fd1SGeert Uytterhoeven cmd = send_buf->cid; 24111227fd1SGeert Uytterhoeven do { 24211227fd1SGeert Uytterhoeven /* read header */ 24313a5e30cSGeoff Levand res = ps3av_vuart_read(ps3av->dev, recv_buf, PS3AV_HDR_SIZE, 24411227fd1SGeert Uytterhoeven timeout); 24511227fd1SGeert Uytterhoeven if (res != PS3AV_HDR_SIZE) { 24613a5e30cSGeoff Levand dev_dbg(&ps3av->dev->core, 24711227fd1SGeert Uytterhoeven "%s: ps3av_vuart_read() failed (result=%d)\n", 248253f04e7SGeert Uytterhoeven __func__, res); 24911227fd1SGeert Uytterhoeven return res; 25011227fd1SGeert Uytterhoeven } 25111227fd1SGeert Uytterhoeven 25211227fd1SGeert Uytterhoeven /* read body */ 25313a5e30cSGeoff Levand res = ps3av_vuart_read(ps3av->dev, &recv_buf->cid, 25411227fd1SGeert Uytterhoeven recv_buf->size, timeout); 25511227fd1SGeert Uytterhoeven if (res < 0) { 25613a5e30cSGeoff Levand dev_dbg(&ps3av->dev->core, 25711227fd1SGeert Uytterhoeven "%s: ps3av_vuart_read() failed (result=%d)\n", 258253f04e7SGeert Uytterhoeven __func__, res); 25911227fd1SGeert Uytterhoeven return res; 26011227fd1SGeert Uytterhoeven } 26111227fd1SGeert Uytterhoeven res += PS3AV_HDR_SIZE; /* total len */ 26211227fd1SGeert Uytterhoeven event = ps3av_parse_event_packet(recv_buf); 26311227fd1SGeert Uytterhoeven /* ret > 0 event packet */ 26411227fd1SGeert Uytterhoeven } while (event); 26511227fd1SGeert Uytterhoeven 26611227fd1SGeert Uytterhoeven if ((cmd | PS3AV_REPLY_BIT) != recv_buf->cid) { 26713a5e30cSGeoff Levand dev_dbg(&ps3av->dev->core, "%s: reply err (result=%x)\n", 268253f04e7SGeert Uytterhoeven __func__, recv_buf->cid); 26911227fd1SGeert Uytterhoeven return -EINVAL; 27011227fd1SGeert Uytterhoeven } 27111227fd1SGeert Uytterhoeven 27211227fd1SGeert Uytterhoeven return 0; 27311227fd1SGeert Uytterhoeven } 27411227fd1SGeert Uytterhoeven 27511227fd1SGeert Uytterhoeven static int ps3av_process_reply_packet(struct ps3av_send_hdr *cmd_buf, 27611227fd1SGeert Uytterhoeven const struct ps3av_reply_hdr *recv_buf, 27711227fd1SGeert Uytterhoeven int user_buf_size) 27811227fd1SGeert Uytterhoeven { 27911227fd1SGeert Uytterhoeven int return_len; 28011227fd1SGeert Uytterhoeven 28111227fd1SGeert Uytterhoeven if (recv_buf->version != PS3AV_VERSION) { 28213a5e30cSGeoff Levand dev_dbg(&ps3av->dev->core, "reply_packet invalid version:%x\n", 28311227fd1SGeert Uytterhoeven recv_buf->version); 28411227fd1SGeert Uytterhoeven return -EFAULT; 28511227fd1SGeert Uytterhoeven } 28611227fd1SGeert Uytterhoeven return_len = recv_buf->size + PS3AV_HDR_SIZE; 28711227fd1SGeert Uytterhoeven if (return_len > user_buf_size) 28811227fd1SGeert Uytterhoeven return_len = user_buf_size; 28911227fd1SGeert Uytterhoeven memcpy(cmd_buf, recv_buf, return_len); 29011227fd1SGeert Uytterhoeven return 0; /* success */ 29111227fd1SGeert Uytterhoeven } 29211227fd1SGeert Uytterhoeven 29311227fd1SGeert Uytterhoeven void ps3av_set_hdr(u32 cid, u16 size, struct ps3av_send_hdr *hdr) 29411227fd1SGeert Uytterhoeven { 29511227fd1SGeert Uytterhoeven hdr->version = PS3AV_VERSION; 29611227fd1SGeert Uytterhoeven hdr->size = size - PS3AV_HDR_SIZE; 29711227fd1SGeert Uytterhoeven hdr->cid = cid; 29811227fd1SGeert Uytterhoeven } 29911227fd1SGeert Uytterhoeven 30011227fd1SGeert Uytterhoeven int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size, 30111227fd1SGeert Uytterhoeven struct ps3av_send_hdr *buf) 30211227fd1SGeert Uytterhoeven { 30311227fd1SGeert Uytterhoeven int res = 0; 30411227fd1SGeert Uytterhoeven u32 *table; 30511227fd1SGeert Uytterhoeven 30613a5e30cSGeoff Levand BUG_ON(!ps3av); 30711227fd1SGeert Uytterhoeven 30813a5e30cSGeoff Levand mutex_lock(&ps3av->mutex); 30911227fd1SGeert Uytterhoeven 31011227fd1SGeert Uytterhoeven table = ps3av_search_cmd_table(cid, PS3AV_CID_MASK); 31111227fd1SGeert Uytterhoeven BUG_ON(!table); 31211227fd1SGeert Uytterhoeven BUG_ON(send_len < PS3AV_HDR_SIZE); 31311227fd1SGeert Uytterhoeven BUG_ON(usr_buf_size < send_len); 31411227fd1SGeert Uytterhoeven BUG_ON(usr_buf_size > PS3AV_BUF_SIZE); 31511227fd1SGeert Uytterhoeven 31611227fd1SGeert Uytterhoeven /* create header */ 31711227fd1SGeert Uytterhoeven ps3av_set_hdr(cid, send_len, buf); 31811227fd1SGeert Uytterhoeven 31911227fd1SGeert Uytterhoeven /* send packet via vuart */ 32013a5e30cSGeoff Levand res = ps3av_send_cmd_pkt(buf, &ps3av->recv_buf.reply_hdr, send_len, 32111227fd1SGeert Uytterhoeven usr_buf_size); 32211227fd1SGeert Uytterhoeven if (res < 0) { 32311227fd1SGeert Uytterhoeven printk(KERN_ERR 32411227fd1SGeert Uytterhoeven "%s: ps3av_send_cmd_pkt() failed (result=%d)\n", 325253f04e7SGeert Uytterhoeven __func__, res); 32611227fd1SGeert Uytterhoeven goto err; 32711227fd1SGeert Uytterhoeven } 32811227fd1SGeert Uytterhoeven 32911227fd1SGeert Uytterhoeven /* process reply packet */ 33013a5e30cSGeoff Levand res = ps3av_process_reply_packet(buf, &ps3av->recv_buf.reply_hdr, 33111227fd1SGeert Uytterhoeven usr_buf_size); 33211227fd1SGeert Uytterhoeven if (res < 0) { 33311227fd1SGeert Uytterhoeven printk(KERN_ERR "%s: put_return_status() failed (result=%d)\n", 334253f04e7SGeert Uytterhoeven __func__, res); 33511227fd1SGeert Uytterhoeven goto err; 33611227fd1SGeert Uytterhoeven } 33711227fd1SGeert Uytterhoeven 33813a5e30cSGeoff Levand mutex_unlock(&ps3av->mutex); 33911227fd1SGeert Uytterhoeven return 0; 34011227fd1SGeert Uytterhoeven 34111227fd1SGeert Uytterhoeven err: 34213a5e30cSGeoff Levand mutex_unlock(&ps3av->mutex); 343253f04e7SGeert Uytterhoeven printk(KERN_ERR "%s: failed cid:%x res:%d\n", __func__, cid, res); 34411227fd1SGeert Uytterhoeven return res; 34511227fd1SGeert Uytterhoeven } 34611227fd1SGeert Uytterhoeven 34711227fd1SGeert Uytterhoeven static int ps3av_set_av_video_mute(u32 mute) 34811227fd1SGeert Uytterhoeven { 34911227fd1SGeert Uytterhoeven int i, num_of_av_port, res; 35011227fd1SGeert Uytterhoeven 35113a5e30cSGeoff Levand num_of_av_port = ps3av->av_hw_conf.num_of_hdmi + 35213a5e30cSGeoff Levand ps3av->av_hw_conf.num_of_avmulti; 35311227fd1SGeert Uytterhoeven /* video mute on */ 35411227fd1SGeert Uytterhoeven for (i = 0; i < num_of_av_port; i++) { 35513a5e30cSGeoff Levand res = ps3av_cmd_av_video_mute(1, &ps3av->av_port[i], mute); 35611227fd1SGeert Uytterhoeven if (res < 0) 35711227fd1SGeert Uytterhoeven return -1; 35811227fd1SGeert Uytterhoeven } 35911227fd1SGeert Uytterhoeven 36011227fd1SGeert Uytterhoeven return 0; 36111227fd1SGeert Uytterhoeven } 36211227fd1SGeert Uytterhoeven 36311227fd1SGeert Uytterhoeven static int ps3av_set_video_disable_sig(void) 36411227fd1SGeert Uytterhoeven { 36511227fd1SGeert Uytterhoeven int i, num_of_hdmi_port, num_of_av_port, res; 36611227fd1SGeert Uytterhoeven 36713a5e30cSGeoff Levand num_of_hdmi_port = ps3av->av_hw_conf.num_of_hdmi; 36813a5e30cSGeoff Levand num_of_av_port = ps3av->av_hw_conf.num_of_hdmi + 36913a5e30cSGeoff Levand ps3av->av_hw_conf.num_of_avmulti; 37011227fd1SGeert Uytterhoeven 37111227fd1SGeert Uytterhoeven /* tv mute */ 37211227fd1SGeert Uytterhoeven for (i = 0; i < num_of_hdmi_port; i++) { 37313a5e30cSGeoff Levand res = ps3av_cmd_av_tv_mute(ps3av->av_port[i], 37411227fd1SGeert Uytterhoeven PS3AV_CMD_MUTE_ON); 37511227fd1SGeert Uytterhoeven if (res < 0) 37611227fd1SGeert Uytterhoeven return -1; 37711227fd1SGeert Uytterhoeven } 37811227fd1SGeert Uytterhoeven msleep(100); 37911227fd1SGeert Uytterhoeven 38011227fd1SGeert Uytterhoeven /* video mute on */ 38111227fd1SGeert Uytterhoeven for (i = 0; i < num_of_av_port; i++) { 38213a5e30cSGeoff Levand res = ps3av_cmd_av_video_disable_sig(ps3av->av_port[i]); 38311227fd1SGeert Uytterhoeven if (res < 0) 38411227fd1SGeert Uytterhoeven return -1; 38511227fd1SGeert Uytterhoeven if (i < num_of_hdmi_port) { 38613a5e30cSGeoff Levand res = ps3av_cmd_av_tv_mute(ps3av->av_port[i], 38711227fd1SGeert Uytterhoeven PS3AV_CMD_MUTE_OFF); 38811227fd1SGeert Uytterhoeven if (res < 0) 38911227fd1SGeert Uytterhoeven return -1; 39011227fd1SGeert Uytterhoeven } 39111227fd1SGeert Uytterhoeven } 39211227fd1SGeert Uytterhoeven msleep(300); 39311227fd1SGeert Uytterhoeven 39411227fd1SGeert Uytterhoeven return 0; 39511227fd1SGeert Uytterhoeven } 39611227fd1SGeert Uytterhoeven 39711227fd1SGeert Uytterhoeven static int ps3av_set_audio_mute(u32 mute) 39811227fd1SGeert Uytterhoeven { 39911227fd1SGeert Uytterhoeven int i, num_of_av_port, num_of_opt_port, res; 40011227fd1SGeert Uytterhoeven 40113a5e30cSGeoff Levand num_of_av_port = ps3av->av_hw_conf.num_of_hdmi + 40213a5e30cSGeoff Levand ps3av->av_hw_conf.num_of_avmulti; 40313a5e30cSGeoff Levand num_of_opt_port = ps3av->av_hw_conf.num_of_spdif; 40411227fd1SGeert Uytterhoeven 40511227fd1SGeert Uytterhoeven for (i = 0; i < num_of_av_port; i++) { 40613a5e30cSGeoff Levand res = ps3av_cmd_av_audio_mute(1, &ps3av->av_port[i], mute); 40711227fd1SGeert Uytterhoeven if (res < 0) 40811227fd1SGeert Uytterhoeven return -1; 40911227fd1SGeert Uytterhoeven } 41011227fd1SGeert Uytterhoeven for (i = 0; i < num_of_opt_port; i++) { 41113a5e30cSGeoff Levand res = ps3av_cmd_audio_mute(1, &ps3av->opt_port[i], mute); 41211227fd1SGeert Uytterhoeven if (res < 0) 41311227fd1SGeert Uytterhoeven return -1; 41411227fd1SGeert Uytterhoeven } 41511227fd1SGeert Uytterhoeven 41611227fd1SGeert Uytterhoeven return 0; 41711227fd1SGeert Uytterhoeven } 41811227fd1SGeert Uytterhoeven 41911227fd1SGeert Uytterhoeven int ps3av_set_audio_mode(u32 ch, u32 fs, u32 word_bits, u32 format, u32 source) 42011227fd1SGeert Uytterhoeven { 42111227fd1SGeert Uytterhoeven struct ps3av_pkt_avb_param avb_param; 42211227fd1SGeert Uytterhoeven int i, num_of_audio, vid, res; 42311227fd1SGeert Uytterhoeven struct ps3av_pkt_audio_mode audio_mode; 42411227fd1SGeert Uytterhoeven u32 len = 0; 42511227fd1SGeert Uytterhoeven 42613a5e30cSGeoff Levand num_of_audio = ps3av->av_hw_conf.num_of_hdmi + 42713a5e30cSGeoff Levand ps3av->av_hw_conf.num_of_avmulti + 42813a5e30cSGeoff Levand ps3av->av_hw_conf.num_of_spdif; 42911227fd1SGeert Uytterhoeven 43011227fd1SGeert Uytterhoeven avb_param.num_of_video_pkt = 0; 43111227fd1SGeert Uytterhoeven avb_param.num_of_audio_pkt = PS3AV_AVB_NUM_AUDIO; /* always 0 */ 43211227fd1SGeert Uytterhoeven avb_param.num_of_av_video_pkt = 0; 43313a5e30cSGeoff Levand avb_param.num_of_av_audio_pkt = ps3av->av_hw_conf.num_of_hdmi; 43411227fd1SGeert Uytterhoeven 43513a5e30cSGeoff Levand vid = video_mode_table[ps3av->ps3av_mode].vid; 43611227fd1SGeert Uytterhoeven 43711227fd1SGeert Uytterhoeven /* audio mute */ 43811227fd1SGeert Uytterhoeven ps3av_set_audio_mute(PS3AV_CMD_MUTE_ON); 43911227fd1SGeert Uytterhoeven 44011227fd1SGeert Uytterhoeven /* audio inactive */ 44113a5e30cSGeoff Levand res = ps3av_cmd_audio_active(0, ps3av->audio_port); 44211227fd1SGeert Uytterhoeven if (res < 0) 44313a5e30cSGeoff Levand dev_dbg(&ps3av->dev->core, 44411227fd1SGeert Uytterhoeven "ps3av_cmd_audio_active OFF failed\n"); 44511227fd1SGeert Uytterhoeven 44611227fd1SGeert Uytterhoeven /* audio_pkt */ 44711227fd1SGeert Uytterhoeven for (i = 0; i < num_of_audio; i++) { 44813a5e30cSGeoff Levand ps3av_cmd_set_audio_mode(&audio_mode, ps3av->av_port[i], ch, 44913a5e30cSGeoff Levand fs, word_bits, format, source); 45013a5e30cSGeoff Levand if (i < ps3av->av_hw_conf.num_of_hdmi) { 45111227fd1SGeert Uytterhoeven /* hdmi only */ 45211227fd1SGeert Uytterhoeven len += ps3av_cmd_set_av_audio_param(&avb_param.buf[len], 45313a5e30cSGeoff Levand ps3av->av_port[i], 45411227fd1SGeert Uytterhoeven &audio_mode, vid); 45511227fd1SGeert Uytterhoeven } 45611227fd1SGeert Uytterhoeven /* audio_mode pkt should be sent separately */ 45711227fd1SGeert Uytterhoeven res = ps3av_cmd_audio_mode(&audio_mode); 45811227fd1SGeert Uytterhoeven if (res < 0) 45913a5e30cSGeoff Levand dev_dbg(&ps3av->dev->core, 46011227fd1SGeert Uytterhoeven "ps3av_cmd_audio_mode failed, port:%x\n", i); 46111227fd1SGeert Uytterhoeven } 46211227fd1SGeert Uytterhoeven 46311227fd1SGeert Uytterhoeven /* send command using avb pkt */ 46411227fd1SGeert Uytterhoeven len += offsetof(struct ps3av_pkt_avb_param, buf); 46511227fd1SGeert Uytterhoeven res = ps3av_cmd_avb_param(&avb_param, len); 46611227fd1SGeert Uytterhoeven if (res < 0) 46713a5e30cSGeoff Levand dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n"); 46811227fd1SGeert Uytterhoeven 46911227fd1SGeert Uytterhoeven /* audio mute */ 47011227fd1SGeert Uytterhoeven ps3av_set_audio_mute(PS3AV_CMD_MUTE_OFF); 47111227fd1SGeert Uytterhoeven 47211227fd1SGeert Uytterhoeven /* audio active */ 47313a5e30cSGeoff Levand res = ps3av_cmd_audio_active(1, ps3av->audio_port); 47411227fd1SGeert Uytterhoeven if (res < 0) 47513a5e30cSGeoff Levand dev_dbg(&ps3av->dev->core, 47613a5e30cSGeoff Levand "ps3av_cmd_audio_active ON failed\n"); 47711227fd1SGeert Uytterhoeven 47811227fd1SGeert Uytterhoeven return 0; 47911227fd1SGeert Uytterhoeven } 48011227fd1SGeert Uytterhoeven 48111227fd1SGeert Uytterhoeven EXPORT_SYMBOL_GPL(ps3av_set_audio_mode); 48211227fd1SGeert Uytterhoeven 48311227fd1SGeert Uytterhoeven static int ps3av_set_videomode(void) 48411227fd1SGeert Uytterhoeven { 48511227fd1SGeert Uytterhoeven /* av video mute */ 48611227fd1SGeert Uytterhoeven ps3av_set_av_video_mute(PS3AV_CMD_MUTE_ON); 48711227fd1SGeert Uytterhoeven 48811227fd1SGeert Uytterhoeven /* wake up ps3avd to do the actual video mode setting */ 48913a5e30cSGeoff Levand queue_work(ps3av->wq, &ps3av->work); 49011227fd1SGeert Uytterhoeven 49111227fd1SGeert Uytterhoeven return 0; 49211227fd1SGeert Uytterhoeven } 49311227fd1SGeert Uytterhoeven 4948ca0bf75SMasashi Kimoto static void ps3av_set_videomode_packet(u32 id) 49511227fd1SGeert Uytterhoeven { 49611227fd1SGeert Uytterhoeven struct ps3av_pkt_avb_param avb_param; 4978ca0bf75SMasashi Kimoto unsigned int i; 49811227fd1SGeert Uytterhoeven u32 len = 0, av_video_cs; 49911227fd1SGeert Uytterhoeven const struct avset_video_mode *video_mode; 50011227fd1SGeert Uytterhoeven int res; 50111227fd1SGeert Uytterhoeven 50211227fd1SGeert Uytterhoeven video_mode = &video_mode_table[id & PS3AV_MODE_MASK]; 50311227fd1SGeert Uytterhoeven 50411227fd1SGeert Uytterhoeven avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */ 50511227fd1SGeert Uytterhoeven avb_param.num_of_audio_pkt = 0; 50613a5e30cSGeoff Levand avb_param.num_of_av_video_pkt = ps3av->av_hw_conf.num_of_hdmi + 50713a5e30cSGeoff Levand ps3av->av_hw_conf.num_of_avmulti; 50811227fd1SGeert Uytterhoeven avb_param.num_of_av_audio_pkt = 0; 50911227fd1SGeert Uytterhoeven 51011227fd1SGeert Uytterhoeven /* video_pkt */ 51111227fd1SGeert Uytterhoeven for (i = 0; i < avb_param.num_of_video_pkt; i++) 51211227fd1SGeert Uytterhoeven len += ps3av_cmd_set_video_mode(&avb_param.buf[len], 51313a5e30cSGeoff Levand ps3av->head[i], video_mode->vid, 51411227fd1SGeert Uytterhoeven video_mode->fmt, id); 51511227fd1SGeert Uytterhoeven /* av_video_pkt */ 51611227fd1SGeert Uytterhoeven for (i = 0; i < avb_param.num_of_av_video_pkt; i++) { 51711227fd1SGeert Uytterhoeven if (id & PS3AV_MODE_DVI || id & PS3AV_MODE_RGB) 51811227fd1SGeert Uytterhoeven av_video_cs = RGB8; 51911227fd1SGeert Uytterhoeven else 52011227fd1SGeert Uytterhoeven av_video_cs = video_mode->cs; 52111227fd1SGeert Uytterhoeven #ifndef PS3AV_HDMI_YUV 52213a5e30cSGeoff Levand if (ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_0 || 52313a5e30cSGeoff Levand ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_1) 52411227fd1SGeert Uytterhoeven av_video_cs = RGB8; /* use RGB for HDMI */ 52511227fd1SGeert Uytterhoeven #endif 52611227fd1SGeert Uytterhoeven len += ps3av_cmd_set_av_video_cs(&avb_param.buf[len], 52713a5e30cSGeoff Levand ps3av->av_port[i], 52811227fd1SGeert Uytterhoeven video_mode->vid, av_video_cs, 52911227fd1SGeert Uytterhoeven video_mode->aspect, id); 53011227fd1SGeert Uytterhoeven } 53111227fd1SGeert Uytterhoeven /* send command using avb pkt */ 53211227fd1SGeert Uytterhoeven len += offsetof(struct ps3av_pkt_avb_param, buf); 53311227fd1SGeert Uytterhoeven res = ps3av_cmd_avb_param(&avb_param, len); 53411227fd1SGeert Uytterhoeven if (res == PS3AV_STATUS_NO_SYNC_HEAD) 53511227fd1SGeert Uytterhoeven printk(KERN_WARNING 53611227fd1SGeert Uytterhoeven "%s: Command failed. Please try your request again. \n", 537253f04e7SGeert Uytterhoeven __func__); 53811227fd1SGeert Uytterhoeven else if (res) 53913a5e30cSGeoff Levand dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n"); 5408ca0bf75SMasashi Kimoto } 5418ca0bf75SMasashi Kimoto 5428ca0bf75SMasashi Kimoto static void ps3av_set_videomode_cont(u32 id, u32 old_id) 5438ca0bf75SMasashi Kimoto { 5448ca0bf75SMasashi Kimoto static int vesa = 0; 5458ca0bf75SMasashi Kimoto int res; 5468ca0bf75SMasashi Kimoto 5478ca0bf75SMasashi Kimoto /* video signal off */ 5488ca0bf75SMasashi Kimoto ps3av_set_video_disable_sig(); 5498ca0bf75SMasashi Kimoto 5508ca0bf75SMasashi Kimoto /* 5518ca0bf75SMasashi Kimoto * AV backend needs non-VESA mode setting at least one time 5528ca0bf75SMasashi Kimoto * when VESA mode is used. 5538ca0bf75SMasashi Kimoto */ 5548ca0bf75SMasashi Kimoto if (vesa == 0 && (id & PS3AV_MODE_MASK) >= 11) { 5558ca0bf75SMasashi Kimoto /* vesa mode */ 5568ca0bf75SMasashi Kimoto ps3av_set_videomode_packet(2); /* 480P */ 5578ca0bf75SMasashi Kimoto } 5588ca0bf75SMasashi Kimoto vesa = 1; 5598ca0bf75SMasashi Kimoto 5608ca0bf75SMasashi Kimoto /* Retail PS3 product doesn't support this */ 5618ca0bf75SMasashi Kimoto if (id & PS3AV_MODE_HDCP_OFF) { 5628ca0bf75SMasashi Kimoto res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF); 5638ca0bf75SMasashi Kimoto if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) 5648ca0bf75SMasashi Kimoto dev_dbg(&ps3av->dev->core, "Not supported\n"); 5658ca0bf75SMasashi Kimoto else if (res) 5668ca0bf75SMasashi Kimoto dev_dbg(&ps3av->dev->core, 5678ca0bf75SMasashi Kimoto "ps3av_cmd_av_hdmi_mode failed\n"); 5688ca0bf75SMasashi Kimoto } else if (old_id & PS3AV_MODE_HDCP_OFF) { 5698ca0bf75SMasashi Kimoto res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL); 5708ca0bf75SMasashi Kimoto if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) 5718ca0bf75SMasashi Kimoto dev_dbg(&ps3av->dev->core, 5728ca0bf75SMasashi Kimoto "ps3av_cmd_av_hdmi_mode failed\n"); 5738ca0bf75SMasashi Kimoto } 5748ca0bf75SMasashi Kimoto 5758ca0bf75SMasashi Kimoto ps3av_set_videomode_packet(id); 57611227fd1SGeert Uytterhoeven 57711227fd1SGeert Uytterhoeven msleep(1500); 57811227fd1SGeert Uytterhoeven /* av video mute */ 57911227fd1SGeert Uytterhoeven ps3av_set_av_video_mute(PS3AV_CMD_MUTE_OFF); 58011227fd1SGeert Uytterhoeven } 58111227fd1SGeert Uytterhoeven 5825caf5db8SGeert Uytterhoeven static void ps3avd(struct work_struct *work) 58311227fd1SGeert Uytterhoeven { 58413a5e30cSGeoff Levand ps3av_set_videomode_cont(ps3av->ps3av_mode, ps3av->ps3av_mode_old); 58513a5e30cSGeoff Levand complete(&ps3av->done); 58611227fd1SGeert Uytterhoeven } 58711227fd1SGeert Uytterhoeven 58811227fd1SGeert Uytterhoeven static int ps3av_vid2table_id(int vid) 58911227fd1SGeert Uytterhoeven { 59011227fd1SGeert Uytterhoeven int i; 59111227fd1SGeert Uytterhoeven 59211227fd1SGeert Uytterhoeven for (i = 1; i < ARRAY_SIZE(video_mode_table); i++) 59311227fd1SGeert Uytterhoeven if (video_mode_table[i].vid == vid) 59411227fd1SGeert Uytterhoeven return i; 59511227fd1SGeert Uytterhoeven return -1; 59611227fd1SGeert Uytterhoeven } 59711227fd1SGeert Uytterhoeven 59811227fd1SGeert Uytterhoeven static int ps3av_resbit2vid(u32 res_50, u32 res_60) 59911227fd1SGeert Uytterhoeven { 60011227fd1SGeert Uytterhoeven int vid = -1; 60111227fd1SGeert Uytterhoeven 60211227fd1SGeert Uytterhoeven if (res_50 > res_60) { /* if res_50 == res_60, res_60 will be used */ 60311227fd1SGeert Uytterhoeven if (res_50 & PS3AV_RESBIT_1920x1080P) 60411227fd1SGeert Uytterhoeven vid = PS3AV_CMD_VIDEO_VID_1080P_50HZ; 60511227fd1SGeert Uytterhoeven else if (res_50 & PS3AV_RESBIT_1920x1080I) 60611227fd1SGeert Uytterhoeven vid = PS3AV_CMD_VIDEO_VID_1080I_50HZ; 60711227fd1SGeert Uytterhoeven else if (res_50 & PS3AV_RESBIT_1280x720P) 60811227fd1SGeert Uytterhoeven vid = PS3AV_CMD_VIDEO_VID_720P_50HZ; 60911227fd1SGeert Uytterhoeven else if (res_50 & PS3AV_RESBIT_720x576P) 61011227fd1SGeert Uytterhoeven vid = PS3AV_CMD_VIDEO_VID_576P; 61111227fd1SGeert Uytterhoeven else 61211227fd1SGeert Uytterhoeven vid = -1; 61311227fd1SGeert Uytterhoeven } else { 61411227fd1SGeert Uytterhoeven if (res_60 & PS3AV_RESBIT_1920x1080P) 61511227fd1SGeert Uytterhoeven vid = PS3AV_CMD_VIDEO_VID_1080P_60HZ; 61611227fd1SGeert Uytterhoeven else if (res_60 & PS3AV_RESBIT_1920x1080I) 61711227fd1SGeert Uytterhoeven vid = PS3AV_CMD_VIDEO_VID_1080I_60HZ; 61811227fd1SGeert Uytterhoeven else if (res_60 & PS3AV_RESBIT_1280x720P) 61911227fd1SGeert Uytterhoeven vid = PS3AV_CMD_VIDEO_VID_720P_60HZ; 62011227fd1SGeert Uytterhoeven else if (res_60 & PS3AV_RESBIT_720x480P) 62111227fd1SGeert Uytterhoeven vid = PS3AV_CMD_VIDEO_VID_480P; 62211227fd1SGeert Uytterhoeven else 62311227fd1SGeert Uytterhoeven vid = -1; 62411227fd1SGeert Uytterhoeven } 62511227fd1SGeert Uytterhoeven return vid; 62611227fd1SGeert Uytterhoeven } 62711227fd1SGeert Uytterhoeven 62811227fd1SGeert Uytterhoeven static int ps3av_hdmi_get_vid(struct ps3av_info_monitor *info) 62911227fd1SGeert Uytterhoeven { 63011227fd1SGeert Uytterhoeven u32 res_50, res_60; 63111227fd1SGeert Uytterhoeven int vid = -1; 63211227fd1SGeert Uytterhoeven 63311227fd1SGeert Uytterhoeven if (info->monitor_type != PS3AV_MONITOR_TYPE_HDMI) 63411227fd1SGeert Uytterhoeven return -1; 63511227fd1SGeert Uytterhoeven 63611227fd1SGeert Uytterhoeven /* check native resolution */ 63711227fd1SGeert Uytterhoeven res_50 = info->res_50.native & PS3AV_RES_MASK_50; 63811227fd1SGeert Uytterhoeven res_60 = info->res_60.native & PS3AV_RES_MASK_60; 63911227fd1SGeert Uytterhoeven if (res_50 || res_60) { 64011227fd1SGeert Uytterhoeven vid = ps3av_resbit2vid(res_50, res_60); 64111227fd1SGeert Uytterhoeven return vid; 64211227fd1SGeert Uytterhoeven } 64311227fd1SGeert Uytterhoeven 64411227fd1SGeert Uytterhoeven /* check resolution */ 64511227fd1SGeert Uytterhoeven res_50 = info->res_50.res_bits & PS3AV_RES_MASK_50; 64611227fd1SGeert Uytterhoeven res_60 = info->res_60.res_bits & PS3AV_RES_MASK_60; 64711227fd1SGeert Uytterhoeven if (res_50 || res_60) { 64811227fd1SGeert Uytterhoeven vid = ps3av_resbit2vid(res_50, res_60); 64911227fd1SGeert Uytterhoeven return vid; 65011227fd1SGeert Uytterhoeven } 65111227fd1SGeert Uytterhoeven 65213a5e30cSGeoff Levand if (ps3av->region & PS3AV_REGION_60) 65311227fd1SGeert Uytterhoeven vid = PS3AV_DEFAULT_HDMI_VID_REG_60; 65411227fd1SGeert Uytterhoeven else 65511227fd1SGeert Uytterhoeven vid = PS3AV_DEFAULT_HDMI_VID_REG_50; 65611227fd1SGeert Uytterhoeven return vid; 65711227fd1SGeert Uytterhoeven } 65811227fd1SGeert Uytterhoeven 659eea820abSGeert Uytterhoeven static void ps3av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *monitor_info) 660eea820abSGeert Uytterhoeven { 661eea820abSGeert Uytterhoeven const struct ps3av_info_monitor *info = &monitor_info->info; 662eea820abSGeert Uytterhoeven const struct ps3av_info_audio *audio = info->audio; 663eea820abSGeert Uytterhoeven char id[sizeof(info->monitor_id)*3+1]; 664eea820abSGeert Uytterhoeven int i; 665eea820abSGeert Uytterhoeven 666eea820abSGeert Uytterhoeven pr_debug("Monitor Info: size %u\n", monitor_info->send_hdr.size); 667eea820abSGeert Uytterhoeven 668eea820abSGeert Uytterhoeven pr_debug("avport: %02x\n", info->avport); 669eea820abSGeert Uytterhoeven for (i = 0; i < sizeof(info->monitor_id); i++) 670eea820abSGeert Uytterhoeven sprintf(&id[i*3], " %02x", info->monitor_id[i]); 671eea820abSGeert Uytterhoeven pr_debug("monitor_id: %s\n", id); 672eea820abSGeert Uytterhoeven pr_debug("monitor_type: %02x\n", info->monitor_type); 673eea820abSGeert Uytterhoeven pr_debug("monitor_name: %.*s\n", (int)sizeof(info->monitor_name), 674eea820abSGeert Uytterhoeven info->monitor_name); 675eea820abSGeert Uytterhoeven 676eea820abSGeert Uytterhoeven /* resolution */ 677eea820abSGeert Uytterhoeven pr_debug("resolution_60: bits: %08x native: %08x\n", 678eea820abSGeert Uytterhoeven info->res_60.res_bits, info->res_60.native); 679eea820abSGeert Uytterhoeven pr_debug("resolution_50: bits: %08x native: %08x\n", 680eea820abSGeert Uytterhoeven info->res_50.res_bits, info->res_50.native); 681eea820abSGeert Uytterhoeven pr_debug("resolution_other: bits: %08x native: %08x\n", 682eea820abSGeert Uytterhoeven info->res_other.res_bits, info->res_other.native); 683eea820abSGeert Uytterhoeven pr_debug("resolution_vesa: bits: %08x native: %08x\n", 684eea820abSGeert Uytterhoeven info->res_vesa.res_bits, info->res_vesa.native); 685eea820abSGeert Uytterhoeven 686eea820abSGeert Uytterhoeven /* color space */ 687eea820abSGeert Uytterhoeven pr_debug("color space rgb: %02x\n", info->cs.rgb); 688eea820abSGeert Uytterhoeven pr_debug("color space yuv444: %02x\n", info->cs.yuv444); 689eea820abSGeert Uytterhoeven pr_debug("color space yuv422: %02x\n", info->cs.yuv422); 690eea820abSGeert Uytterhoeven 691eea820abSGeert Uytterhoeven /* color info */ 692eea820abSGeert Uytterhoeven pr_debug("color info red: X %04x Y %04x\n", info->color.red_x, 693eea820abSGeert Uytterhoeven info->color.red_y); 694eea820abSGeert Uytterhoeven pr_debug("color info green: X %04x Y %04x\n", info->color.green_x, 695eea820abSGeert Uytterhoeven info->color.green_y); 696eea820abSGeert Uytterhoeven pr_debug("color info blue: X %04x Y %04x\n", info->color.blue_x, 697eea820abSGeert Uytterhoeven info->color.blue_y); 698eea820abSGeert Uytterhoeven pr_debug("color info white: X %04x Y %04x\n", info->color.white_x, 699eea820abSGeert Uytterhoeven info->color.white_y); 700eea820abSGeert Uytterhoeven pr_debug("color info gamma: %08x\n", info->color.gamma); 701eea820abSGeert Uytterhoeven 702eea820abSGeert Uytterhoeven /* other info */ 703eea820abSGeert Uytterhoeven pr_debug("supported_AI: %02x\n", info->supported_ai); 704eea820abSGeert Uytterhoeven pr_debug("speaker_info: %02x\n", info->speaker_info); 705eea820abSGeert Uytterhoeven pr_debug("num of audio: %02x\n", info->num_of_audio_block); 706eea820abSGeert Uytterhoeven 707eea820abSGeert Uytterhoeven /* audio block */ 708eea820abSGeert Uytterhoeven for (i = 0; i < info->num_of_audio_block; i++) { 709eea820abSGeert Uytterhoeven pr_debug("audio[%d] type: %02x max_ch: %02x fs: %02x sbit: " 710eea820abSGeert Uytterhoeven "%02x\n", 711eea820abSGeert Uytterhoeven i, audio->type, audio->max_num_of_ch, audio->fs, 712eea820abSGeert Uytterhoeven audio->sbit); 713eea820abSGeert Uytterhoeven audio++; 714eea820abSGeert Uytterhoeven } 715eea820abSGeert Uytterhoeven } 716eea820abSGeert Uytterhoeven 71711227fd1SGeert Uytterhoeven static int ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf, 71811227fd1SGeert Uytterhoeven int boot) 71911227fd1SGeert Uytterhoeven { 72011227fd1SGeert Uytterhoeven int i, res, vid = -1, dvi = 0, rgb = 0; 72111227fd1SGeert Uytterhoeven struct ps3av_pkt_av_get_monitor_info monitor_info; 72211227fd1SGeert Uytterhoeven struct ps3av_info_monitor *info; 72311227fd1SGeert Uytterhoeven 72411227fd1SGeert Uytterhoeven /* get vid for hdmi */ 72511227fd1SGeert Uytterhoeven for (i = 0; i < av_hw_conf->num_of_hdmi; i++) { 72611227fd1SGeert Uytterhoeven res = ps3av_cmd_video_get_monitor_info(&monitor_info, 72711227fd1SGeert Uytterhoeven PS3AV_CMD_AVPORT_HDMI_0 + 72811227fd1SGeert Uytterhoeven i); 72911227fd1SGeert Uytterhoeven if (res < 0) 73011227fd1SGeert Uytterhoeven return -1; 73111227fd1SGeert Uytterhoeven 732eea820abSGeert Uytterhoeven ps3av_monitor_info_dump(&monitor_info); 73311227fd1SGeert Uytterhoeven info = &monitor_info.info; 73411227fd1SGeert Uytterhoeven /* check DVI */ 73511227fd1SGeert Uytterhoeven if (info->monitor_type == PS3AV_MONITOR_TYPE_DVI) { 73611227fd1SGeert Uytterhoeven dvi = PS3AV_MODE_DVI; 73711227fd1SGeert Uytterhoeven break; 73811227fd1SGeert Uytterhoeven } 73911227fd1SGeert Uytterhoeven /* check HDMI */ 74011227fd1SGeert Uytterhoeven vid = ps3av_hdmi_get_vid(info); 74111227fd1SGeert Uytterhoeven if (vid != -1) { 74211227fd1SGeert Uytterhoeven /* got valid vid */ 74311227fd1SGeert Uytterhoeven break; 74411227fd1SGeert Uytterhoeven } 74511227fd1SGeert Uytterhoeven } 74611227fd1SGeert Uytterhoeven 74711227fd1SGeert Uytterhoeven if (dvi) { 74811227fd1SGeert Uytterhoeven /* DVI mode */ 74911227fd1SGeert Uytterhoeven vid = PS3AV_DEFAULT_DVI_VID; 75011227fd1SGeert Uytterhoeven } else if (vid == -1) { 75111227fd1SGeert Uytterhoeven /* no HDMI interface or HDMI is off */ 75213a5e30cSGeoff Levand if (ps3av->region & PS3AV_REGION_60) 75311227fd1SGeert Uytterhoeven vid = PS3AV_DEFAULT_AVMULTI_VID_REG_60; 75411227fd1SGeert Uytterhoeven else 75511227fd1SGeert Uytterhoeven vid = PS3AV_DEFAULT_AVMULTI_VID_REG_50; 75613a5e30cSGeoff Levand if (ps3av->region & PS3AV_REGION_RGB) 75711227fd1SGeert Uytterhoeven rgb = PS3AV_MODE_RGB; 75811227fd1SGeert Uytterhoeven } else if (boot) { 75911227fd1SGeert Uytterhoeven /* HDMI: using DEFAULT HDMI_VID while booting up */ 76011227fd1SGeert Uytterhoeven info = &monitor_info.info; 76113a5e30cSGeoff Levand if (ps3av->region & PS3AV_REGION_60) { 76211227fd1SGeert Uytterhoeven if (info->res_60.res_bits & PS3AV_RESBIT_720x480P) 76311227fd1SGeert Uytterhoeven vid = PS3AV_DEFAULT_HDMI_VID_REG_60; 76411227fd1SGeert Uytterhoeven else if (info->res_50.res_bits & PS3AV_RESBIT_720x576P) 76511227fd1SGeert Uytterhoeven vid = PS3AV_DEFAULT_HDMI_VID_REG_50; 76611227fd1SGeert Uytterhoeven else { 76711227fd1SGeert Uytterhoeven /* default */ 76811227fd1SGeert Uytterhoeven vid = PS3AV_DEFAULT_HDMI_VID_REG_60; 76911227fd1SGeert Uytterhoeven } 77011227fd1SGeert Uytterhoeven } else { 77111227fd1SGeert Uytterhoeven if (info->res_50.res_bits & PS3AV_RESBIT_720x576P) 77211227fd1SGeert Uytterhoeven vid = PS3AV_DEFAULT_HDMI_VID_REG_50; 77311227fd1SGeert Uytterhoeven else if (info->res_60.res_bits & PS3AV_RESBIT_720x480P) 77411227fd1SGeert Uytterhoeven vid = PS3AV_DEFAULT_HDMI_VID_REG_60; 77511227fd1SGeert Uytterhoeven else { 77611227fd1SGeert Uytterhoeven /* default */ 77711227fd1SGeert Uytterhoeven vid = PS3AV_DEFAULT_HDMI_VID_REG_50; 77811227fd1SGeert Uytterhoeven } 77911227fd1SGeert Uytterhoeven } 78011227fd1SGeert Uytterhoeven } 78111227fd1SGeert Uytterhoeven 78211227fd1SGeert Uytterhoeven return (ps3av_vid2table_id(vid) | dvi | rgb); 78311227fd1SGeert Uytterhoeven } 78411227fd1SGeert Uytterhoeven 78511227fd1SGeert Uytterhoeven static int ps3av_get_hw_conf(struct ps3av *ps3av) 78611227fd1SGeert Uytterhoeven { 78711227fd1SGeert Uytterhoeven int i, j, k, res; 788eea820abSGeert Uytterhoeven const struct ps3av_pkt_av_get_hw_conf *hw_conf; 78911227fd1SGeert Uytterhoeven 79011227fd1SGeert Uytterhoeven /* get av_hw_conf */ 79111227fd1SGeert Uytterhoeven res = ps3av_cmd_av_get_hw_conf(&ps3av->av_hw_conf); 79211227fd1SGeert Uytterhoeven if (res < 0) 79311227fd1SGeert Uytterhoeven return -1; 79411227fd1SGeert Uytterhoeven 795eea820abSGeert Uytterhoeven hw_conf = &ps3av->av_hw_conf; 796eea820abSGeert Uytterhoeven pr_debug("av_h_conf: num of hdmi: %u\n", hw_conf->num_of_hdmi); 797eea820abSGeert Uytterhoeven pr_debug("av_h_conf: num of avmulti: %u\n", hw_conf->num_of_avmulti); 798eea820abSGeert Uytterhoeven pr_debug("av_h_conf: num of spdif: %u\n", hw_conf->num_of_spdif); 79911227fd1SGeert Uytterhoeven 80011227fd1SGeert Uytterhoeven for (i = 0; i < PS3AV_HEAD_MAX; i++) 80111227fd1SGeert Uytterhoeven ps3av->head[i] = PS3AV_CMD_VIDEO_HEAD_A + i; 80211227fd1SGeert Uytterhoeven for (i = 0; i < PS3AV_OPT_PORT_MAX; i++) 80311227fd1SGeert Uytterhoeven ps3av->opt_port[i] = PS3AV_CMD_AVPORT_SPDIF_0 + i; 804eea820abSGeert Uytterhoeven for (i = 0; i < hw_conf->num_of_hdmi; i++) 80511227fd1SGeert Uytterhoeven ps3av->av_port[i] = PS3AV_CMD_AVPORT_HDMI_0 + i; 806eea820abSGeert Uytterhoeven for (j = 0; j < hw_conf->num_of_avmulti; j++) 80711227fd1SGeert Uytterhoeven ps3av->av_port[i + j] = PS3AV_CMD_AVPORT_AVMULTI_0 + j; 808eea820abSGeert Uytterhoeven for (k = 0; k < hw_conf->num_of_spdif; k++) 80911227fd1SGeert Uytterhoeven ps3av->av_port[i + j + k] = PS3AV_CMD_AVPORT_SPDIF_0 + k; 81011227fd1SGeert Uytterhoeven 81111227fd1SGeert Uytterhoeven /* set all audio port */ 81211227fd1SGeert Uytterhoeven ps3av->audio_port = PS3AV_CMD_AUDIO_PORT_HDMI_0 81311227fd1SGeert Uytterhoeven | PS3AV_CMD_AUDIO_PORT_HDMI_1 81411227fd1SGeert Uytterhoeven | PS3AV_CMD_AUDIO_PORT_AVMULTI_0 81511227fd1SGeert Uytterhoeven | PS3AV_CMD_AUDIO_PORT_SPDIF_0 | PS3AV_CMD_AUDIO_PORT_SPDIF_1; 81611227fd1SGeert Uytterhoeven 81711227fd1SGeert Uytterhoeven return 0; 81811227fd1SGeert Uytterhoeven } 81911227fd1SGeert Uytterhoeven 82011227fd1SGeert Uytterhoeven /* set mode using id */ 82111227fd1SGeert Uytterhoeven int ps3av_set_video_mode(u32 id, int boot) 82211227fd1SGeert Uytterhoeven { 82311227fd1SGeert Uytterhoeven int size; 82411227fd1SGeert Uytterhoeven u32 option; 82511227fd1SGeert Uytterhoeven 82611227fd1SGeert Uytterhoeven size = ARRAY_SIZE(video_mode_table); 82711227fd1SGeert Uytterhoeven if ((id & PS3AV_MODE_MASK) > size - 1 || id < 0) { 82813a5e30cSGeoff Levand dev_dbg(&ps3av->dev->core, "%s: error id :%d\n", __func__, id); 82911227fd1SGeert Uytterhoeven return -EINVAL; 83011227fd1SGeert Uytterhoeven } 83111227fd1SGeert Uytterhoeven 83211227fd1SGeert Uytterhoeven /* auto mode */ 83311227fd1SGeert Uytterhoeven option = id & ~PS3AV_MODE_MASK; 83411227fd1SGeert Uytterhoeven if ((id & PS3AV_MODE_MASK) == 0) { 83513a5e30cSGeoff Levand id = ps3av_auto_videomode(&ps3av->av_hw_conf, boot); 83611227fd1SGeert Uytterhoeven if (id < 1) { 837253f04e7SGeert Uytterhoeven printk(KERN_ERR "%s: invalid id :%d\n", __func__, id); 83811227fd1SGeert Uytterhoeven return -EINVAL; 83911227fd1SGeert Uytterhoeven } 84011227fd1SGeert Uytterhoeven id |= option; 84111227fd1SGeert Uytterhoeven } 84211227fd1SGeert Uytterhoeven 84311227fd1SGeert Uytterhoeven /* set videomode */ 84413a5e30cSGeoff Levand wait_for_completion(&ps3av->done); 84513a5e30cSGeoff Levand ps3av->ps3av_mode_old = ps3av->ps3av_mode; 84613a5e30cSGeoff Levand ps3av->ps3av_mode = id; 84711227fd1SGeert Uytterhoeven if (ps3av_set_videomode()) 84813a5e30cSGeoff Levand ps3av->ps3av_mode = ps3av->ps3av_mode_old; 84911227fd1SGeert Uytterhoeven 85011227fd1SGeert Uytterhoeven return 0; 85111227fd1SGeert Uytterhoeven } 85211227fd1SGeert Uytterhoeven 85311227fd1SGeert Uytterhoeven EXPORT_SYMBOL_GPL(ps3av_set_video_mode); 85411227fd1SGeert Uytterhoeven 85564072901SMasashi Kimoto int ps3av_get_auto_mode(int boot) 85664072901SMasashi Kimoto { 85713a5e30cSGeoff Levand return ps3av_auto_videomode(&ps3av->av_hw_conf, boot); 85864072901SMasashi Kimoto } 85964072901SMasashi Kimoto 86064072901SMasashi Kimoto EXPORT_SYMBOL_GPL(ps3av_get_auto_mode); 86164072901SMasashi Kimoto 86211227fd1SGeert Uytterhoeven int ps3av_set_mode(u32 id, int boot) 86311227fd1SGeert Uytterhoeven { 86411227fd1SGeert Uytterhoeven int res; 86511227fd1SGeert Uytterhoeven 86611227fd1SGeert Uytterhoeven res = ps3av_set_video_mode(id, boot); 86711227fd1SGeert Uytterhoeven if (res) 86811227fd1SGeert Uytterhoeven return res; 86911227fd1SGeert Uytterhoeven 87011227fd1SGeert Uytterhoeven res = ps3av_set_audio_mode(PS3AV_CMD_AUDIO_NUM_OF_CH_2, 87111227fd1SGeert Uytterhoeven PS3AV_CMD_AUDIO_FS_48K, 87211227fd1SGeert Uytterhoeven PS3AV_CMD_AUDIO_WORD_BITS_16, 87311227fd1SGeert Uytterhoeven PS3AV_CMD_AUDIO_FORMAT_PCM, 87411227fd1SGeert Uytterhoeven PS3AV_CMD_AUDIO_SOURCE_SERIAL); 87511227fd1SGeert Uytterhoeven if (res) 87611227fd1SGeert Uytterhoeven return res; 87711227fd1SGeert Uytterhoeven 87811227fd1SGeert Uytterhoeven return 0; 87911227fd1SGeert Uytterhoeven } 88011227fd1SGeert Uytterhoeven 88111227fd1SGeert Uytterhoeven EXPORT_SYMBOL_GPL(ps3av_set_mode); 88211227fd1SGeert Uytterhoeven 88311227fd1SGeert Uytterhoeven int ps3av_get_mode(void) 88411227fd1SGeert Uytterhoeven { 88513a5e30cSGeoff Levand return ps3av ? ps3av->ps3av_mode : 0; 88611227fd1SGeert Uytterhoeven } 88711227fd1SGeert Uytterhoeven 88811227fd1SGeert Uytterhoeven EXPORT_SYMBOL_GPL(ps3av_get_mode); 88911227fd1SGeert Uytterhoeven 89011227fd1SGeert Uytterhoeven int ps3av_get_scanmode(int id) 89111227fd1SGeert Uytterhoeven { 89211227fd1SGeert Uytterhoeven int size; 89311227fd1SGeert Uytterhoeven 89411227fd1SGeert Uytterhoeven id = id & PS3AV_MODE_MASK; 89511227fd1SGeert Uytterhoeven size = ARRAY_SIZE(video_mode_table); 89611227fd1SGeert Uytterhoeven if (id > size - 1 || id < 0) { 897253f04e7SGeert Uytterhoeven printk(KERN_ERR "%s: invalid mode %d\n", __func__, id); 89811227fd1SGeert Uytterhoeven return -EINVAL; 89911227fd1SGeert Uytterhoeven } 90011227fd1SGeert Uytterhoeven return video_mode_table[id].interlace; 90111227fd1SGeert Uytterhoeven } 90211227fd1SGeert Uytterhoeven 90311227fd1SGeert Uytterhoeven EXPORT_SYMBOL_GPL(ps3av_get_scanmode); 90411227fd1SGeert Uytterhoeven 90511227fd1SGeert Uytterhoeven int ps3av_get_refresh_rate(int id) 90611227fd1SGeert Uytterhoeven { 90711227fd1SGeert Uytterhoeven int size; 90811227fd1SGeert Uytterhoeven 90911227fd1SGeert Uytterhoeven id = id & PS3AV_MODE_MASK; 91011227fd1SGeert Uytterhoeven size = ARRAY_SIZE(video_mode_table); 91111227fd1SGeert Uytterhoeven if (id > size - 1 || id < 0) { 912253f04e7SGeert Uytterhoeven printk(KERN_ERR "%s: invalid mode %d\n", __func__, id); 91311227fd1SGeert Uytterhoeven return -EINVAL; 91411227fd1SGeert Uytterhoeven } 91511227fd1SGeert Uytterhoeven return video_mode_table[id].freq; 91611227fd1SGeert Uytterhoeven } 91711227fd1SGeert Uytterhoeven 91811227fd1SGeert Uytterhoeven EXPORT_SYMBOL_GPL(ps3av_get_refresh_rate); 91911227fd1SGeert Uytterhoeven 92011227fd1SGeert Uytterhoeven /* get resolution by video_mode */ 92111227fd1SGeert Uytterhoeven int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres) 92211227fd1SGeert Uytterhoeven { 92311227fd1SGeert Uytterhoeven int size; 92411227fd1SGeert Uytterhoeven 92511227fd1SGeert Uytterhoeven id = id & PS3AV_MODE_MASK; 92611227fd1SGeert Uytterhoeven size = ARRAY_SIZE(video_mode_table); 92711227fd1SGeert Uytterhoeven if (id > size - 1 || id < 0) { 928253f04e7SGeert Uytterhoeven printk(KERN_ERR "%s: invalid mode %d\n", __func__, id); 92911227fd1SGeert Uytterhoeven return -EINVAL; 93011227fd1SGeert Uytterhoeven } 93111227fd1SGeert Uytterhoeven *xres = video_mode_table[id].x; 93211227fd1SGeert Uytterhoeven *yres = video_mode_table[id].y; 93311227fd1SGeert Uytterhoeven return 0; 93411227fd1SGeert Uytterhoeven } 93511227fd1SGeert Uytterhoeven 93611227fd1SGeert Uytterhoeven EXPORT_SYMBOL_GPL(ps3av_video_mode2res); 93711227fd1SGeert Uytterhoeven 93811227fd1SGeert Uytterhoeven /* mute */ 93911227fd1SGeert Uytterhoeven int ps3av_video_mute(int mute) 94011227fd1SGeert Uytterhoeven { 94111227fd1SGeert Uytterhoeven return ps3av_set_av_video_mute(mute ? PS3AV_CMD_MUTE_ON 94211227fd1SGeert Uytterhoeven : PS3AV_CMD_MUTE_OFF); 94311227fd1SGeert Uytterhoeven } 94411227fd1SGeert Uytterhoeven 94511227fd1SGeert Uytterhoeven EXPORT_SYMBOL_GPL(ps3av_video_mute); 94611227fd1SGeert Uytterhoeven 94711227fd1SGeert Uytterhoeven int ps3av_audio_mute(int mute) 94811227fd1SGeert Uytterhoeven { 94911227fd1SGeert Uytterhoeven return ps3av_set_audio_mute(mute ? PS3AV_CMD_MUTE_ON 95011227fd1SGeert Uytterhoeven : PS3AV_CMD_MUTE_OFF); 95111227fd1SGeert Uytterhoeven } 95211227fd1SGeert Uytterhoeven 95311227fd1SGeert Uytterhoeven EXPORT_SYMBOL_GPL(ps3av_audio_mute); 95411227fd1SGeert Uytterhoeven 95513a5e30cSGeoff Levand void ps3av_register_flip_ctl(void (*flip_ctl)(int on, void *data), 95613a5e30cSGeoff Levand void *flip_data) 95711227fd1SGeert Uytterhoeven { 95813a5e30cSGeoff Levand mutex_lock(&ps3av->mutex); 95913a5e30cSGeoff Levand ps3av->flip_ctl = flip_ctl; 96013a5e30cSGeoff Levand ps3av->flip_data = flip_data; 96113a5e30cSGeoff Levand mutex_unlock(&ps3av->mutex); 96211227fd1SGeert Uytterhoeven } 96313a5e30cSGeoff Levand EXPORT_SYMBOL_GPL(ps3av_register_flip_ctl); 96411227fd1SGeert Uytterhoeven 96513a5e30cSGeoff Levand void ps3av_flip_ctl(int on) 96611227fd1SGeert Uytterhoeven { 96713a5e30cSGeoff Levand mutex_lock(&ps3av->mutex); 96813a5e30cSGeoff Levand if (ps3av->flip_ctl) 96913a5e30cSGeoff Levand ps3av->flip_ctl(on, ps3av->flip_data); 97013a5e30cSGeoff Levand mutex_unlock(&ps3av->mutex); 97111227fd1SGeert Uytterhoeven } 97211227fd1SGeert Uytterhoeven 97313a5e30cSGeoff Levand static int ps3av_probe(struct ps3_system_bus_device *dev) 97411227fd1SGeert Uytterhoeven { 97511227fd1SGeert Uytterhoeven int res; 97611227fd1SGeert Uytterhoeven u32 id; 97711227fd1SGeert Uytterhoeven 97813a5e30cSGeoff Levand dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); 97913a5e30cSGeoff Levand dev_dbg(&dev->core, " timeout=%d\n", timeout); 98011227fd1SGeert Uytterhoeven 98113a5e30cSGeoff Levand if (ps3av) { 98213a5e30cSGeoff Levand dev_err(&dev->core, "Only one ps3av device is supported\n"); 98313a5e30cSGeoff Levand return -EBUSY; 98413a5e30cSGeoff Levand } 98511227fd1SGeert Uytterhoeven 98613a5e30cSGeoff Levand ps3av = kzalloc(sizeof(*ps3av), GFP_KERNEL); 98713a5e30cSGeoff Levand if (!ps3av) 9885caf5db8SGeert Uytterhoeven return -ENOMEM; 98911227fd1SGeert Uytterhoeven 99013a5e30cSGeoff Levand mutex_init(&ps3av->mutex); 99113a5e30cSGeoff Levand ps3av->ps3av_mode = 0; 99213a5e30cSGeoff Levand ps3av->dev = dev; 99313a5e30cSGeoff Levand 99413a5e30cSGeoff Levand INIT_WORK(&ps3av->work, ps3avd); 99513a5e30cSGeoff Levand init_completion(&ps3av->done); 99613a5e30cSGeoff Levand complete(&ps3av->done); 99713a5e30cSGeoff Levand ps3av->wq = create_singlethread_workqueue("ps3avd"); 99813a5e30cSGeoff Levand if (!ps3av->wq) 99913a5e30cSGeoff Levand goto fail; 100013a5e30cSGeoff Levand 100111227fd1SGeert Uytterhoeven switch (ps3_os_area_get_av_multi_out()) { 100211227fd1SGeert Uytterhoeven case PS3_PARAM_AV_MULTI_OUT_NTSC: 100313a5e30cSGeoff Levand ps3av->region = PS3AV_REGION_60; 100411227fd1SGeert Uytterhoeven break; 100511227fd1SGeert Uytterhoeven case PS3_PARAM_AV_MULTI_OUT_PAL_YCBCR: 100611227fd1SGeert Uytterhoeven case PS3_PARAM_AV_MULTI_OUT_SECAM: 100713a5e30cSGeoff Levand ps3av->region = PS3AV_REGION_50; 100811227fd1SGeert Uytterhoeven break; 100911227fd1SGeert Uytterhoeven case PS3_PARAM_AV_MULTI_OUT_PAL_RGB: 101013a5e30cSGeoff Levand ps3av->region = PS3AV_REGION_50 | PS3AV_REGION_RGB; 101111227fd1SGeert Uytterhoeven break; 101211227fd1SGeert Uytterhoeven default: 101313a5e30cSGeoff Levand ps3av->region = PS3AV_REGION_60; 101411227fd1SGeert Uytterhoeven break; 101511227fd1SGeert Uytterhoeven } 101611227fd1SGeert Uytterhoeven 101711227fd1SGeert Uytterhoeven /* init avsetting modules */ 101811227fd1SGeert Uytterhoeven res = ps3av_cmd_init(); 101911227fd1SGeert Uytterhoeven if (res < 0) 1020253f04e7SGeert Uytterhoeven printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __func__, 102111227fd1SGeert Uytterhoeven res); 102211227fd1SGeert Uytterhoeven 102313a5e30cSGeoff Levand ps3av_get_hw_conf(ps3av); 102413a5e30cSGeoff Levand id = ps3av_auto_videomode(&ps3av->av_hw_conf, 1); 102513a5e30cSGeoff Levand mutex_lock(&ps3av->mutex); 102613a5e30cSGeoff Levand ps3av->ps3av_mode = id; 102713a5e30cSGeoff Levand mutex_unlock(&ps3av->mutex); 102811227fd1SGeert Uytterhoeven 102913a5e30cSGeoff Levand dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); 103011227fd1SGeert Uytterhoeven 103111227fd1SGeert Uytterhoeven return 0; 103213a5e30cSGeoff Levand 103313a5e30cSGeoff Levand fail: 103413a5e30cSGeoff Levand kfree(ps3av); 103513a5e30cSGeoff Levand ps3av = NULL; 103613a5e30cSGeoff Levand return -ENOMEM; 103711227fd1SGeert Uytterhoeven } 103811227fd1SGeert Uytterhoeven 103913a5e30cSGeoff Levand static int ps3av_remove(struct ps3_system_bus_device *dev) 104011227fd1SGeert Uytterhoeven { 104113a5e30cSGeoff Levand dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); 104213a5e30cSGeoff Levand if (ps3av) { 104311227fd1SGeert Uytterhoeven ps3av_cmd_fin(); 104413a5e30cSGeoff Levand if (ps3av->wq) 104513a5e30cSGeoff Levand destroy_workqueue(ps3av->wq); 104613a5e30cSGeoff Levand kfree(ps3av); 104713a5e30cSGeoff Levand ps3av = NULL; 104811227fd1SGeert Uytterhoeven } 104911227fd1SGeert Uytterhoeven 105013a5e30cSGeoff Levand dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); 105111227fd1SGeert Uytterhoeven return 0; 105211227fd1SGeert Uytterhoeven } 105311227fd1SGeert Uytterhoeven 105413a5e30cSGeoff Levand static void ps3av_shutdown(struct ps3_system_bus_device *dev) 105511227fd1SGeert Uytterhoeven { 105613a5e30cSGeoff Levand dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); 105711227fd1SGeert Uytterhoeven ps3av_remove(dev); 105813a5e30cSGeoff Levand dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); 105911227fd1SGeert Uytterhoeven } 106011227fd1SGeert Uytterhoeven 106111227fd1SGeert Uytterhoeven static struct ps3_vuart_port_driver ps3av_driver = { 106213a5e30cSGeoff Levand .core.match_id = PS3_MATCH_ID_AV_SETTINGS, 106313a5e30cSGeoff Levand .core.core.name = "ps3_av", 106411227fd1SGeert Uytterhoeven .probe = ps3av_probe, 106511227fd1SGeert Uytterhoeven .remove = ps3av_remove, 106611227fd1SGeert Uytterhoeven .shutdown = ps3av_shutdown, 106711227fd1SGeert Uytterhoeven }; 106811227fd1SGeert Uytterhoeven 106911227fd1SGeert Uytterhoeven static int ps3av_module_init(void) 107011227fd1SGeert Uytterhoeven { 1071ef596c69SGeert Uytterhoeven int error; 1072ef596c69SGeert Uytterhoeven 1073ef596c69SGeert Uytterhoeven if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) 1074ef596c69SGeert Uytterhoeven return -ENODEV; 1075ef596c69SGeert Uytterhoeven 107613a5e30cSGeoff Levand pr_debug(" -> %s:%d\n", __func__, __LINE__); 107713a5e30cSGeoff Levand 1078ef596c69SGeert Uytterhoeven error = ps3_vuart_port_driver_register(&ps3av_driver); 107911227fd1SGeert Uytterhoeven if (error) { 108011227fd1SGeert Uytterhoeven printk(KERN_ERR 108111227fd1SGeert Uytterhoeven "%s: ps3_vuart_port_driver_register failed %d\n", 1082253f04e7SGeert Uytterhoeven __func__, error); 108311227fd1SGeert Uytterhoeven return error; 108411227fd1SGeert Uytterhoeven } 108511227fd1SGeert Uytterhoeven 108613a5e30cSGeoff Levand pr_debug(" <- %s:%d\n", __func__, __LINE__); 108711227fd1SGeert Uytterhoeven return error; 108811227fd1SGeert Uytterhoeven } 108911227fd1SGeert Uytterhoeven 109011227fd1SGeert Uytterhoeven static void __exit ps3av_module_exit(void) 109111227fd1SGeert Uytterhoeven { 109213a5e30cSGeoff Levand pr_debug(" -> %s:%d\n", __func__, __LINE__); 109311227fd1SGeert Uytterhoeven ps3_vuart_port_driver_unregister(&ps3av_driver); 109413a5e30cSGeoff Levand pr_debug(" <- %s:%d\n", __func__, __LINE__); 109511227fd1SGeert Uytterhoeven } 109611227fd1SGeert Uytterhoeven 109711227fd1SGeert Uytterhoeven subsys_initcall(ps3av_module_init); 109811227fd1SGeert Uytterhoeven module_exit(ps3av_module_exit); 109913a5e30cSGeoff Levand 110013a5e30cSGeoff Levand MODULE_LICENSE("GPL v2"); 110113a5e30cSGeoff Levand MODULE_DESCRIPTION("PS3 AV Settings Driver"); 110213a5e30cSGeoff Levand MODULE_AUTHOR("Sony Computer Entertainment Inc."); 110313a5e30cSGeoff Levand MODULE_ALIAS(PS3_MODULE_ALIAS_AV_SETTINGS); 1104