2008-04-28 20:24:33 -03:00
/*
* cx18 ADEC firmware functions
*
* Copyright ( C ) 2007 Hans Verkuil < hverkuil @ xs4all . nl >
2010-05-23 18:53:35 -03:00
* Copyright ( C ) 2008 Andy Walls < awalls @ md . metrocast . net >
2008-04-28 20:24:33 -03:00
*
* 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 ; either version 2
* of the License , or ( at your option ) any later version .
*
* 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 "cx18-driver.h"
2008-08-30 16:03:44 -03:00
# include "cx18-io.h"
2008-04-28 20:24:33 -03:00
# include <linux/firmware.h>
2009-04-26 18:46:14 -03:00
# define CX18_AUDIO_ENABLE 0xc72014
# define CX18_AI1_MUX_MASK 0x30
# define CX18_AI1_MUX_I2S1 0x00
# define CX18_AI1_MUX_I2S2 0x10
# define CX18_AI1_MUX_843_I2S 0x20
# define CX18_AI1_MUX_INVALID 0x30
2008-04-28 20:24:33 -03:00
# define FWFILE "v4l-cx23418-dig.fw"
2009-04-26 17:02:25 -03:00
static int cx18_av_verifyfw ( struct cx18 * cx , const struct firmware * fw )
{
struct v4l2_subdev * sd = & cx - > av_state . sd ;
int ret = 0 ;
const u8 * data ;
u32 size ;
int addr ;
u32 expected , dl_control ;
/* Ensure we put the 8051 in reset and enable firmware upload mode */
dl_control = cx18_av_read4 ( cx , CXADEC_DL_CTL ) ;
do {
dl_control & = 0x00ffffff ;
dl_control | = 0x0f000000 ;
cx18_av_write4_noretry ( cx , CXADEC_DL_CTL , dl_control ) ;
dl_control = cx18_av_read4 ( cx , CXADEC_DL_CTL ) ;
} while ( ( dl_control & 0xff000000 ) ! = 0x0f000000 ) ;
/* Read and auto increment until at address 0x0000 */
while ( dl_control & 0x3fff )
dl_control = cx18_av_read4 ( cx , CXADEC_DL_CTL ) ;
data = fw - > data ;
size = fw - > size ;
for ( addr = 0 ; addr < size ; addr + + ) {
dl_control & = 0xffff3fff ; /* ignore top 2 bits of address */
expected = 0x0f000000 | ( ( u32 ) data [ addr ] < < 16 ) | addr ;
if ( expected ! = dl_control ) {
CX18_ERR_DEV ( sd , " verification of %s firmware load "
" failed: expected %#010x got %#010x \n " ,
FWFILE , expected , dl_control ) ;
ret = - EIO ;
break ;
}
dl_control = cx18_av_read4 ( cx , CXADEC_DL_CTL ) ;
}
if ( ret = = 0 )
CX18_INFO_DEV ( sd , " verified load of %s firmware (%d bytes) \n " ,
FWFILE , size ) ;
return ret ;
}
2008-04-28 20:24:33 -03:00
int cx18_av_loadfw ( struct cx18 * cx )
{
2009-02-21 22:27:37 -03:00
struct v4l2_subdev * sd = & cx - > av_state . sd ;
2008-04-28 20:24:33 -03:00
const struct firmware * fw = NULL ;
u32 size ;
2009-04-26 18:46:14 -03:00
u32 u , v ;
2008-07-08 17:38:56 +01:00
const u8 * ptr ;
2008-04-28 20:24:33 -03:00
int i ;
2008-09-03 17:11:54 -03:00
int retries1 = 0 ;
2008-04-28 20:24:33 -03:00
2009-01-10 21:54:39 -03:00
if ( request_firmware ( & fw , FWFILE , & cx - > pci_dev - > dev ) ! = 0 ) {
2009-02-21 22:27:37 -03:00
CX18_ERR_DEV ( sd , " unable to open firmware %s \n " , FWFILE ) ;
2008-04-28 20:24:33 -03:00
return - EINVAL ;
}
2008-06-28 08:03:02 -03:00
/* The firmware load often has byte errors, so allow for several
retries , both at byte level and at the firmware load level . */
2008-09-03 17:11:54 -03:00
while ( retries1 < 5 ) {
2008-11-02 10:59:04 -03:00
cx18_av_write4_expect ( cx , CXADEC_CHIP_CTRL , 0x00010000 ,
0x00008430 , 0xffffffff ) ; /* cx25843 */
cx18_av_write_expect ( cx , CXADEC_STD_DET_CTL , 0xf6 , 0xf6 , 0xff ) ;
2008-04-28 20:24:33 -03:00
2008-11-02 10:59:04 -03:00
/* Reset the Mako core, Register is alias of CXADEC_CHIP_CTRL */
cx18_av_write4_expect ( cx , 0x8100 , 0x00010000 ,
0x00008430 , 0xffffffff ) ; /* cx25843 */
2008-04-28 20:24:33 -03:00
2008-06-28 08:03:02 -03:00
/* Put the 8051 in reset and enable firmware upload */
2008-09-28 21:46:02 -03:00
cx18_av_write4_noretry ( cx , CXADEC_DL_CTL , 0x0F000000 ) ;
2008-04-28 20:24:33 -03:00
2008-06-28 08:03:02 -03:00
ptr = fw - > data ;
size = fw - > size ;
2008-04-28 20:24:33 -03:00
2008-06-28 08:03:02 -03:00
for ( i = 0 ; i < size ; i + + ) {
u32 dl_control = 0x0F000000 | i | ( ( u32 ) ptr [ i ] < < 16 ) ;
u32 value = 0 ;
2008-09-03 17:11:54 -03:00
int retries2 ;
2008-09-28 21:46:02 -03:00
int unrec_err = 0 ;
2008-04-28 20:24:33 -03:00
2008-11-02 18:15:28 -03:00
for ( retries2 = 0 ; retries2 < CX18_MAX_MMIO_WR_RETRIES ;
2008-09-28 21:46:02 -03:00
retries2 + + ) {
cx18_av_write4_noretry ( cx , CXADEC_DL_CTL ,
dl_control ) ;
2008-06-28 08:03:02 -03:00
udelay ( 10 ) ;
2008-11-16 23:33:41 -03:00
value = cx18_av_read4 ( cx , CXADEC_DL_CTL ) ;
2008-06-28 08:03:02 -03:00
if ( value = = dl_control )
break ;
/* Check if we can correct the byte by changing
the address . We can only write the lower
address byte of the address . */
if ( ( value & 0x3F00 ) ! = ( dl_control & 0x3F00 ) ) {
2008-09-28 21:46:02 -03:00
unrec_err = 1 ;
2008-06-28 08:03:02 -03:00
break ;
}
}
2008-11-02 18:15:28 -03:00
if ( unrec_err | | retries2 > = CX18_MAX_MMIO_WR_RETRIES )
2008-04-28 20:24:33 -03:00
break ;
}
2008-06-28 08:03:02 -03:00
if ( i = = size )
break ;
2008-09-03 17:11:54 -03:00
retries1 + + ;
2008-06-28 08:03:02 -03:00
}
2008-09-03 17:11:54 -03:00
if ( retries1 > = 5 ) {
2009-02-21 22:27:37 -03:00
CX18_ERR_DEV ( sd , " unable to load firmware %s \n " , FWFILE ) ;
2008-06-28 08:03:02 -03:00
release_firmware ( fw ) ;
return - EIO ;
2008-04-28 20:24:33 -03:00
}
2008-11-02 10:59:04 -03:00
cx18_av_write4_expect ( cx , CXADEC_DL_CTL ,
2009-04-26 17:02:25 -03:00
0x03000000 | fw - > size , 0x03000000 , 0x13000000 ) ;
CX18_INFO_DEV ( sd , " loaded %s firmware (%d bytes) \n " , FWFILE , size ) ;
if ( cx18_av_verifyfw ( cx , fw ) = = 0 )
cx18_av_write4_expect ( cx , CXADEC_DL_CTL ,
2008-11-02 10:59:04 -03:00
0x13000000 | fw - > size , 0x13000000 , 0x13000000 ) ;
2008-04-28 20:24:33 -03:00
/* Output to the 416 */
cx18_av_and_or4 ( cx , CXADEC_PIN_CTRL1 , ~ 0 , 0x78000 ) ;
/* Audio input control 1 set to Sony mode */
/* Audio output input 2 is 0 for slave operation input */
/* 0xC4000914[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */
/* 0xC4000914[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge
after WS transition for first bit of audio word . */
cx18_av_write4 ( cx , CXADEC_I2S_IN_CTL , 0x000000A0 ) ;
/* Audio output control 1 is set to Sony mode */
/* Audio output control 2 is set to 1 for master mode */
/* 0xC4000918[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */
/* 0xC4000918[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge
after WS transition for first bit of audio word . */
/* 0xC4000918[8]: 0 = slave operation, 1 = master (SCK_OUT and WS_OUT
are generated ) */
cx18_av_write4 ( cx , CXADEC_I2S_OUT_CTL , 0x000001A0 ) ;
2009-01-01 11:09:24 -03:00
/* set alt I2s master clock to /0x16 and enable alt divider i2s
2008-04-28 20:24:33 -03:00
passthrough */
2009-01-01 11:09:24 -03:00
cx18_av_write4 ( cx , CXADEC_PIN_CFG3 , 0x5600B687 ) ;
2008-04-28 20:24:33 -03:00
2008-11-02 10:59:04 -03:00
cx18_av_write4_expect ( cx , CXADEC_STD_DET_CTL , 0x000000F6 , 0x000000F6 ,
0x3F00FFFF ) ;
2008-04-28 20:24:33 -03:00
/* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */
/* Set bit 0 in register 0x9CC to signify that this is MiniMe. */
/* Register 0x09CC is defined by the Merlin firmware, and doesn't
have a name in the spec . */
cx18_av_write4 ( cx , 0x09CC , 1 ) ;
2008-08-30 16:03:44 -03:00
v = cx18_read_reg ( cx , CX18_AUDIO_ENABLE ) ;
/* If bit 11 is 1, clear bit 10 */
2008-04-28 20:24:33 -03:00
if ( v & 0x800 )
2009-01-30 22:39:26 -03:00
cx18_write_reg_expect ( cx , v & 0xFFFFFBFF , CX18_AUDIO_ENABLE ,
0 , 0x400 ) ;
2008-04-28 20:24:33 -03:00
2009-04-26 18:46:14 -03:00
/* Toggle the AI1 MUX */
v = cx18_read_reg ( cx , CX18_AUDIO_ENABLE ) ;
u = v & CX18_AI1_MUX_MASK ;
v & = ~ CX18_AI1_MUX_MASK ;
if ( u = = CX18_AI1_MUX_843_I2S | | u = = CX18_AI1_MUX_INVALID ) {
/* Switch to I2S1 */
v | = CX18_AI1_MUX_I2S1 ;
cx18_write_reg_expect ( cx , v | 0xb00 , CX18_AUDIO_ENABLE ,
v , CX18_AI1_MUX_MASK ) ;
/* Switch back to the A/V decoder core I2S output */
v = ( v & ~ CX18_AI1_MUX_MASK ) | CX18_AI1_MUX_843_I2S ;
} else {
/* Switch to the A/V decoder core I2S output */
v | = CX18_AI1_MUX_843_I2S ;
cx18_write_reg_expect ( cx , v | 0xb00 , CX18_AUDIO_ENABLE ,
v , CX18_AI1_MUX_MASK ) ;
/* Switch back to I2S1 or I2S2 */
v = ( v & ~ CX18_AI1_MUX_MASK ) | u ;
}
cx18_write_reg_expect ( cx , v | 0xb00 , CX18_AUDIO_ENABLE ,
v , CX18_AI1_MUX_MASK ) ;
2008-04-28 20:24:33 -03:00
/* Enable WW auto audio standard detection */
v = cx18_av_read4 ( cx , CXADEC_STD_DET_CTL ) ;
v | = 0xFF ; /* Auto by default */
v | = 0x400 ; /* Stereo by default */
v | = 0x14000000 ;
2008-11-02 10:59:04 -03:00
cx18_av_write4_expect ( cx , CXADEC_STD_DET_CTL , v , v , 0x3F00FFFF ) ;
2008-04-28 20:24:33 -03:00
release_firmware ( fw ) ;
return 0 ;
}
2012-07-27 12:45:21 -03:00
MODULE_FIRMWARE ( FWFILE ) ;