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
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published
* by the Free Software Foundation ; version 2 of the License .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/delay.h>
# include <asm/ps3av.h>
2007-02-12 11:55:25 +03:00
# include <asm/ps3fb.h>
2007-02-12 11:55:16 +03:00
# include <asm/ps3.h>
# 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 ;
}
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 ) ;
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 ;
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 ;
u8 * p = ns ;
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 ] ;
* p + + = ns_val & 0x000000FF ;
* p + + = ( ns_val & 0x0000FF00 ) > > 8 ;
* p = ( ns_val & 0x00FF0000 ) > > 16 ;
}
# 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
const u8 * p ;
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 ) {
p = enable ;
ret = ( ( p [ 0 ] < < 4 ) + ( p [ 1 ] < < 5 ) + ( p [ 2 ] < < 6 ) + ( p [ 3 ] < < 7 ) ) |
0x01 ;
} 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
const u8 * p ;
u8 ret = 0 ;
2007-02-12 11:55:16 +03:00
p = map ;
ret = p [ 0 ] + ( p [ 1 ] < < 2 ) + ( p [ 2 ] < < 4 ) + ( p [ 3 ] < < 6 ) ;
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 */
static const u8 ps3av_mode_cs_info [ ] = {
0x00 , 0x09 , 0x00 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00
} ;
# 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 )
{
int spdif_through , spdif_bitstream ;
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 ;
}
spdif_through = spdif_bitstream = 0 ; /* XXX not supported */
/* 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 ;
/* fall through */
case PS3AV_CMD_AUDIO_NUM_OF_CH_6 :
audio - > audio_enable [ 2 ] = 1 ;
audio - > audio_enable [ 1 ] = 1 ;
/* fall through */
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 ;
}
/* pass through setting */
if ( spdif_through & &
( avport = = PS3AV_CMD_AVPORT_SPDIF_0 | |
avport = = PS3AV_CMD_AVPORT_SPDIF_1 ) ) {
audio - > audio_word_bits = PS3AV_CMD_AUDIO_WORD_BITS_16 ;
audio - > audio_source = PS3AV_CMD_AUDIO_SOURCE_SPDIF ;
if ( spdif_bitstream ) {
audio - > audio_format = PS3AV_CMD_AUDIO_FORMAT_BITSTREAM ;
audio - > audio_cs_info [ 0 ] | = CS_BIT ;
}
}
}
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 ;
2007-02-12 11:55:25 +03:00
ps3fb_flip_ctl ( 0 ) ; /* flip off */
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 :
2007-02-12 11:55:25 +03:00
ps3fb_flip_ctl ( 1 ) ; /* flip on */
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 ;
}
# ifdef PS3AV_DEBUG
void ps3av_cmd_av_hw_conf_dump ( const struct ps3av_pkt_av_get_hw_conf * hw_conf )
{
printk ( " av_h_conf:num of hdmi:%d \n " , hw_conf - > num_of_hdmi ) ;
printk ( " av_h_conf:num of avmulti:%d \n " , hw_conf - > num_of_avmulti ) ;
printk ( " av_h_conf:num of spdif:%d \n " , hw_conf - > num_of_spdif ) ;
}
void ps3av_cmd_av_monitor_info_dump ( const struct ps3av_pkt_av_get_monitor_info * monitor_info )
{
const struct ps3av_info_monitor * info = & monitor_info - > info ;
const struct ps3av_info_audio * audio = info - > audio ;
int i ;
printk ( " Monitor Info: size%d \n " , monitor_info - > send_hdr . size ) ;
printk ( " avport:%02x \n " , info - > avport ) ;
printk ( " monitor_id: " ) ;
for ( i = 0 ; i < 10 ; i + + )
printk ( " %02x " , info - > monitor_id [ i ] ) ;
printk ( " \n monitor_type:%02x \n " , info - > monitor_type ) ;
printk ( " monitor_name: " ) ;
for ( i = 0 ; i < 16 ; i + + )
printk ( " %c " , info - > monitor_name [ i ] ) ;
/* resolution */
printk ( " \n resolution_60: bits:%08x native:%08x \n " ,
info - > res_60 . res_bits , info - > res_60 . native ) ;
printk ( " resolution_50: bits:%08x native:%08x \n " ,
info - > res_50 . res_bits , info - > res_50 . native ) ;
printk ( " resolution_other: bits:%08x native:%08x \n " ,
info - > res_other . res_bits , info - > res_other . native ) ;
printk ( " resolution_vesa: bits:%08x native:%08x \n " ,
info - > res_vesa . res_bits , info - > res_vesa . native ) ;
/* color space */
printk ( " color space rgb:%02x \n " , info - > cs . rgb ) ;
printk ( " color space yuv444:%02x \n " , info - > cs . yuv444 ) ;
printk ( " color space yuv422:%02x \n " , info - > cs . yuv422 ) ;
/* color info */
printk ( " color info red:X %04x Y %04x \n " ,
info - > color . red_x , info - > color . red_y ) ;
printk ( " color info green:X %04x Y %04x \n " ,
info - > color . green_x , info - > color . green_y ) ;
printk ( " color info blue:X %04x Y %04x \n " ,
info - > color . blue_x , info - > color . blue_y ) ;
printk ( " color info white:X %04x Y %04x \n " ,
info - > color . white_x , info - > color . white_y ) ;
printk ( " color info gamma: %08x \n " , info - > color . gamma ) ;
/* other info */
printk ( " supported_AI:%02x \n " , info - > supported_ai ) ;
printk ( " speaker_info:%02x \n " , info - > speaker_info ) ;
printk ( " num of audio:%02x \n " , info - > num_of_audio_block ) ;
/* audio block */
for ( i = 0 ; i < info - > num_of_audio_block ; i + + ) {
printk ( " 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 + + ;
}
}
# endif /* PS3AV_DEBUG */
# 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 )
/************************* vuart ***************************/
# define POLLING_INTERVAL 25 /* in msec */
int ps3av_vuart_write ( struct ps3_vuart_port_device * dev , const void * buf ,
unsigned long size )
{
int error = ps3_vuart_write ( dev , buf , size ) ;
return error ? error : size ;
}
int ps3av_vuart_read ( struct ps3_vuart_port_device * dev , void * buf ,
unsigned long size , int timeout )
{
int error ;
int loopcnt = 0 ;
timeout = ( timeout + POLLING_INTERVAL - 1 ) / POLLING_INTERVAL ;
while ( loopcnt + + < = timeout ) {
error = ps3_vuart_read ( dev , buf , size ) ;
if ( ! error )
return size ;
if ( error ! = - EAGAIN ) {
printk ( KERN_ERR " %s: ps3_vuart_read failed %d \n " ,
2007-05-02 16:48:38 +04:00
__func__ , error ) ;
2007-02-12 11:55:16 +03:00
return error ;
}
msleep ( POLLING_INTERVAL ) ;
}
return - EWOULDBLOCK ;
}