brintos

brintos / linux-shallow public Read only

0
0
Text · 23.2 KiB · c222066 Raw
925 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2006 Sony Computer Entertainment Inc.4 * Copyright 2006, 2007 Sony Corporation5 *6 * AV backend support for PS37 */8 9#include <linux/module.h>10#include <linux/kernel.h>11#include <linux/delay.h>12 13#include <asm/ps3av.h>14#include <asm/ps3.h>15#include <asm/ps3gpu.h>16 17#include "vuart.h"18 19static const struct video_fmt {20	u32 format;21	u32 order;22} ps3av_video_fmt_table[] = {23	{ PS3AV_CMD_VIDEO_FORMAT_ARGB_8BIT, PS3AV_CMD_VIDEO_ORDER_RGB },24	{ PS3AV_CMD_VIDEO_FORMAT_ARGB_8BIT, PS3AV_CMD_VIDEO_ORDER_BGR },25};26 27static const struct {28	int cs;29	u32 av;30	u32 bl;31} ps3av_cs_video2av_table[] = {32	{33		.cs = PS3AV_CMD_VIDEO_CS_RGB_8,34		.av = PS3AV_CMD_AV_CS_RGB_8,35		.bl = PS3AV_CMD_AV_CS_836	}, {37		.cs = PS3AV_CMD_VIDEO_CS_RGB_10,38		.av = PS3AV_CMD_AV_CS_RGB_8,39		.bl = PS3AV_CMD_AV_CS_840	}, {41		.cs = PS3AV_CMD_VIDEO_CS_RGB_12,42		.av = PS3AV_CMD_AV_CS_RGB_8,43		.bl = PS3AV_CMD_AV_CS_844	}, {45		.cs = PS3AV_CMD_VIDEO_CS_YUV444_8,46		.av = PS3AV_CMD_AV_CS_YUV444_8,47		.bl = PS3AV_CMD_AV_CS_848	}, {49		.cs = PS3AV_CMD_VIDEO_CS_YUV444_10,50		.av = PS3AV_CMD_AV_CS_YUV444_8,51		.bl = PS3AV_CMD_AV_CS_1052	}, {53		.cs = PS3AV_CMD_VIDEO_CS_YUV444_12,54		.av = PS3AV_CMD_AV_CS_YUV444_8,55		.bl = PS3AV_CMD_AV_CS_1056	}, {57		.cs = PS3AV_CMD_VIDEO_CS_YUV422_8,58		.av = PS3AV_CMD_AV_CS_YUV422_8,59		.bl = PS3AV_CMD_AV_CS_1060	}, {61		.cs = PS3AV_CMD_VIDEO_CS_YUV422_10,62		.av = PS3AV_CMD_AV_CS_YUV422_8,63		.bl = PS3AV_CMD_AV_CS_1064	}, {65		.cs = PS3AV_CMD_VIDEO_CS_YUV422_12,66		.av = PS3AV_CMD_AV_CS_YUV422_8,67		.bl = PS3AV_CMD_AV_CS_1268	}, {69		.cs = PS3AV_CMD_VIDEO_CS_XVYCC_8,70		.av = PS3AV_CMD_AV_CS_XVYCC_8,71		.bl = PS3AV_CMD_AV_CS_1272	}, {73		.cs = PS3AV_CMD_VIDEO_CS_XVYCC_10,74		.av = PS3AV_CMD_AV_CS_XVYCC_8,75		.bl = PS3AV_CMD_AV_CS_1276	}, {77		.cs = PS3AV_CMD_VIDEO_CS_XVYCC_12,78		.av = PS3AV_CMD_AV_CS_XVYCC_8,79		.bl = PS3AV_CMD_AV_CS_1280	}81};82 83static u32 ps3av_cs_video2av(int cs)84{85	unsigned int i;86 87	for (i = 0; i < ARRAY_SIZE(ps3av_cs_video2av_table); i++)88		if (ps3av_cs_video2av_table[i].cs == cs)89			return ps3av_cs_video2av_table[i].av;90 91	return PS3AV_CMD_AV_CS_RGB_8;92}93 94static u32 ps3av_cs_video2av_bitlen(int cs)95{96	unsigned int i;97 98	for (i = 0; i < ARRAY_SIZE(ps3av_cs_video2av_table); i++)99		if (ps3av_cs_video2av_table[i].cs == cs)100			return ps3av_cs_video2av_table[i].bl;101 102	return PS3AV_CMD_AV_CS_8;103}104 105static const struct {106	int vid;107	u32 av;108} ps3av_vid_video2av_table[] = {109	{ PS3AV_CMD_VIDEO_VID_480I, PS3AV_CMD_AV_VID_480I },110	{ PS3AV_CMD_VIDEO_VID_480P, PS3AV_CMD_AV_VID_480P },111	{ PS3AV_CMD_VIDEO_VID_576I, PS3AV_CMD_AV_VID_576I },112	{ PS3AV_CMD_VIDEO_VID_576P, PS3AV_CMD_AV_VID_576P },113	{ PS3AV_CMD_VIDEO_VID_1080I_60HZ, PS3AV_CMD_AV_VID_1080I_60HZ },114	{ PS3AV_CMD_VIDEO_VID_720P_60HZ, PS3AV_CMD_AV_VID_720P_60HZ },115	{ PS3AV_CMD_VIDEO_VID_1080P_60HZ, PS3AV_CMD_AV_VID_1080P_60HZ },116	{ PS3AV_CMD_VIDEO_VID_1080I_50HZ, PS3AV_CMD_AV_VID_1080I_50HZ },117	{ PS3AV_CMD_VIDEO_VID_720P_50HZ, PS3AV_CMD_AV_VID_720P_50HZ },118	{ PS3AV_CMD_VIDEO_VID_1080P_50HZ, PS3AV_CMD_AV_VID_1080P_50HZ },119	{ PS3AV_CMD_VIDEO_VID_WXGA, PS3AV_CMD_AV_VID_WXGA },120	{ PS3AV_CMD_VIDEO_VID_SXGA, PS3AV_CMD_AV_VID_SXGA },121	{ PS3AV_CMD_VIDEO_VID_WUXGA, PS3AV_CMD_AV_VID_WUXGA }122};123 124static u32 ps3av_vid_video2av(int vid)125{126	unsigned int i;127 128	for (i = 0; i < ARRAY_SIZE(ps3av_vid_video2av_table); i++)129		if (ps3av_vid_video2av_table[i].vid == vid)130			return ps3av_vid_video2av_table[i].av;131 132	return PS3AV_CMD_AV_VID_480P;133}134 135static int ps3av_hdmi_range(void)136{137	if (ps3_compare_firmware_version(1, 8, 0) < 0)138		return 0;139	else140		return 1; /* supported */141}142 143int ps3av_cmd_init(void)144{145	int res;146	struct ps3av_pkt_av_init av_init;147	struct ps3av_pkt_video_init video_init;148	struct ps3av_pkt_audio_init audio_init;149 150	/* video init */151	memset(&video_init, 0, sizeof(video_init));152 153	res = ps3av_do_pkt(PS3AV_CID_VIDEO_INIT, sizeof(video_init.send_hdr),154			   sizeof(video_init), &video_init.send_hdr);155	if (res < 0)156		return res;157 158	res = get_status(&video_init);159	if (res) {160		printk(KERN_ERR "PS3AV_CID_VIDEO_INIT: failed %x\n", res);161		return res;162	}163 164	/* audio init */165	memset(&audio_init, 0, sizeof(audio_init));166 167	res = ps3av_do_pkt(PS3AV_CID_AUDIO_INIT, sizeof(audio_init.send_hdr),168			   sizeof(audio_init), &audio_init.send_hdr);169	if (res < 0)170		return res;171 172	res = get_status(&audio_init);173	if (res) {174		printk(KERN_ERR "PS3AV_CID_AUDIO_INIT: failed %x\n", res);175		return res;176	}177 178	/* av init */179	memset(&av_init, 0, sizeof(av_init));180	av_init.event_bit = 0;181 182	res = ps3av_do_pkt(PS3AV_CID_AV_INIT, sizeof(av_init), sizeof(av_init),183			   &av_init.send_hdr);184	if (res < 0)185		return res;186 187	res = get_status(&av_init);188	if (res)189		printk(KERN_ERR "PS3AV_CID_AV_INIT: failed %x\n", res);190 191	return res;192}193 194int ps3av_cmd_fin(void)195{196	int res;197	struct ps3av_pkt_av_fin av_fin;198 199	memset(&av_fin, 0, sizeof(av_fin));200 201	res = ps3av_do_pkt(PS3AV_CID_AV_FIN, sizeof(av_fin.send_hdr),202			   sizeof(av_fin), &av_fin.send_hdr);203	if (res < 0)204		return res;205 206	res = get_status(&av_fin);207	if (res)208		printk(KERN_ERR "PS3AV_CID_AV_FIN: failed %x\n", res);209 210	return res;211}212 213int ps3av_cmd_av_video_mute(int num_of_port, u32 *port, u32 mute)214{215	int i, send_len, res;216	struct ps3av_pkt_av_video_mute av_video_mute;217 218	if (num_of_port > PS3AV_MUTE_PORT_MAX)219		return -EINVAL;220 221	memset(&av_video_mute, 0, sizeof(av_video_mute));222	for (i = 0; i < num_of_port; i++) {223		av_video_mute.mute[i].avport = port[i];224		av_video_mute.mute[i].mute = mute;225	}226 227	send_len = sizeof(av_video_mute.send_hdr) +228	    sizeof(struct ps3av_av_mute) * num_of_port;229	res = ps3av_do_pkt(PS3AV_CID_AV_VIDEO_MUTE, send_len,230			   sizeof(av_video_mute), &av_video_mute.send_hdr);231	if (res < 0)232		return res;233 234	res = get_status(&av_video_mute);235	if (res)236		printk(KERN_ERR "PS3AV_CID_AV_VIDEO_MUTE: failed %x\n", res);237 238	return res;239}240 241int ps3av_cmd_av_video_disable_sig(u32 port)242{243	int res;244	struct ps3av_pkt_av_video_disable_sig av_video_sig;245 246	memset(&av_video_sig, 0, sizeof(av_video_sig));247	av_video_sig.avport = port;248 249	res = ps3av_do_pkt(PS3AV_CID_AV_VIDEO_DISABLE_SIG,250			   sizeof(av_video_sig), sizeof(av_video_sig),251			   &av_video_sig.send_hdr);252	if (res < 0)253		return res;254 255	res = get_status(&av_video_sig);256	if (res)257		printk(KERN_ERR258		       "PS3AV_CID_AV_VIDEO_DISABLE_SIG: failed %x port:%x\n",259		       res, port);260 261	return res;262}263 264int ps3av_cmd_av_tv_mute(u32 avport, u32 mute)265{266	int res;267	struct ps3av_pkt_av_tv_mute tv_mute;268 269	memset(&tv_mute, 0, sizeof(tv_mute));270	tv_mute.avport = avport;271	tv_mute.mute = mute;272 273	res = ps3av_do_pkt(PS3AV_CID_AV_TV_MUTE, sizeof(tv_mute),274			   sizeof(tv_mute), &tv_mute.send_hdr);275	if (res < 0)276		return res;277 278	res = get_status(&tv_mute);279	if (res)280		printk(KERN_ERR "PS3AV_CID_AV_TV_MUTE: failed %x port:%x\n",281		       res, avport);282 283	return res;284}285 286int ps3av_cmd_enable_event(void)287{288	int res;289	struct ps3av_pkt_av_event av_event;290 291	memset(&av_event, 0, sizeof(av_event));292	av_event.event_bit = PS3AV_CMD_EVENT_BIT_UNPLUGGED |293	    PS3AV_CMD_EVENT_BIT_PLUGGED | PS3AV_CMD_EVENT_BIT_HDCP_DONE;294 295	res = ps3av_do_pkt(PS3AV_CID_AV_ENABLE_EVENT, sizeof(av_event),296			   sizeof(av_event), &av_event.send_hdr);297	if (res < 0)298		return res;299 300	res = get_status(&av_event);301	if (res)302		printk(KERN_ERR "PS3AV_CID_AV_ENABLE_EVENT: failed %x\n", res);303 304	return res;305}306 307int ps3av_cmd_av_hdmi_mode(u8 mode)308{309	int res;310	struct ps3av_pkt_av_hdmi_mode hdmi_mode;311 312	memset(&hdmi_mode, 0, sizeof(hdmi_mode));313	hdmi_mode.mode = mode;314 315	res = ps3av_do_pkt(PS3AV_CID_AV_HDMI_MODE, sizeof(hdmi_mode),316			   sizeof(hdmi_mode), &hdmi_mode.send_hdr);317	if (res < 0)318		return res;319 320	res = get_status(&hdmi_mode);321	if (res && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE)322		printk(KERN_ERR "PS3AV_CID_AV_HDMI_MODE: failed %x\n", res);323 324	return res;325}326 327u32 ps3av_cmd_set_av_video_cs(void *p, u32 avport, int video_vid, int cs_out,328			      int aspect, u32 id)329{330	struct ps3av_pkt_av_video_cs *av_video_cs;331 332	av_video_cs = (struct ps3av_pkt_av_video_cs *)p;333	if (video_vid == -1)334		video_vid = PS3AV_CMD_VIDEO_VID_720P_60HZ;335	if (cs_out == -1)336		cs_out = PS3AV_CMD_VIDEO_CS_YUV444_8;337	if (aspect == -1)338		aspect = 0;339 340	memset(av_video_cs, 0, sizeof(*av_video_cs));341	ps3av_set_hdr(PS3AV_CID_AV_VIDEO_CS, sizeof(*av_video_cs),342		      &av_video_cs->send_hdr);343	av_video_cs->avport = avport;344	/* should be same as video_mode.resolution */345	av_video_cs->av_vid = ps3av_vid_video2av(video_vid);346	av_video_cs->av_cs_out = ps3av_cs_video2av(cs_out);347	/* should be same as video_mode.video_cs_out */348	av_video_cs->av_cs_in = ps3av_cs_video2av(PS3AV_CMD_VIDEO_CS_RGB_8);349	av_video_cs->bitlen_out = ps3av_cs_video2av_bitlen(cs_out);350	if ((id & PS3AV_MODE_WHITE) && ps3av_hdmi_range())351		av_video_cs->super_white = PS3AV_CMD_AV_SUPER_WHITE_ON;352	else /* default off */353		av_video_cs->super_white = PS3AV_CMD_AV_SUPER_WHITE_OFF;354	av_video_cs->aspect = aspect;355	if (id & PS3AV_MODE_DITHER) {356		av_video_cs->dither = PS3AV_CMD_AV_DITHER_ON357		    | PS3AV_CMD_AV_DITHER_8BIT;358	} else {359		/* default off */360		av_video_cs->dither = PS3AV_CMD_AV_DITHER_OFF;361	}362 363	return sizeof(*av_video_cs);364}365 366u32 ps3av_cmd_set_video_mode(void *p, u32 head, int video_vid, int video_fmt,367			     u32 id)368{369	struct ps3av_pkt_video_mode *video_mode;370	u32 x, y;371 372	video_mode = (struct ps3av_pkt_video_mode *)p;373	if (video_vid == -1)374		video_vid = PS3AV_CMD_VIDEO_VID_720P_60HZ;375	if (video_fmt == -1)376		video_fmt = PS3AV_CMD_VIDEO_FMT_X8R8G8B8;377 378	if (ps3av_video_mode2res(id, &x, &y))379		return 0;380 381	/* video mode */382	memset(video_mode, 0, sizeof(*video_mode));383	ps3av_set_hdr(PS3AV_CID_VIDEO_MODE, sizeof(*video_mode),384		      &video_mode->send_hdr);385	video_mode->video_head = head;386	if (video_vid == PS3AV_CMD_VIDEO_VID_480I387	    && head == PS3AV_CMD_VIDEO_HEAD_B)388		video_mode->video_vid = PS3AV_CMD_VIDEO_VID_480I_A;389	else390		video_mode->video_vid = video_vid;391	video_mode->width = (u16) x;392	video_mode->height = (u16) y;393	video_mode->pitch = video_mode->width * 4;	/* line_length */394	video_mode->video_out_format = PS3AV_CMD_VIDEO_OUT_FORMAT_RGB_12BIT;395	video_mode->video_format = ps3av_video_fmt_table[video_fmt].format;396	if ((id & PS3AV_MODE_COLOR) && ps3av_hdmi_range())397		video_mode->video_cl_cnv = PS3AV_CMD_VIDEO_CL_CNV_DISABLE_LUT;398	else /* default enable */399		video_mode->video_cl_cnv = PS3AV_CMD_VIDEO_CL_CNV_ENABLE_LUT;400	video_mode->video_order = ps3av_video_fmt_table[video_fmt].order;401 402	pr_debug("%s: video_mode:vid:%x width:%d height:%d pitch:%d out_format:%d format:%x order:%x\n",403		__func__, video_vid, video_mode->width, video_mode->height,404		video_mode->pitch, video_mode->video_out_format,405		video_mode->video_format, video_mode->video_order);406	return sizeof(*video_mode);407}408 409int ps3av_cmd_video_format_black(u32 head, u32 video_fmt, u32 mute)410{411	int res;412	struct ps3av_pkt_video_format video_format;413 414	memset(&video_format, 0, sizeof(video_format));415	video_format.video_head = head;416	if (mute != PS3AV_CMD_MUTE_OFF)417		video_format.video_format = PS3AV_CMD_VIDEO_FORMAT_BLACK;418	else419		video_format.video_format =420		    ps3av_video_fmt_table[video_fmt].format;421	video_format.video_order = ps3av_video_fmt_table[video_fmt].order;422 423	res = ps3av_do_pkt(PS3AV_CID_VIDEO_FORMAT, sizeof(video_format),424			   sizeof(video_format), &video_format.send_hdr);425	if (res < 0)426		return res;427 428	res = get_status(&video_format);429	if (res)430		printk(KERN_ERR "PS3AV_CID_VIDEO_FORMAT: failed %x\n", res);431 432	return res;433}434 435 436int ps3av_cmd_av_audio_mute(int num_of_port, u32 *port, u32 mute)437{438	int i, res;439	struct ps3av_pkt_av_audio_mute av_audio_mute;440 441	if (num_of_port > PS3AV_MUTE_PORT_MAX)442		return -EINVAL;443 444	/* audio mute */445	memset(&av_audio_mute, 0, sizeof(av_audio_mute));446	for (i = 0; i < num_of_port; i++) {447		av_audio_mute.mute[i].avport = port[i];448		av_audio_mute.mute[i].mute = mute;449	}450 451	res = ps3av_do_pkt(PS3AV_CID_AV_AUDIO_MUTE,452			   sizeof(av_audio_mute.send_hdr) +453			   sizeof(struct ps3av_av_mute) * num_of_port,454			   sizeof(av_audio_mute), &av_audio_mute.send_hdr);455	if (res < 0)456		return res;457 458	res = get_status(&av_audio_mute);459	if (res)460		printk(KERN_ERR "PS3AV_CID_AV_AUDIO_MUTE: failed %x\n", res);461 462	return res;463}464 465static const struct {466	u32 fs;467	u8 mclk;468} ps3av_cnv_mclk_table[] = {469	{ PS3AV_CMD_AUDIO_FS_44K, PS3AV_CMD_AV_MCLK_512 },470	{ PS3AV_CMD_AUDIO_FS_48K, PS3AV_CMD_AV_MCLK_512 },471	{ PS3AV_CMD_AUDIO_FS_88K, PS3AV_CMD_AV_MCLK_256 },472	{ PS3AV_CMD_AUDIO_FS_96K, PS3AV_CMD_AV_MCLK_256 },473	{ PS3AV_CMD_AUDIO_FS_176K, PS3AV_CMD_AV_MCLK_128 },474	{ PS3AV_CMD_AUDIO_FS_192K, PS3AV_CMD_AV_MCLK_128 }475};476 477static u8 ps3av_cnv_mclk(u32 fs)478{479	unsigned int i;480 481	for (i = 0; i < ARRAY_SIZE(ps3av_cnv_mclk_table); i++)482		if (ps3av_cnv_mclk_table[i].fs == fs)483			return ps3av_cnv_mclk_table[i].mclk;484 485	printk(KERN_ERR "%s failed, fs:%x\n", __func__, fs);486	return 0;487}488 489#define BASE	PS3AV_CMD_AUDIO_FS_44K490 491static const u32 ps3av_ns_table[][5] = {492					/*   D1,    D2,    D3,    D4,    D5 */493	[PS3AV_CMD_AUDIO_FS_44K-BASE] =	{  6272,  6272, 17836, 17836,  8918 },494	[PS3AV_CMD_AUDIO_FS_48K-BASE] =	{  6144,  6144, 11648, 11648,  5824 },495	[PS3AV_CMD_AUDIO_FS_88K-BASE] =	{ 12544, 12544, 35672, 35672, 17836 },496	[PS3AV_CMD_AUDIO_FS_96K-BASE] =	{ 12288, 12288, 23296, 23296, 11648 },497	[PS3AV_CMD_AUDIO_FS_176K-BASE] =	{ 25088, 25088, 71344, 71344, 35672 },498	[PS3AV_CMD_AUDIO_FS_192K-BASE] =	{ 24576, 24576, 46592, 46592, 23296 }499};500 501static void ps3av_cnv_ns(u8 *ns, u32 fs, u32 video_vid)502{503	u32 av_vid, ns_val;504	int d;505 506	d = ns_val = 0;507	av_vid = ps3av_vid_video2av(video_vid);508	switch (av_vid) {509	case PS3AV_CMD_AV_VID_480I:510	case PS3AV_CMD_AV_VID_576I:511		d = 0;512		break;513	case PS3AV_CMD_AV_VID_480P:514	case PS3AV_CMD_AV_VID_576P:515		d = 1;516		break;517	case PS3AV_CMD_AV_VID_1080I_60HZ:518	case PS3AV_CMD_AV_VID_1080I_50HZ:519		d = 2;520		break;521	case PS3AV_CMD_AV_VID_720P_60HZ:522	case PS3AV_CMD_AV_VID_720P_50HZ:523		d = 3;524		break;525	case PS3AV_CMD_AV_VID_1080P_60HZ:526	case PS3AV_CMD_AV_VID_1080P_50HZ:527	case PS3AV_CMD_AV_VID_WXGA:528	case PS3AV_CMD_AV_VID_SXGA:529	case PS3AV_CMD_AV_VID_WUXGA:530		d = 4;531		break;532	default:533		printk(KERN_ERR "%s failed, vid:%x\n", __func__, video_vid);534		break;535	}536 537	if (fs < PS3AV_CMD_AUDIO_FS_44K || fs > PS3AV_CMD_AUDIO_FS_192K)538		printk(KERN_ERR "%s failed, fs:%x\n", __func__, fs);539	else540		ns_val = ps3av_ns_table[PS3AV_CMD_AUDIO_FS_44K-BASE][d];541 542	*ns++ = ns_val & 0x000000FF;543	*ns++ = (ns_val & 0x0000FF00) >> 8;544	*ns = (ns_val & 0x00FF0000) >> 16;545}546 547#undef BASE548 549static u8 ps3av_cnv_enable(u32 source, const u8 *enable)550{551	u8 ret = 0;552 553	if (source == PS3AV_CMD_AUDIO_SOURCE_SPDIF) {554		ret = 0x03;555	} else if (source == PS3AV_CMD_AUDIO_SOURCE_SERIAL) {556		ret = ((enable[0] << 4) + (enable[1] << 5) + (enable[2] << 6) +557		       (enable[3] << 7)) | 0x01;558	} else559		printk(KERN_ERR "%s failed, source:%x\n", __func__, source);560	return ret;561}562 563static u8 ps3av_cnv_fifomap(const u8 *map)564{565	u8 ret = 0;566 567	ret = map[0] + (map[1] << 2) + (map[2] << 4) + (map[3] << 6);568	return ret;569}570 571static u8 ps3av_cnv_inputlen(u32 word_bits)572{573	u8 ret = 0;574 575	switch (word_bits) {576	case PS3AV_CMD_AUDIO_WORD_BITS_16:577		ret = PS3AV_CMD_AV_INPUTLEN_16;578		break;579	case PS3AV_CMD_AUDIO_WORD_BITS_20:580		ret = PS3AV_CMD_AV_INPUTLEN_20;581		break;582	case PS3AV_CMD_AUDIO_WORD_BITS_24:583		ret = PS3AV_CMD_AV_INPUTLEN_24;584		break;585	default:586		printk(KERN_ERR "%s failed, word_bits:%x\n", __func__,587		       word_bits);588		break;589	}590	return ret;591}592 593static u8 ps3av_cnv_layout(u32 num_of_ch)594{595	if (num_of_ch > PS3AV_CMD_AUDIO_NUM_OF_CH_8) {596		printk(KERN_ERR "%s failed, num_of_ch:%x\n", __func__,597		       num_of_ch);598		return 0;599	}600 601	return num_of_ch == PS3AV_CMD_AUDIO_NUM_OF_CH_2 ? 0x0 : 0x1;602}603 604static void ps3av_cnv_info(struct ps3av_audio_info_frame *info,605			   const struct ps3av_pkt_audio_mode *mode)606{607	info->pb1.cc = mode->audio_num_of_ch + 1;	/* CH2:0x01 --- CH8:0x07 */608	info->pb1.ct = 0;609	info->pb2.sf = 0;610	info->pb2.ss = 0;611 612	info->pb3 = 0;		/* check mode->audio_format ?? */613	info->pb4 = mode->audio_layout;614	info->pb5.dm = mode->audio_downmix;615	info->pb5.lsv = mode->audio_downmix_level;616}617 618static void ps3av_cnv_chstat(u8 *chstat, const u8 *cs_info)619{620	memcpy(chstat, cs_info, 5);621}622 623u32 ps3av_cmd_set_av_audio_param(void *p, u32 port,624				 const struct ps3av_pkt_audio_mode *audio_mode,625				 u32 video_vid)626{627	struct ps3av_pkt_av_audio_param *param;628 629	param = (struct ps3av_pkt_av_audio_param *)p;630 631	memset(param, 0, sizeof(*param));632	ps3av_set_hdr(PS3AV_CID_AV_AUDIO_PARAM, sizeof(*param),633		      &param->send_hdr);634 635	param->avport = port;636	param->mclk = ps3av_cnv_mclk(audio_mode->audio_fs) | 0x80;637	ps3av_cnv_ns(param->ns, audio_mode->audio_fs, video_vid);638	param->enable = ps3av_cnv_enable(audio_mode->audio_source,639					 audio_mode->audio_enable);640	param->swaplr = 0x09;641	param->fifomap = ps3av_cnv_fifomap(audio_mode->audio_map);642	param->inputctrl = 0x49;643	param->inputlen = ps3av_cnv_inputlen(audio_mode->audio_word_bits);644	param->layout = ps3av_cnv_layout(audio_mode->audio_num_of_ch);645	ps3av_cnv_info(&param->info, audio_mode);646	ps3av_cnv_chstat(param->chstat, audio_mode->audio_cs_info);647 648	return sizeof(*param);649}650 651/* default cs val */652u8 ps3av_mode_cs_info[] = {653	0x00, 0x09, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00654};655EXPORT_SYMBOL_GPL(ps3av_mode_cs_info);656 657#define CS_44	0x00658#define CS_48	0x02659#define CS_88	0x08660#define CS_96	0x0a661#define CS_176	0x0c662#define CS_192	0x0e663#define CS_MASK	0x0f664#define CS_BIT	0x40665 666void ps3av_cmd_set_audio_mode(struct ps3av_pkt_audio_mode *audio, u32 avport,667			      u32 ch, u32 fs, u32 word_bits, u32 format,668			      u32 source)669{670	int spdif_through;671	int i;672 673	if (!(ch | fs | format | word_bits | source)) {674		ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2;675		fs = PS3AV_CMD_AUDIO_FS_48K;676		word_bits = PS3AV_CMD_AUDIO_WORD_BITS_16;677		format = PS3AV_CMD_AUDIO_FORMAT_PCM;678		source = PS3AV_CMD_AUDIO_SOURCE_SERIAL;679	}680 681	/* audio mode */682	memset(audio, 0, sizeof(*audio));683	ps3av_set_hdr(PS3AV_CID_AUDIO_MODE, sizeof(*audio), &audio->send_hdr);684 685	audio->avport = (u8) avport;686	audio->mask = 0x0FFF;	/* XXX set all */687	audio->audio_num_of_ch = ch;688	audio->audio_fs = fs;689	audio->audio_word_bits = word_bits;690	audio->audio_format = format;691	audio->audio_source = source;692 693	switch (ch) {694	case PS3AV_CMD_AUDIO_NUM_OF_CH_8:695		audio->audio_enable[3] = 1;696		fallthrough;697	case PS3AV_CMD_AUDIO_NUM_OF_CH_6:698		audio->audio_enable[2] = 1;699		audio->audio_enable[1] = 1;700		fallthrough;701	case PS3AV_CMD_AUDIO_NUM_OF_CH_2:702	default:703		audio->audio_enable[0] = 1;704	}705 706	/* audio swap L/R */707	for (i = 0; i < 4; i++)708		audio->audio_swap[i] = PS3AV_CMD_AUDIO_SWAP_0;	/* no swap */709 710	/* audio serial input mapping */711	audio->audio_map[0] = PS3AV_CMD_AUDIO_MAP_OUTPUT_0;712	audio->audio_map[1] = PS3AV_CMD_AUDIO_MAP_OUTPUT_1;713	audio->audio_map[2] = PS3AV_CMD_AUDIO_MAP_OUTPUT_2;714	audio->audio_map[3] = PS3AV_CMD_AUDIO_MAP_OUTPUT_3;715 716	/* audio speaker layout */717	if (avport == PS3AV_CMD_AVPORT_HDMI_0 ||718	    avport == PS3AV_CMD_AVPORT_HDMI_1) {719		switch (ch) {720		case PS3AV_CMD_AUDIO_NUM_OF_CH_8:721			audio->audio_layout = PS3AV_CMD_AUDIO_LAYOUT_8CH;722			break;723		case PS3AV_CMD_AUDIO_NUM_OF_CH_6:724			audio->audio_layout = PS3AV_CMD_AUDIO_LAYOUT_6CH;725			break;726		case PS3AV_CMD_AUDIO_NUM_OF_CH_2:727		default:728			audio->audio_layout = PS3AV_CMD_AUDIO_LAYOUT_2CH;729			break;730		}731	} else {732		audio->audio_layout = PS3AV_CMD_AUDIO_LAYOUT_2CH;733	}734 735	/* audio downmix permission */736	audio->audio_downmix = PS3AV_CMD_AUDIO_DOWNMIX_PERMITTED;737	/* audio downmix level shift (0:0dB to 15:15dB) */738	audio->audio_downmix_level = 0;	/* 0dB */739 740	/* set ch status */741	for (i = 0; i < 8; i++)742		audio->audio_cs_info[i] = ps3av_mode_cs_info[i];743 744	switch (fs) {745	case PS3AV_CMD_AUDIO_FS_44K:746		audio->audio_cs_info[3] &= ~CS_MASK;747		audio->audio_cs_info[3] |= CS_44;748		break;749	case PS3AV_CMD_AUDIO_FS_88K:750		audio->audio_cs_info[3] &= ~CS_MASK;751		audio->audio_cs_info[3] |= CS_88;752		break;753	case PS3AV_CMD_AUDIO_FS_96K:754		audio->audio_cs_info[3] &= ~CS_MASK;755		audio->audio_cs_info[3] |= CS_96;756		break;757	case PS3AV_CMD_AUDIO_FS_176K:758		audio->audio_cs_info[3] &= ~CS_MASK;759		audio->audio_cs_info[3] |= CS_176;760		break;761	case PS3AV_CMD_AUDIO_FS_192K:762		audio->audio_cs_info[3] &= ~CS_MASK;763		audio->audio_cs_info[3] |= CS_192;764		break;765	default:766		break;767	}768 769	/* non-audio bit */770	spdif_through = audio->audio_cs_info[0] & 0x02;771 772	/* pass through setting */773	if (spdif_through &&774	    (avport == PS3AV_CMD_AVPORT_SPDIF_0 ||775	     avport == PS3AV_CMD_AVPORT_SPDIF_1 ||776	     avport == PS3AV_CMD_AVPORT_HDMI_0 ||777	     avport == PS3AV_CMD_AVPORT_HDMI_1)) {778		audio->audio_word_bits = PS3AV_CMD_AUDIO_WORD_BITS_16;779		audio->audio_format = PS3AV_CMD_AUDIO_FORMAT_BITSTREAM;780	}781}782 783int ps3av_cmd_audio_mode(struct ps3av_pkt_audio_mode *audio_mode)784{785	int res;786 787	res = ps3av_do_pkt(PS3AV_CID_AUDIO_MODE, sizeof(*audio_mode),788			   sizeof(*audio_mode), &audio_mode->send_hdr);789	if (res < 0)790		return res;791 792	res = get_status(audio_mode);793	if (res)794		printk(KERN_ERR "PS3AV_CID_AUDIO_MODE: failed %x\n", res);795 796	return res;797}798 799int ps3av_cmd_audio_mute(int num_of_port, u32 *port, u32 mute)800{801	int i, res;802	struct ps3av_pkt_audio_mute audio_mute;803 804	if (num_of_port > PS3AV_OPT_PORT_MAX)805		return -EINVAL;806 807	/* audio mute */808	memset(&audio_mute, 0, sizeof(audio_mute));809	for (i = 0; i < num_of_port; i++) {810		audio_mute.mute[i].avport = port[i];811		audio_mute.mute[i].mute = mute;812	}813 814	res = ps3av_do_pkt(PS3AV_CID_AUDIO_MUTE,815			   sizeof(audio_mute.send_hdr) +816			   sizeof(struct ps3av_audio_mute) * num_of_port,817			   sizeof(audio_mute), &audio_mute.send_hdr);818	if (res < 0)819		return res;820 821	res = get_status(&audio_mute);822	if (res)823		printk(KERN_ERR "PS3AV_CID_AUDIO_MUTE: failed %x\n", res);824 825	return res;826}827 828int ps3av_cmd_audio_active(int active, u32 port)829{830	int res;831	struct ps3av_pkt_audio_active audio_active;832	u32 cid;833 834	/* audio active */835	memset(&audio_active, 0, sizeof(audio_active));836	audio_active.audio_port = port;837	cid = active ? PS3AV_CID_AUDIO_ACTIVE : PS3AV_CID_AUDIO_INACTIVE;838 839	res = ps3av_do_pkt(cid, sizeof(audio_active), sizeof(audio_active),840			   &audio_active.send_hdr);841	if (res < 0)842		return res;843 844	res = get_status(&audio_active);845	if (res)846		printk(KERN_ERR "PS3AV_CID_AUDIO_ACTIVE:%x failed %x\n", cid,847		       res);848 849	return res;850}851 852int ps3av_cmd_avb_param(struct ps3av_pkt_avb_param *avb, u32 send_len)853{854	int res;855 856	mutex_lock(&ps3_gpu_mutex);857 858	/* avb packet */859	res = ps3av_do_pkt(PS3AV_CID_AVB_PARAM, send_len, sizeof(*avb),860			   &avb->send_hdr);861	if (res < 0)862		goto out;863 864	res = get_status(avb);865	if (res)866		pr_debug("%s: PS3AV_CID_AVB_PARAM: failed %x\n", __func__,867			 res);868 869      out:870	mutex_unlock(&ps3_gpu_mutex);871	return res;872}873 874int ps3av_cmd_av_get_hw_conf(struct ps3av_pkt_av_get_hw_conf *hw_conf)875{876	int res;877 878	memset(hw_conf, 0, sizeof(*hw_conf));879 880	res = ps3av_do_pkt(PS3AV_CID_AV_GET_HW_CONF, sizeof(hw_conf->send_hdr),881			   sizeof(*hw_conf), &hw_conf->send_hdr);882	if (res < 0)883		return res;884 885	res = get_status(hw_conf);886	if (res)887		printk(KERN_ERR "PS3AV_CID_AV_GET_HW_CONF: failed %x\n", res);888 889	return res;890}891 892int ps3av_cmd_video_get_monitor_info(struct ps3av_pkt_av_get_monitor_info *info,893				     u32 avport)894{895	int res;896 897	memset(info, 0, sizeof(*info));898	info->avport = avport;899 900	res = ps3av_do_pkt(PS3AV_CID_AV_GET_MONITOR_INFO,901			   sizeof(info->send_hdr) + sizeof(info->avport) +902			   sizeof(info->reserved),903			   sizeof(*info), &info->send_hdr);904	if (res < 0)905		return res;906 907	res = get_status(info);908	if (res)909		printk(KERN_ERR "PS3AV_CID_AV_GET_MONITOR_INFO: failed %x\n",910		       res);911 912	return res;913}914 915#define PS3AV_AV_LAYOUT_0 (PS3AV_CMD_AV_LAYOUT_32 \916		| PS3AV_CMD_AV_LAYOUT_44 \917		| PS3AV_CMD_AV_LAYOUT_48)918 919#define PS3AV_AV_LAYOUT_1 (PS3AV_AV_LAYOUT_0 \920		| PS3AV_CMD_AV_LAYOUT_88 \921		| PS3AV_CMD_AV_LAYOUT_96 \922		| PS3AV_CMD_AV_LAYOUT_176 \923		| PS3AV_CMD_AV_LAYOUT_192)924 925