aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ps3/ps3av_cmd.c
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/ps3/ps3av_cmd.c
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/ps3/ps3av_cmd.c')
-rw-r--r--drivers/ps3/ps3av_cmd.c1017
1 files changed, 1017 insertions, 0 deletions
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}