2019-05-27 09:55:12 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2007-02-12 11:55:16 +03:00
/*
* Copyright ( C ) 2006 Sony Computer Entertainment Inc .
* Copyright 2006 , 2007 Sony Corporation
*
* AV backend support for PS3
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/delay.h>
2009-06-10 08:38:48 +04:00
2007-02-12 11:55:16 +03:00
# include <asm/ps3av.h>
# include <asm/ps3.h>
2009-06-10 08:38:48 +04:00
# include <asm/ps3gpu.h>
2007-02-12 11:55:16 +03:00
# include "vuart.h"
static const struct video_fmt {
u32 format ;
u32 order ;
} ps3av_video_fmt_table [ ] = {
{ PS3AV_CMD_VIDEO_FORMAT_ARGB_8BIT , PS3AV_CMD_VIDEO_ORDER_RGB } ,
{ PS3AV_CMD_VIDEO_FORMAT_ARGB_8BIT , PS3AV_CMD_VIDEO_ORDER_BGR } ,
} ;
static const struct {
int cs ;
u32 av ;
u32 bl ;
} ps3av_cs_video2av_table [ ] = {
{
. cs = PS3AV_CMD_VIDEO_CS_RGB_8 ,
. av = PS3AV_CMD_AV_CS_RGB_8 ,
. bl = PS3AV_CMD_AV_CS_8
} , {
. cs = PS3AV_CMD_VIDEO_CS_RGB_10 ,
. av = PS3AV_CMD_AV_CS_RGB_8 ,
. bl = PS3AV_CMD_AV_CS_8
} , {
. cs = PS3AV_CMD_VIDEO_CS_RGB_12 ,
. av = PS3AV_CMD_AV_CS_RGB_8 ,
. bl = PS3AV_CMD_AV_CS_8
} , {
. cs = PS3AV_CMD_VIDEO_CS_YUV444_8 ,
. av = PS3AV_CMD_AV_CS_YUV444_8 ,
. bl = PS3AV_CMD_AV_CS_8
} , {
. cs = PS3AV_CMD_VIDEO_CS_YUV444_10 ,
. av = PS3AV_CMD_AV_CS_YUV444_8 ,
. bl = PS3AV_CMD_AV_CS_10
} , {
. cs = PS3AV_CMD_VIDEO_CS_YUV444_12 ,
. av = PS3AV_CMD_AV_CS_YUV444_8 ,
. bl = PS3AV_CMD_AV_CS_10
} , {
. cs = PS3AV_CMD_VIDEO_CS_YUV422_8 ,
. av = PS3AV_CMD_AV_CS_YUV422_8 ,
. bl = PS3AV_CMD_AV_CS_10
} , {
. cs = PS3AV_CMD_VIDEO_CS_YUV422_10 ,
. av = PS3AV_CMD_AV_CS_YUV422_8 ,
. bl = PS3AV_CMD_AV_CS_10
} , {
. cs = PS3AV_CMD_VIDEO_CS_YUV422_12 ,
. av = PS3AV_CMD_AV_CS_YUV422_8 ,
. bl = PS3AV_CMD_AV_CS_12
} , {
. cs = PS3AV_CMD_VIDEO_CS_XVYCC_8 ,
. av = PS3AV_CMD_AV_CS_XVYCC_8 ,
. bl = PS3AV_CMD_AV_CS_12
} , {
. cs = PS3AV_CMD_VIDEO_CS_XVYCC_10 ,
. av = PS3AV_CMD_AV_CS_XVYCC_8 ,
. bl = PS3AV_CMD_AV_CS_12
} , {
. cs = PS3AV_CMD_VIDEO_CS_XVYCC_12 ,
. av = PS3AV_CMD_AV_CS_XVYCC_8 ,
. bl = PS3AV_CMD_AV_CS_12
}
} ;
static u32 ps3av_cs_video2av ( int cs )
{
unsigned int i ;
for ( i = 0 ; i < ARRAY_SIZE ( ps3av_cs_video2av_table ) ; i + + )
if ( ps3av_cs_video2av_table [ i ] . cs = = cs )
return ps3av_cs_video2av_table [ i ] . av ;
return PS3AV_CMD_AV_CS_RGB_8 ;
}
static u32 ps3av_cs_video2av_bitlen ( int cs )
{
unsigned int i ;
for ( i = 0 ; i < ARRAY_SIZE ( ps3av_cs_video2av_table ) ; i + + )
if ( ps3av_cs_video2av_table [ i ] . cs = = cs )
return ps3av_cs_video2av_table [ i ] . bl ;
return PS3AV_CMD_AV_CS_8 ;
}
static const struct {
int vid ;
u32 av ;
} ps3av_vid_video2av_table [ ] = {
{ PS3AV_CMD_VIDEO_VID_480I , PS3AV_CMD_AV_VID_480I } ,
{ PS3AV_CMD_VIDEO_VID_480P , PS3AV_CMD_AV_VID_480P } ,
{ PS3AV_CMD_VIDEO_VID_576I , PS3AV_CMD_AV_VID_576I } ,
{ PS3AV_CMD_VIDEO_VID_576P , PS3AV_CMD_AV_VID_576P } ,
{ PS3AV_CMD_VIDEO_VID_1080I_60HZ , PS3AV_CMD_AV_VID_1080I_60HZ } ,
{ PS3AV_CMD_VIDEO_VID_720P_60HZ , PS3AV_CMD_AV_VID_720P_60HZ } ,
{ PS3AV_CMD_VIDEO_VID_1080P_60HZ , PS3AV_CMD_AV_VID_1080P_60HZ } ,
{ PS3AV_CMD_VIDEO_VID_1080I_50HZ , PS3AV_CMD_AV_VID_1080I_50HZ } ,
{ PS3AV_CMD_VIDEO_VID_720P_50HZ , PS3AV_CMD_AV_VID_720P_50HZ } ,
{ PS3AV_CMD_VIDEO_VID_1080P_50HZ , PS3AV_CMD_AV_VID_1080P_50HZ } ,
{ PS3AV_CMD_VIDEO_VID_WXGA , PS3AV_CMD_AV_VID_WXGA } ,
{ PS3AV_CMD_VIDEO_VID_SXGA , PS3AV_CMD_AV_VID_SXGA } ,
{ PS3AV_CMD_VIDEO_VID_WUXGA , PS3AV_CMD_AV_VID_WUXGA }
} ;
static u32 ps3av_vid_video2av ( int vid )
{
unsigned int i ;
for ( i = 0 ; i < ARRAY_SIZE ( ps3av_vid_video2av_table ) ; i + + )
if ( ps3av_vid_video2av_table [ i ] . vid = = vid )
return ps3av_vid_video2av_table [ i ] . av ;
return PS3AV_CMD_AV_VID_480P ;
}
2007-06-16 01:19:10 +04:00
static int ps3av_hdmi_range ( void )
{
if ( ps3_compare_firmware_version ( 1 , 8 , 0 ) < 0 )
return 0 ;
else
return 1 ; /* supported */
}
2007-02-12 11:55:16 +03:00
int ps3av_cmd_init ( void )
{
int res ;
struct ps3av_pkt_av_init av_init ;
struct ps3av_pkt_video_init video_init ;
struct ps3av_pkt_audio_init audio_init ;
/* video init */
memset ( & video_init , 0 , sizeof ( video_init ) ) ;
res = ps3av_do_pkt ( PS3AV_CID_VIDEO_INIT , sizeof ( video_init . send_hdr ) ,
sizeof ( video_init ) , & video_init . send_hdr ) ;
if ( res < 0 )
return res ;
res = get_status ( & video_init ) ;
if ( res ) {
printk ( KERN_ERR " PS3AV_CID_VIDEO_INIT: failed %x \n " , res ) ;
return res ;
}
/* audio init */
memset ( & audio_init , 0 , sizeof ( audio_init ) ) ;
res = ps3av_do_pkt ( PS3AV_CID_AUDIO_INIT , sizeof ( audio_init . send_hdr ) ,
sizeof ( audio_init ) , & audio_init . send_hdr ) ;
if ( res < 0 )
return res ;
res = get_status ( & audio_init ) ;
if ( res ) {
printk ( KERN_ERR " PS3AV_CID_AUDIO_INIT: failed %x \n " , res ) ;
return res ;
}
/* av init */
memset ( & av_init , 0 , sizeof ( av_init ) ) ;
av_init . event_bit = 0 ;
res = ps3av_do_pkt ( PS3AV_CID_AV_INIT , sizeof ( av_init ) , sizeof ( av_init ) ,
& av_init . send_hdr ) ;
if ( res < 0 )
return res ;
res = get_status ( & av_init ) ;
if ( res )
printk ( KERN_ERR " PS3AV_CID_AV_INIT: failed %x \n " , res ) ;
return res ;
}
int ps3av_cmd_fin ( void )
{
int res ;
struct ps3av_pkt_av_fin av_fin ;
memset ( & av_fin , 0 , sizeof ( av_fin ) ) ;
res = ps3av_do_pkt ( PS3AV_CID_AV_FIN , sizeof ( av_fin . send_hdr ) ,
sizeof ( av_fin ) , & av_fin . send_hdr ) ;
if ( res < 0 )
return res ;
res = get_status ( & av_fin ) ;
if ( res )
printk ( KERN_ERR " PS3AV_CID_AV_FIN: failed %x \n " , res ) ;
return res ;
}
int ps3av_cmd_av_video_mute ( int num_of_port , u32 * port , u32 mute )
{
int i , send_len , res ;
struct ps3av_pkt_av_video_mute av_video_mute ;
if ( num_of_port > PS3AV_MUTE_PORT_MAX )
return - EINVAL ;
memset ( & av_video_mute , 0 , sizeof ( av_video_mute ) ) ;
for ( i = 0 ; i < num_of_port ; i + + ) {
av_video_mute . mute [ i ] . avport = port [ i ] ;
av_video_mute . mute [ i ] . mute = mute ;
}
send_len = sizeof ( av_video_mute . send_hdr ) +
sizeof ( struct ps3av_av_mute ) * num_of_port ;
res = ps3av_do_pkt ( PS3AV_CID_AV_VIDEO_MUTE , send_len ,
sizeof ( av_video_mute ) , & av_video_mute . send_hdr ) ;
if ( res < 0 )
return res ;
res = get_status ( & av_video_mute ) ;
if ( res )
printk ( KERN_ERR " PS3AV_CID_AV_VIDEO_MUTE: failed %x \n " , res ) ;
return res ;
}
int ps3av_cmd_av_video_disable_sig ( u32 port )
{
int res ;
struct ps3av_pkt_av_video_disable_sig av_video_sig ;
memset ( & av_video_sig , 0 , sizeof ( av_video_sig ) ) ;
av_video_sig . avport = port ;
res = ps3av_do_pkt ( PS3AV_CID_AV_VIDEO_DISABLE_SIG ,
sizeof ( av_video_sig ) , sizeof ( av_video_sig ) ,
& av_video_sig . send_hdr ) ;
if ( res < 0 )
return res ;
res = get_status ( & av_video_sig ) ;
if ( res )
printk ( KERN_ERR
" PS3AV_CID_AV_VIDEO_DISABLE_SIG: failed %x port:%x \n " ,
res , port ) ;
return res ;
}
int ps3av_cmd_av_tv_mute ( u32 avport , u32 mute )
{
int res ;
struct ps3av_pkt_av_tv_mute tv_mute ;
memset ( & tv_mute , 0 , sizeof ( tv_mute ) ) ;
tv_mute . avport = avport ;
tv_mute . mute = mute ;
res = ps3av_do_pkt ( PS3AV_CID_AV_TV_MUTE , sizeof ( tv_mute ) ,
sizeof ( tv_mute ) , & tv_mute . send_hdr ) ;
if ( res < 0 )
return res ;
res = get_status ( & tv_mute ) ;
if ( res )
printk ( KERN_ERR " PS3AV_CID_AV_TV_MUTE: failed %x port:%x \n " ,
res , avport ) ;
return res ;
}
int ps3av_cmd_enable_event ( void )
{
int res ;
struct ps3av_pkt_av_event av_event ;
memset ( & av_event , 0 , sizeof ( av_event ) ) ;
av_event . event_bit = PS3AV_CMD_EVENT_BIT_UNPLUGGED |
PS3AV_CMD_EVENT_BIT_PLUGGED | PS3AV_CMD_EVENT_BIT_HDCP_DONE ;
res = ps3av_do_pkt ( PS3AV_CID_AV_ENABLE_EVENT , sizeof ( av_event ) ,
sizeof ( av_event ) , & av_event . send_hdr ) ;
if ( res < 0 )
return res ;
res = get_status ( & av_event ) ;
if ( res )
printk ( KERN_ERR " PS3AV_CID_AV_ENABLE_EVENT: failed %x \n " , res ) ;
return res ;
}
int ps3av_cmd_av_hdmi_mode ( u8 mode )
{
int res ;
struct ps3av_pkt_av_hdmi_mode hdmi_mode ;
memset ( & hdmi_mode , 0 , sizeof ( hdmi_mode ) ) ;
hdmi_mode . mode = mode ;
res = ps3av_do_pkt ( PS3AV_CID_AV_HDMI_MODE , sizeof ( hdmi_mode ) ,
sizeof ( hdmi_mode ) , & hdmi_mode . send_hdr ) ;
if ( res < 0 )
return res ;
res = get_status ( & hdmi_mode ) ;
if ( res & & res ! = PS3AV_STATUS_UNSUPPORTED_HDMI_MODE )
printk ( KERN_ERR " PS3AV_CID_AV_HDMI_MODE: failed %x \n " , res ) ;
return res ;
}
u32 ps3av_cmd_set_av_video_cs ( void * p , u32 avport , int video_vid , int cs_out ,
int aspect , u32 id )
{
struct ps3av_pkt_av_video_cs * av_video_cs ;
av_video_cs = ( struct ps3av_pkt_av_video_cs * ) p ;
if ( video_vid = = - 1 )
video_vid = PS3AV_CMD_VIDEO_VID_720P_60HZ ;
if ( cs_out = = - 1 )
cs_out = PS3AV_CMD_VIDEO_CS_YUV444_8 ;
if ( aspect = = - 1 )
aspect = 0 ;
memset ( av_video_cs , 0 , sizeof ( * av_video_cs ) ) ;
ps3av_set_hdr ( PS3AV_CID_AV_VIDEO_CS , sizeof ( * av_video_cs ) ,
& av_video_cs - > send_hdr ) ;
av_video_cs - > avport = avport ;
/* should be same as video_mode.resolution */
av_video_cs - > av_vid = ps3av_vid_video2av ( video_vid ) ;
av_video_cs - > av_cs_out = ps3av_cs_video2av ( cs_out ) ;
/* should be same as video_mode.video_cs_out */
av_video_cs - > av_cs_in = ps3av_cs_video2av ( PS3AV_CMD_VIDEO_CS_RGB_8 ) ;
av_video_cs - > bitlen_out = ps3av_cs_video2av_bitlen ( cs_out ) ;
2007-06-16 01:19:10 +04:00
if ( ( id & PS3AV_MODE_WHITE ) & & ps3av_hdmi_range ( ) )
av_video_cs - > super_white = PS3AV_CMD_AV_SUPER_WHITE_ON ;
else /* default off */
av_video_cs - > super_white = PS3AV_CMD_AV_SUPER_WHITE_OFF ;
2007-02-12 11:55:16 +03:00
av_video_cs - > aspect = aspect ;
if ( id & PS3AV_MODE_DITHER ) {
av_video_cs - > dither = PS3AV_CMD_AV_DITHER_ON
| PS3AV_CMD_AV_DITHER_8BIT ;
} else {
/* default off */
av_video_cs - > dither = PS3AV_CMD_AV_DITHER_OFF ;
}
return sizeof ( * av_video_cs ) ;
}
u32 ps3av_cmd_set_video_mode ( void * p , u32 head , int video_vid , int video_fmt ,
u32 id )
{
struct ps3av_pkt_video_mode * video_mode ;
u32 x , y ;
video_mode = ( struct ps3av_pkt_video_mode * ) p ;
if ( video_vid = = - 1 )
video_vid = PS3AV_CMD_VIDEO_VID_720P_60HZ ;
if ( video_fmt = = - 1 )
video_fmt = PS3AV_CMD_VIDEO_FMT_X8R8G8B8 ;
if ( ps3av_video_mode2res ( id , & x , & y ) )
return 0 ;
/* video mode */
memset ( video_mode , 0 , sizeof ( * video_mode ) ) ;
ps3av_set_hdr ( PS3AV_CID_VIDEO_MODE , sizeof ( * video_mode ) ,
& video_mode - > send_hdr ) ;
video_mode - > video_head = head ;
if ( video_vid = = PS3AV_CMD_VIDEO_VID_480I
& & head = = PS3AV_CMD_VIDEO_HEAD_B )
video_mode - > video_vid = PS3AV_CMD_VIDEO_VID_480I_A ;
else
video_mode - > video_vid = video_vid ;
video_mode - > width = ( u16 ) x ;
video_mode - > height = ( u16 ) y ;
video_mode - > pitch = video_mode - > width * 4 ; /* line_length */
video_mode - > video_out_format = PS3AV_CMD_VIDEO_OUT_FORMAT_RGB_12BIT ;
video_mode - > video_format = ps3av_video_fmt_table [ video_fmt ] . format ;
2007-06-16 01:19:10 +04:00
if ( ( id & PS3AV_MODE_COLOR ) & & ps3av_hdmi_range ( ) )
video_mode - > video_cl_cnv = PS3AV_CMD_VIDEO_CL_CNV_DISABLE_LUT ;
else /* default enable */
video_mode - > video_cl_cnv = PS3AV_CMD_VIDEO_CL_CNV_ENABLE_LUT ;
2007-02-12 11:55:16 +03:00
video_mode - > video_order = ps3av_video_fmt_table [ video_fmt ] . order ;
pr_debug ( " %s: video_mode:vid:%x width:%d height:%d pitch:%d out_format:%d format:%x order:%x \n " ,
2007-05-02 16:48:38 +04:00
__func__ , video_vid , video_mode - > width , video_mode - > height ,
2007-02-12 11:55:16 +03:00
video_mode - > pitch , video_mode - > video_out_format ,
video_mode - > video_format , video_mode - > video_order ) ;
return sizeof ( * video_mode ) ;
}
int ps3av_cmd_video_format_black ( u32 head , u32 video_fmt , u32 mute )
{
int res ;
struct ps3av_pkt_video_format video_format ;
memset ( & video_format , 0 , sizeof ( video_format ) ) ;
video_format . video_head = head ;
if ( mute ! = PS3AV_CMD_MUTE_OFF )
video_format . video_format = PS3AV_CMD_VIDEO_FORMAT_BLACK ;
else
video_format . video_format =
ps3av_video_fmt_table [ video_fmt ] . format ;
video_format . video_order = ps3av_video_fmt_table [ video_fmt ] . order ;
res = ps3av_do_pkt ( PS3AV_CID_VIDEO_FORMAT , sizeof ( video_format ) ,
sizeof ( video_format ) , & video_format . send_hdr ) ;
if ( res < 0 )
return res ;
res = get_status ( & video_format ) ;
if ( res )
printk ( KERN_ERR " PS3AV_CID_VIDEO_FORMAT: failed %x \n " , res ) ;
return res ;
}
int ps3av_cmd_av_audio_mute ( int num_of_port , u32 * port , u32 mute )
{
int i , res ;
struct ps3av_pkt_av_audio_mute av_audio_mute ;
if ( num_of_port > PS3AV_MUTE_PORT_MAX )
return - EINVAL ;
/* audio mute */
memset ( & av_audio_mute , 0 , sizeof ( av_audio_mute ) ) ;
for ( i = 0 ; i < num_of_port ; i + + ) {
av_audio_mute . mute [ i ] . avport = port [ i ] ;
av_audio_mute . mute [ i ] . mute = mute ;
}
res = ps3av_do_pkt ( PS3AV_CID_AV_AUDIO_MUTE ,
sizeof ( av_audio_mute . send_hdr ) +
sizeof ( struct ps3av_av_mute ) * num_of_port ,
sizeof ( av_audio_mute ) , & av_audio_mute . send_hdr ) ;
if ( res < 0 )
return res ;
res = get_status ( & av_audio_mute ) ;
if ( res )
printk ( KERN_ERR " PS3AV_CID_AV_AUDIO_MUTE: failed %x \n " , res ) ;
return res ;
}
static const struct {
u32 fs ;
u8 mclk ;
} ps3av_cnv_mclk_table [ ] = {
{ PS3AV_CMD_AUDIO_FS_44K , PS3AV_CMD_AV_MCLK_512 } ,
{ PS3AV_CMD_AUDIO_FS_48K , PS3AV_CMD_AV_MCLK_512 } ,
{ PS3AV_CMD_AUDIO_FS_88K , PS3AV_CMD_AV_MCLK_256 } ,
{ PS3AV_CMD_AUDIO_FS_96K , PS3AV_CMD_AV_MCLK_256 } ,
{ PS3AV_CMD_AUDIO_FS_176K , PS3AV_CMD_AV_MCLK_128 } ,
{ PS3AV_CMD_AUDIO_FS_192K , PS3AV_CMD_AV_MCLK_128 }
} ;
static u8 ps3av_cnv_mclk ( u32 fs )
{
unsigned int i ;
for ( i = 0 ; i < ARRAY_SIZE ( ps3av_cnv_mclk_table ) ; i + + )
if ( ps3av_cnv_mclk_table [ i ] . fs = = fs )
return ps3av_cnv_mclk_table [ i ] . mclk ;
2007-05-02 16:48:38 +04:00
printk ( KERN_ERR " %s failed, fs:%x \n " , __func__ , fs ) ;
2007-02-12 11:55:16 +03:00
return 0 ;
}
# define BASE PS3AV_CMD_AUDIO_FS_44K
static const u32 ps3av_ns_table [ ] [ 5 ] = {
/* D1, D2, D3, D4, D5 */
2007-03-14 12:19:30 +03:00
[ PS3AV_CMD_AUDIO_FS_44K - BASE ] = { 6272 , 6272 , 17836 , 17836 , 8918 } ,
[ PS3AV_CMD_AUDIO_FS_48K - BASE ] = { 6144 , 6144 , 11648 , 11648 , 5824 } ,
[ PS3AV_CMD_AUDIO_FS_88K - BASE ] = { 12544 , 12544 , 35672 , 35672 , 17836 } ,
[ PS3AV_CMD_AUDIO_FS_96K - BASE ] = { 12288 , 12288 , 23296 , 23296 , 11648 } ,
[ PS3AV_CMD_AUDIO_FS_176K - BASE ] = { 25088 , 25088 , 71344 , 71344 , 35672 } ,
[ PS3AV_CMD_AUDIO_FS_192K - BASE ] = { 24576 , 24576 , 46592 , 46592 , 23296 }
2007-02-12 11:55:16 +03:00
} ;
static void ps3av_cnv_ns ( u8 * ns , u32 fs , u32 video_vid )
{
u32 av_vid , ns_val ;
int d ;
d = ns_val = 0 ;
av_vid = ps3av_vid_video2av ( video_vid ) ;
switch ( av_vid ) {
case PS3AV_CMD_AV_VID_480I :
case PS3AV_CMD_AV_VID_576I :
d = 0 ;
break ;
case PS3AV_CMD_AV_VID_480P :
case PS3AV_CMD_AV_VID_576P :
d = 1 ;
break ;
case PS3AV_CMD_AV_VID_1080I_60HZ :
case PS3AV_CMD_AV_VID_1080I_50HZ :
d = 2 ;
break ;
case PS3AV_CMD_AV_VID_720P_60HZ :
case PS3AV_CMD_AV_VID_720P_50HZ :
d = 3 ;
break ;
case PS3AV_CMD_AV_VID_1080P_60HZ :
case PS3AV_CMD_AV_VID_1080P_50HZ :
case PS3AV_CMD_AV_VID_WXGA :
case PS3AV_CMD_AV_VID_SXGA :
case PS3AV_CMD_AV_VID_WUXGA :
d = 4 ;
break ;
default :
2007-05-02 16:48:38 +04:00
printk ( KERN_ERR " %s failed, vid:%x \n " , __func__ , video_vid ) ;
2007-02-12 11:55:16 +03:00
break ;
}
if ( fs < PS3AV_CMD_AUDIO_FS_44K | | fs > PS3AV_CMD_AUDIO_FS_192K )
2007-05-02 16:48:38 +04:00
printk ( KERN_ERR " %s failed, fs:%x \n " , __func__ , fs ) ;
2007-02-12 11:55:16 +03:00
else
ns_val = ps3av_ns_table [ PS3AV_CMD_AUDIO_FS_44K - BASE ] [ d ] ;
2007-10-16 12:29:40 +04:00
* ns + + = ns_val & 0x000000FF ;
* ns + + = ( ns_val & 0x0000FF00 ) > > 8 ;
* ns = ( ns_val & 0x00FF0000 ) > > 16 ;
2007-02-12 11:55:16 +03:00
}
# undef BASE
2007-03-14 12:19:30 +03:00
static u8 ps3av_cnv_enable ( u32 source , const u8 * enable )
2007-02-12 11:55:16 +03:00
{
2007-03-14 12:19:30 +03:00
u8 ret = 0 ;
2007-02-12 11:55:16 +03:00
if ( source = = PS3AV_CMD_AUDIO_SOURCE_SPDIF ) {
ret = 0x03 ;
} else if ( source = = PS3AV_CMD_AUDIO_SOURCE_SERIAL ) {
2007-10-16 12:29:40 +04:00
ret = ( ( enable [ 0 ] < < 4 ) + ( enable [ 1 ] < < 5 ) + ( enable [ 2 ] < < 6 ) +
( enable [ 3 ] < < 7 ) ) | 0x01 ;
2007-02-12 11:55:16 +03:00
} else
2007-05-02 16:48:38 +04:00
printk ( KERN_ERR " %s failed, source:%x \n " , __func__ , source ) ;
2007-02-12 11:55:16 +03:00
return ret ;
}
2007-03-14 12:19:30 +03:00
static u8 ps3av_cnv_fifomap ( const u8 * map )
2007-02-12 11:55:16 +03:00
{
2007-03-14 12:19:30 +03:00
u8 ret = 0 ;
2007-02-12 11:55:16 +03:00
2007-10-16 12:29:40 +04:00
ret = map [ 0 ] + ( map [ 1 ] < < 2 ) + ( map [ 2 ] < < 4 ) + ( map [ 3 ] < < 6 ) ;
2007-02-12 11:55:16 +03:00
return ret ;
}
static u8 ps3av_cnv_inputlen ( u32 word_bits )
{
u8 ret = 0 ;
switch ( word_bits ) {
case PS3AV_CMD_AUDIO_WORD_BITS_16 :
ret = PS3AV_CMD_AV_INPUTLEN_16 ;
break ;
case PS3AV_CMD_AUDIO_WORD_BITS_20 :
ret = PS3AV_CMD_AV_INPUTLEN_20 ;
break ;
case PS3AV_CMD_AUDIO_WORD_BITS_24 :
ret = PS3AV_CMD_AV_INPUTLEN_24 ;
break ;
default :
2007-05-02 16:48:38 +04:00
printk ( KERN_ERR " %s failed, word_bits:%x \n " , __func__ ,
2007-02-12 11:55:16 +03:00
word_bits ) ;
break ;
}
return ret ;
}
static u8 ps3av_cnv_layout ( u32 num_of_ch )
{
if ( num_of_ch > PS3AV_CMD_AUDIO_NUM_OF_CH_8 ) {
2007-05-02 16:48:38 +04:00
printk ( KERN_ERR " %s failed, num_of_ch:%x \n " , __func__ ,
2007-02-12 11:55:16 +03:00
num_of_ch ) ;
return 0 ;
}
return num_of_ch = = PS3AV_CMD_AUDIO_NUM_OF_CH_2 ? 0x0 : 0x1 ;
}
static void ps3av_cnv_info ( struct ps3av_audio_info_frame * info ,
const struct ps3av_pkt_audio_mode * mode )
{
info - > pb1 . cc = mode - > audio_num_of_ch + 1 ; /* CH2:0x01 --- CH8:0x07 */
info - > pb1 . ct = 0 ;
info - > pb2 . sf = 0 ;
info - > pb2 . ss = 0 ;
info - > pb3 = 0 ; /* check mode->audio_format ?? */
info - > pb4 = mode - > audio_layout ;
info - > pb5 . dm = mode - > audio_downmix ;
info - > pb5 . lsv = mode - > audio_downmix_level ;
}
2007-03-14 12:19:30 +03:00
static void ps3av_cnv_chstat ( u8 * chstat , const u8 * cs_info )
2007-02-12 11:55:16 +03:00
{
memcpy ( chstat , cs_info , 5 ) ;
}
u32 ps3av_cmd_set_av_audio_param ( void * p , u32 port ,
const struct ps3av_pkt_audio_mode * audio_mode ,
u32 video_vid )
{
struct ps3av_pkt_av_audio_param * param ;
param = ( struct ps3av_pkt_av_audio_param * ) p ;
memset ( param , 0 , sizeof ( * param ) ) ;
ps3av_set_hdr ( PS3AV_CID_AV_AUDIO_PARAM , sizeof ( * param ) ,
& param - > send_hdr ) ;
param - > avport = port ;
param - > mclk = ps3av_cnv_mclk ( audio_mode - > audio_fs ) | 0x80 ;
ps3av_cnv_ns ( param - > ns , audio_mode - > audio_fs , video_vid ) ;
param - > enable = ps3av_cnv_enable ( audio_mode - > audio_source ,
audio_mode - > audio_enable ) ;
param - > swaplr = 0x09 ;
param - > fifomap = ps3av_cnv_fifomap ( audio_mode - > audio_map ) ;
param - > inputctrl = 0x49 ;
param - > inputlen = ps3av_cnv_inputlen ( audio_mode - > audio_word_bits ) ;
param - > layout = ps3av_cnv_layout ( audio_mode - > audio_num_of_ch ) ;
ps3av_cnv_info ( & param - > info , audio_mode ) ;
ps3av_cnv_chstat ( param - > chstat , audio_mode - > audio_cs_info ) ;
return sizeof ( * param ) ;
}
/* default cs val */
2008-10-20 10:05:10 +04:00
u8 ps3av_mode_cs_info [ ] = {
2007-02-12 11:55:16 +03:00
0x00 , 0x09 , 0x00 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00
} ;
2008-10-20 10:05:10 +04:00
EXPORT_SYMBOL_GPL ( ps3av_mode_cs_info ) ;
2007-02-12 11:55:16 +03:00
# define CS_44 0x00
# define CS_48 0x02
# define CS_88 0x08
# define CS_96 0x0a
# define CS_176 0x0c
# define CS_192 0x0e
# define CS_MASK 0x0f
# define CS_BIT 0x40
void ps3av_cmd_set_audio_mode ( struct ps3av_pkt_audio_mode * audio , u32 avport ,
u32 ch , u32 fs , u32 word_bits , u32 format ,
u32 source )
{
2008-10-20 10:05:10 +04:00
int spdif_through ;
2007-02-12 11:55:16 +03:00
int i ;
if ( ! ( ch | fs | format | word_bits | source ) ) {
ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2 ;
fs = PS3AV_CMD_AUDIO_FS_48K ;
word_bits = PS3AV_CMD_AUDIO_WORD_BITS_16 ;
format = PS3AV_CMD_AUDIO_FORMAT_PCM ;
source = PS3AV_CMD_AUDIO_SOURCE_SERIAL ;
}
/* audio mode */
memset ( audio , 0 , sizeof ( * audio ) ) ;
ps3av_set_hdr ( PS3AV_CID_AUDIO_MODE , sizeof ( * audio ) , & audio - > send_hdr ) ;
audio - > avport = ( u8 ) avport ;
audio - > mask = 0x0FFF ; /* XXX set all */
audio - > audio_num_of_ch = ch ;
audio - > audio_fs = fs ;
audio - > audio_word_bits = word_bits ;
audio - > audio_format = format ;
audio - > audio_source = source ;
switch ( ch ) {
case PS3AV_CMD_AUDIO_NUM_OF_CH_8 :
audio - > audio_enable [ 3 ] = 1 ;
2020-08-24 01:36:59 +03:00
fallthrough ;
2007-02-12 11:55:16 +03:00
case PS3AV_CMD_AUDIO_NUM_OF_CH_6 :
audio - > audio_enable [ 2 ] = 1 ;
audio - > audio_enable [ 1 ] = 1 ;
2020-08-24 01:36:59 +03:00
fallthrough ;
2007-02-12 11:55:16 +03:00
case PS3AV_CMD_AUDIO_NUM_OF_CH_2 :
default :
audio - > audio_enable [ 0 ] = 1 ;
}
/* audio swap L/R */
for ( i = 0 ; i < 4 ; i + + )
audio - > audio_swap [ i ] = PS3AV_CMD_AUDIO_SWAP_0 ; /* no swap */
/* audio serial input mapping */
audio - > audio_map [ 0 ] = PS3AV_CMD_AUDIO_MAP_OUTPUT_0 ;
audio - > audio_map [ 1 ] = PS3AV_CMD_AUDIO_MAP_OUTPUT_1 ;
audio - > audio_map [ 2 ] = PS3AV_CMD_AUDIO_MAP_OUTPUT_2 ;
audio - > audio_map [ 3 ] = PS3AV_CMD_AUDIO_MAP_OUTPUT_3 ;
/* audio speaker layout */
if ( avport = = PS3AV_CMD_AVPORT_HDMI_0 | |
avport = = PS3AV_CMD_AVPORT_HDMI_1 ) {
switch ( ch ) {
case PS3AV_CMD_AUDIO_NUM_OF_CH_8 :
audio - > audio_layout = PS3AV_CMD_AUDIO_LAYOUT_8CH ;
break ;
case PS3AV_CMD_AUDIO_NUM_OF_CH_6 :
audio - > audio_layout = PS3AV_CMD_AUDIO_LAYOUT_6CH ;
break ;
case PS3AV_CMD_AUDIO_NUM_OF_CH_2 :
default :
audio - > audio_layout = PS3AV_CMD_AUDIO_LAYOUT_2CH ;
break ;
}
} else {
audio - > audio_layout = PS3AV_CMD_AUDIO_LAYOUT_2CH ;
}
/* audio downmix permission */
audio - > audio_downmix = PS3AV_CMD_AUDIO_DOWNMIX_PERMITTED ;
/* audio downmix level shift (0:0dB to 15:15dB) */
audio - > audio_downmix_level = 0 ; /* 0dB */
/* set ch status */
for ( i = 0 ; i < 8 ; i + + )
audio - > audio_cs_info [ i ] = ps3av_mode_cs_info [ i ] ;
switch ( fs ) {
case PS3AV_CMD_AUDIO_FS_44K :
audio - > audio_cs_info [ 3 ] & = ~ CS_MASK ;
audio - > audio_cs_info [ 3 ] | = CS_44 ;
break ;
case PS3AV_CMD_AUDIO_FS_88K :
audio - > audio_cs_info [ 3 ] & = ~ CS_MASK ;
audio - > audio_cs_info [ 3 ] | = CS_88 ;
break ;
case PS3AV_CMD_AUDIO_FS_96K :
audio - > audio_cs_info [ 3 ] & = ~ CS_MASK ;
audio - > audio_cs_info [ 3 ] | = CS_96 ;
break ;
case PS3AV_CMD_AUDIO_FS_176K :
audio - > audio_cs_info [ 3 ] & = ~ CS_MASK ;
audio - > audio_cs_info [ 3 ] | = CS_176 ;
break ;
case PS3AV_CMD_AUDIO_FS_192K :
audio - > audio_cs_info [ 3 ] & = ~ CS_MASK ;
audio - > audio_cs_info [ 3 ] | = CS_192 ;
break ;
default :
break ;
}
2008-10-20 10:05:10 +04:00
/* non-audio bit */
spdif_through = audio - > audio_cs_info [ 0 ] & 0x02 ;
2007-02-12 11:55:16 +03:00
/* pass through setting */
if ( spdif_through & &
( avport = = PS3AV_CMD_AVPORT_SPDIF_0 | |
2008-10-20 10:05:10 +04:00
avport = = PS3AV_CMD_AVPORT_SPDIF_1 | |
avport = = PS3AV_CMD_AVPORT_HDMI_0 | |
avport = = PS3AV_CMD_AVPORT_HDMI_1 ) ) {
2007-02-12 11:55:16 +03:00
audio - > audio_word_bits = PS3AV_CMD_AUDIO_WORD_BITS_16 ;
2008-10-20 10:05:10 +04:00
audio - > audio_format = PS3AV_CMD_AUDIO_FORMAT_BITSTREAM ;
2007-02-12 11:55:16 +03:00
}
}
int ps3av_cmd_audio_mode ( struct ps3av_pkt_audio_mode * audio_mode )
{
int res ;
res = ps3av_do_pkt ( PS3AV_CID_AUDIO_MODE , sizeof ( * audio_mode ) ,
sizeof ( * audio_mode ) , & audio_mode - > send_hdr ) ;
if ( res < 0 )
return res ;
res = get_status ( audio_mode ) ;
if ( res )
printk ( KERN_ERR " PS3AV_CID_AUDIO_MODE: failed %x \n " , res ) ;
return res ;
}
int ps3av_cmd_audio_mute ( int num_of_port , u32 * port , u32 mute )
{
int i , res ;
struct ps3av_pkt_audio_mute audio_mute ;
if ( num_of_port > PS3AV_OPT_PORT_MAX )
return - EINVAL ;
/* audio mute */
memset ( & audio_mute , 0 , sizeof ( audio_mute ) ) ;
for ( i = 0 ; i < num_of_port ; i + + ) {
audio_mute . mute [ i ] . avport = port [ i ] ;
audio_mute . mute [ i ] . mute = mute ;
}
res = ps3av_do_pkt ( PS3AV_CID_AUDIO_MUTE ,
sizeof ( audio_mute . send_hdr ) +
sizeof ( struct ps3av_audio_mute ) * num_of_port ,
sizeof ( audio_mute ) , & audio_mute . send_hdr ) ;
if ( res < 0 )
return res ;
res = get_status ( & audio_mute ) ;
if ( res )
printk ( KERN_ERR " PS3AV_CID_AUDIO_MUTE: failed %x \n " , res ) ;
return res ;
}
int ps3av_cmd_audio_active ( int active , u32 port )
{
int res ;
struct ps3av_pkt_audio_active audio_active ;
u32 cid ;
/* audio active */
memset ( & audio_active , 0 , sizeof ( audio_active ) ) ;
audio_active . audio_port = port ;
cid = active ? PS3AV_CID_AUDIO_ACTIVE : PS3AV_CID_AUDIO_INACTIVE ;
res = ps3av_do_pkt ( cid , sizeof ( audio_active ) , sizeof ( audio_active ) ,
& audio_active . send_hdr ) ;
if ( res < 0 )
return res ;
res = get_status ( & audio_active ) ;
if ( res )
printk ( KERN_ERR " PS3AV_CID_AUDIO_ACTIVE:%x failed %x \n " , cid ,
res ) ;
return res ;
}
int ps3av_cmd_avb_param ( struct ps3av_pkt_avb_param * avb , u32 send_len )
{
int res ;
2008-10-30 11:12:58 +03:00
mutex_lock ( & ps3_gpu_mutex ) ;
2007-02-12 11:55:16 +03:00
2007-02-12 11:55:25 +03:00
/* avb packet */
2007-02-12 11:55:16 +03:00
res = ps3av_do_pkt ( PS3AV_CID_AVB_PARAM , send_len , sizeof ( * avb ) ,
& avb - > send_hdr ) ;
if ( res < 0 )
goto out ;
res = get_status ( avb ) ;
if ( res )
2007-05-02 16:48:38 +04:00
pr_debug ( " %s: PS3AV_CID_AVB_PARAM: failed %x \n " , __func__ ,
2007-02-12 11:55:16 +03:00
res ) ;
out :
2008-10-30 11:12:58 +03:00
mutex_unlock ( & ps3_gpu_mutex ) ;
2007-02-12 11:55:16 +03:00
return res ;
}
int ps3av_cmd_av_get_hw_conf ( struct ps3av_pkt_av_get_hw_conf * hw_conf )
{
int res ;
memset ( hw_conf , 0 , sizeof ( * hw_conf ) ) ;
res = ps3av_do_pkt ( PS3AV_CID_AV_GET_HW_CONF , sizeof ( hw_conf - > send_hdr ) ,
sizeof ( * hw_conf ) , & hw_conf - > send_hdr ) ;
if ( res < 0 )
return res ;
res = get_status ( hw_conf ) ;
if ( res )
printk ( KERN_ERR " PS3AV_CID_AV_GET_HW_CONF: failed %x \n " , res ) ;
return res ;
}
int ps3av_cmd_video_get_monitor_info ( struct ps3av_pkt_av_get_monitor_info * info ,
u32 avport )
{
int res ;
memset ( info , 0 , sizeof ( * info ) ) ;
info - > avport = avport ;
res = ps3av_do_pkt ( PS3AV_CID_AV_GET_MONITOR_INFO ,
sizeof ( info - > send_hdr ) + sizeof ( info - > avport ) +
sizeof ( info - > reserved ) ,
sizeof ( * info ) , & info - > send_hdr ) ;
if ( res < 0 )
return res ;
res = get_status ( info ) ;
if ( res )
printk ( KERN_ERR " PS3AV_CID_AV_GET_MONITOR_INFO: failed %x \n " ,
res ) ;
return res ;
}
# define PS3AV_AV_LAYOUT_0 (PS3AV_CMD_AV_LAYOUT_32 \
| PS3AV_CMD_AV_LAYOUT_44 \
| PS3AV_CMD_AV_LAYOUT_48 )
# define PS3AV_AV_LAYOUT_1 (PS3AV_AV_LAYOUT_0 \
| PS3AV_CMD_AV_LAYOUT_88 \
| PS3AV_CMD_AV_LAYOUT_96 \
| PS3AV_CMD_AV_LAYOUT_176 \
| PS3AV_CMD_AV_LAYOUT_192 )