1 /* 2 * Copyright (C) 2006 Sony Computer Entertainment Inc. 3 * Copyright 2006, 2007 Sony Corporation 4 * 5 * AV backend support for PS3 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published 9 * by the Free Software Foundation; version 2 of the License. 10 * 11 * This program is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21 #include <linux/module.h> 22 #include <linux/delay.h> 23 #include <linux/notifier.h> 24 #include <linux/reboot.h> 25 #include <linux/kernel.h> 26 #include <linux/ioctl.h> 27 28 #include <asm/firmware.h> 29 #include <asm/lv1call.h> 30 #include <asm/ps3av.h> 31 #include <asm/ps3.h> 32 33 #include "vuart.h" 34 35 #define BUFSIZE 4096 /* vuart buf size */ 36 #define PS3AV_BUF_SIZE 512 /* max packet size */ 37 38 static int timeout = 5000; /* in msec ( 5 sec ) */ 39 module_param(timeout, int, 0644); 40 41 static struct ps3av { 42 int available; 43 struct mutex mutex; 44 struct work_struct work; 45 struct completion done; 46 struct workqueue_struct *wq; 47 int open_count; 48 struct ps3_vuart_port_device *dev; 49 50 int region; 51 struct ps3av_pkt_av_get_hw_conf av_hw_conf; 52 u32 av_port[PS3AV_AV_PORT_MAX + PS3AV_OPT_PORT_MAX]; 53 u32 opt_port[PS3AV_OPT_PORT_MAX]; 54 u32 head[PS3AV_HEAD_MAX]; 55 u32 audio_port; 56 int ps3av_mode; 57 int ps3av_mode_old; 58 } ps3av; 59 60 static struct ps3_vuart_port_device ps3av_dev = { 61 .match_id = PS3_MATCH_ID_AV_SETTINGS 62 }; 63 64 /* color space */ 65 #define YUV444 PS3AV_CMD_VIDEO_CS_YUV444_8 66 #define RGB8 PS3AV_CMD_VIDEO_CS_RGB_8 67 /* format */ 68 #define XRGB PS3AV_CMD_VIDEO_FMT_X8R8G8B8 69 /* aspect */ 70 #define A_N PS3AV_CMD_AV_ASPECT_4_3 71 #define A_W PS3AV_CMD_AV_ASPECT_16_9 72 static const struct avset_video_mode { 73 u32 cs; 74 u32 fmt; 75 u32 vid; 76 u32 aspect; 77 u32 x; 78 u32 y; 79 u32 interlace; 80 u32 freq; 81 } video_mode_table[] = { 82 { 0, }, /* auto */ 83 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480, 1, 60}, 84 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480, 0, 60}, 85 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_N, 1280, 720, 0, 60}, 86 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080, 1, 60}, 87 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080, 0, 60}, 88 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576, 1, 50}, 89 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576, 0, 50}, 90 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_N, 1280, 720, 0, 50}, 91 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080, 1, 50}, 92 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080, 0, 50}, 93 { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768, 0, 60}, 94 { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA, A_N, 1280, 1024, 0, 60}, 95 { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA, A_W, 1920, 1200, 0, 60}, 96 }; 97 98 /* supported CIDs */ 99 static u32 cmd_table[] = { 100 /* init */ 101 PS3AV_CID_AV_INIT, 102 PS3AV_CID_AV_FIN, 103 PS3AV_CID_VIDEO_INIT, 104 PS3AV_CID_AUDIO_INIT, 105 106 /* set */ 107 PS3AV_CID_AV_ENABLE_EVENT, 108 PS3AV_CID_AV_DISABLE_EVENT, 109 110 PS3AV_CID_AV_VIDEO_CS, 111 PS3AV_CID_AV_VIDEO_MUTE, 112 PS3AV_CID_AV_VIDEO_DISABLE_SIG, 113 PS3AV_CID_AV_AUDIO_PARAM, 114 PS3AV_CID_AV_AUDIO_MUTE, 115 PS3AV_CID_AV_HDMI_MODE, 116 PS3AV_CID_AV_TV_MUTE, 117 118 PS3AV_CID_VIDEO_MODE, 119 PS3AV_CID_VIDEO_FORMAT, 120 PS3AV_CID_VIDEO_PITCH, 121 122 PS3AV_CID_AUDIO_MODE, 123 PS3AV_CID_AUDIO_MUTE, 124 PS3AV_CID_AUDIO_ACTIVE, 125 PS3AV_CID_AUDIO_INACTIVE, 126 PS3AV_CID_AVB_PARAM, 127 128 /* get */ 129 PS3AV_CID_AV_GET_HW_CONF, 130 PS3AV_CID_AV_GET_MONITOR_INFO, 131 132 /* event */ 133 PS3AV_CID_EVENT_UNPLUGGED, 134 PS3AV_CID_EVENT_PLUGGED, 135 PS3AV_CID_EVENT_HDCP_DONE, 136 PS3AV_CID_EVENT_HDCP_FAIL, 137 PS3AV_CID_EVENT_HDCP_AUTH, 138 PS3AV_CID_EVENT_HDCP_ERROR, 139 140 0 141 }; 142 143 #define PS3AV_EVENT_CMD_MASK 0x10000000 144 #define PS3AV_EVENT_ID_MASK 0x0000ffff 145 #define PS3AV_CID_MASK 0xffffffff 146 #define PS3AV_REPLY_BIT 0x80000000 147 148 #define ps3av_event_get_port_id(cid) ((cid >> 16) & 0xff) 149 150 static u32 *ps3av_search_cmd_table(u32 cid, u32 mask) 151 { 152 u32 *table; 153 int i; 154 155 table = cmd_table; 156 for (i = 0;; table++, i++) { 157 if ((*table & mask) == (cid & mask)) 158 break; 159 if (*table == 0) 160 return NULL; 161 } 162 return table; 163 } 164 165 static int ps3av_parse_event_packet(const struct ps3av_reply_hdr *hdr) 166 { 167 u32 *table; 168 169 if (hdr->cid & PS3AV_EVENT_CMD_MASK) { 170 table = ps3av_search_cmd_table(hdr->cid, PS3AV_EVENT_CMD_MASK); 171 if (table) 172 dev_dbg(&ps3av_dev.core, 173 "recv event packet cid:%08x port:0x%x size:%d\n", 174 hdr->cid, ps3av_event_get_port_id(hdr->cid), 175 hdr->size); 176 else 177 printk(KERN_ERR 178 "%s: failed event packet, cid:%08x size:%d\n", 179 __func__, hdr->cid, hdr->size); 180 return 1; /* receive event packet */ 181 } 182 return 0; 183 } 184 185 static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf, 186 struct ps3av_reply_hdr *recv_buf, int write_len, 187 int read_len) 188 { 189 int res; 190 u32 cmd; 191 int event; 192 193 if (!ps3av.available) 194 return -ENODEV; 195 196 /* send pkt */ 197 res = ps3av_vuart_write(ps3av.dev, send_buf, write_len); 198 if (res < 0) { 199 dev_dbg(&ps3av_dev.core, 200 "%s: ps3av_vuart_write() failed (result=%d)\n", 201 __func__, res); 202 return res; 203 } 204 205 /* recv pkt */ 206 cmd = send_buf->cid; 207 do { 208 /* read header */ 209 res = ps3av_vuart_read(ps3av.dev, recv_buf, PS3AV_HDR_SIZE, 210 timeout); 211 if (res != PS3AV_HDR_SIZE) { 212 dev_dbg(&ps3av_dev.core, 213 "%s: ps3av_vuart_read() failed (result=%d)\n", 214 __func__, res); 215 return res; 216 } 217 218 /* read body */ 219 res = ps3av_vuart_read(ps3av.dev, &recv_buf->cid, 220 recv_buf->size, timeout); 221 if (res < 0) { 222 dev_dbg(&ps3av_dev.core, 223 "%s: ps3av_vuart_read() failed (result=%d)\n", 224 __func__, res); 225 return res; 226 } 227 res += PS3AV_HDR_SIZE; /* total len */ 228 event = ps3av_parse_event_packet(recv_buf); 229 /* ret > 0 event packet */ 230 } while (event); 231 232 if ((cmd | PS3AV_REPLY_BIT) != recv_buf->cid) { 233 dev_dbg(&ps3av_dev.core, "%s: reply err (result=%x)\n", 234 __func__, recv_buf->cid); 235 return -EINVAL; 236 } 237 238 return 0; 239 } 240 241 static int ps3av_process_reply_packet(struct ps3av_send_hdr *cmd_buf, 242 const struct ps3av_reply_hdr *recv_buf, 243 int user_buf_size) 244 { 245 int return_len; 246 247 if (recv_buf->version != PS3AV_VERSION) { 248 dev_dbg(&ps3av_dev.core, "reply_packet invalid version:%x\n", 249 recv_buf->version); 250 return -EFAULT; 251 } 252 return_len = recv_buf->size + PS3AV_HDR_SIZE; 253 if (return_len > user_buf_size) 254 return_len = user_buf_size; 255 memcpy(cmd_buf, recv_buf, return_len); 256 return 0; /* success */ 257 } 258 259 void ps3av_set_hdr(u32 cid, u16 size, struct ps3av_send_hdr *hdr) 260 { 261 hdr->version = PS3AV_VERSION; 262 hdr->size = size - PS3AV_HDR_SIZE; 263 hdr->cid = cid; 264 } 265 266 int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size, 267 struct ps3av_send_hdr *buf) 268 { 269 int res = 0; 270 static union { 271 struct ps3av_reply_hdr reply_hdr; 272 u8 raw[PS3AV_BUF_SIZE]; 273 } recv_buf; 274 275 u32 *table; 276 277 BUG_ON(!ps3av.available); 278 279 mutex_lock(&ps3av.mutex); 280 281 table = ps3av_search_cmd_table(cid, PS3AV_CID_MASK); 282 BUG_ON(!table); 283 BUG_ON(send_len < PS3AV_HDR_SIZE); 284 BUG_ON(usr_buf_size < send_len); 285 BUG_ON(usr_buf_size > PS3AV_BUF_SIZE); 286 287 /* create header */ 288 ps3av_set_hdr(cid, send_len, buf); 289 290 /* send packet via vuart */ 291 res = ps3av_send_cmd_pkt(buf, &recv_buf.reply_hdr, send_len, 292 usr_buf_size); 293 if (res < 0) { 294 printk(KERN_ERR 295 "%s: ps3av_send_cmd_pkt() failed (result=%d)\n", 296 __func__, res); 297 goto err; 298 } 299 300 /* process reply packet */ 301 res = ps3av_process_reply_packet(buf, &recv_buf.reply_hdr, 302 usr_buf_size); 303 if (res < 0) { 304 printk(KERN_ERR "%s: put_return_status() failed (result=%d)\n", 305 __func__, res); 306 goto err; 307 } 308 309 mutex_unlock(&ps3av.mutex); 310 return 0; 311 312 err: 313 mutex_unlock(&ps3av.mutex); 314 printk(KERN_ERR "%s: failed cid:%x res:%d\n", __func__, cid, res); 315 return res; 316 } 317 318 static int ps3av_set_av_video_mute(u32 mute) 319 { 320 int i, num_of_av_port, res; 321 322 num_of_av_port = ps3av.av_hw_conf.num_of_hdmi + 323 ps3av.av_hw_conf.num_of_avmulti; 324 /* video mute on */ 325 for (i = 0; i < num_of_av_port; i++) { 326 res = ps3av_cmd_av_video_mute(1, &ps3av.av_port[i], mute); 327 if (res < 0) 328 return -1; 329 } 330 331 return 0; 332 } 333 334 static int ps3av_set_video_disable_sig(void) 335 { 336 int i, num_of_hdmi_port, num_of_av_port, res; 337 338 num_of_hdmi_port = ps3av.av_hw_conf.num_of_hdmi; 339 num_of_av_port = ps3av.av_hw_conf.num_of_hdmi + 340 ps3av.av_hw_conf.num_of_avmulti; 341 342 /* tv mute */ 343 for (i = 0; i < num_of_hdmi_port; i++) { 344 res = ps3av_cmd_av_tv_mute(ps3av.av_port[i], 345 PS3AV_CMD_MUTE_ON); 346 if (res < 0) 347 return -1; 348 } 349 msleep(100); 350 351 /* video mute on */ 352 for (i = 0; i < num_of_av_port; i++) { 353 res = ps3av_cmd_av_video_disable_sig(ps3av.av_port[i]); 354 if (res < 0) 355 return -1; 356 if (i < num_of_hdmi_port) { 357 res = ps3av_cmd_av_tv_mute(ps3av.av_port[i], 358 PS3AV_CMD_MUTE_OFF); 359 if (res < 0) 360 return -1; 361 } 362 } 363 msleep(300); 364 365 return 0; 366 } 367 368 static int ps3av_set_audio_mute(u32 mute) 369 { 370 int i, num_of_av_port, num_of_opt_port, res; 371 372 num_of_av_port = ps3av.av_hw_conf.num_of_hdmi + 373 ps3av.av_hw_conf.num_of_avmulti; 374 num_of_opt_port = ps3av.av_hw_conf.num_of_spdif; 375 376 for (i = 0; i < num_of_av_port; i++) { 377 res = ps3av_cmd_av_audio_mute(1, &ps3av.av_port[i], mute); 378 if (res < 0) 379 return -1; 380 } 381 for (i = 0; i < num_of_opt_port; i++) { 382 res = ps3av_cmd_audio_mute(1, &ps3av.opt_port[i], mute); 383 if (res < 0) 384 return -1; 385 } 386 387 return 0; 388 } 389 390 int ps3av_set_audio_mode(u32 ch, u32 fs, u32 word_bits, u32 format, u32 source) 391 { 392 struct ps3av_pkt_avb_param avb_param; 393 int i, num_of_audio, vid, res; 394 struct ps3av_pkt_audio_mode audio_mode; 395 u32 len = 0; 396 397 num_of_audio = ps3av.av_hw_conf.num_of_hdmi + 398 ps3av.av_hw_conf.num_of_avmulti + 399 ps3av.av_hw_conf.num_of_spdif; 400 401 avb_param.num_of_video_pkt = 0; 402 avb_param.num_of_audio_pkt = PS3AV_AVB_NUM_AUDIO; /* always 0 */ 403 avb_param.num_of_av_video_pkt = 0; 404 avb_param.num_of_av_audio_pkt = ps3av.av_hw_conf.num_of_hdmi; 405 406 vid = video_mode_table[ps3av.ps3av_mode].vid; 407 408 /* audio mute */ 409 ps3av_set_audio_mute(PS3AV_CMD_MUTE_ON); 410 411 /* audio inactive */ 412 res = ps3av_cmd_audio_active(0, ps3av.audio_port); 413 if (res < 0) 414 dev_dbg(&ps3av_dev.core, 415 "ps3av_cmd_audio_active OFF failed\n"); 416 417 /* audio_pkt */ 418 for (i = 0; i < num_of_audio; i++) { 419 ps3av_cmd_set_audio_mode(&audio_mode, ps3av.av_port[i], ch, fs, 420 word_bits, format, source); 421 if (i < ps3av.av_hw_conf.num_of_hdmi) { 422 /* hdmi only */ 423 len += ps3av_cmd_set_av_audio_param(&avb_param.buf[len], 424 ps3av.av_port[i], 425 &audio_mode, vid); 426 } 427 /* audio_mode pkt should be sent separately */ 428 res = ps3av_cmd_audio_mode(&audio_mode); 429 if (res < 0) 430 dev_dbg(&ps3av_dev.core, 431 "ps3av_cmd_audio_mode failed, port:%x\n", i); 432 } 433 434 /* send command using avb pkt */ 435 len += offsetof(struct ps3av_pkt_avb_param, buf); 436 res = ps3av_cmd_avb_param(&avb_param, len); 437 if (res < 0) 438 dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n"); 439 440 /* audio mute */ 441 ps3av_set_audio_mute(PS3AV_CMD_MUTE_OFF); 442 443 /* audio active */ 444 res = ps3av_cmd_audio_active(1, ps3av.audio_port); 445 if (res < 0) 446 dev_dbg(&ps3av_dev.core, "ps3av_cmd_audio_active ON failed\n"); 447 448 return 0; 449 } 450 451 EXPORT_SYMBOL_GPL(ps3av_set_audio_mode); 452 453 static int ps3av_set_videomode(void) 454 { 455 /* av video mute */ 456 ps3av_set_av_video_mute(PS3AV_CMD_MUTE_ON); 457 458 /* wake up ps3avd to do the actual video mode setting */ 459 queue_work(ps3av.wq, &ps3av.work); 460 461 return 0; 462 } 463 464 static void ps3av_set_videomode_cont(u32 id, u32 old_id) 465 { 466 struct ps3av_pkt_avb_param avb_param; 467 int i; 468 u32 len = 0, av_video_cs; 469 const struct avset_video_mode *video_mode; 470 int res; 471 472 video_mode = &video_mode_table[id & PS3AV_MODE_MASK]; 473 474 avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */ 475 avb_param.num_of_audio_pkt = 0; 476 avb_param.num_of_av_video_pkt = ps3av.av_hw_conf.num_of_hdmi + 477 ps3av.av_hw_conf.num_of_avmulti; 478 avb_param.num_of_av_audio_pkt = 0; 479 480 /* video signal off */ 481 ps3av_set_video_disable_sig(); 482 483 /* Retail PS3 product doesn't support this */ 484 if (id & PS3AV_MODE_HDCP_OFF) { 485 res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF); 486 if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) 487 dev_dbg(&ps3av_dev.core, "Not supported\n"); 488 else if (res) 489 dev_dbg(&ps3av_dev.core, 490 "ps3av_cmd_av_hdmi_mode failed\n"); 491 } else if (old_id & PS3AV_MODE_HDCP_OFF) { 492 res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL); 493 if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) 494 dev_dbg(&ps3av_dev.core, 495 "ps3av_cmd_av_hdmi_mode failed\n"); 496 } 497 498 /* video_pkt */ 499 for (i = 0; i < avb_param.num_of_video_pkt; i++) 500 len += ps3av_cmd_set_video_mode(&avb_param.buf[len], 501 ps3av.head[i], video_mode->vid, 502 video_mode->fmt, id); 503 /* av_video_pkt */ 504 for (i = 0; i < avb_param.num_of_av_video_pkt; i++) { 505 if (id & PS3AV_MODE_DVI || id & PS3AV_MODE_RGB) 506 av_video_cs = RGB8; 507 else 508 av_video_cs = video_mode->cs; 509 #ifndef PS3AV_HDMI_YUV 510 if (ps3av.av_port[i] == PS3AV_CMD_AVPORT_HDMI_0 || 511 ps3av.av_port[i] == PS3AV_CMD_AVPORT_HDMI_1) 512 av_video_cs = RGB8; /* use RGB for HDMI */ 513 #endif 514 len += ps3av_cmd_set_av_video_cs(&avb_param.buf[len], 515 ps3av.av_port[i], 516 video_mode->vid, av_video_cs, 517 video_mode->aspect, id); 518 } 519 /* send command using avb pkt */ 520 len += offsetof(struct ps3av_pkt_avb_param, buf); 521 res = ps3av_cmd_avb_param(&avb_param, len); 522 if (res == PS3AV_STATUS_NO_SYNC_HEAD) 523 printk(KERN_WARNING 524 "%s: Command failed. Please try your request again. \n", 525 __func__); 526 else if (res) 527 dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n"); 528 529 msleep(1500); 530 /* av video mute */ 531 ps3av_set_av_video_mute(PS3AV_CMD_MUTE_OFF); 532 } 533 534 static void ps3avd(struct work_struct *work) 535 { 536 ps3av_set_videomode_cont(ps3av.ps3av_mode, ps3av.ps3av_mode_old); 537 complete(&ps3av.done); 538 } 539 540 static int ps3av_vid2table_id(int vid) 541 { 542 int i; 543 544 for (i = 1; i < ARRAY_SIZE(video_mode_table); i++) 545 if (video_mode_table[i].vid == vid) 546 return i; 547 return -1; 548 } 549 550 static int ps3av_resbit2vid(u32 res_50, u32 res_60) 551 { 552 int vid = -1; 553 554 if (res_50 > res_60) { /* if res_50 == res_60, res_60 will be used */ 555 if (res_50 & PS3AV_RESBIT_1920x1080P) 556 vid = PS3AV_CMD_VIDEO_VID_1080P_50HZ; 557 else if (res_50 & PS3AV_RESBIT_1920x1080I) 558 vid = PS3AV_CMD_VIDEO_VID_1080I_50HZ; 559 else if (res_50 & PS3AV_RESBIT_1280x720P) 560 vid = PS3AV_CMD_VIDEO_VID_720P_50HZ; 561 else if (res_50 & PS3AV_RESBIT_720x576P) 562 vid = PS3AV_CMD_VIDEO_VID_576P; 563 else 564 vid = -1; 565 } else { 566 if (res_60 & PS3AV_RESBIT_1920x1080P) 567 vid = PS3AV_CMD_VIDEO_VID_1080P_60HZ; 568 else if (res_60 & PS3AV_RESBIT_1920x1080I) 569 vid = PS3AV_CMD_VIDEO_VID_1080I_60HZ; 570 else if (res_60 & PS3AV_RESBIT_1280x720P) 571 vid = PS3AV_CMD_VIDEO_VID_720P_60HZ; 572 else if (res_60 & PS3AV_RESBIT_720x480P) 573 vid = PS3AV_CMD_VIDEO_VID_480P; 574 else 575 vid = -1; 576 } 577 return vid; 578 } 579 580 static int ps3av_hdmi_get_vid(struct ps3av_info_monitor *info) 581 { 582 u32 res_50, res_60; 583 int vid = -1; 584 585 if (info->monitor_type != PS3AV_MONITOR_TYPE_HDMI) 586 return -1; 587 588 /* check native resolution */ 589 res_50 = info->res_50.native & PS3AV_RES_MASK_50; 590 res_60 = info->res_60.native & PS3AV_RES_MASK_60; 591 if (res_50 || res_60) { 592 vid = ps3av_resbit2vid(res_50, res_60); 593 return vid; 594 } 595 596 /* check resolution */ 597 res_50 = info->res_50.res_bits & PS3AV_RES_MASK_50; 598 res_60 = info->res_60.res_bits & PS3AV_RES_MASK_60; 599 if (res_50 || res_60) { 600 vid = ps3av_resbit2vid(res_50, res_60); 601 return vid; 602 } 603 604 if (ps3av.region & PS3AV_REGION_60) 605 vid = PS3AV_DEFAULT_HDMI_VID_REG_60; 606 else 607 vid = PS3AV_DEFAULT_HDMI_VID_REG_50; 608 return vid; 609 } 610 611 static int ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf, 612 int boot) 613 { 614 int i, res, vid = -1, dvi = 0, rgb = 0; 615 struct ps3av_pkt_av_get_monitor_info monitor_info; 616 struct ps3av_info_monitor *info; 617 618 /* get vid for hdmi */ 619 for (i = 0; i < av_hw_conf->num_of_hdmi; i++) { 620 res = ps3av_cmd_video_get_monitor_info(&monitor_info, 621 PS3AV_CMD_AVPORT_HDMI_0 + 622 i); 623 if (res < 0) 624 return -1; 625 626 ps3av_cmd_av_monitor_info_dump(&monitor_info); 627 info = &monitor_info.info; 628 /* check DVI */ 629 if (info->monitor_type == PS3AV_MONITOR_TYPE_DVI) { 630 dvi = PS3AV_MODE_DVI; 631 break; 632 } 633 /* check HDMI */ 634 vid = ps3av_hdmi_get_vid(info); 635 if (vid != -1) { 636 /* got valid vid */ 637 break; 638 } 639 } 640 641 if (dvi) { 642 /* DVI mode */ 643 vid = PS3AV_DEFAULT_DVI_VID; 644 } else if (vid == -1) { 645 /* no HDMI interface or HDMI is off */ 646 if (ps3av.region & PS3AV_REGION_60) 647 vid = PS3AV_DEFAULT_AVMULTI_VID_REG_60; 648 else 649 vid = PS3AV_DEFAULT_AVMULTI_VID_REG_50; 650 if (ps3av.region & PS3AV_REGION_RGB) 651 rgb = PS3AV_MODE_RGB; 652 } else if (boot) { 653 /* HDMI: using DEFAULT HDMI_VID while booting up */ 654 info = &monitor_info.info; 655 if (ps3av.region & PS3AV_REGION_60) { 656 if (info->res_60.res_bits & PS3AV_RESBIT_720x480P) 657 vid = PS3AV_DEFAULT_HDMI_VID_REG_60; 658 else if (info->res_50.res_bits & PS3AV_RESBIT_720x576P) 659 vid = PS3AV_DEFAULT_HDMI_VID_REG_50; 660 else { 661 /* default */ 662 vid = PS3AV_DEFAULT_HDMI_VID_REG_60; 663 } 664 } else { 665 if (info->res_50.res_bits & PS3AV_RESBIT_720x576P) 666 vid = PS3AV_DEFAULT_HDMI_VID_REG_50; 667 else if (info->res_60.res_bits & PS3AV_RESBIT_720x480P) 668 vid = PS3AV_DEFAULT_HDMI_VID_REG_60; 669 else { 670 /* default */ 671 vid = PS3AV_DEFAULT_HDMI_VID_REG_50; 672 } 673 } 674 } 675 676 return (ps3av_vid2table_id(vid) | dvi | rgb); 677 } 678 679 static int ps3av_get_hw_conf(struct ps3av *ps3av) 680 { 681 int i, j, k, res; 682 683 /* get av_hw_conf */ 684 res = ps3av_cmd_av_get_hw_conf(&ps3av->av_hw_conf); 685 if (res < 0) 686 return -1; 687 688 ps3av_cmd_av_hw_conf_dump(&ps3av->av_hw_conf); 689 690 for (i = 0; i < PS3AV_HEAD_MAX; i++) 691 ps3av->head[i] = PS3AV_CMD_VIDEO_HEAD_A + i; 692 for (i = 0; i < PS3AV_OPT_PORT_MAX; i++) 693 ps3av->opt_port[i] = PS3AV_CMD_AVPORT_SPDIF_0 + i; 694 for (i = 0; i < ps3av->av_hw_conf.num_of_hdmi; i++) 695 ps3av->av_port[i] = PS3AV_CMD_AVPORT_HDMI_0 + i; 696 for (j = 0; j < ps3av->av_hw_conf.num_of_avmulti; j++) 697 ps3av->av_port[i + j] = PS3AV_CMD_AVPORT_AVMULTI_0 + j; 698 for (k = 0; k < ps3av->av_hw_conf.num_of_spdif; k++) 699 ps3av->av_port[i + j + k] = PS3AV_CMD_AVPORT_SPDIF_0 + k; 700 701 /* set all audio port */ 702 ps3av->audio_port = PS3AV_CMD_AUDIO_PORT_HDMI_0 703 | PS3AV_CMD_AUDIO_PORT_HDMI_1 704 | PS3AV_CMD_AUDIO_PORT_AVMULTI_0 705 | PS3AV_CMD_AUDIO_PORT_SPDIF_0 | PS3AV_CMD_AUDIO_PORT_SPDIF_1; 706 707 return 0; 708 } 709 710 /* set mode using id */ 711 int ps3av_set_video_mode(u32 id, int boot) 712 { 713 int size; 714 u32 option; 715 716 size = ARRAY_SIZE(video_mode_table); 717 if ((id & PS3AV_MODE_MASK) > size - 1 || id < 0) { 718 dev_dbg(&ps3av_dev.core, "%s: error id :%d\n", __func__, id); 719 return -EINVAL; 720 } 721 722 /* auto mode */ 723 option = id & ~PS3AV_MODE_MASK; 724 if ((id & PS3AV_MODE_MASK) == 0) { 725 id = ps3av_auto_videomode(&ps3av.av_hw_conf, boot); 726 if (id < 1) { 727 printk(KERN_ERR "%s: invalid id :%d\n", __func__, id); 728 return -EINVAL; 729 } 730 id |= option; 731 } 732 733 /* set videomode */ 734 wait_for_completion(&ps3av.done); 735 ps3av.ps3av_mode_old = ps3av.ps3av_mode; 736 ps3av.ps3av_mode = id; 737 if (ps3av_set_videomode()) 738 ps3av.ps3av_mode = ps3av.ps3av_mode_old; 739 740 return 0; 741 } 742 743 EXPORT_SYMBOL_GPL(ps3av_set_video_mode); 744 745 int ps3av_get_auto_mode(int boot) 746 { 747 return ps3av_auto_videomode(&ps3av.av_hw_conf, boot); 748 } 749 750 EXPORT_SYMBOL_GPL(ps3av_get_auto_mode); 751 752 int ps3av_set_mode(u32 id, int boot) 753 { 754 int res; 755 756 res = ps3av_set_video_mode(id, boot); 757 if (res) 758 return res; 759 760 res = ps3av_set_audio_mode(PS3AV_CMD_AUDIO_NUM_OF_CH_2, 761 PS3AV_CMD_AUDIO_FS_48K, 762 PS3AV_CMD_AUDIO_WORD_BITS_16, 763 PS3AV_CMD_AUDIO_FORMAT_PCM, 764 PS3AV_CMD_AUDIO_SOURCE_SERIAL); 765 if (res) 766 return res; 767 768 return 0; 769 } 770 771 EXPORT_SYMBOL_GPL(ps3av_set_mode); 772 773 int ps3av_get_mode(void) 774 { 775 return ps3av.ps3av_mode; 776 } 777 778 EXPORT_SYMBOL_GPL(ps3av_get_mode); 779 780 int ps3av_get_scanmode(int id) 781 { 782 int size; 783 784 id = id & PS3AV_MODE_MASK; 785 size = ARRAY_SIZE(video_mode_table); 786 if (id > size - 1 || id < 0) { 787 printk(KERN_ERR "%s: invalid mode %d\n", __func__, id); 788 return -EINVAL; 789 } 790 return video_mode_table[id].interlace; 791 } 792 793 EXPORT_SYMBOL_GPL(ps3av_get_scanmode); 794 795 int ps3av_get_refresh_rate(int id) 796 { 797 int size; 798 799 id = id & PS3AV_MODE_MASK; 800 size = ARRAY_SIZE(video_mode_table); 801 if (id > size - 1 || id < 0) { 802 printk(KERN_ERR "%s: invalid mode %d\n", __func__, id); 803 return -EINVAL; 804 } 805 return video_mode_table[id].freq; 806 } 807 808 EXPORT_SYMBOL_GPL(ps3av_get_refresh_rate); 809 810 /* get resolution by video_mode */ 811 int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres) 812 { 813 int size; 814 815 id = id & PS3AV_MODE_MASK; 816 size = ARRAY_SIZE(video_mode_table); 817 if (id > size - 1 || id < 0) { 818 printk(KERN_ERR "%s: invalid mode %d\n", __func__, id); 819 return -EINVAL; 820 } 821 *xres = video_mode_table[id].x; 822 *yres = video_mode_table[id].y; 823 return 0; 824 } 825 826 EXPORT_SYMBOL_GPL(ps3av_video_mode2res); 827 828 /* mute */ 829 int ps3av_video_mute(int mute) 830 { 831 return ps3av_set_av_video_mute(mute ? PS3AV_CMD_MUTE_ON 832 : PS3AV_CMD_MUTE_OFF); 833 } 834 835 EXPORT_SYMBOL_GPL(ps3av_video_mute); 836 837 int ps3av_audio_mute(int mute) 838 { 839 return ps3av_set_audio_mute(mute ? PS3AV_CMD_MUTE_ON 840 : PS3AV_CMD_MUTE_OFF); 841 } 842 843 EXPORT_SYMBOL_GPL(ps3av_audio_mute); 844 845 int ps3av_dev_open(void) 846 { 847 int status = 0; 848 849 mutex_lock(&ps3av.mutex); 850 if (!ps3av.open_count++) { 851 status = lv1_gpu_open(0); 852 if (status) { 853 printk(KERN_ERR "%s: lv1_gpu_open failed %d\n", 854 __func__, status); 855 ps3av.open_count--; 856 } 857 } 858 mutex_unlock(&ps3av.mutex); 859 860 return status; 861 } 862 863 EXPORT_SYMBOL_GPL(ps3av_dev_open); 864 865 int ps3av_dev_close(void) 866 { 867 int status = 0; 868 869 mutex_lock(&ps3av.mutex); 870 if (ps3av.open_count <= 0) { 871 printk(KERN_ERR "%s: GPU already closed\n", __func__); 872 status = -1; 873 } else if (!--ps3av.open_count) { 874 status = lv1_gpu_close(); 875 if (status) 876 printk(KERN_WARNING "%s: lv1_gpu_close failed %d\n", 877 __func__, status); 878 } 879 mutex_unlock(&ps3av.mutex); 880 881 return status; 882 } 883 884 EXPORT_SYMBOL_GPL(ps3av_dev_close); 885 886 static int ps3av_probe(struct ps3_vuart_port_device *dev) 887 { 888 int res; 889 u32 id; 890 891 dev_dbg(&ps3av_dev.core, "init ...\n"); 892 dev_dbg(&ps3av_dev.core, " timeout=%d\n", timeout); 893 894 memset(&ps3av, 0, sizeof(ps3av)); 895 896 mutex_init(&ps3av.mutex); 897 ps3av.ps3av_mode = 0; 898 ps3av.dev = dev; 899 900 INIT_WORK(&ps3av.work, ps3avd); 901 init_completion(&ps3av.done); 902 complete(&ps3av.done); 903 ps3av.wq = create_singlethread_workqueue("ps3avd"); 904 if (!ps3av.wq) 905 return -ENOMEM; 906 907 ps3av.available = 1; 908 switch (ps3_os_area_get_av_multi_out()) { 909 case PS3_PARAM_AV_MULTI_OUT_NTSC: 910 ps3av.region = PS3AV_REGION_60; 911 break; 912 case PS3_PARAM_AV_MULTI_OUT_PAL_YCBCR: 913 case PS3_PARAM_AV_MULTI_OUT_SECAM: 914 ps3av.region = PS3AV_REGION_50; 915 break; 916 case PS3_PARAM_AV_MULTI_OUT_PAL_RGB: 917 ps3av.region = PS3AV_REGION_50 | PS3AV_REGION_RGB; 918 break; 919 default: 920 ps3av.region = PS3AV_REGION_60; 921 break; 922 } 923 924 /* init avsetting modules */ 925 res = ps3av_cmd_init(); 926 if (res < 0) 927 printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __func__, 928 res); 929 930 ps3av_get_hw_conf(&ps3av); 931 id = ps3av_auto_videomode(&ps3av.av_hw_conf, 1); 932 mutex_lock(&ps3av.mutex); 933 ps3av.ps3av_mode = id; 934 mutex_unlock(&ps3av.mutex); 935 936 dev_dbg(&ps3av_dev.core, "init...done\n"); 937 938 return 0; 939 } 940 941 static int ps3av_remove(struct ps3_vuart_port_device *dev) 942 { 943 if (ps3av.available) { 944 ps3av_cmd_fin(); 945 if (ps3av.wq) 946 destroy_workqueue(ps3av.wq); 947 ps3av.available = 0; 948 } 949 950 return 0; 951 } 952 953 static void ps3av_shutdown(struct ps3_vuart_port_device *dev) 954 { 955 ps3av_remove(dev); 956 } 957 958 static struct ps3_vuart_port_driver ps3av_driver = { 959 .match_id = PS3_MATCH_ID_AV_SETTINGS, 960 .core = { 961 .name = "ps3_av", 962 }, 963 .probe = ps3av_probe, 964 .remove = ps3av_remove, 965 .shutdown = ps3av_shutdown, 966 }; 967 968 static int ps3av_module_init(void) 969 { 970 int error; 971 972 if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) 973 return -ENODEV; 974 975 error = ps3_vuart_port_driver_register(&ps3av_driver); 976 if (error) { 977 printk(KERN_ERR 978 "%s: ps3_vuart_port_driver_register failed %d\n", 979 __func__, error); 980 return error; 981 } 982 983 error = ps3_vuart_port_device_register(&ps3av_dev); 984 if (error) 985 printk(KERN_ERR 986 "%s: ps3_vuart_port_device_register failed %d\n", 987 __func__, error); 988 989 return error; 990 } 991 992 static void __exit ps3av_module_exit(void) 993 { 994 device_unregister(&ps3av_dev.core); 995 ps3_vuart_port_driver_unregister(&ps3av_driver); 996 } 997 998 subsys_initcall(ps3av_module_init); 999 module_exit(ps3av_module_exit); 1000