2006-12-07 15:43:59 -08:00
/*
2009-03-23 18:07:23 -07:00
* Mailbox reservation modules for OMAP2 / 3
2006-12-07 15:43:59 -08:00
*
2009-03-23 18:07:23 -07:00
* Copyright ( C ) 2006 - 2009 Nokia Corporation
2006-12-07 15:43:59 -08:00
* Written by : Hiroshi DOYU < Hiroshi . DOYU @ nokia . com >
2009-03-23 18:07:23 -07:00
* and Paul Mundt
2006-12-07 15:43:59 -08: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 .
*/
2011-11-07 12:27:10 -08:00
# include <linux/module.h>
2006-12-07 15:43:59 -08:00
# include <linux/clk.h>
# include <linux/err.h>
# include <linux/platform_device.h>
2008-09-06 12:10:45 +01:00
# include <linux/io.h>
2011-02-24 12:51:33 -08:00
# include <linux/pm_runtime.h>
2012-08-27 17:43:01 -07:00
2009-10-20 09:40:47 -07:00
# include <plat/mailbox.h>
2006-12-07 15:43:59 -08:00
2012-08-31 10:59:07 -07:00
# include "soc.h"
2009-03-23 18:07:23 -07:00
# define MAILBOX_REVISION 0x000
# 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-07 15:43:59 -08:00
2012-05-08 16:31:13 -07:00
# define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 0x10 * (u))
# define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 0x10 * (u))
# define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 0x10 * (u))
2009-11-22 10:11:22 -08:00
# define MAILBOX_IRQ_NEWMSG(m) (1 << (2 * (m)))
# define MAILBOX_IRQ_NOTFULL(m) (1 << (2 * (m) + 1))
2006-12-07 15:43:59 -08:00
2009-03-23 18:07:26 -07:00
# define MBOX_REG_SIZE 0x120
2009-11-22 10:11:22 -08:00
# define OMAP4_MBOX_REG_SIZE 0x130
2009-03-23 18:07:26 -07:00
# define MBOX_NR_REGS (MBOX_REG_SIZE / sizeof(u32))
2009-11-22 10:11:22 -08:00
# define OMAP4_MBOX_NR_REGS (OMAP4_MBOX_REG_SIZE / sizeof(u32))
2009-03-23 18:07:26 -07:00
2009-03-23 18:07:23 -07:00
static void __iomem * mbox_base ;
2006-12-07 15:43:59 -08: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-11-22 10:11:22 -08:00
u32 ctx [ OMAP4_MBOX_NR_REGS ] ;
unsigned long irqdisable ;
2006-12-07 15:43:59 -08:00
} ;
2007-07-30 14:04:04 +03:00
static void omap2_mbox_enable_irq ( struct omap_mbox * mbox ,
omap_mbox_type_t irq ) ;
2009-03-23 18:07:23 -07:00
static inline unsigned int mbox_read_reg ( size_t ofs )
2006-12-07 15:43:59 -08:00
{
2009-03-23 18:07:23 -07:00
return __raw_readl ( mbox_base + ofs ) ;
2006-12-07 15:43:59 -08:00
}
2009-03-23 18:07:23 -07:00
static inline void mbox_write_reg ( u32 val , size_t ofs )
2006-12-07 15:43:59 -08:00
{
2009-03-23 18:07:23 -07:00
__raw_writel ( val , mbox_base + ofs ) ;
2006-12-07 15:43:59 -08:00
}
/* Mailbox H/W preparations */
2007-07-30 14:04:04 +03:00
static int omap2_mbox_startup ( struct omap_mbox * mbox )
2006-12-07 15:43:59 -08:00
{
2009-09-24 16:23:09 -07:00
u32 l ;
2006-12-07 15:43:59 -08:00
2011-02-24 12:51:33 -08:00
pm_runtime_enable ( mbox - > dev - > parent ) ;
pm_runtime_get_sync ( mbox - > dev - > parent ) ;
2009-09-24 16:23:09 -07:00
2009-03-23 18:07:24 -07:00
l = mbox_read_reg ( MAILBOX_REVISION ) ;
2010-06-11 15:51:37 +00:00
pr_debug ( " omap mailbox rev %d.%d \n " , ( l & 0xf0 ) > > 4 , ( l & 0x0f ) ) ;
2009-03-23 18:07:24 -07:00
2006-12-07 15:43:59 -08:00
return 0 ;
}
2007-07-30 14:04:04 +03:00
static void omap2_mbox_shutdown ( struct omap_mbox * mbox )
2006-12-07 15:43:59 -08:00
{
2011-02-24 12:51:33 -08:00
pm_runtime_put_sync ( mbox - > dev - > parent ) ;
pm_runtime_disable ( mbox - > dev - > parent ) ;
2006-12-07 15:43:59 -08:00
}
/* Mailbox FIFO handle functions */
2007-07-30 14:04:04 +03:00
static mbox_msg_t omap2_mbox_fifo_read ( struct omap_mbox * mbox )
2006-12-07 15:43:59 -08: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 14:04:04 +03:00
static void omap2_mbox_fifo_write ( struct omap_mbox * mbox , mbox_msg_t msg )
2006-12-07 15:43:59 -08:00
{
struct omap_mbox2_fifo * fifo =
& ( ( struct omap_mbox2_priv * ) mbox - > priv ) - > tx_fifo ;
mbox_write_reg ( msg , fifo - > msg ) ;
}
2007-07-30 14:04:04 +03:00
static int omap2_mbox_fifo_empty ( struct omap_mbox * mbox )
2006-12-07 15:43:59 -08: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 14:04:04 +03:00
static int omap2_mbox_fifo_full ( struct omap_mbox * mbox )
2006-12-07 15:43:59 -08:00
{
struct omap_mbox2_fifo * fifo =
& ( ( struct omap_mbox2_priv * ) mbox - > priv ) - > tx_fifo ;
2009-11-22 10:11:22 -08:00
return mbox_read_reg ( fifo - > fifo_stat ) ;
2006-12-07 15:43:59 -08:00
}
/* Mailbox IRQ handle functions */
2007-07-30 14:04:04 +03:00
static void omap2_mbox_enable_irq ( struct omap_mbox * mbox ,
2006-12-07 15:43:59 -08:00
omap_mbox_type_t irq )
{
2010-09-27 19:04:32 -07:00
struct omap_mbox2_priv * p = mbox - > priv ;
2006-12-07 15:43:59 -08:00
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 14:04:04 +03:00
static void omap2_mbox_disable_irq ( struct omap_mbox * mbox ,
2006-12-07 15:43:59 -08:00
omap_mbox_type_t irq )
{
2010-09-27 19:04:32 -07:00
struct omap_mbox2_priv * p = mbox - > priv ;
2011-03-02 22:14:18 +00:00
u32 bit = ( irq = = IRQ_TX ) ? p - > notfull_bit : p - > newmsg_bit ;
if ( ! cpu_is_omap44xx ( ) )
bit = mbox_read_reg ( p - > irqdisable ) & ~ bit ;
mbox_write_reg ( bit , p - > irqdisable ) ;
2006-12-07 15:43:59 -08:00
}
2007-07-30 14:04:04 +03:00
static void omap2_mbox_ack_irq ( struct omap_mbox * mbox ,
2006-12-07 15:43:59 -08:00
omap_mbox_type_t irq )
{
2010-09-27 19:04:32 -07:00
struct omap_mbox2_priv * p = mbox - > priv ;
2006-12-07 15:43:59 -08:00
u32 bit = ( irq = = IRQ_TX ) ? p - > notfull_bit : p - > newmsg_bit ;
mbox_write_reg ( bit , p - > irqstatus ) ;
2009-09-24 16:23:10 -07:00
/* Flush posted write for irq status to avoid spurious interrupts */
mbox_read_reg ( p - > irqstatus ) ;
2006-12-07 15:43:59 -08:00
}
2007-07-30 14:04:04 +03:00
static int omap2_mbox_is_irq ( struct omap_mbox * mbox ,
2006-12-07 15:43:59 -08:00
omap_mbox_type_t irq )
{
2010-09-27 19:04:32 -07:00
struct omap_mbox2_priv * p = mbox - > priv ;
2006-12-07 15:43:59 -08:00
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 ) ;
2009-11-22 10:11:22 -08:00
return ( int ) ( enable & status & bit ) ;
2006-12-07 15:43:59 -08:00
}
2009-03-23 18:07:26 -07:00
static void omap2_mbox_save_ctx ( struct omap_mbox * mbox )
{
int i ;
struct omap_mbox2_priv * p = mbox - > priv ;
2009-11-22 10:11:22 -08:00
int nr_regs ;
if ( cpu_is_omap44xx ( ) )
nr_regs = OMAP4_MBOX_NR_REGS ;
else
nr_regs = MBOX_NR_REGS ;
for ( i = 0 ; i < nr_regs ; i + + ) {
2009-03-23 18:07:26 -07:00
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 ;
2009-11-22 10:11:22 -08:00
int nr_regs ;
if ( cpu_is_omap44xx ( ) )
nr_regs = OMAP4_MBOX_NR_REGS ;
else
nr_regs = MBOX_NR_REGS ;
for ( i = 0 ; i < nr_regs ; i + + ) {
2009-03-23 18:07:26 -07:00
mbox_write_reg ( p - > ctx [ i ] , i * sizeof ( u32 ) ) ;
dev_dbg ( mbox - > dev , " %s: [%02x] %08x \n " , __func__ ,
i , p - > ctx [ i ] ) ;
}
}
2006-12-07 15:43:59 -08: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-23 18:07:26 -07:00
. save_ctx = omap2_mbox_save_ctx ,
. restore_ctx = omap2_mbox_restore_ctx ,
2006-12-07 15:43:59 -08: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 */
2010-06-11 15:51:38 +00:00
2010-10-22 20:10:58 -05:00
# if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP2)
2006-12-07 15:43:59 -08:00
/* DSP */
static struct omap_mbox2_priv omap2_mbox_dsp_priv = {
. tx_fifo = {
2009-03-23 18:07:23 -07:00
. msg = MAILBOX_MESSAGE ( 0 ) ,
. fifo_stat = MAILBOX_FIFOSTATUS ( 0 ) ,
2006-12-07 15:43:59 -08:00
} ,
. rx_fifo = {
2009-03-23 18:07:23 -07:00
. msg = MAILBOX_MESSAGE ( 1 ) ,
. msg_stat = MAILBOX_MSGSTATUS ( 1 ) ,
2006-12-07 15:43:59 -08:00
} ,
2009-03-23 18:07:23 -07:00
. irqenable = MAILBOX_IRQENABLE ( 0 ) ,
. irqstatus = MAILBOX_IRQSTATUS ( 0 ) ,
2006-12-07 15:43:59 -08:00
. notfull_bit = MAILBOX_IRQ_NOTFULL ( 0 ) ,
. newmsg_bit = MAILBOX_IRQ_NEWMSG ( 1 ) ,
2009-11-22 10:11:22 -08:00
. irqdisable = MAILBOX_IRQENABLE ( 0 ) ,
} ;
2010-06-11 15:51:38 +00:00
struct omap_mbox mbox_dsp_info = {
. name = " dsp " ,
. ops = & omap2_mbox_ops ,
. priv = & omap2_mbox_dsp_priv ,
} ;
2010-06-11 15:51:47 +00:00
# endif
2010-06-11 15:51:38 +00:00
2010-10-22 20:10:58 -05:00
# if defined(CONFIG_ARCH_OMAP3)
2010-06-11 15:51:45 +00:00
struct omap_mbox * omap3_mboxes [ ] = { & mbox_dsp_info , NULL } ;
2010-06-11 15:51:47 +00:00
# endif
2010-06-11 15:51:45 +00:00
2011-01-27 16:39:40 -08:00
# if defined(CONFIG_SOC_OMAP2420)
2010-06-11 15:51:38 +00:00
/* IVA */
static struct omap_mbox2_priv omap2_mbox_iva_priv = {
. tx_fifo = {
. msg = MAILBOX_MESSAGE ( 2 ) ,
. fifo_stat = MAILBOX_FIFOSTATUS ( 2 ) ,
} ,
. rx_fifo = {
. msg = MAILBOX_MESSAGE ( 3 ) ,
. msg_stat = MAILBOX_MSGSTATUS ( 3 ) ,
} ,
. irqenable = MAILBOX_IRQENABLE ( 3 ) ,
. irqstatus = MAILBOX_IRQSTATUS ( 3 ) ,
. notfull_bit = MAILBOX_IRQ_NOTFULL ( 2 ) ,
. newmsg_bit = MAILBOX_IRQ_NEWMSG ( 3 ) ,
. irqdisable = MAILBOX_IRQENABLE ( 3 ) ,
} ;
static struct omap_mbox mbox_iva_info = {
. name = " iva " ,
. ops = & omap2_mbox_ops ,
. priv = & omap2_mbox_iva_priv ,
} ;
2012-02-23 10:53:35 +02:00
# endif
2010-06-11 15:51:45 +00:00
2012-02-23 10:53:35 +02:00
# ifdef CONFIG_ARCH_OMAP2
struct omap_mbox * omap2_mboxes [ ] = {
& mbox_dsp_info ,
# ifdef CONFIG_SOC_OMAP2420
& mbox_iva_info ,
# endif
NULL
} ;
2010-06-11 15:51:38 +00:00
# endif
2010-06-11 15:51:47 +00:00
# if defined(CONFIG_ARCH_OMAP4)
2010-06-11 15:51:38 +00:00
/* OMAP4 */
2009-11-22 10:11:22 -08:00
static struct omap_mbox2_priv omap2_mbox_1_priv = {
. tx_fifo = {
. msg = MAILBOX_MESSAGE ( 0 ) ,
. fifo_stat = MAILBOX_FIFOSTATUS ( 0 ) ,
} ,
. rx_fifo = {
. msg = MAILBOX_MESSAGE ( 1 ) ,
. msg_stat = MAILBOX_MSGSTATUS ( 1 ) ,
} ,
. irqenable = OMAP4_MAILBOX_IRQENABLE ( 0 ) ,
. irqstatus = OMAP4_MAILBOX_IRQSTATUS ( 0 ) ,
. notfull_bit = MAILBOX_IRQ_NOTFULL ( 0 ) ,
. newmsg_bit = MAILBOX_IRQ_NEWMSG ( 1 ) ,
. irqdisable = OMAP4_MAILBOX_IRQENABLE_CLR ( 0 ) ,
2006-12-07 15:43:59 -08:00
} ;
2009-11-22 10:11:22 -08:00
struct omap_mbox mbox_1_info = {
. name = " mailbox-1 " ,
. ops = & omap2_mbox_ops ,
. priv = & omap2_mbox_1_priv ,
} ;
static struct omap_mbox2_priv omap2_mbox_2_priv = {
. tx_fifo = {
. msg = MAILBOX_MESSAGE ( 3 ) ,
. fifo_stat = MAILBOX_FIFOSTATUS ( 3 ) ,
} ,
. rx_fifo = {
. msg = MAILBOX_MESSAGE ( 2 ) ,
. msg_stat = MAILBOX_MSGSTATUS ( 2 ) ,
} ,
. irqenable = OMAP4_MAILBOX_IRQENABLE ( 0 ) ,
. irqstatus = OMAP4_MAILBOX_IRQSTATUS ( 0 ) ,
. notfull_bit = MAILBOX_IRQ_NOTFULL ( 3 ) ,
. newmsg_bit = MAILBOX_IRQ_NEWMSG ( 2 ) ,
. irqdisable = OMAP4_MAILBOX_IRQENABLE_CLR ( 0 ) ,
} ;
struct omap_mbox mbox_2_info = {
. name = " mailbox-2 " ,
. ops = & omap2_mbox_ops ,
. priv = & omap2_mbox_2_priv ,
} ;
2010-06-11 15:51:45 +00:00
struct omap_mbox * omap4_mboxes [ ] = { & mbox_1_info , & mbox_2_info , NULL } ;
2010-06-11 15:51:47 +00:00
# endif
2010-06-11 15:51:45 +00:00
2009-03-23 18:07:25 -07:00
static int __devinit omap2_mbox_probe ( struct platform_device * pdev )
2006-12-07 15:43:59 -08:00
{
2010-06-11 15:51:45 +00:00
struct resource * mem ;
2009-03-23 18:07:23 -07:00
int ret ;
2010-06-11 15:51:46 +00:00
struct omap_mbox * * list ;
2006-12-07 15:43:59 -08:00
2010-06-11 15:51:47 +00:00
if ( false )
;
2010-10-22 20:10:58 -05:00
# if defined(CONFIG_ARCH_OMAP3)
else if ( cpu_is_omap34xx ( ) ) {
2010-06-11 15:51:45 +00:00
list = omap3_mboxes ;
2011-02-24 12:51:33 -08:00
list [ 0 ] - > irq = platform_get_irq ( pdev , 0 ) ;
2006-12-07 15:43:59 -08:00
}
2010-06-11 15:51:47 +00:00
# endif
2010-10-22 20:10:58 -05:00
# if defined(CONFIG_ARCH_OMAP2)
else if ( cpu_is_omap2430 ( ) ) {
list = omap2_mboxes ;
2011-02-24 12:51:33 -08:00
list [ 0 ] - > irq = platform_get_irq ( pdev , 0 ) ;
2010-10-22 20:10:58 -05:00
} else if ( cpu_is_omap2420 ( ) ) {
2010-06-11 15:51:45 +00:00
list = omap2_mboxes ;
2006-12-07 15:43:59 -08:00
2010-06-11 15:51:45 +00:00
list [ 0 ] - > irq = platform_get_irq_byname ( pdev , " dsp " ) ;
list [ 1 ] - > irq = platform_get_irq_byname ( pdev , " iva " ) ;
}
# endif
2010-06-11 15:51:47 +00:00
# if defined(CONFIG_ARCH_OMAP4)
2010-06-11 15:51:45 +00:00
else if ( cpu_is_omap44xx ( ) ) {
list = omap4_mboxes ;
2009-11-22 10:11:22 -08:00
2011-02-24 12:51:33 -08:00
list [ 0 ] - > irq = list [ 1 ] - > irq = platform_get_irq ( pdev , 0 ) ;
2006-12-07 15:43:59 -08:00
}
2010-06-11 15:51:47 +00:00
# endif
2010-06-11 15:51:45 +00:00
else {
pr_err ( " %s: platform not supported \n " , __func__ ) ;
return - ENODEV ;
2009-11-22 10:11:22 -08:00
}
2009-03-23 18:07:23 -07:00
2010-06-11 15:51:45 +00:00
mem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
mbox_base = ioremap ( mem - > start , resource_size ( mem ) ) ;
if ( ! mbox_base )
return - ENOMEM ;
2010-06-11 15:51:46 +00:00
ret = omap_mbox_register ( & pdev - > dev , list ) ;
if ( ret ) {
iounmap ( mbox_base ) ;
return ret ;
2006-12-07 15:43:59 -08:00
}
2010-12-01 14:15:08 -06:00
return 0 ;
2006-12-07 15:43:59 -08:00
}
2009-03-23 18:07:25 -07:00
static int __devexit omap2_mbox_remove ( struct platform_device * pdev )
2006-12-07 15:43:59 -08:00
{
2010-06-11 15:51:46 +00:00
omap_mbox_unregister ( ) ;
2009-03-23 18:07:23 -07:00
iounmap ( mbox_base ) ;
2006-12-07 15:43:59 -08:00
return 0 ;
}
static struct platform_driver omap2_mbox_driver = {
. probe = omap2_mbox_probe ,
2009-03-23 18:07:25 -07:00
. remove = __devexit_p ( omap2_mbox_remove ) ,
2006-12-07 15:43:59 -08:00
. driver = {
2010-06-11 15:51:48 +00:00
. name = " omap-mailbox " ,
2006-12-07 15:43:59 -08: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 ) ;
}
2012-03-04 12:01:11 +02:00
module_init ( omap2_mbox_init ) ;
2006-12-07 15:43:59 -08:00
module_exit ( omap2_mbox_exit ) ;
2009-03-23 18:07:23 -07:00
MODULE_LICENSE ( " GPL v2 " ) ;
2009-11-22 10:11:22 -08:00
MODULE_DESCRIPTION ( " omap mailbox: omap2/3/4 architecture specific functions " ) ;
2010-05-05 15:33:07 +00:00
MODULE_AUTHOR ( " Hiroshi DOYU <Hiroshi.DOYU@nokia.com> " ) ;
MODULE_AUTHOR ( " Paul Mundt " ) ;
2010-06-11 15:51:48 +00:00
MODULE_ALIAS ( " platform:omap2-mailbox " ) ;