2011-10-20 20:53:35 +04:00
/*
* OMAP Remote Processor driver
*
* Copyright ( C ) 2011 Texas Instruments , Inc .
* Copyright ( C ) 2011 Google , Inc .
*
* Ohad Ben - Cohen < ohad @ wizery . com >
* Brian Swetland < swetland @ google . com >
* Fernando Guzman Lugo < fernando . lugo @ ti . com >
* Mark Grosen < mgrosen @ ti . com >
* Suman Anna < s - anna @ ti . com >
* Hari Kanigeri < h - kanigeri2 @ ti . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation .
*
* 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 .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/err.h>
# include <linux/platform_device.h>
# include <linux/dma-mapping.h>
# include <linux/remoteproc.h>
# include <plat/mailbox.h>
# include <plat/remoteproc.h>
# include "omap_remoteproc.h"
# include "remoteproc_internal.h"
/**
* struct omap_rproc - omap remote processor state
* @ mbox : omap mailbox handle
* @ nb : notifier block that will be invoked on inbound mailbox messages
* @ rproc : rproc handle
*/
struct omap_rproc {
struct omap_mbox * mbox ;
struct notifier_block nb ;
struct rproc * rproc ;
} ;
/**
* omap_rproc_mbox_callback ( ) - inbound mailbox message handler
* @ this : notifier block
* @ index : unused
* @ data : mailbox payload
*
* This handler is invoked by omap ' s mailbox driver whenever a mailbox
* message is received . Usually , the mailbox payload simply contains
* the index of the virtqueue that is kicked by the remote processor ,
* and we let remoteproc core handle it .
*
* In addition to virtqueue indices , we also have some out - of - band values
* that indicates different events . Those values are deliberately very
* big so they don ' t coincide with virtqueue indices .
*/
static int omap_rproc_mbox_callback ( struct notifier_block * this ,
unsigned long index , void * data )
{
mbox_msg_t msg = ( mbox_msg_t ) data ;
struct omap_rproc * oproc = container_of ( this , struct omap_rproc , nb ) ;
struct device * dev = oproc - > rproc - > dev ;
const char * name = oproc - > rproc - > name ;
dev_dbg ( dev , " mbox msg: 0x%x \n " , msg ) ;
switch ( msg ) {
case RP_MBOX_CRASH :
/* just log this for now. later, we'll also do recovery */
dev_err ( dev , " omap rproc %s crashed \n " , name ) ;
break ;
case RP_MBOX_ECHO_REPLY :
dev_info ( dev , " received echo reply from %s \n " , name ) ;
break ;
default :
2012-02-13 14:24:50 +04:00
/* msg contains the index of the triggered vring */
2011-10-20 20:53:35 +04:00
if ( rproc_vq_interrupt ( oproc - > rproc , msg ) = = IRQ_NONE )
dev_dbg ( dev , " no message was found in vqid %d \n " , msg ) ;
}
return NOTIFY_DONE ;
}
/* kick a virtqueue */
static void omap_rproc_kick ( struct rproc * rproc , int vqid )
{
struct omap_rproc * oproc = rproc - > priv ;
int ret ;
/* send the index of the triggered virtqueue in the mailbox payload */
ret = omap_mbox_msg_send ( oproc - > mbox , vqid ) ;
if ( ret )
dev_err ( rproc - > dev , " omap_mbox_msg_send failed: %d \n " , ret ) ;
}
/*
* Power up the remote processor .
*
* This function will be invoked only after the firmware for this rproc
* was loaded , parsed successfully , and all of its resource requirements
* were met .
*/
static int omap_rproc_start ( struct rproc * rproc )
{
struct omap_rproc * oproc = rproc - > priv ;
struct platform_device * pdev = to_platform_device ( rproc - > dev ) ;
struct omap_rproc_pdata * pdata = pdev - > dev . platform_data ;
int ret ;
oproc - > nb . notifier_call = omap_rproc_mbox_callback ;
/* every omap rproc is assigned a mailbox instance for messaging */
oproc - > mbox = omap_mbox_get ( pdata - > mbox_name , & oproc - > nb ) ;
if ( IS_ERR ( oproc - > mbox ) ) {
ret = PTR_ERR ( oproc - > mbox ) ;
dev_err ( rproc - > dev , " omap_mbox_get failed: %d \n " , ret ) ;
return ret ;
}
/*
* Ping the remote processor . this is only for sanity - sake ;
* there is no functional effect whatsoever .
*
* Note that the reply will _not_ arrive immediately : this message
* will wait in the mailbox fifo until the remote processor is booted .
*/
ret = omap_mbox_msg_send ( oproc - > mbox , RP_MBOX_ECHO_REQUEST ) ;
if ( ret ) {
dev_err ( rproc - > dev , " omap_mbox_get failed: %d \n " , ret ) ;
goto put_mbox ;
}
ret = pdata - > device_enable ( pdev ) ;
if ( ret ) {
dev_err ( rproc - > dev , " omap_device_enable failed: %d \n " , ret ) ;
goto put_mbox ;
}
return 0 ;
put_mbox :
omap_mbox_put ( oproc - > mbox , & oproc - > nb ) ;
return ret ;
}
/* power off the remote processor */
static int omap_rproc_stop ( struct rproc * rproc )
{
struct platform_device * pdev = to_platform_device ( rproc - > dev ) ;
struct omap_rproc_pdata * pdata = pdev - > dev . platform_data ;
struct omap_rproc * oproc = rproc - > priv ;
int ret ;
ret = pdata - > device_shutdown ( pdev ) ;
if ( ret )
return ret ;
omap_mbox_put ( oproc - > mbox , & oproc - > nb ) ;
return 0 ;
}
static struct rproc_ops omap_rproc_ops = {
. start = omap_rproc_start ,
. stop = omap_rproc_stop ,
. kick = omap_rproc_kick ,
} ;
static int __devinit omap_rproc_probe ( struct platform_device * pdev )
{
struct omap_rproc_pdata * pdata = pdev - > dev . platform_data ;
struct omap_rproc * oproc ;
struct rproc * rproc ;
int ret ;
ret = dma_set_coherent_mask ( & pdev - > dev , DMA_BIT_MASK ( 32 ) ) ;
if ( ret ) {
dev_err ( pdev - > dev . parent , " dma_set_coherent_mask: %d \n " , ret ) ;
return ret ;
}
rproc = rproc_alloc ( & pdev - > dev , pdata - > name , & omap_rproc_ops ,
pdata - > firmware , sizeof ( * oproc ) ) ;
if ( ! rproc )
return - ENOMEM ;
oproc = rproc - > priv ;
oproc - > rproc = rproc ;
platform_set_drvdata ( pdev , rproc ) ;
ret = rproc_register ( rproc ) ;
if ( ret )
goto free_rproc ;
return 0 ;
free_rproc :
rproc_free ( rproc ) ;
return ret ;
}
static int __devexit omap_rproc_remove ( struct platform_device * pdev )
{
struct rproc * rproc = platform_get_drvdata ( pdev ) ;
return rproc_unregister ( rproc ) ;
}
static struct platform_driver omap_rproc_driver = {
. probe = omap_rproc_probe ,
. remove = __devexit_p ( omap_rproc_remove ) ,
. driver = {
. name = " omap-rproc " ,
. owner = THIS_MODULE ,
} ,
} ;
2011-12-13 16:41:47 +04:00
module_platform_driver ( omap_rproc_driver ) ;
2011-10-20 20:53:35 +04:00
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " OMAP Remote Processor control driver " ) ;