// SPDX-License-Identifier: GPL-2.0-only /* * PS3 AV backend support. * * Copyright (C) 2007 Sony Computer Entertainment Inc. * Copyright 2007 Sony Corp.
*/
staticint ps3av_send_cmd_pkt(conststruct ps3av_send_hdr *send_buf, struct ps3av_reply_hdr *recv_buf, int write_len, int read_len)
{ int res;
u32 cmd; int event;
staticint ps3av_set_av_video_mute(u32 mute)
{ int i, num_of_av_port, res;
num_of_av_port = ps3av->av_hw_conf.num_of_hdmi +
ps3av->av_hw_conf.num_of_avmulti; /* video mute on */ for (i = 0; i < num_of_av_port; i++) {
res = ps3av_cmd_av_video_mute(1, &ps3av->av_port[i], mute); if (res < 0) return -1;
}
return 0;
}
staticint ps3av_set_video_disable_sig(void)
{ int i, num_of_hdmi_port, num_of_av_port, res;
/* tv mute */ for (i = 0; i < num_of_hdmi_port; i++) {
res = ps3av_cmd_av_tv_mute(ps3av->av_port[i],
PS3AV_CMD_MUTE_ON); if (res < 0) return -1;
}
msleep(100);
/* video mute on */ for (i = 0; i < num_of_av_port; i++) {
res = ps3av_cmd_av_video_disable_sig(ps3av->av_port[i]); if (res < 0) return -1; if (i < num_of_hdmi_port) {
res = ps3av_cmd_av_tv_mute(ps3av->av_port[i],
PS3AV_CMD_MUTE_OFF); if (res < 0) return -1;
}
}
msleep(300);
return 0;
}
staticint ps3av_set_audio_mute(u32 mute)
{ int i, num_of_av_port, num_of_opt_port, res;
for (i = 0; i < num_of_av_port; i++) {
res = ps3av_cmd_av_audio_mute(1, &ps3av->av_port[i], mute); if (res < 0) return -1;
} for (i = 0; i < num_of_opt_port; i++) {
res = ps3av_cmd_audio_mute(1, &ps3av->opt_port[i], mute); if (res < 0) return -1;
}
return 0;
}
int ps3av_set_audio_mode(u32 ch, u32 fs, u32 word_bits, u32 format, u32 source)
{ struct ps3av_pkt_avb_param avb_param; int i, num_of_audio, vid, res; struct ps3av_pkt_audio_mode audio_mode;
u32 len = 0;
/* audio inactive */
res = ps3av_cmd_audio_active(0, ps3av->audio_port); if (res < 0)
dev_dbg(&ps3av->dev->core, "ps3av_cmd_audio_active OFF failed\n");
/* audio_pkt */ for (i = 0; i < num_of_audio; i++) {
ps3av_cmd_set_audio_mode(&audio_mode, ps3av->av_port[i], ch,
fs, word_bits, format, source); if (i < ps3av->av_hw_conf.num_of_hdmi) { /* hdmi only */
len += ps3av_cmd_set_av_audio_param(&avb_param.buf[len],
ps3av->av_port[i],
&audio_mode, vid);
} /* audio_mode pkt should be sent separately */
res = ps3av_cmd_audio_mode(&audio_mode); if (res < 0)
dev_dbg(&ps3av->dev->core, "ps3av_cmd_audio_mode failed, port:%x\n", i);
}
/* send command using avb pkt */
len += offsetof(struct ps3av_pkt_avb_param, buf);
res = ps3av_cmd_avb_param(&avb_param, len); if (res < 0)
dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n");
avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */
avb_param.num_of_audio_pkt = 0;
avb_param.num_of_av_video_pkt = ps3av->av_hw_conf.num_of_hdmi +
ps3av->av_hw_conf.num_of_avmulti;
avb_param.num_of_av_audio_pkt = 0;
/* video_pkt */ for (i = 0; i < avb_param.num_of_video_pkt; i++)
len += ps3av_cmd_set_video_mode(&avb_param.buf[len],
ps3av->head[i], video_mode->vid,
video_mode->fmt, id); /* av_video_pkt */ for (i = 0; i < avb_param.num_of_av_video_pkt; i++) { if (id & PS3AV_MODE_DVI || id & PS3AV_MODE_RGB)
av_video_cs = RGB8; else
av_video_cs = video_mode->cs; #ifndef PS3AV_HDMI_YUV if (ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_0 ||
ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_1)
av_video_cs = RGB8; /* use RGB for HDMI */ #endif
len += ps3av_cmd_set_av_video_cs(&avb_param.buf[len],
ps3av->av_port[i],
video_mode->vid, av_video_cs,
video_mode->aspect, id);
} /* send command using avb pkt */
len += offsetof(struct ps3av_pkt_avb_param, buf);
res = ps3av_cmd_avb_param(&avb_param, len); if (res == PS3AV_STATUS_NO_SYNC_HEAD)
printk(KERN_WARNING "%s: Command failed. Please try your request again.\n",
__func__); elseif (res)
dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n");
}
staticvoid ps3av_set_videomode_cont(u32 id, u32 old_id)
{ staticint vesa; int res;
/* video signal off */
ps3av_set_video_disable_sig();
/* * AV backend needs non-VESA mode setting at least one time * when VESA mode is used.
*/ if (vesa == 0 && (id & PS3AV_MODE_MASK) >= PS3AV_MODE_WXGA) { /* vesa mode */
ps3av_set_videomode_packet(PS3AV_MODE_480P);
}
vesa = 1;
/* Retail PS3 product doesn't support this */ if (id & PS3AV_MODE_HDCP_OFF) {
res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF); if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE)
dev_dbg(&ps3av->dev->core, "Not supported\n"); elseif (res)
dev_dbg(&ps3av->dev->core, "ps3av_cmd_av_hdmi_mode failed\n");
} elseif (old_id & PS3AV_MODE_HDCP_OFF) {
res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL); if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE)
dev_dbg(&ps3av->dev->core, "ps3av_cmd_av_hdmi_mode failed\n");
}
ps3av_set_videomode_packet(id);
msleep(1500); /* av video mute */
ps3av_set_av_video_mute(PS3AV_CMD_MUTE_OFF);
}
/* color space */
pr_debug("color space rgb: %02x\n", info->cs.rgb);
pr_debug("color space yuv444: %02x\n", info->cs.yuv444);
pr_debug("color space yuv422: %02x\n", info->cs.yuv422);
/* color info */
pr_debug("color info red: X %04x Y %04x\n", info->color.red_x,
info->color.red_y);
pr_debug("color info green: X %04x Y %04x\n", info->color.green_x,
info->color.green_y);
pr_debug("color info blue: X %04x Y %04x\n", info->color.blue_x,
info->color.blue_y);
pr_debug("color info white: X %04x Y %04x\n", info->color.white_x,
info->color.white_y);
pr_debug("color info gamma: %08x\n", info->color.gamma);
/* other info */
pr_debug("supported_AI: %02x\n", info->supported_ai);
pr_debug("speaker_info: %02x\n", info->speaker_info);
pr_debug("num of audio: %02x\n", info->num_of_audio_block);
/* audio block */ for (i = 0; i < info->num_of_audio_block; i++) {
pr_debug( "audio[%d] type: %02x max_ch: %02x fs: %02x sbit: %02x\n",
i, audio->type, audio->max_num_of_ch, audio->fs,
audio->sbit);
audio++;
}
}
for (i = 0; i < ARRAY_SIZE(ps3av_monitor_quirks); i++) {
quirk = &ps3av_monitor_quirks[i]; if (!strncmp(info->monitor_name, quirk->monitor_name, sizeof(info->monitor_name))) {
pr_info("%s: Applying quirk for %s\n", __func__,
quirk->monitor_name);
info->res_60.res_bits &= ~quirk->clear_60;
info->res_60.native &= ~quirk->clear_60; break;
}
}
}
staticint ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf)
{ int i, res, id = 0, dvi = 0, rgb = 0; struct ps3av_pkt_av_get_monitor_info monitor_info; struct ps3av_info_monitor *info;
/* get mode id for hdmi */ for (i = 0; i < av_hw_conf->num_of_hdmi && !id; i++) {
res = ps3av_cmd_video_get_monitor_info(&monitor_info,
PS3AV_CMD_AVPORT_HDMI_0 +
i); if (res < 0) return -1;
ps3av_monitor_info_dump(&monitor_info);
info = &monitor_info.info;
ps3av_fixup_monitor_info(info);
switch (info->monitor_type) { case PS3AV_MONITOR_TYPE_DVI:
dvi = PS3AV_MODE_DVI;
fallthrough; case PS3AV_MONITOR_TYPE_HDMI:
id = ps3av_hdmi_get_id(info); break;
}
}
if (!id) { /* no HDMI interface or HDMI is off */ if (ps3av->region & PS3AV_REGION_60)
id = PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_60; else
id = PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_50; if (ps3av->region & PS3AV_REGION_RGB)
rgb = PS3AV_MODE_RGB;
pr_debug("%s: Using avmulti mode %d\n", __func__, id);
}
return id | dvi | rgb;
}
staticint ps3av_get_hw_conf(struct ps3av *ps3av)
{ int i, j, k, res; conststruct ps3av_pkt_av_get_hw_conf *hw_conf;
/* get av_hw_conf */
res = ps3av_cmd_av_get_hw_conf(&ps3av->av_hw_conf); if (res < 0) return -1;
hw_conf = &ps3av->av_hw_conf;
pr_debug("av_h_conf: num of hdmi: %u\n", hw_conf->num_of_hdmi);
pr_debug("av_h_conf: num of avmulti: %u\n", hw_conf->num_of_avmulti);
pr_debug("av_h_conf: num of spdif: %u\n", hw_conf->num_of_spdif);
for (i = 0; i < PS3AV_HEAD_MAX; i++)
ps3av->head[i] = PS3AV_CMD_VIDEO_HEAD_A + i; for (i = 0; i < PS3AV_OPT_PORT_MAX; i++)
ps3av->opt_port[i] = PS3AV_CMD_AVPORT_SPDIF_0 + i; for (i = 0; i < hw_conf->num_of_hdmi; i++)
ps3av->av_port[i] = PS3AV_CMD_AVPORT_HDMI_0 + i; for (j = 0; j < hw_conf->num_of_avmulti; j++)
ps3av->av_port[i + j] = PS3AV_CMD_AVPORT_AVMULTI_0 + j; for (k = 0; k < hw_conf->num_of_spdif; k++)
ps3av->av_port[i + j + k] = PS3AV_CMD_AVPORT_SPDIF_0 + k;
/* set all audio port */
ps3av->audio_port = PS3AV_CMD_AUDIO_PORT_HDMI_0
| PS3AV_CMD_AUDIO_PORT_HDMI_1
| PS3AV_CMD_AUDIO_PORT_AVMULTI_0
| PS3AV_CMD_AUDIO_PORT_SPDIF_0 | PS3AV_CMD_AUDIO_PORT_SPDIF_1;
return 0;
}
/* set mode using id */ int ps3av_set_video_mode(int id)
{ int size;
u32 option;
size = ARRAY_SIZE(video_mode_table); if ((id & PS3AV_MODE_MASK) > size - 1 || id < 0) {
dev_dbg(&ps3av->dev->core, "%s: error id :%d\n", __func__, id); return -EINVAL;
}
/* auto mode */
option = id & ~PS3AV_MODE_MASK; if ((id & PS3AV_MODE_MASK) == PS3AV_MODE_AUTO) {
id = ps3av_auto_videomode(&ps3av->av_hw_conf); if (id < 1) {
printk(KERN_ERR "%s: invalid id :%d\n", __func__, id); return -EINVAL;
}
id |= option;
}
/* set videomode */
wait_for_completion(&ps3av->done);
ps3av->ps3av_mode_old = ps3av->ps3av_mode;
ps3av->ps3av_mode = id; if (ps3av_set_videomode())
ps3av->ps3av_mode = ps3av->ps3av_mode_old;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.