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