xref: /linux/drivers/ps3/ps3av.c (revision d2912cb15bdda8ba4a5dd73396ad62641af2f520)
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_dbg(&ps3av->dev->core,
221 			"%s: ps3av_vuart_write() failed (result=%d)\n",
222 			__func__, 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_dbg(&ps3av->dev->core,
234 				"%s: ps3av_vuart_read() failed (result=%d)\n",
235 				__func__, 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_dbg(&ps3av->dev->core,
244 				"%s: ps3av_vuart_read() failed (result=%d)\n",
245 				__func__, 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_dbg(&ps3av->dev->core, "%s: reply err (result=%x)\n",
255 			__func__, 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 			/* fall through */
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