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