2006-12-08 02:43:59 +03:00
/*
2009-03-24 04:07:23 +03:00
* Mailbox reservation modules for OMAP2 / 3
2006-12-08 02:43:59 +03:00
*
2009-03-24 04:07:23 +03:00
* Copyright ( C ) 2006 - 2009 Nokia Corporation
2006-12-08 02:43:59 +03:00
* Written by : Hiroshi DOYU < Hiroshi . DOYU @ nokia . com >
2009-03-24 04:07:23 +03:00
* and Paul Mundt
2006-12-08 02:43:59 +03:00
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*/
# include <linux/kernel.h>
# include <linux/clk.h>
# include <linux/err.h>
# include <linux/platform_device.h>
2008-09-06 15:10:45 +04:00
# include <linux/io.h>
2008-08-05 19:14:15 +04:00
# include <mach/mailbox.h>
# include <mach/irqs.h>
2006-12-08 02:43:59 +03:00
2009-03-24 04:07:23 +03:00
# define MAILBOX_REVISION 0x000
# define MAILBOX_SYSCONFIG 0x010
# define MAILBOX_SYSSTATUS 0x014
# define MAILBOX_MESSAGE(m) (0x040 + 4 * (m))
# define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m))
# define MAILBOX_MSGSTATUS(m) (0x0c0 + 4 * (m))
# define MAILBOX_IRQSTATUS(u) (0x100 + 8 * (u))
# define MAILBOX_IRQENABLE(u) (0x104 + 8 * (u))
2006-12-08 02:43:59 +03:00
2009-03-24 04:07:23 +03:00
# define MAILBOX_IRQ_NEWMSG(u) (1 << (2 * (u)))
# define MAILBOX_IRQ_NOTFULL(u) (1 << (2 * (u) + 1))
2006-12-08 02:43:59 +03:00
2009-03-24 04:07:26 +03:00
# define MBOX_REG_SIZE 0x120
# define MBOX_NR_REGS (MBOX_REG_SIZE / sizeof(u32))
2009-03-24 04:07:23 +03:00
static void __iomem * mbox_base ;
2006-12-08 02:43:59 +03:00
struct omap_mbox2_fifo {
unsigned long msg ;
unsigned long fifo_stat ;
unsigned long msg_stat ;
} ;
struct omap_mbox2_priv {
struct omap_mbox2_fifo tx_fifo ;
struct omap_mbox2_fifo rx_fifo ;
unsigned long irqenable ;
unsigned long irqstatus ;
u32 newmsg_bit ;
u32 notfull_bit ;
2009-03-24 04:07:26 +03:00
u32 ctx [ MBOX_NR_REGS ] ;
2006-12-08 02:43:59 +03:00
} ;
static struct clk * mbox_ick_handle ;
2007-07-30 15:04:04 +04:00
static void omap2_mbox_enable_irq ( struct omap_mbox * mbox ,
omap_mbox_type_t irq ) ;
2009-03-24 04:07:23 +03:00
static inline unsigned int mbox_read_reg ( size_t ofs )
2006-12-08 02:43:59 +03:00
{
2009-03-24 04:07:23 +03:00
return __raw_readl ( mbox_base + ofs ) ;
2006-12-08 02:43:59 +03:00
}
2009-03-24 04:07:23 +03:00
static inline void mbox_write_reg ( u32 val , size_t ofs )
2006-12-08 02:43:59 +03:00
{
2009-03-24 04:07:23 +03:00
__raw_writel ( val , mbox_base + ofs ) ;
2006-12-08 02:43:59 +03:00
}
/* Mailbox H/W preparations */
2007-07-30 15:04:04 +04:00
static int omap2_mbox_startup ( struct omap_mbox * mbox )
2006-12-08 02:43:59 +03:00
{
unsigned int l ;
mbox_ick_handle = clk_get ( NULL , " mailboxes_ick " ) ;
if ( IS_ERR ( mbox_ick_handle ) ) {
printk ( " Could not get mailboxes_ick \n " ) ;
return - ENODEV ;
}
clk_enable ( mbox_ick_handle ) ;
2009-03-24 04:07:24 +03:00
l = mbox_read_reg ( MAILBOX_REVISION ) ;
pr_info ( " omap mailbox rev %d.%d \n " , ( l & 0xf0 ) > > 4 , ( l & 0x0f ) ) ;
2006-12-08 02:43:59 +03:00
/* set smart-idle & autoidle */
l = mbox_read_reg ( MAILBOX_SYSCONFIG ) ;
l | = 0x00000011 ;
mbox_write_reg ( l , MAILBOX_SYSCONFIG ) ;
2007-07-30 15:04:04 +04:00
omap2_mbox_enable_irq ( mbox , IRQ_RX ) ;
2006-12-08 02:43:59 +03:00
return 0 ;
}
2007-07-30 15:04:04 +04:00
static void omap2_mbox_shutdown ( struct omap_mbox * mbox )
2006-12-08 02:43:59 +03:00
{
clk_disable ( mbox_ick_handle ) ;
clk_put ( mbox_ick_handle ) ;
}
/* Mailbox FIFO handle functions */
2007-07-30 15:04:04 +04:00
static mbox_msg_t omap2_mbox_fifo_read ( struct omap_mbox * mbox )
2006-12-08 02:43:59 +03:00
{
struct omap_mbox2_fifo * fifo =
& ( ( struct omap_mbox2_priv * ) mbox - > priv ) - > rx_fifo ;
return ( mbox_msg_t ) mbox_read_reg ( fifo - > msg ) ;
}
2007-07-30 15:04:04 +04:00
static void omap2_mbox_fifo_write ( struct omap_mbox * mbox , mbox_msg_t msg )
2006-12-08 02:43:59 +03:00
{
struct omap_mbox2_fifo * fifo =
& ( ( struct omap_mbox2_priv * ) mbox - > priv ) - > tx_fifo ;
mbox_write_reg ( msg , fifo - > msg ) ;
}
2007-07-30 15:04:04 +04:00
static int omap2_mbox_fifo_empty ( struct omap_mbox * mbox )
2006-12-08 02:43:59 +03:00
{
struct omap_mbox2_fifo * fifo =
& ( ( struct omap_mbox2_priv * ) mbox - > priv ) - > rx_fifo ;
return ( mbox_read_reg ( fifo - > msg_stat ) = = 0 ) ;
}
2007-07-30 15:04:04 +04:00
static int omap2_mbox_fifo_full ( struct omap_mbox * mbox )
2006-12-08 02:43:59 +03:00
{
struct omap_mbox2_fifo * fifo =
& ( ( struct omap_mbox2_priv * ) mbox - > priv ) - > tx_fifo ;
return ( mbox_read_reg ( fifo - > fifo_stat ) ) ;
}
/* Mailbox IRQ handle functions */
2007-07-30 15:04:04 +04:00
static void omap2_mbox_enable_irq ( struct omap_mbox * mbox ,
2006-12-08 02:43:59 +03:00
omap_mbox_type_t irq )
{
struct omap_mbox2_priv * p = ( struct omap_mbox2_priv * ) mbox - > priv ;
u32 l , bit = ( irq = = IRQ_TX ) ? p - > notfull_bit : p - > newmsg_bit ;
l = mbox_read_reg ( p - > irqenable ) ;
l | = bit ;
mbox_write_reg ( l , p - > irqenable ) ;
}
2007-07-30 15:04:04 +04:00
static void omap2_mbox_disable_irq ( struct omap_mbox * mbox ,
2006-12-08 02:43:59 +03:00
omap_mbox_type_t irq )
{
struct omap_mbox2_priv * p = ( struct omap_mbox2_priv * ) mbox - > priv ;
u32 l , bit = ( irq = = IRQ_TX ) ? p - > notfull_bit : p - > newmsg_bit ;
l = mbox_read_reg ( p - > irqenable ) ;
l & = ~ bit ;
mbox_write_reg ( l , p - > irqenable ) ;
}
2007-07-30 15:04:04 +04:00
static void omap2_mbox_ack_irq ( struct omap_mbox * mbox ,
2006-12-08 02:43:59 +03:00
omap_mbox_type_t irq )
{
struct omap_mbox2_priv * p = ( struct omap_mbox2_priv * ) mbox - > priv ;
u32 bit = ( irq = = IRQ_TX ) ? p - > notfull_bit : p - > newmsg_bit ;
mbox_write_reg ( bit , p - > irqstatus ) ;
}
2007-07-30 15:04:04 +04:00
static int omap2_mbox_is_irq ( struct omap_mbox * mbox ,
2006-12-08 02:43:59 +03:00
omap_mbox_type_t irq )
{
struct omap_mbox2_priv * p = ( struct omap_mbox2_priv * ) mbox - > priv ;
u32 bit = ( irq = = IRQ_TX ) ? p - > notfull_bit : p - > newmsg_bit ;
u32 enable = mbox_read_reg ( p - > irqenable ) ;
u32 status = mbox_read_reg ( p - > irqstatus ) ;
return ( enable & status & bit ) ;
}
2009-03-24 04:07:26 +03:00
static void omap2_mbox_save_ctx ( struct omap_mbox * mbox )
{
int i ;
struct omap_mbox2_priv * p = mbox - > priv ;
for ( i = 0 ; i < MBOX_NR_REGS ; i + + ) {
p - > ctx [ i ] = mbox_read_reg ( i * sizeof ( u32 ) ) ;
dev_dbg ( mbox - > dev , " %s: [%02x] %08x \n " , __func__ ,
i , p - > ctx [ i ] ) ;
}
}
static void omap2_mbox_restore_ctx ( struct omap_mbox * mbox )
{
int i ;
struct omap_mbox2_priv * p = mbox - > priv ;
for ( i = 0 ; i < MBOX_NR_REGS ; i + + ) {
mbox_write_reg ( p - > ctx [ i ] , i * sizeof ( u32 ) ) ;
dev_dbg ( mbox - > dev , " %s: [%02x] %08x \n " , __func__ ,
i , p - > ctx [ i ] ) ;
}
}
2006-12-08 02:43:59 +03:00
static struct omap_mbox_ops omap2_mbox_ops = {
. type = OMAP_MBOX_TYPE2 ,
. startup = omap2_mbox_startup ,
. shutdown = omap2_mbox_shutdown ,
. fifo_read = omap2_mbox_fifo_read ,
. fifo_write = omap2_mbox_fifo_write ,
. fifo_empty = omap2_mbox_fifo_empty ,
. fifo_full = omap2_mbox_fifo_full ,
. enable_irq = omap2_mbox_enable_irq ,
. disable_irq = omap2_mbox_disable_irq ,
. ack_irq = omap2_mbox_ack_irq ,
. is_irq = omap2_mbox_is_irq ,
2009-03-24 04:07:26 +03:00
. save_ctx = omap2_mbox_save_ctx ,
. restore_ctx = omap2_mbox_restore_ctx ,
2006-12-08 02:43:59 +03:00
} ;
/*
* MAILBOX 0 : ARM - > DSP ,
* MAILBOX 1 : ARM < - DSP .
* MAILBOX 2 : ARM - > IVA ,
* MAILBOX 3 : ARM < - IVA .
*/
/* FIXME: the following structs should be filled automatically by the user id */
/* DSP */
static struct omap_mbox2_priv omap2_mbox_dsp_priv = {
. tx_fifo = {
2009-03-24 04:07:23 +03:00
. msg = MAILBOX_MESSAGE ( 0 ) ,
. fifo_stat = MAILBOX_FIFOSTATUS ( 0 ) ,
2006-12-08 02:43:59 +03:00
} ,
. rx_fifo = {
2009-03-24 04:07:23 +03:00
. msg = MAILBOX_MESSAGE ( 1 ) ,
. msg_stat = MAILBOX_MSGSTATUS ( 1 ) ,
2006-12-08 02:43:59 +03:00
} ,
2009-03-24 04:07:23 +03:00
. irqenable = MAILBOX_IRQENABLE ( 0 ) ,
. irqstatus = MAILBOX_IRQSTATUS ( 0 ) ,
2006-12-08 02:43:59 +03:00
. notfull_bit = MAILBOX_IRQ_NOTFULL ( 0 ) ,
. newmsg_bit = MAILBOX_IRQ_NEWMSG ( 1 ) ,
} ;
struct omap_mbox mbox_dsp_info = {
. name = " dsp " ,
. ops = & omap2_mbox_ops ,
. priv = & omap2_mbox_dsp_priv ,
} ;
EXPORT_SYMBOL ( mbox_dsp_info ) ;
2009-03-24 04:07:23 +03:00
# if defined(CONFIG_ARCH_OMAP2420) /* IVA */
2006-12-08 02:43:59 +03:00
static struct omap_mbox2_priv omap2_mbox_iva_priv = {
. tx_fifo = {
2009-03-24 04:07:23 +03:00
. msg = MAILBOX_MESSAGE ( 2 ) ,
. fifo_stat = MAILBOX_FIFOSTATUS ( 2 ) ,
2006-12-08 02:43:59 +03:00
} ,
. rx_fifo = {
2009-03-24 04:07:23 +03:00
. msg = MAILBOX_MESSAGE ( 3 ) ,
. msg_stat = MAILBOX_MSGSTATUS ( 3 ) ,
2006-12-08 02:43:59 +03:00
} ,
2009-03-24 04:07:23 +03:00
. irqenable = MAILBOX_IRQENABLE ( 3 ) ,
. irqstatus = MAILBOX_IRQSTATUS ( 3 ) ,
2006-12-08 02:43:59 +03:00
. notfull_bit = MAILBOX_IRQ_NOTFULL ( 2 ) ,
. newmsg_bit = MAILBOX_IRQ_NEWMSG ( 3 ) ,
} ;
static struct omap_mbox mbox_iva_info = {
. name = " iva " ,
. ops = & omap2_mbox_ops ,
. priv = & omap2_mbox_iva_priv ,
} ;
2009-03-24 04:07:23 +03:00
# endif
2006-12-08 02:43:59 +03:00
2009-03-24 04:07:25 +03:00
static int __devinit omap2_mbox_probe ( struct platform_device * pdev )
2006-12-08 02:43:59 +03:00
{
struct resource * res ;
2009-03-24 04:07:23 +03:00
int ret ;
2006-12-08 02:43:59 +03:00
/* MBOX base */
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( unlikely ( ! res ) ) {
dev_err ( & pdev - > dev , " invalid mem resource \n " ) ;
return - ENODEV ;
}
2009-03-24 04:07:23 +03:00
mbox_base = ioremap ( res - > start , res - > end - res - > start ) ;
if ( ! mbox_base )
return - ENOMEM ;
2006-12-08 02:43:59 +03:00
2009-03-24 04:07:23 +03:00
/* DSP or IVA2 IRQ */
2009-06-23 14:30:22 +04:00
ret = platform_get_irq ( pdev , 0 ) ;
if ( ret < 0 ) {
2006-12-08 02:43:59 +03:00
dev_err ( & pdev - > dev , " invalid irq resource \n " ) ;
2009-03-24 04:07:23 +03:00
goto err_dsp ;
2006-12-08 02:43:59 +03:00
}
2009-06-23 14:30:22 +04:00
mbox_dsp_info . irq = ret ;
2006-12-08 02:43:59 +03:00
2009-03-24 04:07:25 +03:00
ret = omap_mbox_register ( & pdev - > dev , & mbox_dsp_info ) ;
2009-03-24 04:07:23 +03:00
if ( ret )
goto err_dsp ;
# if defined(CONFIG_ARCH_OMAP2420) /* IVA */
if ( cpu_is_omap2420 ( ) ) {
/* IVA IRQ */
res = platform_get_resource ( pdev , IORESOURCE_IRQ , 1 ) ;
if ( unlikely ( ! res ) ) {
dev_err ( & pdev - > dev , " invalid irq resource \n " ) ;
ret = - ENODEV ;
goto err_iva1 ;
}
mbox_iva_info . irq = res - > start ;
2009-03-24 04:07:25 +03:00
ret = omap_mbox_register ( & pdev - > dev , & mbox_iva_info ) ;
2009-03-24 04:07:23 +03:00
if ( ret )
goto err_iva1 ;
2006-12-08 02:43:59 +03:00
}
2009-03-24 04:07:23 +03:00
# endif
return 0 ;
2006-12-08 02:43:59 +03:00
2009-03-24 04:07:23 +03:00
err_iva1 :
omap_mbox_unregister ( & mbox_dsp_info ) ;
err_dsp :
iounmap ( mbox_base ) ;
2006-12-08 02:43:59 +03:00
return ret ;
}
2009-03-24 04:07:25 +03:00
static int __devexit omap2_mbox_remove ( struct platform_device * pdev )
2006-12-08 02:43:59 +03:00
{
2009-03-24 04:07:23 +03:00
# if defined(CONFIG_ARCH_OMAP2420)
omap_mbox_unregister ( & mbox_iva_info ) ;
# endif
2006-12-08 02:43:59 +03:00
omap_mbox_unregister ( & mbox_dsp_info ) ;
2009-03-24 04:07:23 +03:00
iounmap ( mbox_base ) ;
2006-12-08 02:43:59 +03:00
return 0 ;
}
static struct platform_driver omap2_mbox_driver = {
. probe = omap2_mbox_probe ,
2009-03-24 04:07:25 +03:00
. remove = __devexit_p ( omap2_mbox_remove ) ,
2006-12-08 02:43:59 +03:00
. driver = {
2009-03-24 04:07:25 +03:00
. name = " omap2-mailbox " ,
2006-12-08 02:43:59 +03:00
} ,
} ;
static int __init omap2_mbox_init ( void )
{
return platform_driver_register ( & omap2_mbox_driver ) ;
}
static void __exit omap2_mbox_exit ( void )
{
platform_driver_unregister ( & omap2_mbox_driver ) ;
}
module_init ( omap2_mbox_init ) ;
module_exit ( omap2_mbox_exit ) ;
2009-03-24 04:07:23 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " omap mailbox: omap2/3 architecture specific functions " ) ;
MODULE_AUTHOR ( " Hiroshi DOYU <Hiroshi.DOYU@nokia.com>, Paul Mundt " ) ;
2009-03-24 04:07:25 +03:00
MODULE_ALIAS ( " platform:omap2-mailbox " ) ;