aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorGeert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>2007-02-12 03:55:16 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-12 12:48:44 -0500
commit11227fd1922dc5dda691586852cfd220dd383f37 (patch)
treee6631b1e5be83876bbe2c6e5cea3a427ce61a3fa /drivers
parent5b8e8ee6c65a34d8aafaeb8e2eaa97e496c2567c (diff)
[PATCH] ps3: AV Settings Driver
Add the PS3 AV Settings Driver. The AV Settings driver is used to control Audio and Video settings. It communicates with the policy manager through the virtual uart. Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com> Cc: James Simmons <jsimmons@infradead.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ps3/Makefile1
-rw-r--r--drivers/ps3/ps3av.c974
-rw-r--r--drivers/ps3/ps3av_cmd.c1017
3 files changed, 1992 insertions, 0 deletions
diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile
index d547cf50ca9d..96958c03cf61 100644
--- a/drivers/ps3/Makefile
+++ b/drivers/ps3/Makefile
@@ -1 +1,2 @@
1obj-$(CONFIG_PS3_VUART) += vuart.o 1obj-$(CONFIG_PS3_VUART) += vuart.o
2obj-$(CONFIG_PS3_PS3AV) += ps3av.o ps3av_cmd.o
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
new file mode 100644
index 000000000000..1926b4d3e1f4
--- /dev/null
+++ b/drivers/ps3/ps3av.c
@@ -0,0 +1,974 @@
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#include <asm/lv1call.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
36static int timeout = 5000; /* in msec ( 5 sec ) */
37module_param(timeout, int, 0644);
38
39static struct ps3av ps3av;
40
41static struct ps3_vuart_port_device ps3av_dev = {
42 .match_id = PS3_MATCH_ID_AV_SETTINGS
43};
44
45/* color space */
46#define YUV444 PS3AV_CMD_VIDEO_CS_YUV444_8
47#define RGB8 PS3AV_CMD_VIDEO_CS_RGB_8
48/* format */
49#define XRGB PS3AV_CMD_VIDEO_FMT_X8R8G8B8
50/* aspect */
51#define A_N PS3AV_CMD_AV_ASPECT_4_3
52#define A_W PS3AV_CMD_AV_ASPECT_16_9
53static const struct avset_video_mode {
54 u32 cs;
55 u32 fmt;
56 u32 vid;
57 u32 aspect;
58 u32 x;
59 u32 y;
60 u32 interlace;
61 u32 freq;
62} video_mode_table[] = {
63 { 0, }, /* auto */
64 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480, 1, 60},
65 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480, 0, 60},
66 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_N, 1280, 720, 0, 60},
67 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080, 1, 60},
68 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080, 0, 60},
69 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576, 1, 50},
70 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576, 0, 50},
71 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_N, 1280, 720, 0, 50},
72 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080, 1, 50},
73 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080, 0, 50},
74 { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768, 0, 60},
75 { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA, A_N, 1280, 1024, 0, 60},
76 { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA, A_W, 1920, 1200, 0, 60},
77};
78
79/* supported CIDs */
80static u32 cmd_table[] = {
81 /* init */
82 PS3AV_CID_AV_INIT,
83 PS3AV_CID_AV_FIN,
84 PS3AV_CID_VIDEO_INIT,
85 PS3AV_CID_AUDIO_INIT,
86
87 /* set */
88 PS3AV_CID_AV_ENABLE_EVENT,
89 PS3AV_CID_AV_DISABLE_EVENT,
90
91 PS3AV_CID_AV_VIDEO_CS,
92 PS3AV_CID_AV_VIDEO_MUTE,
93 PS3AV_CID_AV_VIDEO_DISABLE_SIG,
94 PS3AV_CID_AV_AUDIO_PARAM,
95 PS3AV_CID_AV_AUDIO_MUTE,
96 PS3AV_CID_AV_HDMI_MODE,
97 PS3AV_CID_AV_TV_MUTE,
98
99 PS3AV_CID_VIDEO_MODE,
100 PS3AV_CID_VIDEO_FORMAT,
101 PS3AV_CID_VIDEO_PITCH,
102
103 PS3AV_CID_AUDIO_MODE,
104 PS3AV_CID_AUDIO_MUTE,
105 PS3AV_CID_AUDIO_ACTIVE,
106 PS3AV_CID_AUDIO_INACTIVE,
107 PS3AV_CID_AVB_PARAM,
108
109 /* get */
110 PS3AV_CID_AV_GET_HW_CONF,
111 PS3AV_CID_AV_GET_MONITOR_INFO,
112
113 /* event */
114 PS3AV_CID_EVENT_UNPLUGGED,
115 PS3AV_CID_EVENT_PLUGGED,
116 PS3AV_CID_EVENT_HDCP_DONE,
117 PS3AV_CID_EVENT_HDCP_FAIL,
118 PS3AV_CID_EVENT_HDCP_AUTH,
119 PS3AV_CID_EVENT_HDCP_ERROR,
120
121 0
122};
123
124#define PS3AV_EVENT_CMD_MASK 0x10000000
125#define PS3AV_EVENT_ID_MASK 0x0000ffff
126#define PS3AV_CID_MASK 0xffffffff
127#define PS3AV_REPLY_BIT 0x80000000
128
129#define ps3av_event_get_port_id(cid) ((cid >> 16) & 0xff)
130
131static u32 *ps3av_search_cmd_table(u32 cid, u32 mask)
132{
133 u32 *table;
134 int i;
135
136 table = cmd_table;
137 for (i = 0;; table++, i++) {
138 if ((*table & mask) == (cid & mask))
139 break;
140 if (*table == 0)
141 return NULL;
142 }
143 return table;
144}
145
146static int ps3av_parse_event_packet(const struct ps3av_reply_hdr *hdr)
147{
148 u32 *table;
149
150 if (hdr->cid & PS3AV_EVENT_CMD_MASK) {
151 table = ps3av_search_cmd_table(hdr->cid, PS3AV_EVENT_CMD_MASK);
152 if (table)
153 dev_dbg(&ps3av_dev.core,
154 "recv event packet cid:%08x port:0x%x size:%d\n",
155 hdr->cid, ps3av_event_get_port_id(hdr->cid),
156 hdr->size);
157 else
158 printk(KERN_ERR
159 "%s: failed event packet, cid:%08x size:%d\n",
160 __FUNCTION__, hdr->cid, hdr->size);
161 return 1; /* receive event packet */
162 }
163 return 0;
164}
165
166static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
167 struct ps3av_reply_hdr *recv_buf, int write_len,
168 int read_len)
169{
170 int res;
171 u32 cmd;
172 int event;
173
174 if (!ps3av.available)
175 return -ENODEV;
176
177 /* send pkt */
178 res = ps3av_vuart_write(ps3av.dev, send_buf, write_len);
179 if (res < 0) {
180 dev_dbg(&ps3av_dev.core,
181 "%s: ps3av_vuart_write() failed (result=%d)\n",
182 __FUNCTION__, res);
183 return res;
184 }
185
186 /* recv pkt */
187 cmd = send_buf->cid;
188 do {
189 /* read header */
190 res = ps3av_vuart_read(ps3av.dev, recv_buf, PS3AV_HDR_SIZE,
191 timeout);
192 if (res != PS3AV_HDR_SIZE) {
193 dev_dbg(&ps3av_dev.core,
194 "%s: ps3av_vuart_read() failed (result=%d)\n",
195 __FUNCTION__, res);
196 return res;
197 }
198
199 /* read body */
200 res = ps3av_vuart_read(ps3av.dev, &recv_buf->cid,
201 recv_buf->size, timeout);
202 if (res < 0) {
203 dev_dbg(&ps3av_dev.core,
204 "%s: ps3av_vuart_read() failed (result=%d)\n",
205 __FUNCTION__, res);
206 return res;
207 }
208 res += PS3AV_HDR_SIZE; /* total len */
209 event = ps3av_parse_event_packet(recv_buf);
210 /* ret > 0 event packet */
211 } while (event);
212
213 if ((cmd | PS3AV_REPLY_BIT) != recv_buf->cid) {
214 dev_dbg(&ps3av_dev.core, "%s: reply err (result=%x)\n",
215 __FUNCTION__, recv_buf->cid);
216 return -EINVAL;
217 }
218
219 return 0;
220}
221
222static int ps3av_process_reply_packet(struct ps3av_send_hdr *cmd_buf,
223 const struct ps3av_reply_hdr *recv_buf,
224 int user_buf_size)
225{
226 int return_len;
227
228 if (recv_buf->version != PS3AV_VERSION) {
229 dev_dbg(&ps3av_dev.core, "reply_packet invalid version:%x\n",
230 recv_buf->version);
231 return -EFAULT;
232 }
233 return_len = recv_buf->size + PS3AV_HDR_SIZE;
234 if (return_len > user_buf_size)
235 return_len = user_buf_size;
236 memcpy(cmd_buf, recv_buf, return_len);
237 return 0; /* success */
238}
239
240void ps3av_set_hdr(u32 cid, u16 size, struct ps3av_send_hdr *hdr)
241{
242 hdr->version = PS3AV_VERSION;
243 hdr->size = size - PS3AV_HDR_SIZE;
244 hdr->cid = cid;
245}
246
247int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
248 struct ps3av_send_hdr *buf)
249{
250 int res = 0;
251 union {
252 struct ps3av_reply_hdr reply_hdr;
253 u8 raw[PS3AV_BUF_SIZE];
254 } recv_buf;
255
256 u32 *table;
257
258 BUG_ON(!ps3av.available);
259
260 if (down_interruptible(&ps3av.sem))
261 return -ERESTARTSYS;
262
263 table = ps3av_search_cmd_table(cid, PS3AV_CID_MASK);
264 BUG_ON(!table);
265 BUG_ON(send_len < PS3AV_HDR_SIZE);
266 BUG_ON(usr_buf_size < send_len);
267 BUG_ON(usr_buf_size > PS3AV_BUF_SIZE);
268
269 /* create header */
270 ps3av_set_hdr(cid, send_len, buf);
271
272 /* send packet via vuart */
273 res = ps3av_send_cmd_pkt(buf, &recv_buf.reply_hdr, send_len,
274 usr_buf_size);
275 if (res < 0) {
276 printk(KERN_ERR
277 "%s: ps3av_send_cmd_pkt() failed (result=%d)\n",
278 __FUNCTION__, res);
279 goto err;
280 }
281
282 /* process reply packet */
283 res = ps3av_process_reply_packet(buf, &recv_buf.reply_hdr,
284 usr_buf_size);
285 if (res < 0) {
286 printk(KERN_ERR "%s: put_return_status() failed (result=%d)\n",
287 __FUNCTION__, res);
288 goto err;
289 }
290
291 up(&ps3av.sem);
292 return 0;
293
294 err:
295 up(&ps3av.sem);
296 printk(KERN_ERR "%s: failed cid:%x res:%d\n", __FUNCTION__, cid, res);
297 return res;
298}
299
300static int ps3av_set_av_video_mute(u32 mute)
301{
302 int i, num_of_av_port, res;
303
304 num_of_av_port = ps3av.av_hw_conf.num_of_hdmi +
305 ps3av.av_hw_conf.num_of_avmulti;
306 /* video mute on */
307 for (i = 0; i < num_of_av_port; i++) {
308 res = ps3av_cmd_av_video_mute(1, &ps3av.av_port[i], mute);
309 if (res < 0)
310 return -1;
311 }
312
313 return 0;
314}
315
316static int ps3av_set_video_disable_sig(void)
317{
318 int i, num_of_hdmi_port, num_of_av_port, res;
319
320 num_of_hdmi_port = ps3av.av_hw_conf.num_of_hdmi;
321 num_of_av_port = ps3av.av_hw_conf.num_of_hdmi +
322 ps3av.av_hw_conf.num_of_avmulti;
323
324 /* tv mute */
325 for (i = 0; i < num_of_hdmi_port; i++) {
326 res = ps3av_cmd_av_tv_mute(ps3av.av_port[i],
327 PS3AV_CMD_MUTE_ON);
328 if (res < 0)
329 return -1;
330 }
331 msleep(100);
332
333 /* video mute on */
334 for (i = 0; i < num_of_av_port; i++) {
335 res = ps3av_cmd_av_video_disable_sig(ps3av.av_port[i]);
336 if (res < 0)
337 return -1;
338 if (i < num_of_hdmi_port) {
339 res = ps3av_cmd_av_tv_mute(ps3av.av_port[i],
340 PS3AV_CMD_MUTE_OFF);
341 if (res < 0)
342 return -1;
343 }
344 }
345 msleep(300);
346
347 return 0;
348}
349
350static int ps3av_set_audio_mute(u32 mute)
351{
352 int i, num_of_av_port, num_of_opt_port, res;
353
354 num_of_av_port = ps3av.av_hw_conf.num_of_hdmi +
355 ps3av.av_hw_conf.num_of_avmulti;
356 num_of_opt_port = ps3av.av_hw_conf.num_of_spdif;
357
358 for (i = 0; i < num_of_av_port; i++) {
359 res = ps3av_cmd_av_audio_mute(1, &ps3av.av_port[i], mute);
360 if (res < 0)
361 return -1;
362 }
363 for (i = 0; i < num_of_opt_port; i++) {
364 res = ps3av_cmd_audio_mute(1, &ps3av.opt_port[i], mute);
365 if (res < 0)
366 return -1;
367 }
368
369 return 0;
370}
371
372int ps3av_set_audio_mode(u32 ch, u32 fs, u32 word_bits, u32 format, u32 source)
373{
374 struct ps3av_pkt_avb_param avb_param;
375 int i, num_of_audio, vid, res;
376 struct ps3av_pkt_audio_mode audio_mode;
377 u32 len = 0;
378
379 num_of_audio = ps3av.av_hw_conf.num_of_hdmi +
380 ps3av.av_hw_conf.num_of_avmulti +
381 ps3av.av_hw_conf.num_of_spdif;
382
383 avb_param.num_of_video_pkt = 0;
384 avb_param.num_of_audio_pkt = PS3AV_AVB_NUM_AUDIO; /* always 0 */
385 avb_param.num_of_av_video_pkt = 0;
386 avb_param.num_of_av_audio_pkt = ps3av.av_hw_conf.num_of_hdmi;
387
388 vid = video_mode_table[ps3av.ps3av_mode].vid;
389
390 /* audio mute */
391 ps3av_set_audio_mute(PS3AV_CMD_MUTE_ON);
392
393 /* audio inactive */
394 res = ps3av_cmd_audio_active(0, ps3av.audio_port);
395 if (res < 0)
396 dev_dbg(&ps3av_dev.core,
397 "ps3av_cmd_audio_active OFF failed\n");
398
399 /* audio_pkt */
400 for (i = 0; i < num_of_audio; i++) {
401 ps3av_cmd_set_audio_mode(&audio_mode, ps3av.av_port[i], ch, fs,
402 word_bits, format, source);
403 if (i < ps3av.av_hw_conf.num_of_hdmi) {
404 /* hdmi only */
405 len += ps3av_cmd_set_av_audio_param(&avb_param.buf[len],
406 ps3av.av_port[i],
407 &audio_mode, vid);
408 }
409 /* audio_mode pkt should be sent separately */
410 res = ps3av_cmd_audio_mode(&audio_mode);
411 if (res < 0)
412 dev_dbg(&ps3av_dev.core,
413 "ps3av_cmd_audio_mode failed, port:%x\n", i);
414 }
415
416 /* send command using avb pkt */
417 len += offsetof(struct ps3av_pkt_avb_param, buf);
418 res = ps3av_cmd_avb_param(&avb_param, len);
419 if (res < 0)
420 dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n");
421
422 /* audio mute */
423 ps3av_set_audio_mute(PS3AV_CMD_MUTE_OFF);
424
425 /* audio active */
426 res = ps3av_cmd_audio_active(1, ps3av.audio_port);
427 if (res < 0)
428 dev_dbg(&ps3av_dev.core, "ps3av_cmd_audio_active ON failed\n");
429
430 return 0;
431}
432
433EXPORT_SYMBOL_GPL(ps3av_set_audio_mode);
434
435static int ps3av_set_videomode(void)
436{
437 /* av video mute */
438 ps3av_set_av_video_mute(PS3AV_CMD_MUTE_ON);
439
440 /* wake up ps3avd to do the actual video mode setting */
441 up(&ps3av.ping);
442
443 return 0;
444}
445
446static void ps3av_set_videomode_cont(u32 id, u32 old_id)
447{
448 struct ps3av_pkt_avb_param avb_param;
449 int i;
450 u32 len = 0, av_video_cs;
451 const struct avset_video_mode *video_mode;
452 int res;
453
454 video_mode = &video_mode_table[id & PS3AV_MODE_MASK];
455
456 avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */
457 avb_param.num_of_audio_pkt = 0;
458 avb_param.num_of_av_video_pkt = ps3av.av_hw_conf.num_of_hdmi +
459 ps3av.av_hw_conf.num_of_avmulti;
460 avb_param.num_of_av_audio_pkt = 0;
461
462 /* video signal off */
463 ps3av_set_video_disable_sig();
464
465 /* Retail PS3 product doesn't support this */
466 if (id & PS3AV_MODE_HDCP_OFF) {
467 res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF);
468 if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE)
469 dev_dbg(&ps3av_dev.core, "Not supported\n");
470 else if (res)
471 dev_dbg(&ps3av_dev.core,
472 "ps3av_cmd_av_hdmi_mode failed\n");
473 } else if (old_id & PS3AV_MODE_HDCP_OFF) {
474 res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL);
475 if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE)
476 dev_dbg(&ps3av_dev.core,
477 "ps3av_cmd_av_hdmi_mode failed\n");
478 }
479
480 /* video_pkt */
481 for (i = 0; i < avb_param.num_of_video_pkt; i++)
482 len += ps3av_cmd_set_video_mode(&avb_param.buf[len],
483 ps3av.head[i], video_mode->vid,
484 video_mode->fmt, id);
485 /* av_video_pkt */
486 for (i = 0; i < avb_param.num_of_av_video_pkt; i++) {
487 if (id & PS3AV_MODE_DVI || id & PS3AV_MODE_RGB)
488 av_video_cs = RGB8;
489 else
490 av_video_cs = video_mode->cs;
491#ifndef PS3AV_HDMI_YUV
492 if (ps3av.av_port[i] == PS3AV_CMD_AVPORT_HDMI_0 ||
493 ps3av.av_port[i] == PS3AV_CMD_AVPORT_HDMI_1)
494 av_video_cs = RGB8; /* use RGB for HDMI */
495#endif
496 len += ps3av_cmd_set_av_video_cs(&avb_param.buf[len],
497 ps3av.av_port[i],
498 video_mode->vid, av_video_cs,
499 video_mode->aspect, id);
500 }
501 /* send command using avb pkt */
502 len += offsetof(struct ps3av_pkt_avb_param, buf);
503 res = ps3av_cmd_avb_param(&avb_param, len);
504 if (res == PS3AV_STATUS_NO_SYNC_HEAD)
505 printk(KERN_WARNING
506 "%s: Command failed. Please try your request again. \n",
507 __FUNCTION__);
508 else if (res)
509 dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n");
510
511 msleep(1500);
512 /* av video mute */
513 ps3av_set_av_video_mute(PS3AV_CMD_MUTE_OFF);
514}
515
516static int ps3avd(void *p)
517{
518 struct ps3av *info = p;
519
520 daemonize("ps3avd");
521 while (1) {
522 down(&info->ping);
523 ps3av_set_videomode_cont(info->ps3av_mode,
524 info->ps3av_mode_old);
525 up(&info->pong);
526 }
527 return 0;
528}
529
530static int ps3av_vid2table_id(int vid)
531{
532 int i;
533
534 for (i = 1; i < ARRAY_SIZE(video_mode_table); i++)
535 if (video_mode_table[i].vid == vid)
536 return i;
537 return -1;
538}
539
540static int ps3av_resbit2vid(u32 res_50, u32 res_60)
541{
542 int vid = -1;
543
544 if (res_50 > res_60) { /* if res_50 == res_60, res_60 will be used */
545 if (res_50 & PS3AV_RESBIT_1920x1080P)
546 vid = PS3AV_CMD_VIDEO_VID_1080P_50HZ;
547 else if (res_50 & PS3AV_RESBIT_1920x1080I)
548 vid = PS3AV_CMD_VIDEO_VID_1080I_50HZ;
549 else if (res_50 & PS3AV_RESBIT_1280x720P)
550 vid = PS3AV_CMD_VIDEO_VID_720P_50HZ;
551 else if (res_50 & PS3AV_RESBIT_720x576P)
552 vid = PS3AV_CMD_VIDEO_VID_576P;
553 else
554 vid = -1;
555 } else {
556 if (res_60 & PS3AV_RESBIT_1920x1080P)
557 vid = PS3AV_CMD_VIDEO_VID_1080P_60HZ;
558 else if (res_60 & PS3AV_RESBIT_1920x1080I)
559 vid = PS3AV_CMD_VIDEO_VID_1080I_60HZ;
560 else if (res_60 & PS3AV_RESBIT_1280x720P)
561 vid = PS3AV_CMD_VIDEO_VID_720P_60HZ;
562 else if (res_60 & PS3AV_RESBIT_720x480P)
563 vid = PS3AV_CMD_VIDEO_VID_480P;
564 else
565 vid = -1;
566 }
567 return vid;
568}
569
570static int ps3av_hdmi_get_vid(struct ps3av_info_monitor *info)
571{
572 u32 res_50, res_60;
573 int vid = -1;
574
575 if (info->monitor_type != PS3AV_MONITOR_TYPE_HDMI)
576 return -1;
577
578 /* check native resolution */
579 res_50 = info->res_50.native & PS3AV_RES_MASK_50;
580 res_60 = info->res_60.native & PS3AV_RES_MASK_60;
581 if (res_50 || res_60) {
582 vid = ps3av_resbit2vid(res_50, res_60);
583 return vid;
584 }
585
586 /* check resolution */
587 res_50 = info->res_50.res_bits & PS3AV_RES_MASK_50;
588 res_60 = info->res_60.res_bits & PS3AV_RES_MASK_60;
589 if (res_50 || res_60) {
590 vid = ps3av_resbit2vid(res_50, res_60);
591 return vid;
592 }
593
594 if (ps3av.region & PS3AV_REGION_60)
595 vid = PS3AV_DEFAULT_HDMI_VID_REG_60;
596 else
597 vid = PS3AV_DEFAULT_HDMI_VID_REG_50;
598 return vid;
599}
600
601static int ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf,
602 int boot)
603{
604 int i, res, vid = -1, dvi = 0, rgb = 0;
605 struct ps3av_pkt_av_get_monitor_info monitor_info;
606 struct ps3av_info_monitor *info;
607
608 /* get vid for hdmi */
609 for (i = 0; i < av_hw_conf->num_of_hdmi; i++) {
610 res = ps3av_cmd_video_get_monitor_info(&monitor_info,
611 PS3AV_CMD_AVPORT_HDMI_0 +
612 i);
613 if (res < 0)
614 return -1;
615
616 ps3av_cmd_av_monitor_info_dump(&monitor_info);
617 info = &monitor_info.info;
618 /* check DVI */
619 if (info->monitor_type == PS3AV_MONITOR_TYPE_DVI) {
620 dvi = PS3AV_MODE_DVI;
621 break;
622 }
623 /* check HDMI */
624 vid = ps3av_hdmi_get_vid(info);
625 if (vid != -1) {
626 /* got valid vid */
627 break;
628 }
629 }
630
631 if (dvi) {
632 /* DVI mode */
633 vid = PS3AV_DEFAULT_DVI_VID;
634 } else if (vid == -1) {
635 /* no HDMI interface or HDMI is off */
636 if (ps3av.region & PS3AV_REGION_60)
637 vid = PS3AV_DEFAULT_AVMULTI_VID_REG_60;
638 else
639 vid = PS3AV_DEFAULT_AVMULTI_VID_REG_50;
640 if (ps3av.region & PS3AV_REGION_RGB)
641 rgb = PS3AV_MODE_RGB;
642 } else if (boot) {
643 /* HDMI: using DEFAULT HDMI_VID while booting up */
644 info = &monitor_info.info;
645 if (ps3av.region & PS3AV_REGION_60) {
646 if (info->res_60.res_bits & PS3AV_RESBIT_720x480P)
647 vid = PS3AV_DEFAULT_HDMI_VID_REG_60;
648 else if (info->res_50.res_bits & PS3AV_RESBIT_720x576P)
649 vid = PS3AV_DEFAULT_HDMI_VID_REG_50;
650 else {
651 /* default */
652 vid = PS3AV_DEFAULT_HDMI_VID_REG_60;
653 }
654 } else {
655 if (info->res_50.res_bits & PS3AV_RESBIT_720x576P)
656 vid = PS3AV_DEFAULT_HDMI_VID_REG_50;
657 else if (info->res_60.res_bits & PS3AV_RESBIT_720x480P)
658 vid = PS3AV_DEFAULT_HDMI_VID_REG_60;
659 else {
660 /* default */
661 vid = PS3AV_DEFAULT_HDMI_VID_REG_50;
662 }
663 }
664 }
665
666 return (ps3av_vid2table_id(vid) | dvi | rgb);
667}
668
669static int ps3av_get_hw_conf(struct ps3av *ps3av)
670{
671 int i, j, k, res;
672
673 /* get av_hw_conf */
674 res = ps3av_cmd_av_get_hw_conf(&ps3av->av_hw_conf);
675 if (res < 0)
676 return -1;
677
678 ps3av_cmd_av_hw_conf_dump(&ps3av->av_hw_conf);
679
680 for (i = 0; i < PS3AV_HEAD_MAX; i++)
681 ps3av->head[i] = PS3AV_CMD_VIDEO_HEAD_A + i;
682 for (i = 0; i < PS3AV_OPT_PORT_MAX; i++)
683 ps3av->opt_port[i] = PS3AV_CMD_AVPORT_SPDIF_0 + i;
684 for (i = 0; i < ps3av->av_hw_conf.num_of_hdmi; i++)
685 ps3av->av_port[i] = PS3AV_CMD_AVPORT_HDMI_0 + i;
686 for (j = 0; j < ps3av->av_hw_conf.num_of_avmulti; j++)
687 ps3av->av_port[i + j] = PS3AV_CMD_AVPORT_AVMULTI_0 + j;
688 for (k = 0; k < ps3av->av_hw_conf.num_of_spdif; k++)
689 ps3av->av_port[i + j + k] = PS3AV_CMD_AVPORT_SPDIF_0 + k;
690
691 /* set all audio port */
692 ps3av->audio_port = PS3AV_CMD_AUDIO_PORT_HDMI_0
693 | PS3AV_CMD_AUDIO_PORT_HDMI_1
694 | PS3AV_CMD_AUDIO_PORT_AVMULTI_0
695 | PS3AV_CMD_AUDIO_PORT_SPDIF_0 | PS3AV_CMD_AUDIO_PORT_SPDIF_1;
696
697 return 0;
698}
699
700/* set mode using id */
701int ps3av_set_video_mode(u32 id, int boot)
702{
703 int size;
704 u32 option;
705
706 size = ARRAY_SIZE(video_mode_table);
707 if ((id & PS3AV_MODE_MASK) > size - 1 || id < 0) {
708 dev_dbg(&ps3av_dev.core, "%s: error id :%d\n", __FUNCTION__,
709 id);
710 return -EINVAL;
711 }
712
713 /* auto mode */
714 option = id & ~PS3AV_MODE_MASK;
715 if ((id & PS3AV_MODE_MASK) == 0) {
716 id = ps3av_auto_videomode(&ps3av.av_hw_conf, boot);
717 if (id < 1) {
718 printk(KERN_ERR "%s: invalid id :%d\n", __FUNCTION__,
719 id);
720 return -EINVAL;
721 }
722 id |= option;
723 }
724
725 /* set videomode */
726 down(&ps3av.pong);
727 ps3av.ps3av_mode_old = ps3av.ps3av_mode;
728 ps3av.ps3av_mode = id;
729 if (ps3av_set_videomode())
730 ps3av.ps3av_mode = ps3av.ps3av_mode_old;
731
732 return 0;
733}
734
735EXPORT_SYMBOL_GPL(ps3av_set_video_mode);
736
737int ps3av_set_mode(u32 id, int boot)
738{
739 int res;
740
741 res = ps3av_set_video_mode(id, boot);
742 if (res)
743 return res;
744
745 res = ps3av_set_audio_mode(PS3AV_CMD_AUDIO_NUM_OF_CH_2,
746 PS3AV_CMD_AUDIO_FS_48K,
747 PS3AV_CMD_AUDIO_WORD_BITS_16,
748 PS3AV_CMD_AUDIO_FORMAT_PCM,
749 PS3AV_CMD_AUDIO_SOURCE_SERIAL);
750 if (res)
751 return res;
752
753 return 0;
754}
755
756EXPORT_SYMBOL_GPL(ps3av_set_mode);
757
758int ps3av_get_mode(void)
759{
760 return ps3av.ps3av_mode;
761}
762
763EXPORT_SYMBOL_GPL(ps3av_get_mode);
764
765int ps3av_get_scanmode(int id)
766{
767 int size;
768
769 id = id & PS3AV_MODE_MASK;
770 size = ARRAY_SIZE(video_mode_table);
771 if (id > size - 1 || id < 0) {
772 printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id);
773 return -EINVAL;
774 }
775 return video_mode_table[id].interlace;
776}
777
778EXPORT_SYMBOL_GPL(ps3av_get_scanmode);
779
780int ps3av_get_refresh_rate(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", __FUNCTION__, id);
788 return -EINVAL;
789 }
790 return video_mode_table[id].freq;
791}
792
793EXPORT_SYMBOL_GPL(ps3av_get_refresh_rate);
794
795/* get resolution by video_mode */
796int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres)
797{
798 int size;
799
800 id = id & PS3AV_MODE_MASK;
801 size = ARRAY_SIZE(video_mode_table);
802 if (id > size - 1 || id < 0) {
803 printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id);
804 return -EINVAL;
805 }
806 *xres = video_mode_table[id].x;
807 *yres = video_mode_table[id].y;
808 return 0;
809}
810
811EXPORT_SYMBOL_GPL(ps3av_video_mode2res);
812
813/* mute */
814int ps3av_video_mute(int mute)
815{
816 return ps3av_set_av_video_mute(mute ? PS3AV_CMD_MUTE_ON
817 : PS3AV_CMD_MUTE_OFF);
818}
819
820EXPORT_SYMBOL_GPL(ps3av_video_mute);
821
822int ps3av_audio_mute(int mute)
823{
824 return ps3av_set_audio_mute(mute ? PS3AV_CMD_MUTE_ON
825 : PS3AV_CMD_MUTE_OFF);
826}
827
828EXPORT_SYMBOL_GPL(ps3av_audio_mute);
829
830int ps3av_dev_open(void)
831{
832 int status = 0;
833
834 mutex_lock(&ps3av.mutex);
835 if (!ps3av.open_count++) {
836 status = lv1_gpu_open(0);
837 if (status) {
838 printk(KERN_ERR "%s: lv1_gpu_open failed %d\n",
839 __FUNCTION__, status);
840 ps3av.open_count--;
841 }
842 }
843 mutex_unlock(&ps3av.mutex);
844
845 return status;
846}
847
848EXPORT_SYMBOL_GPL(ps3av_dev_open);
849
850int ps3av_dev_close(void)
851{
852 int status = 0;
853
854 mutex_lock(&ps3av.mutex);
855 if (ps3av.open_count <= 0) {
856 printk(KERN_ERR "%s: GPU already closed\n", __FUNCTION__);
857 status = -1;
858 } else if (!--ps3av.open_count) {
859 status = lv1_gpu_close();
860 if (status)
861 printk(KERN_WARNING "%s: lv1_gpu_close failed %d\n",
862 __FUNCTION__, status);
863 }
864 mutex_unlock(&ps3av.mutex);
865
866 return status;
867}
868
869EXPORT_SYMBOL_GPL(ps3av_dev_close);
870
871static int ps3av_probe(struct ps3_vuart_port_device *dev)
872{
873 int res;
874 u32 id;
875
876 dev_dbg(&ps3av_dev.core, "init ...\n");
877 dev_dbg(&ps3av_dev.core, " timeout=%d\n", timeout);
878
879 memset(&ps3av, 0, sizeof(ps3av));
880
881 init_MUTEX(&ps3av.sem);
882 init_MUTEX_LOCKED(&ps3av.ping);
883 init_MUTEX(&ps3av.pong);
884 mutex_init(&ps3av.mutex);
885 ps3av.ps3av_mode = 0;
886 ps3av.dev = dev;
887 kernel_thread(ps3avd, &ps3av, CLONE_KERNEL);
888
889 ps3av.available = 1;
890 switch (ps3_os_area_get_av_multi_out()) {
891 case PS3_PARAM_AV_MULTI_OUT_NTSC:
892 ps3av.region = PS3AV_REGION_60;
893 break;
894 case PS3_PARAM_AV_MULTI_OUT_PAL_YCBCR:
895 case PS3_PARAM_AV_MULTI_OUT_SECAM:
896 ps3av.region = PS3AV_REGION_50;
897 break;
898 case PS3_PARAM_AV_MULTI_OUT_PAL_RGB:
899 ps3av.region = PS3AV_REGION_50 | PS3AV_REGION_RGB;
900 break;
901 default:
902 ps3av.region = PS3AV_REGION_60;
903 break;
904 }
905
906 /* init avsetting modules */
907 res = ps3av_cmd_init();
908 if (res < 0)
909 printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __FUNCTION__,
910 res);
911
912 ps3av_get_hw_conf(&ps3av);
913 id = ps3av_auto_videomode(&ps3av.av_hw_conf, 1);
914 mutex_lock(&ps3av.mutex);
915 ps3av.ps3av_mode = id;
916 mutex_unlock(&ps3av.mutex);
917
918 dev_dbg(&ps3av_dev.core, "init...done\n");
919
920 return 0;
921}
922
923static int ps3av_remove(struct ps3_vuart_port_device *dev)
924{
925 if (ps3av.available) {
926 ps3av_cmd_fin();
927 ps3av.available = 0;
928 }
929
930 return 0;
931}
932
933static void ps3av_shutdown(struct ps3_vuart_port_device *dev)
934{
935 ps3av_remove(dev);
936}
937
938static struct ps3_vuart_port_driver ps3av_driver = {
939 .match_id = PS3_MATCH_ID_AV_SETTINGS,
940 .core = {
941 .name = "ps3_av",
942 },
943 .probe = ps3av_probe,
944 .remove = ps3av_remove,
945 .shutdown = ps3av_shutdown,
946};
947
948static int ps3av_module_init(void)
949{
950 int error = ps3_vuart_port_driver_register(&ps3av_driver);
951 if (error) {
952 printk(KERN_ERR
953 "%s: ps3_vuart_port_driver_register failed %d\n",
954 __FUNCTION__, error);
955 return error;
956 }
957
958 error = ps3_vuart_port_device_register(&ps3av_dev);
959 if (error)
960 printk(KERN_ERR
961 "%s: ps3_vuart_port_device_register failed %d\n",
962 __FUNCTION__, error);
963
964 return error;
965}
966
967static void __exit ps3av_module_exit(void)
968{
969 device_unregister(&ps3av_dev.core);
970 ps3_vuart_port_driver_unregister(&ps3av_driver);
971}
972
973subsys_initcall(ps3av_module_init);
974module_exit(ps3av_module_exit);
diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c
new file mode 100644
index 000000000000..b3d1bc40a1b8
--- /dev/null
+++ b/drivers/ps3/ps3av_cmd.c
@@ -0,0 +1,1017 @@
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/kernel.h>
23#include <linux/delay.h>
24#include <asm/ps3av.h>
25#include <asm/ps3.h>
26
27#include "vuart.h"
28
29static const struct video_fmt {
30 u32 format;
31 u32 order;
32} ps3av_video_fmt_table[] = {
33 { PS3AV_CMD_VIDEO_FORMAT_ARGB_8BIT, PS3AV_CMD_VIDEO_ORDER_RGB },
34 { PS3AV_CMD_VIDEO_FORMAT_ARGB_8BIT, PS3AV_CMD_VIDEO_ORDER_BGR },
35};
36
37static const struct {
38 int cs;
39 u32 av;
40 u32 bl;
41} ps3av_cs_video2av_table[] = {
42 {
43 .cs = PS3AV_CMD_VIDEO_CS_RGB_8,
44 .av = PS3AV_CMD_AV_CS_RGB_8,
45 .bl = PS3AV_CMD_AV_CS_8
46 }, {
47 .cs = PS3AV_CMD_VIDEO_CS_RGB_10,
48 .av = PS3AV_CMD_AV_CS_RGB_8,
49 .bl = PS3AV_CMD_AV_CS_8
50 }, {
51 .cs = PS3AV_CMD_VIDEO_CS_RGB_12,
52 .av = PS3AV_CMD_AV_CS_RGB_8,
53 .bl = PS3AV_CMD_AV_CS_8
54 }, {
55 .cs = PS3AV_CMD_VIDEO_CS_YUV444_8,
56 .av = PS3AV_CMD_AV_CS_YUV444_8,
57 .bl = PS3AV_CMD_AV_CS_8
58 }, {
59 .cs = PS3AV_CMD_VIDEO_CS_YUV444_10,
60 .av = PS3AV_CMD_AV_CS_YUV444_8,
61 .bl = PS3AV_CMD_AV_CS_10
62 }, {
63 .cs = PS3AV_CMD_VIDEO_CS_YUV444_12,
64 .av = PS3AV_CMD_AV_CS_YUV444_8,
65 .bl = PS3AV_CMD_AV_CS_10
66 }, {
67 .cs = PS3AV_CMD_VIDEO_CS_YUV422_8,
68 .av = PS3AV_CMD_AV_CS_YUV422_8,
69 .bl = PS3AV_CMD_AV_CS_10
70 }, {
71 .cs = PS3AV_CMD_VIDEO_CS_YUV422_10,
72 .av = PS3AV_CMD_AV_CS_YUV422_8,
73 .bl = PS3AV_CMD_AV_CS_10
74 }, {
75 .cs = PS3AV_CMD_VIDEO_CS_YUV422_12,
76 .av = PS3AV_CMD_AV_CS_YUV422_8,
77 .bl = PS3AV_CMD_AV_CS_12
78 }, {
79 .cs = PS3AV_CMD_VIDEO_CS_XVYCC_8,
80 .av = PS3AV_CMD_AV_CS_XVYCC_8,
81 .bl = PS3AV_CMD_AV_CS_12
82 }, {
83 .cs = PS3AV_CMD_VIDEO_CS_XVYCC_10,
84 .av = PS3AV_CMD_AV_CS_XVYCC_8,
85 .bl = PS3AV_CMD_AV_CS_12
86 }, {
87 .cs = PS3AV_CMD_VIDEO_CS_XVYCC_12,
88 .av = PS3AV_CMD_AV_CS_XVYCC_8,
89 .bl = PS3AV_CMD_AV_CS_12
90 }
91};
92
93static u32 ps3av_cs_video2av(int cs)
94{
95 unsigned int i;
96
97 for (i = 0; i < ARRAY_SIZE(ps3av_cs_video2av_table); i++)
98 if (ps3av_cs_video2av_table[i].cs == cs)
99 return ps3av_cs_video2av_table[i].av;
100
101 return PS3AV_CMD_AV_CS_RGB_8;
102}
103
104static u32 ps3av_cs_video2av_bitlen(int cs)
105{
106 unsigned int i;
107
108 for (i = 0; i < ARRAY_SIZE(ps3av_cs_video2av_table); i++)
109 if (ps3av_cs_video2av_table[i].cs == cs)
110 return ps3av_cs_video2av_table[i].bl;
111
112 return PS3AV_CMD_AV_CS_8;
113}
114
115static const struct {
116 int vid;
117 u32 av;
118} ps3av_vid_video2av_table[] = {
119 { PS3AV_CMD_VIDEO_VID_480I, PS3AV_CMD_AV_VID_480I },
120 { PS3AV_CMD_VIDEO_VID_480P, PS3AV_CMD_AV_VID_480P },
121 { PS3AV_CMD_VIDEO_VID_576I, PS3AV_CMD_AV_VID_576I },
122 { PS3AV_CMD_VIDEO_VID_576P, PS3AV_CMD_AV_VID_576P },
123 { PS3AV_CMD_VIDEO_VID_1080I_60HZ, PS3AV_CMD_AV_VID_1080I_60HZ },
124 { PS3AV_CMD_VIDEO_VID_720P_60HZ, PS3AV_CMD_AV_VID_720P_60HZ },
125 { PS3AV_CMD_VIDEO_VID_1080P_60HZ, PS3AV_CMD_AV_VID_1080P_60HZ },
126 { PS3AV_CMD_VIDEO_VID_1080I_50HZ, PS3AV_CMD_AV_VID_1080I_50HZ },
127 { PS3AV_CMD_VIDEO_VID_720P_50HZ, PS3AV_CMD_AV_VID_720P_50HZ },
128 { PS3AV_CMD_VIDEO_VID_1080P_50HZ, PS3AV_CMD_AV_VID_1080P_50HZ },
129 { PS3AV_CMD_VIDEO_VID_WXGA, PS3AV_CMD_AV_VID_WXGA },
130 { PS3AV_CMD_VIDEO_VID_SXGA, PS3AV_CMD_AV_VID_SXGA },
131 { PS3AV_CMD_VIDEO_VID_WUXGA, PS3AV_CMD_AV_VID_WUXGA }
132};
133
134static u32 ps3av_vid_video2av(int vid)
135{
136 unsigned int i;
137
138 for (i = 0; i < ARRAY_SIZE(ps3av_vid_video2av_table); i++)
139 if (ps3av_vid_video2av_table[i].vid == vid)
140 return ps3av_vid_video2av_table[i].av;
141
142 return PS3AV_CMD_AV_VID_480P;
143}
144
145int ps3av_cmd_init(void)
146{
147 int res;
148 struct ps3av_pkt_av_init av_init;
149 struct ps3av_pkt_video_init video_init;
150 struct ps3av_pkt_audio_init audio_init;
151
152 /* video init */
153 memset(&video_init, 0, sizeof(video_init));
154
155 res = ps3av_do_pkt(PS3AV_CID_VIDEO_INIT, sizeof(video_init.send_hdr),
156 sizeof(video_init), &video_init.send_hdr);
157 if (res < 0)
158 return res;
159
160 res = get_status(&video_init);
161 if (res) {
162 printk(KERN_ERR "PS3AV_CID_VIDEO_INIT: failed %x\n", res);
163 return res;
164 }
165
166 /* audio init */
167 memset(&audio_init, 0, sizeof(audio_init));
168
169 res = ps3av_do_pkt(PS3AV_CID_AUDIO_INIT, sizeof(audio_init.send_hdr),
170 sizeof(audio_init), &audio_init.send_hdr);
171 if (res < 0)
172 return res;
173
174 res = get_status(&audio_init);
175 if (res) {
176 printk(KERN_ERR "PS3AV_CID_AUDIO_INIT: failed %x\n", res);
177 return res;
178 }
179
180 /* av init */
181 memset(&av_init, 0, sizeof(av_init));
182 av_init.event_bit = 0;
183
184 res = ps3av_do_pkt(PS3AV_CID_AV_INIT, sizeof(av_init), sizeof(av_init),
185 &av_init.send_hdr);
186 if (res < 0)
187 return res;
188
189 res = get_status(&av_init);
190 if (res)
191 printk(KERN_ERR "PS3AV_CID_AV_INIT: failed %x\n", res);
192
193 return res;
194}
195
196int ps3av_cmd_fin(void)
197{
198 int res;
199 struct ps3av_pkt_av_fin av_fin;
200
201 memset(&av_fin, 0, sizeof(av_fin));
202
203 res = ps3av_do_pkt(PS3AV_CID_AV_FIN, sizeof(av_fin.send_hdr),
204 sizeof(av_fin), &av_fin.send_hdr);
205 if (res < 0)
206 return res;
207
208 res = get_status(&av_fin);
209 if (res)
210 printk(KERN_ERR "PS3AV_CID_AV_FIN: failed %x\n", res);
211
212 return res;
213}
214
215int ps3av_cmd_av_video_mute(int num_of_port, u32 *port, u32 mute)
216{
217 int i, send_len, res;
218 struct ps3av_pkt_av_video_mute av_video_mute;
219
220 if (num_of_port > PS3AV_MUTE_PORT_MAX)
221 return -EINVAL;
222
223 memset(&av_video_mute, 0, sizeof(av_video_mute));
224 for (i = 0; i < num_of_port; i++) {
225 av_video_mute.mute[i].avport = port[i];
226 av_video_mute.mute[i].mute = mute;
227 }
228
229 send_len = sizeof(av_video_mute.send_hdr) +
230 sizeof(struct ps3av_av_mute) * num_of_port;
231 res = ps3av_do_pkt(PS3AV_CID_AV_VIDEO_MUTE, send_len,
232 sizeof(av_video_mute), &av_video_mute.send_hdr);
233 if (res < 0)
234 return res;
235
236 res = get_status(&av_video_mute);
237 if (res)
238 printk(KERN_ERR "PS3AV_CID_AV_VIDEO_MUTE: failed %x\n", res);
239
240 return res;
241}
242
243int ps3av_cmd_av_video_disable_sig(u32 port)
244{
245 int res;
246 struct ps3av_pkt_av_video_disable_sig av_video_sig;
247
248 memset(&av_video_sig, 0, sizeof(av_video_sig));
249 av_video_sig.avport = port;
250
251 res = ps3av_do_pkt(PS3AV_CID_AV_VIDEO_DISABLE_SIG,
252 sizeof(av_video_sig), sizeof(av_video_sig),
253 &av_video_sig.send_hdr);
254 if (res < 0)
255 return res;
256
257 res = get_status(&av_video_sig);
258 if (res)
259 printk(KERN_ERR
260 "PS3AV_CID_AV_VIDEO_DISABLE_SIG: failed %x port:%x\n",
261 res, port);
262
263 return res;
264}
265
266int ps3av_cmd_av_tv_mute(u32 avport, u32 mute)
267{
268 int res;
269 struct ps3av_pkt_av_tv_mute tv_mute;
270
271 memset(&tv_mute, 0, sizeof(tv_mute));
272 tv_mute.avport = avport;
273 tv_mute.mute = mute;
274
275 res = ps3av_do_pkt(PS3AV_CID_AV_TV_MUTE, sizeof(tv_mute),
276 sizeof(tv_mute), &tv_mute.send_hdr);
277 if (res < 0)
278 return res;
279
280 res = get_status(&tv_mute);
281 if (res)
282 printk(KERN_ERR "PS3AV_CID_AV_TV_MUTE: failed %x port:%x\n",
283 res, avport);
284
285 return res;
286}
287
288int ps3av_cmd_enable_event(void)
289{
290 int res;
291 struct ps3av_pkt_av_event av_event;
292
293 memset(&av_event, 0, sizeof(av_event));
294 av_event.event_bit = PS3AV_CMD_EVENT_BIT_UNPLUGGED |
295 PS3AV_CMD_EVENT_BIT_PLUGGED | PS3AV_CMD_EVENT_BIT_HDCP_DONE;
296
297 res = ps3av_do_pkt(PS3AV_CID_AV_ENABLE_EVENT, sizeof(av_event),
298 sizeof(av_event), &av_event.send_hdr);
299 if (res < 0)
300 return res;
301
302 res = get_status(&av_event);
303 if (res)
304 printk(KERN_ERR "PS3AV_CID_AV_ENABLE_EVENT: failed %x\n", res);
305
306 return res;
307}
308
309int ps3av_cmd_av_hdmi_mode(u8 mode)
310{
311 int res;
312 struct ps3av_pkt_av_hdmi_mode hdmi_mode;
313
314 memset(&hdmi_mode, 0, sizeof(hdmi_mode));
315 hdmi_mode.mode = mode;
316
317 res = ps3av_do_pkt(PS3AV_CID_AV_HDMI_MODE, sizeof(hdmi_mode),
318 sizeof(hdmi_mode), &hdmi_mode.send_hdr);
319 if (res < 0)
320 return res;
321
322 res = get_status(&hdmi_mode);
323 if (res && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE)
324 printk(KERN_ERR "PS3AV_CID_AV_HDMI_MODE: failed %x\n", res);
325
326 return res;
327}
328
329u32 ps3av_cmd_set_av_video_cs(void *p, u32 avport, int video_vid, int cs_out,
330 int aspect, u32 id)
331{
332 struct ps3av_pkt_av_video_cs *av_video_cs;
333
334 av_video_cs = (struct ps3av_pkt_av_video_cs *)p;
335 if (video_vid == -1)
336 video_vid = PS3AV_CMD_VIDEO_VID_720P_60HZ;
337 if (cs_out == -1)
338 cs_out = PS3AV_CMD_VIDEO_CS_YUV444_8;
339 if (aspect == -1)
340 aspect = 0;
341
342 memset(av_video_cs, 0, sizeof(*av_video_cs));
343 ps3av_set_hdr(PS3AV_CID_AV_VIDEO_CS, sizeof(*av_video_cs),
344 &av_video_cs->send_hdr);
345 av_video_cs->avport = avport;
346 /* should be same as video_mode.resolution */
347 av_video_cs->av_vid = ps3av_vid_video2av(video_vid);
348 av_video_cs->av_cs_out = ps3av_cs_video2av(cs_out);
349 /* should be same as video_mode.video_cs_out */
350 av_video_cs->av_cs_in = ps3av_cs_video2av(PS3AV_CMD_VIDEO_CS_RGB_8);
351 av_video_cs->bitlen_out = ps3av_cs_video2av_bitlen(cs_out);
352 av_video_cs->aspect = aspect;
353 if (id & PS3AV_MODE_DITHER) {
354 av_video_cs->dither = PS3AV_CMD_AV_DITHER_ON
355 | PS3AV_CMD_AV_DITHER_8BIT;
356 } else {
357 /* default off */
358 av_video_cs->dither = PS3AV_CMD_AV_DITHER_OFF;
359 }
360
361 return sizeof(*av_video_cs);
362}
363
364u32 ps3av_cmd_set_video_mode(void *p, u32 head, int video_vid, int video_fmt,
365 u32 id)
366{
367 struct ps3av_pkt_video_mode *video_mode;
368 u32 x, y;
369
370 video_mode = (struct ps3av_pkt_video_mode *)p;
371 if (video_vid == -1)
372 video_vid = PS3AV_CMD_VIDEO_VID_720P_60HZ;
373 if (video_fmt == -1)
374 video_fmt = PS3AV_CMD_VIDEO_FMT_X8R8G8B8;
375
376 if (ps3av_video_mode2res(id, &x, &y))
377 return 0;
378
379 /* video mode */
380 memset(video_mode, 0, sizeof(*video_mode));
381 ps3av_set_hdr(PS3AV_CID_VIDEO_MODE, sizeof(*video_mode),
382 &video_mode->send_hdr);
383 video_mode->video_head = head;
384 if (video_vid == PS3AV_CMD_VIDEO_VID_480I
385 && head == PS3AV_CMD_VIDEO_HEAD_B)
386 video_mode->video_vid = PS3AV_CMD_VIDEO_VID_480I_A;
387 else
388 video_mode->video_vid = video_vid;
389 video_mode->width = (u16) x;
390 video_mode->height = (u16) y;
391 video_mode->pitch = video_mode->width * 4; /* line_length */
392 video_mode->video_out_format = PS3AV_CMD_VIDEO_OUT_FORMAT_RGB_12BIT;
393 video_mode->video_format = ps3av_video_fmt_table[video_fmt].format;
394 video_mode->video_order = ps3av_video_fmt_table[video_fmt].order;
395
396 pr_debug("%s: video_mode:vid:%x width:%d height:%d pitch:%d out_format:%d format:%x order:%x\n",
397 __FUNCTION__, video_vid, video_mode->width, video_mode->height,
398 video_mode->pitch, video_mode->video_out_format,
399 video_mode->video_format, video_mode->video_order);
400 return sizeof(*video_mode);
401}
402
403int ps3av_cmd_video_format_black(u32 head, u32 video_fmt, u32 mute)
404{
405 int res;
406 struct ps3av_pkt_video_format video_format;
407
408 memset(&video_format, 0, sizeof(video_format));
409 video_format.video_head = head;
410 if (mute != PS3AV_CMD_MUTE_OFF)
411 video_format.video_format = PS3AV_CMD_VIDEO_FORMAT_BLACK;
412 else
413 video_format.video_format =
414 ps3av_video_fmt_table[video_fmt].format;
415 video_format.video_order = ps3av_video_fmt_table[video_fmt].order;
416
417 res = ps3av_do_pkt(PS3AV_CID_VIDEO_FORMAT, sizeof(video_format),
418 sizeof(video_format), &video_format.send_hdr);
419 if (res < 0)
420 return res;
421
422 res = get_status(&video_format);
423 if (res)
424 printk(KERN_ERR "PS3AV_CID_VIDEO_FORMAT: failed %x\n", res);
425
426 return res;
427}
428
429
430int ps3av_cmd_av_audio_mute(int num_of_port, u32 *port, u32 mute)
431{
432 int i, res;
433 struct ps3av_pkt_av_audio_mute av_audio_mute;
434
435 if (num_of_port > PS3AV_MUTE_PORT_MAX)
436 return -EINVAL;
437
438 /* audio mute */
439 memset(&av_audio_mute, 0, sizeof(av_audio_mute));
440 for (i = 0; i < num_of_port; i++) {
441 av_audio_mute.mute[i].avport = port[i];
442 av_audio_mute.mute[i].mute = mute;
443 }
444
445 res = ps3av_do_pkt(PS3AV_CID_AV_AUDIO_MUTE,
446 sizeof(av_audio_mute.send_hdr) +
447 sizeof(struct ps3av_av_mute) * num_of_port,
448 sizeof(av_audio_mute), &av_audio_mute.send_hdr);
449 if (res < 0)
450 return res;
451
452 res = get_status(&av_audio_mute);
453 if (res)
454 printk(KERN_ERR "PS3AV_CID_AV_AUDIO_MUTE: failed %x\n", res);
455
456 return res;
457}
458
459static const struct {
460 u32 fs;
461 u8 mclk;
462} ps3av_cnv_mclk_table[] = {
463 { PS3AV_CMD_AUDIO_FS_44K, PS3AV_CMD_AV_MCLK_512 },
464 { PS3AV_CMD_AUDIO_FS_48K, PS3AV_CMD_AV_MCLK_512 },
465 { PS3AV_CMD_AUDIO_FS_88K, PS3AV_CMD_AV_MCLK_256 },
466 { PS3AV_CMD_AUDIO_FS_96K, PS3AV_CMD_AV_MCLK_256 },
467 { PS3AV_CMD_AUDIO_FS_176K, PS3AV_CMD_AV_MCLK_128 },
468 { PS3AV_CMD_AUDIO_FS_192K, PS3AV_CMD_AV_MCLK_128 }
469};
470
471static u8 ps3av_cnv_mclk(u32 fs)
472{
473 unsigned int i;
474
475 for (i = 0; i < ARRAY_SIZE(ps3av_cnv_mclk_table); i++)
476 if (ps3av_cnv_mclk_table[i].fs == fs)
477 return ps3av_cnv_mclk_table[i].mclk;
478
479 printk(KERN_ERR "%s failed, fs:%x\n", __FUNCTION__, fs);
480 return 0;
481}
482
483#define BASE PS3AV_CMD_AUDIO_FS_44K
484
485static const u32 ps3av_ns_table[][5] = {
486 /* D1, D2, D3, D4, D5 */
487 [PS3AV_CMD_AUDIO_FS_44K-BASE] { 6272, 6272, 17836, 17836, 8918 },
488 [PS3AV_CMD_AUDIO_FS_48K-BASE] { 6144, 6144, 11648, 11648, 5824 },
489 [PS3AV_CMD_AUDIO_FS_88K-BASE] { 12544, 12544, 35672, 35672, 17836 },
490 [PS3AV_CMD_AUDIO_FS_96K-BASE] { 12288, 12288, 23296, 23296, 11648 },
491 [PS3AV_CMD_AUDIO_FS_176K-BASE] { 25088, 25088, 71344, 71344, 35672 },
492 [PS3AV_CMD_AUDIO_FS_192K-BASE] { 24576, 24576, 46592, 46592, 23296 }
493};
494
495static void ps3av_cnv_ns(u8 *ns, u32 fs, u32 video_vid)
496{
497 u32 av_vid, ns_val;
498 u8 *p = ns;
499 int d;
500
501 d = ns_val = 0;
502 av_vid = ps3av_vid_video2av(video_vid);
503 switch (av_vid) {
504 case PS3AV_CMD_AV_VID_480I:
505 case PS3AV_CMD_AV_VID_576I:
506 d = 0;
507 break;
508 case PS3AV_CMD_AV_VID_480P:
509 case PS3AV_CMD_AV_VID_576P:
510 d = 1;
511 break;
512 case PS3AV_CMD_AV_VID_1080I_60HZ:
513 case PS3AV_CMD_AV_VID_1080I_50HZ:
514 d = 2;
515 break;
516 case PS3AV_CMD_AV_VID_720P_60HZ:
517 case PS3AV_CMD_AV_VID_720P_50HZ:
518 d = 3;
519 break;
520 case PS3AV_CMD_AV_VID_1080P_60HZ:
521 case PS3AV_CMD_AV_VID_1080P_50HZ:
522 case PS3AV_CMD_AV_VID_WXGA:
523 case PS3AV_CMD_AV_VID_SXGA:
524 case PS3AV_CMD_AV_VID_WUXGA:
525 d = 4;
526 break;
527 default:
528 printk(KERN_ERR "%s failed, vid:%x\n", __FUNCTION__,
529 video_vid);
530 break;
531 }
532
533 if (fs < PS3AV_CMD_AUDIO_FS_44K || fs > PS3AV_CMD_AUDIO_FS_192K)
534 printk(KERN_ERR "%s failed, fs:%x\n", __FUNCTION__, fs);
535 else
536 ns_val = ps3av_ns_table[PS3AV_CMD_AUDIO_FS_44K-BASE][d];
537
538 *p++ = ns_val & 0x000000FF;
539 *p++ = (ns_val & 0x0000FF00) >> 8;
540 *p = (ns_val & 0x00FF0000) >> 16;
541}
542
543#undef BASE
544
545static u8 ps3av_cnv_enable(u32 source, u8 *enable)
546{
547 u8 *p, ret = 0;
548
549 if (source == PS3AV_CMD_AUDIO_SOURCE_SPDIF) {
550 ret = 0x03;
551 } else if (source == PS3AV_CMD_AUDIO_SOURCE_SERIAL) {
552 p = enable;
553 ret = ((p[0] << 4) + (p[1] << 5) + (p[2] << 6) + (p[3] << 7)) |
554 0x01;
555 } else
556 printk(KERN_ERR "%s failed, source:%x\n", __FUNCTION__,
557 source);
558 return ret;
559}
560
561static u8 ps3av_cnv_fifomap(u8 *map)
562{
563 u8 *p, ret = 0;
564
565 p = map;
566 ret = p[0] + (p[1] << 2) + (p[2] << 4) + (p[3] << 6);
567 return ret;
568}
569
570static u8 ps3av_cnv_inputlen(u32 word_bits)
571{
572 u8 ret = 0;
573
574 switch (word_bits) {
575 case PS3AV_CMD_AUDIO_WORD_BITS_16:
576 ret = PS3AV_CMD_AV_INPUTLEN_16;
577 break;
578 case PS3AV_CMD_AUDIO_WORD_BITS_20:
579 ret = PS3AV_CMD_AV_INPUTLEN_20;
580 break;
581 case PS3AV_CMD_AUDIO_WORD_BITS_24:
582 ret = PS3AV_CMD_AV_INPUTLEN_24;
583 break;
584 default:
585 printk(KERN_ERR "%s failed, word_bits:%x\n", __FUNCTION__,
586 word_bits);
587 break;
588 }
589 return ret;
590}
591
592static u8 ps3av_cnv_layout(u32 num_of_ch)
593{
594 if (num_of_ch > PS3AV_CMD_AUDIO_NUM_OF_CH_8) {
595 printk(KERN_ERR "%s failed, num_of_ch:%x\n", __FUNCTION__,
596 num_of_ch);
597 return 0;
598 }
599
600 return num_of_ch == PS3AV_CMD_AUDIO_NUM_OF_CH_2 ? 0x0 : 0x1;
601}
602
603static void ps3av_cnv_info(struct ps3av_audio_info_frame *info,
604 const struct ps3av_pkt_audio_mode *mode)
605{
606 info->pb1.cc = mode->audio_num_of_ch + 1; /* CH2:0x01 --- CH8:0x07 */
607 info->pb1.ct = 0;
608 info->pb2.sf = 0;
609 info->pb2.ss = 0;
610
611 info->pb3 = 0; /* check mode->audio_format ?? */
612 info->pb4 = mode->audio_layout;
613 info->pb5.dm = mode->audio_downmix;
614 info->pb5.lsv = mode->audio_downmix_level;
615}
616
617static void ps3av_cnv_chstat(u8 *chstat, u8 *cs_info)
618{
619 memcpy(chstat, cs_info, 5);
620}
621
622u32 ps3av_cmd_set_av_audio_param(void *p, u32 port,
623 const struct ps3av_pkt_audio_mode *audio_mode,
624 u32 video_vid)
625{
626 struct ps3av_pkt_av_audio_param *param;
627
628 param = (struct ps3av_pkt_av_audio_param *)p;
629
630 memset(param, 0, sizeof(*param));
631 ps3av_set_hdr(PS3AV_CID_AV_AUDIO_PARAM, sizeof(*param),
632 &param->send_hdr);
633
634 param->avport = port;
635 param->mclk = ps3av_cnv_mclk(audio_mode->audio_fs) | 0x80;
636 ps3av_cnv_ns(param->ns, audio_mode->audio_fs, video_vid);
637 param->enable = ps3av_cnv_enable(audio_mode->audio_source,
638 audio_mode->audio_enable);
639 param->swaplr = 0x09;
640 param->fifomap = ps3av_cnv_fifomap(audio_mode->audio_map);
641 param->inputctrl = 0x49;
642 param->inputlen = ps3av_cnv_inputlen(audio_mode->audio_word_bits);
643 param->layout = ps3av_cnv_layout(audio_mode->audio_num_of_ch);
644 ps3av_cnv_info(&param->info, audio_mode);
645 ps3av_cnv_chstat(param->chstat, audio_mode->audio_cs_info);
646
647 return sizeof(*param);
648}
649
650/* default cs val */
651static const u8 ps3av_mode_cs_info[] = {
652 0x00, 0x09, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00
653};
654
655#define CS_44 0x00
656#define CS_48 0x02
657#define CS_88 0x08
658#define CS_96 0x0a
659#define CS_176 0x0c
660#define CS_192 0x0e
661#define CS_MASK 0x0f
662#define CS_BIT 0x40
663
664void ps3av_cmd_set_audio_mode(struct ps3av_pkt_audio_mode *audio, u32 avport,
665 u32 ch, u32 fs, u32 word_bits, u32 format,
666 u32 source)
667{
668 int spdif_through, spdif_bitstream;
669 int i;
670
671 if (!(ch | fs | format | word_bits | source)) {
672 ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2;
673 fs = PS3AV_CMD_AUDIO_FS_48K;
674 word_bits = PS3AV_CMD_AUDIO_WORD_BITS_16;
675 format = PS3AV_CMD_AUDIO_FORMAT_PCM;
676 source = PS3AV_CMD_AUDIO_SOURCE_SERIAL;
677 }
678 spdif_through = spdif_bitstream = 0; /* XXX not supported */
679
680 /* audio mode */
681 memset(audio, 0, sizeof(*audio));
682 ps3av_set_hdr(PS3AV_CID_AUDIO_MODE, sizeof(*audio), &audio->send_hdr);
683
684 audio->avport = (u8) avport;
685 audio->mask = 0x0FFF; /* XXX set all */
686 audio->audio_num_of_ch = ch;
687 audio->audio_fs = fs;
688 audio->audio_word_bits = word_bits;
689 audio->audio_format = format;
690 audio->audio_source = source;
691
692 switch (ch) {
693 case PS3AV_CMD_AUDIO_NUM_OF_CH_8:
694 audio->audio_enable[3] = 1;
695 /* fall through */
696 case PS3AV_CMD_AUDIO_NUM_OF_CH_6:
697 audio->audio_enable[2] = 1;
698 audio->audio_enable[1] = 1;
699 /* fall through */
700 case PS3AV_CMD_AUDIO_NUM_OF_CH_2:
701 default:
702 audio->audio_enable[0] = 1;
703 }
704
705 /* audio swap L/R */
706 for (i = 0; i < 4; i++)
707 audio->audio_swap[i] = PS3AV_CMD_AUDIO_SWAP_0; /* no swap */
708
709 /* audio serial input mapping */
710 audio->audio_map[0] = PS3AV_CMD_AUDIO_MAP_OUTPUT_0;
711 audio->audio_map[1] = PS3AV_CMD_AUDIO_MAP_OUTPUT_1;
712 audio->audio_map[2] = PS3AV_CMD_AUDIO_MAP_OUTPUT_2;
713 audio->audio_map[3] = PS3AV_CMD_AUDIO_MAP_OUTPUT_3;
714
715 /* audio speaker layout */
716 if (avport == PS3AV_CMD_AVPORT_HDMI_0 ||
717 avport == PS3AV_CMD_AVPORT_HDMI_1) {
718 switch (ch) {
719 case PS3AV_CMD_AUDIO_NUM_OF_CH_8:
720 audio->audio_layout = PS3AV_CMD_AUDIO_LAYOUT_8CH;
721 break;
722 case PS3AV_CMD_AUDIO_NUM_OF_CH_6:
723 audio->audio_layout = PS3AV_CMD_AUDIO_LAYOUT_6CH;
724 break;
725 case PS3AV_CMD_AUDIO_NUM_OF_CH_2:
726 default:
727 audio->audio_layout = PS3AV_CMD_AUDIO_LAYOUT_2CH;
728 break;
729 }
730 } else {
731 audio->audio_layout = PS3AV_CMD_AUDIO_LAYOUT_2CH;
732 }
733
734 /* audio downmix permission */
735 audio->audio_downmix = PS3AV_CMD_AUDIO_DOWNMIX_PERMITTED;
736 /* audio downmix level shift (0:0dB to 15:15dB) */
737 audio->audio_downmix_level = 0; /* 0dB */
738
739 /* set ch status */
740 for (i = 0; i < 8; i++)
741 audio->audio_cs_info[i] = ps3av_mode_cs_info[i];
742
743 switch (fs) {
744 case PS3AV_CMD_AUDIO_FS_44K:
745 audio->audio_cs_info[3] &= ~CS_MASK;
746 audio->audio_cs_info[3] |= CS_44;
747 break;
748 case PS3AV_CMD_AUDIO_FS_88K:
749 audio->audio_cs_info[3] &= ~CS_MASK;
750 audio->audio_cs_info[3] |= CS_88;
751 break;
752 case PS3AV_CMD_AUDIO_FS_96K:
753 audio->audio_cs_info[3] &= ~CS_MASK;
754 audio->audio_cs_info[3] |= CS_96;
755 break;
756 case PS3AV_CMD_AUDIO_FS_176K:
757 audio->audio_cs_info[3] &= ~CS_MASK;
758 audio->audio_cs_info[3] |= CS_176;
759 break;
760 case PS3AV_CMD_AUDIO_FS_192K:
761 audio->audio_cs_info[3] &= ~CS_MASK;
762 audio->audio_cs_info[3] |= CS_192;
763 break;
764 default:
765 break;
766 }
767
768 /* pass through setting */
769 if (spdif_through &&
770 (avport == PS3AV_CMD_AVPORT_SPDIF_0 ||
771 avport == PS3AV_CMD_AVPORT_SPDIF_1)) {
772 audio->audio_word_bits = PS3AV_CMD_AUDIO_WORD_BITS_16;
773 audio->audio_source = PS3AV_CMD_AUDIO_SOURCE_SPDIF;
774 if (spdif_bitstream) {
775 audio->audio_format = PS3AV_CMD_AUDIO_FORMAT_BITSTREAM;
776 audio->audio_cs_info[0] |= CS_BIT;
777 }
778 }
779}
780
781int ps3av_cmd_audio_mode(struct ps3av_pkt_audio_mode *audio_mode)
782{
783 int res;
784
785 res = ps3av_do_pkt(PS3AV_CID_AUDIO_MODE, sizeof(*audio_mode),
786 sizeof(*audio_mode), &audio_mode->send_hdr);
787 if (res < 0)
788 return res;
789
790 res = get_status(audio_mode);
791 if (res)
792 printk(KERN_ERR "PS3AV_CID_AUDIO_MODE: failed %x\n", res);
793
794 return res;
795}
796
797int ps3av_cmd_audio_mute(int num_of_port, u32 *port, u32 mute)
798{
799 int i, res;
800 struct ps3av_pkt_audio_mute audio_mute;
801
802 if (num_of_port > PS3AV_OPT_PORT_MAX)
803 return -EINVAL;
804
805 /* audio mute */
806 memset(&audio_mute, 0, sizeof(audio_mute));
807 for (i = 0; i < num_of_port; i++) {
808 audio_mute.mute[i].avport = port[i];
809 audio_mute.mute[i].mute = mute;
810 }
811
812 res = ps3av_do_pkt(PS3AV_CID_AUDIO_MUTE,
813 sizeof(audio_mute.send_hdr) +
814 sizeof(struct ps3av_audio_mute) * num_of_port,
815 sizeof(audio_mute), &audio_mute.send_hdr);
816 if (res < 0)
817 return res;
818
819 res = get_status(&audio_mute);
820 if (res)
821 printk(KERN_ERR "PS3AV_CID_AUDIO_MUTE: failed %x\n", res);
822
823 return res;
824}
825
826int ps3av_cmd_audio_active(int active, u32 port)
827{
828 int res;
829 struct ps3av_pkt_audio_active audio_active;
830 u32 cid;
831
832 /* audio active */
833 memset(&audio_active, 0, sizeof(audio_active));
834 audio_active.audio_port = port;
835 cid = active ? PS3AV_CID_AUDIO_ACTIVE : PS3AV_CID_AUDIO_INACTIVE;
836
837 res = ps3av_do_pkt(cid, sizeof(audio_active), sizeof(audio_active),
838 &audio_active.send_hdr);
839 if (res < 0)
840 return res;
841
842 res = get_status(&audio_active);
843 if (res)
844 printk(KERN_ERR "PS3AV_CID_AUDIO_ACTIVE:%x failed %x\n", cid,
845 res);
846
847 return res;
848}
849
850int ps3av_cmd_avb_param(struct ps3av_pkt_avb_param *avb, u32 send_len)
851{
852 int res;
853
854 /* avb packet */
855
856 res = ps3av_do_pkt(PS3AV_CID_AVB_PARAM, send_len, sizeof(*avb),
857 &avb->send_hdr);
858 if (res < 0)
859 goto out;
860
861 res = get_status(avb);
862 if (res)
863 pr_debug("%s: PS3AV_CID_AVB_PARAM: failed %x\n", __FUNCTION__,
864 res);
865
866 out:
867 return res;
868}
869
870int ps3av_cmd_av_get_hw_conf(struct ps3av_pkt_av_get_hw_conf *hw_conf)
871{
872 int res;
873
874 memset(hw_conf, 0, sizeof(*hw_conf));
875
876 res = ps3av_do_pkt(PS3AV_CID_AV_GET_HW_CONF, sizeof(hw_conf->send_hdr),
877 sizeof(*hw_conf), &hw_conf->send_hdr);
878 if (res < 0)
879 return res;
880
881 res = get_status(hw_conf);
882 if (res)
883 printk(KERN_ERR "PS3AV_CID_AV_GET_HW_CONF: failed %x\n", res);
884
885 return res;
886}
887
888int ps3av_cmd_video_get_monitor_info(struct ps3av_pkt_av_get_monitor_info *info,
889 u32 avport)
890{
891 int res;
892
893 memset(info, 0, sizeof(*info));
894 info->avport = avport;
895
896 res = ps3av_do_pkt(PS3AV_CID_AV_GET_MONITOR_INFO,
897 sizeof(info->send_hdr) + sizeof(info->avport) +
898 sizeof(info->reserved),
899 sizeof(*info), &info->send_hdr);
900 if (res < 0)
901 return res;
902
903 res = get_status(info);
904 if (res)
905 printk(KERN_ERR "PS3AV_CID_AV_GET_MONITOR_INFO: failed %x\n",
906 res);
907
908 return res;
909}
910
911#ifdef PS3AV_DEBUG
912void ps3av_cmd_av_hw_conf_dump(const struct ps3av_pkt_av_get_hw_conf *hw_conf)
913{
914 printk("av_h_conf:num of hdmi:%d\n", hw_conf->num_of_hdmi);
915 printk("av_h_conf:num of avmulti:%d\n", hw_conf->num_of_avmulti);
916 printk("av_h_conf:num of spdif:%d\n", hw_conf->num_of_spdif);
917}
918
919void ps3av_cmd_av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *monitor_info)
920{
921 const struct ps3av_info_monitor *info = &monitor_info->info;
922 const struct ps3av_info_audio *audio = info->audio;
923 int i;
924
925 printk("Monitor Info: size%d\n", monitor_info->send_hdr.size);
926
927 printk("avport:%02x\n", info->avport);
928 printk("monitor_id:");
929 for (i = 0; i < 10; i++)
930 printk("%02x ", info->monitor_id[i]);
931 printk("\nmonitor_type:%02x\n", info->monitor_type);
932 printk("monitor_name:");
933 for (i = 0; i < 16; i++)
934 printk("%c", info->monitor_name[i]);
935
936 /* resolution */
937 printk("\nresolution_60: bits:%08x native:%08x\n",
938 info->res_60.res_bits, info->res_60.native);
939 printk("resolution_50: bits:%08x native:%08x\n",
940 info->res_50.res_bits, info->res_50.native);
941 printk("resolution_other: bits:%08x native:%08x\n",
942 info->res_other.res_bits, info->res_other.native);
943 printk("resolution_vesa: bits:%08x native:%08x\n",
944 info->res_vesa.res_bits, info->res_vesa.native);
945
946 /* color space */
947 printk("color space rgb:%02x\n", info->cs.rgb);
948 printk("color space yuv444:%02x\n", info->cs.yuv444);
949 printk("color space yuv422:%02x\n", info->cs.yuv422);
950
951 /* color info */
952 printk("color info red:X %04x Y %04x\n",
953 info->color.red_x, info->color.red_y);
954 printk("color info green:X %04x Y %04x\n",
955 info->color.green_x, info->color.green_y);
956 printk("color info blue:X %04x Y %04x\n",
957 info->color.blue_x, info->color.blue_y);
958 printk("color info white:X %04x Y %04x\n",
959 info->color.white_x, info->color.white_y);
960 printk("color info gamma: %08x\n", info->color.gamma);
961
962 /* other info */
963 printk("supported_AI:%02x\n", info->supported_ai);
964 printk("speaker_info:%02x\n", info->speaker_info);
965 printk("num of audio:%02x\n", info->num_of_audio_block);
966
967 /* audio block */
968 for (i = 0; i < info->num_of_audio_block; i++) {
969 printk("audio[%d] type:%02x max_ch:%02x fs:%02x sbit:%02x\n",
970 i, audio->type, audio->max_num_of_ch, audio->fs,
971 audio->sbit);
972 audio++;
973 }
974}
975#endif /* PS3AV_DEBUG */
976
977#define PS3AV_AV_LAYOUT_0 (PS3AV_CMD_AV_LAYOUT_32 \
978 | PS3AV_CMD_AV_LAYOUT_44 \
979 | PS3AV_CMD_AV_LAYOUT_48)
980
981#define PS3AV_AV_LAYOUT_1 (PS3AV_AV_LAYOUT_0 \
982 | PS3AV_CMD_AV_LAYOUT_88 \
983 | PS3AV_CMD_AV_LAYOUT_96 \
984 | PS3AV_CMD_AV_LAYOUT_176 \
985 | PS3AV_CMD_AV_LAYOUT_192)
986
987/************************* vuart ***************************/
988
989#define POLLING_INTERVAL 25 /* in msec */
990
991int ps3av_vuart_write(struct ps3_vuart_port_device *dev, const void *buf,
992 unsigned long size)
993{
994 int error = ps3_vuart_write(dev, buf, size);
995 return error ? error : size;
996}
997
998int ps3av_vuart_read(struct ps3_vuart_port_device *dev, void *buf,
999 unsigned long size, int timeout)
1000{
1001 int error;
1002 int loopcnt = 0;
1003
1004 timeout = (timeout + POLLING_INTERVAL - 1) / POLLING_INTERVAL;
1005 while (loopcnt++ <= timeout) {
1006 error = ps3_vuart_read(dev, buf, size);
1007 if (!error)
1008 return size;
1009 if (error != -EAGAIN) {
1010 printk(KERN_ERR "%s: ps3_vuart_read failed %d\n",
1011 __FUNCTION__, error);
1012 return error;
1013 }
1014 msleep(POLLING_INTERVAL);
1015 }
1016 return -EWOULDBLOCK;
1017}