2019-05-27 08:55:21 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2011-10-20 18:53:35 +02:00
/*
* OMAP Remote Processor driver
*
2020-03-24 13:00:22 +02:00
* Copyright ( C ) 2011 - 2020 Texas Instruments Incorporated - http : //www.ti.com/
2011-10-20 18:53:35 +02:00
* 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 >
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/err.h>
2020-03-24 13:00:22 +02:00
# include <linux/of_device.h>
2020-03-24 13:00:26 +02:00
# include <linux/of_reserved_mem.h>
2011-10-20 18:53:35 +02:00
# include <linux/platform_device.h>
# include <linux/dma-mapping.h>
# include <linux/remoteproc.h>
2014-11-03 17:05:50 -06:00
# include <linux/mailbox_client.h>
2013-03-12 17:55:29 -05:00
# include <linux/omap-mailbox.h>
2020-03-24 13:00:22 +02:00
# include <linux/regmap.h>
# include <linux/mfd/syscon.h>
# include <linux/reset.h>
2011-10-20 18:53:35 +02:00
# include "omap_remoteproc.h"
# include "remoteproc_internal.h"
2020-03-24 13:00:22 +02:00
/**
* struct omap_rproc_boot_data - boot data structure for the DSP omap rprocs
* @ syscon : regmap handle for the system control configuration module
* @ boot_reg : boot register offset within the @ syscon regmap
*/
struct omap_rproc_boot_data {
struct regmap * syscon ;
unsigned int boot_reg ;
} ;
2020-03-24 13:00:24 +02:00
/**
* struct omap_rproc_mem - internal memory structure
* @ cpu_addr : MPU virtual address of the memory region
* @ bus_addr : bus address used to access the memory region
* @ dev_addr : device address of the memory region from DSP view
* @ size : size of the memory region
*/
struct omap_rproc_mem {
void __iomem * cpu_addr ;
phys_addr_t bus_addr ;
u32 dev_addr ;
size_t size ;
} ;
2011-10-20 18:53:35 +02:00
/**
* struct omap_rproc - omap remote processor state
2014-11-03 17:05:50 -06:00
* @ mbox : mailbox channel handle
* @ client : mailbox client to request the mailbox channel
2020-03-24 13:00:22 +02:00
* @ boot_data : boot data structure for setting processor boot address
2020-03-24 13:00:24 +02:00
* @ mem : internal memory regions data
* @ num_mems : number of internal memory regions
2011-10-20 18:53:35 +02:00
* @ rproc : rproc handle
2020-03-24 13:00:22 +02:00
* @ reset : reset handle
2011-10-20 18:53:35 +02:00
*/
struct omap_rproc {
2014-11-03 17:05:50 -06:00
struct mbox_chan * mbox ;
struct mbox_client client ;
2020-03-24 13:00:22 +02:00
struct omap_rproc_boot_data * boot_data ;
2020-03-24 13:00:24 +02:00
struct omap_rproc_mem * mem ;
int num_mems ;
2011-10-20 18:53:35 +02:00
struct rproc * rproc ;
2020-03-24 13:00:22 +02:00
struct reset_control * reset ;
} ;
2020-03-24 13:00:24 +02:00
/**
* struct omap_rproc_mem_data - memory definitions for an omap remote processor
* @ name : name for this memory entry
* @ dev_addr : device address for the memory entry
*/
struct omap_rproc_mem_data {
const char * name ;
const u32 dev_addr ;
} ;
2020-03-24 13:00:22 +02:00
/**
* struct omap_rproc_dev_data - device data for the omap remote processor
* @ device_name : device name of the remote processor
2020-03-24 13:00:24 +02:00
* @ mems : memory definitions for this remote processor
2020-03-24 13:00:22 +02:00
*/
struct omap_rproc_dev_data {
const char * device_name ;
2020-03-24 13:00:24 +02:00
const struct omap_rproc_mem_data * mems ;
2011-10-20 18:53:35 +02:00
} ;
/**
* omap_rproc_mbox_callback ( ) - inbound mailbox message handler
2014-11-03 17:05:50 -06:00
* @ client : mailbox client pointer used for requesting the mailbox channel
2011-10-20 18:53:35 +02:00
* @ 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 .
*/
2014-11-03 17:05:50 -06:00
static void omap_rproc_mbox_callback ( struct mbox_client * client , void * data )
2011-10-20 18:53:35 +02:00
{
2014-11-03 17:05:50 -06:00
struct omap_rproc * oproc = container_of ( client , struct omap_rproc ,
client ) ;
remoteproc: maintain a generic child device for each rproc
For each registered rproc, maintain a generic remoteproc device whose
parent is the low level platform-specific device (commonly a pdev, but
it may certainly be any other type of device too).
With this in hand, the resulting device hierarchy might then look like:
omap-rproc.0
|
- remoteproc0 <---- new !
|
- virtio0
|
- virtio1
|
- rpmsg0
|
- rpmsg1
|
- rpmsg2
Where:
- omap-rproc.0 is the low level device that's bound to the
driver which invokes rproc_register()
- remoteproc0 is the result of this patch, and will be added by the
remoteproc framework when rproc_register() is invoked
- virtio0 and virtio1 are vdevs that are registered by remoteproc
when it realizes that they are supported by the firmware
of the physical remote processor represented by omap-rproc.0
- rpmsg0, rpmsg1 and rpmsg2 are rpmsg devices that represent rpmsg
channels, and are registerd by the rpmsg bus when it gets notified
about their existence
Technically, this patch:
- changes 'struct rproc' to contain this generic remoteproc.x device
- creates a new "remoteproc" type, to which this new generic remoteproc.x
device belong to.
- adds a super simple enumeration method for the indices of the
remoteproc.x devices
- updates all dev_* messaging to use the generic remoteproc.x device
instead of the low level platform-specific device
- updates all dma_* allocations to use the parent of remoteproc.x (where
the platform-specific memory pools, most commonly CMA, are to be found)
Adding this generic device has several merits:
- we can now add remoteproc runtime PM support simply by hooking onto the
new "remoteproc" type
- all remoteproc log messages will now carry a common name prefix
instead of having a platform-specific one
- having a device as part of the rproc struct makes it possible to simplify
refcounting (see subsequent patch)
Thanks to Stephen Boyd <sboyd@codeaurora.org> for suggesting and
discussing these ideas in one of the remoteproc review threads and
to Fernando Guzman Lugo <fernando.lugo@ti.com> for trying them out
with the (upcoming) runtime PM support for remoteproc.
Cc: Fernando Guzman Lugo <fernando.lugo@ti.com>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
2012-05-30 22:01:25 +03:00
struct device * dev = oproc - > rproc - > dev . parent ;
2011-10-20 18:53:35 +02:00
const char * name = oproc - > rproc - > name ;
2014-11-03 17:05:50 -06:00
u32 msg = ( u32 ) data ;
2011-10-20 18:53:35 +02:00
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 11:24:50 +01:00
/* msg contains the index of the triggered vring */
2011-10-20 18:53:35 +02:00
if ( rproc_vq_interrupt ( oproc - > rproc , msg ) = = IRQ_NONE )
dev_dbg ( dev , " no message was found in vqid %d \n " , msg ) ;
}
}
/* kick a virtqueue */
static void omap_rproc_kick ( struct rproc * rproc , int vqid )
{
struct omap_rproc * oproc = rproc - > priv ;
remoteproc: maintain a generic child device for each rproc
For each registered rproc, maintain a generic remoteproc device whose
parent is the low level platform-specific device (commonly a pdev, but
it may certainly be any other type of device too).
With this in hand, the resulting device hierarchy might then look like:
omap-rproc.0
|
- remoteproc0 <---- new !
|
- virtio0
|
- virtio1
|
- rpmsg0
|
- rpmsg1
|
- rpmsg2
Where:
- omap-rproc.0 is the low level device that's bound to the
driver which invokes rproc_register()
- remoteproc0 is the result of this patch, and will be added by the
remoteproc framework when rproc_register() is invoked
- virtio0 and virtio1 are vdevs that are registered by remoteproc
when it realizes that they are supported by the firmware
of the physical remote processor represented by omap-rproc.0
- rpmsg0, rpmsg1 and rpmsg2 are rpmsg devices that represent rpmsg
channels, and are registerd by the rpmsg bus when it gets notified
about their existence
Technically, this patch:
- changes 'struct rproc' to contain this generic remoteproc.x device
- creates a new "remoteproc" type, to which this new generic remoteproc.x
device belong to.
- adds a super simple enumeration method for the indices of the
remoteproc.x devices
- updates all dev_* messaging to use the generic remoteproc.x device
instead of the low level platform-specific device
- updates all dma_* allocations to use the parent of remoteproc.x (where
the platform-specific memory pools, most commonly CMA, are to be found)
Adding this generic device has several merits:
- we can now add remoteproc runtime PM support simply by hooking onto the
new "remoteproc" type
- all remoteproc log messages will now carry a common name prefix
instead of having a platform-specific one
- having a device as part of the rproc struct makes it possible to simplify
refcounting (see subsequent patch)
Thanks to Stephen Boyd <sboyd@codeaurora.org> for suggesting and
discussing these ideas in one of the remoteproc review threads and
to Fernando Guzman Lugo <fernando.lugo@ti.com> for trying them out
with the (upcoming) runtime PM support for remoteproc.
Cc: Fernando Guzman Lugo <fernando.lugo@ti.com>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
2012-05-30 22:01:25 +03:00
struct device * dev = rproc - > dev . parent ;
2011-10-20 18:53:35 +02:00
int ret ;
/* send the index of the triggered virtqueue in the mailbox payload */
2014-11-03 17:05:50 -06:00
ret = mbox_send_message ( oproc - > mbox , ( void * ) vqid ) ;
if ( ret < 0 )
2016-08-12 18:42:23 -05:00
dev_err ( dev , " failed to send mailbox message, status = %d \n " ,
ret ) ;
2011-10-20 18:53:35 +02:00
}
2020-03-24 13:00:22 +02:00
/**
* omap_rproc_write_dsp_boot_addr ( ) - set boot address for DSP remote processor
* @ rproc : handle of a remote processor
*
* Set boot address for a supported DSP remote processor .
2020-03-24 13:00:23 +02:00
*
* Return : 0 on success , or - EINVAL if boot address is not aligned properly
2020-03-24 13:00:22 +02:00
*/
2020-03-24 13:00:23 +02:00
static int omap_rproc_write_dsp_boot_addr ( struct rproc * rproc )
2020-03-24 13:00:22 +02:00
{
2020-03-24 13:00:23 +02:00
struct device * dev = rproc - > dev . parent ;
2020-03-24 13:00:22 +02:00
struct omap_rproc * oproc = rproc - > priv ;
struct omap_rproc_boot_data * bdata = oproc - > boot_data ;
u32 offset = bdata - > boot_reg ;
2020-03-24 13:00:23 +02:00
if ( rproc - > bootaddr & ( SZ_1K - 1 ) ) {
dev_err ( dev , " invalid boot address 0x%llx, must be aligned on a 1KB boundary \n " ,
rproc - > bootaddr ) ;
return - EINVAL ;
}
return regmap_write ( bdata - > syscon , offset , rproc - > bootaddr ) ;
2020-03-24 13:00:22 +02:00
}
2011-10-20 18:53:35 +02:00
/*
* 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 ;
remoteproc: maintain a generic child device for each rproc
For each registered rproc, maintain a generic remoteproc device whose
parent is the low level platform-specific device (commonly a pdev, but
it may certainly be any other type of device too).
With this in hand, the resulting device hierarchy might then look like:
omap-rproc.0
|
- remoteproc0 <---- new !
|
- virtio0
|
- virtio1
|
- rpmsg0
|
- rpmsg1
|
- rpmsg2
Where:
- omap-rproc.0 is the low level device that's bound to the
driver which invokes rproc_register()
- remoteproc0 is the result of this patch, and will be added by the
remoteproc framework when rproc_register() is invoked
- virtio0 and virtio1 are vdevs that are registered by remoteproc
when it realizes that they are supported by the firmware
of the physical remote processor represented by omap-rproc.0
- rpmsg0, rpmsg1 and rpmsg2 are rpmsg devices that represent rpmsg
channels, and are registerd by the rpmsg bus when it gets notified
about their existence
Technically, this patch:
- changes 'struct rproc' to contain this generic remoteproc.x device
- creates a new "remoteproc" type, to which this new generic remoteproc.x
device belong to.
- adds a super simple enumeration method for the indices of the
remoteproc.x devices
- updates all dev_* messaging to use the generic remoteproc.x device
instead of the low level platform-specific device
- updates all dma_* allocations to use the parent of remoteproc.x (where
the platform-specific memory pools, most commonly CMA, are to be found)
Adding this generic device has several merits:
- we can now add remoteproc runtime PM support simply by hooking onto the
new "remoteproc" type
- all remoteproc log messages will now carry a common name prefix
instead of having a platform-specific one
- having a device as part of the rproc struct makes it possible to simplify
refcounting (see subsequent patch)
Thanks to Stephen Boyd <sboyd@codeaurora.org> for suggesting and
discussing these ideas in one of the remoteproc review threads and
to Fernando Guzman Lugo <fernando.lugo@ti.com> for trying them out
with the (upcoming) runtime PM support for remoteproc.
Cc: Fernando Guzman Lugo <fernando.lugo@ti.com>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
2012-05-30 22:01:25 +03:00
struct device * dev = rproc - > dev . parent ;
2011-10-20 18:53:35 +02:00
int ret ;
2014-11-03 17:05:50 -06:00
struct mbox_client * client = & oproc - > client ;
2011-10-20 18:53:35 +02:00
2020-03-24 13:00:23 +02:00
if ( oproc - > boot_data ) {
ret = omap_rproc_write_dsp_boot_addr ( rproc ) ;
if ( ret )
return ret ;
}
2012-08-15 10:25:48 -05:00
2014-11-03 17:05:50 -06:00
client - > dev = dev ;
client - > tx_done = NULL ;
client - > rx_callback = omap_rproc_mbox_callback ;
client - > tx_block = false ;
client - > knows_txdone = false ;
2011-10-20 18:53:35 +02:00
2020-03-24 13:00:22 +02:00
oproc - > mbox = mbox_request_channel ( client , 0 ) ;
2011-10-20 18:53:35 +02:00
if ( IS_ERR ( oproc - > mbox ) ) {
2014-11-03 17:05:50 -06:00
ret = - EBUSY ;
dev_err ( dev , " mbox_request_channel failed: %ld \n " ,
PTR_ERR ( oproc - > mbox ) ) ;
2011-10-20 18:53:35 +02:00
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 .
*/
2014-11-03 17:05:50 -06:00
ret = mbox_send_message ( oproc - > mbox , ( void * ) RP_MBOX_ECHO_REQUEST ) ;
if ( ret < 0 ) {
dev_err ( dev , " mbox_send_message failed: %d \n " , ret ) ;
2011-10-20 18:53:35 +02:00
goto put_mbox ;
}
2020-03-24 13:00:22 +02:00
ret = reset_control_deassert ( oproc - > reset ) ;
2011-10-20 18:53:35 +02:00
if ( ret ) {
2020-03-24 13:00:22 +02:00
dev_err ( dev , " reset control deassert failed: %d \n " , ret ) ;
2011-10-20 18:53:35 +02:00
goto put_mbox ;
}
return 0 ;
put_mbox :
2014-11-03 17:05:50 -06:00
mbox_free_channel ( oproc - > mbox ) ;
2011-10-20 18:53:35 +02:00
return ret ;
}
/* power off the remote processor */
static int omap_rproc_stop ( struct rproc * rproc )
{
struct omap_rproc * oproc = rproc - > priv ;
int ret ;
2020-03-24 13:00:22 +02:00
ret = reset_control_assert ( oproc - > reset ) ;
2011-10-20 18:53:35 +02:00
if ( ret )
return ret ;
2014-11-03 17:05:50 -06:00
mbox_free_channel ( oproc - > mbox ) ;
2011-10-20 18:53:35 +02:00
return 0 ;
}
2020-03-24 13:00:25 +02:00
/**
* omap_rproc_da_to_va ( ) - internal memory translation helper
* @ rproc : remote processor to apply the address translation for
* @ da : device address to translate
* @ len : length of the memory buffer
*
* Custom function implementing the rproc . da_to_va ops to provide address
* translation ( device address to kernel virtual address ) for internal RAMs
* present in a DSP or IPU device ) . The translated addresses can be used
* either by the remoteproc core for loading , or by any rpmsg bus drivers .
*
* Return : translated virtual address in kernel memory space on success ,
* or NULL on failure .
*/
static void * omap_rproc_da_to_va ( struct rproc * rproc , u64 da , size_t len )
{
struct omap_rproc * oproc = rproc - > priv ;
int i ;
u32 offset ;
if ( len < = 0 )
return NULL ;
if ( ! oproc - > num_mems )
return NULL ;
for ( i = 0 ; i < oproc - > num_mems ; i + + ) {
if ( da > = oproc - > mem [ i ] . dev_addr & & da + len < =
oproc - > mem [ i ] . dev_addr + oproc - > mem [ i ] . size ) {
offset = da - oproc - > mem [ i ] . dev_addr ;
/* __force to make sparse happy with type conversion */
return ( __force void * ) ( oproc - > mem [ i ] . cpu_addr +
offset ) ;
}
}
return NULL ;
}
2017-01-01 16:13:37 +05:30
static const struct rproc_ops omap_rproc_ops = {
2011-10-20 18:53:35 +02:00
. start = omap_rproc_start ,
. stop = omap_rproc_stop ,
. kick = omap_rproc_kick ,
2020-03-24 13:00:25 +02:00
. da_to_va = omap_rproc_da_to_va ,
2011-10-20 18:53:35 +02:00
} ;
2020-03-24 13:00:24 +02:00
static const struct omap_rproc_mem_data ipu_mems [ ] = {
{ . name = " l2ram " , . dev_addr = 0x20000000 } ,
{ } ,
} ;
2020-03-24 13:00:22 +02:00
static const struct omap_rproc_dev_data omap4_dsp_dev_data = {
. device_name = " dsp " ,
} ;
static const struct omap_rproc_dev_data omap4_ipu_dev_data = {
. device_name = " ipu " ,
2020-03-24 13:00:24 +02:00
. mems = ipu_mems ,
2020-03-24 13:00:22 +02:00
} ;
static const struct omap_rproc_dev_data omap5_dsp_dev_data = {
. device_name = " dsp " ,
} ;
static const struct omap_rproc_dev_data omap5_ipu_dev_data = {
. device_name = " ipu " ,
2020-03-24 13:00:24 +02:00
. mems = ipu_mems ,
2020-03-24 13:00:22 +02:00
} ;
static const struct of_device_id omap_rproc_of_match [ ] = {
{
. compatible = " ti,omap4-dsp " ,
. data = & omap4_dsp_dev_data ,
} ,
{
. compatible = " ti,omap4-ipu " ,
. data = & omap4_ipu_dev_data ,
} ,
{
. compatible = " ti,omap5-dsp " ,
. data = & omap5_dsp_dev_data ,
} ,
{
. compatible = " ti,omap5-ipu " ,
. data = & omap5_ipu_dev_data ,
} ,
{
/* end */
} ,
} ;
MODULE_DEVICE_TABLE ( of , omap_rproc_of_match ) ;
static const char * omap_rproc_get_firmware ( struct platform_device * pdev )
{
const char * fw_name ;
int ret ;
ret = of_property_read_string ( pdev - > dev . of_node , " firmware-name " ,
& fw_name ) ;
if ( ret )
return ERR_PTR ( ret ) ;
return fw_name ;
}
static int omap_rproc_get_boot_data ( struct platform_device * pdev ,
struct rproc * rproc )
{
struct device_node * np = pdev - > dev . of_node ;
struct omap_rproc * oproc = rproc - > priv ;
const struct omap_rproc_dev_data * data ;
int ret ;
data = of_device_get_match_data ( & pdev - > dev ) ;
if ( ! data )
return - ENODEV ;
if ( ! of_property_read_bool ( np , " ti,bootreg " ) )
return 0 ;
oproc - > boot_data = devm_kzalloc ( & pdev - > dev , sizeof ( * oproc - > boot_data ) ,
GFP_KERNEL ) ;
if ( ! oproc - > boot_data )
return - ENOMEM ;
oproc - > boot_data - > syscon =
syscon_regmap_lookup_by_phandle ( np , " ti,bootreg " ) ;
if ( IS_ERR ( oproc - > boot_data - > syscon ) ) {
ret = PTR_ERR ( oproc - > boot_data - > syscon ) ;
return ret ;
}
if ( of_property_read_u32_index ( np , " ti,bootreg " , 1 ,
& oproc - > boot_data - > boot_reg ) ) {
dev_err ( & pdev - > dev , " couldn't get the boot register \n " ) ;
return - EINVAL ;
}
return 0 ;
}
2020-03-24 13:00:24 +02:00
static int omap_rproc_of_get_internal_memories ( struct platform_device * pdev ,
struct rproc * rproc )
{
struct omap_rproc * oproc = rproc - > priv ;
struct device * dev = & pdev - > dev ;
const struct omap_rproc_dev_data * data ;
struct resource * res ;
int num_mems ;
int i ;
data = of_device_get_match_data ( dev ) ;
if ( ! data )
return - ENODEV ;
if ( ! data - > mems )
return 0 ;
num_mems = of_property_count_elems_of_size ( dev - > of_node , " reg " ,
sizeof ( u32 ) ) / 2 ;
oproc - > mem = devm_kcalloc ( dev , num_mems , sizeof ( * oproc - > mem ) ,
GFP_KERNEL ) ;
if ( ! oproc - > mem )
return - ENOMEM ;
for ( i = 0 ; data - > mems [ i ] . name ; i + + ) {
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM ,
data - > mems [ i ] . name ) ;
if ( ! res ) {
dev_err ( dev , " no memory defined for %s \n " ,
data - > mems [ i ] . name ) ;
return - ENOMEM ;
}
oproc - > mem [ i ] . cpu_addr = devm_ioremap_resource ( dev , res ) ;
if ( IS_ERR ( oproc - > mem [ i ] . cpu_addr ) ) {
dev_err ( dev , " failed to parse and map %s memory \n " ,
data - > mems [ i ] . name ) ;
return PTR_ERR ( oproc - > mem [ i ] . cpu_addr ) ;
}
oproc - > mem [ i ] . bus_addr = res - > start ;
oproc - > mem [ i ] . dev_addr = data - > mems [ i ] . dev_addr ;
oproc - > mem [ i ] . size = resource_size ( res ) ;
dev_dbg ( dev , " memory %8s: bus addr %pa size 0x%x va %pK da 0x%x \n " ,
data - > mems [ i ] . name , & oproc - > mem [ i ] . bus_addr ,
oproc - > mem [ i ] . size , oproc - > mem [ i ] . cpu_addr ,
oproc - > mem [ i ] . dev_addr ) ;
}
oproc - > num_mems = num_mems ;
return 0 ;
}
2012-12-21 15:14:44 -08:00
static int omap_rproc_probe ( struct platform_device * pdev )
2011-10-20 18:53:35 +02:00
{
2020-03-24 13:00:22 +02:00
struct device_node * np = pdev - > dev . of_node ;
2011-10-20 18:53:35 +02:00
struct omap_rproc * oproc ;
struct rproc * rproc ;
2020-03-24 13:00:22 +02:00
const char * firmware ;
2011-10-20 18:53:35 +02:00
int ret ;
2020-03-24 13:00:22 +02:00
struct reset_control * reset ;
if ( ! np ) {
dev_err ( & pdev - > dev , " only DT-based devices are supported \n " ) ;
return - ENODEV ;
}
reset = devm_reset_control_array_get_exclusive ( & pdev - > dev ) ;
if ( IS_ERR ( reset ) )
return PTR_ERR ( reset ) ;
firmware = omap_rproc_get_firmware ( pdev ) ;
if ( IS_ERR ( firmware ) )
return PTR_ERR ( firmware ) ;
2011-10-20 18:53:35 +02:00
ret = dma_set_coherent_mask ( & pdev - > dev , DMA_BIT_MASK ( 32 ) ) ;
if ( ret ) {
2012-05-21 16:31:12 +03:00
dev_err ( & pdev - > dev , " dma_set_coherent_mask: %d \n " , ret ) ;
2011-10-20 18:53:35 +02:00
return ret ;
}
2020-03-24 13:00:22 +02:00
rproc = rproc_alloc ( & pdev - > dev , dev_name ( & pdev - > dev ) , & omap_rproc_ops ,
firmware , sizeof ( * oproc ) ) ;
2011-10-20 18:53:35 +02:00
if ( ! rproc )
return - ENOMEM ;
oproc = rproc - > priv ;
oproc - > rproc = rproc ;
2020-03-24 13:00:22 +02:00
oproc - > reset = reset ;
2015-01-09 15:21:58 -06:00
/* All existing OMAP IPU and DSP processors have an MMU */
rproc - > has_iommu = true ;
2011-10-20 18:53:35 +02:00
2020-03-24 13:00:24 +02:00
ret = omap_rproc_of_get_internal_memories ( pdev , rproc ) ;
if ( ret )
goto free_rproc ;
2020-03-24 13:00:22 +02:00
ret = omap_rproc_get_boot_data ( pdev , rproc ) ;
if ( ret )
goto free_rproc ;
2020-03-24 13:00:26 +02:00
ret = of_reserved_mem_device_init ( & pdev - > dev ) ;
if ( ret ) {
dev_warn ( & pdev - > dev , " device does not have specific CMA pool. \n " ) ;
dev_warn ( & pdev - > dev , " Typically this should be provided, \n " ) ;
dev_warn ( & pdev - > dev , " only omit if you know what you are doing. \n " ) ;
}
2011-10-20 18:53:35 +02:00
platform_set_drvdata ( pdev , rproc ) ;
2012-07-04 16:25:06 +03:00
ret = rproc_add ( rproc ) ;
2011-10-20 18:53:35 +02:00
if ( ret )
2020-03-24 13:00:26 +02:00
goto release_mem ;
2011-10-20 18:53:35 +02:00
return 0 ;
2020-03-24 13:00:26 +02:00
release_mem :
of_reserved_mem_device_release ( & pdev - > dev ) ;
2011-10-20 18:53:35 +02:00
free_rproc :
2016-10-02 17:46:38 -07:00
rproc_free ( rproc ) ;
2011-10-20 18:53:35 +02:00
return ret ;
}
2012-12-21 15:14:44 -08:00
static int omap_rproc_remove ( struct platform_device * pdev )
2011-10-20 18:53:35 +02:00
{
struct rproc * rproc = platform_get_drvdata ( pdev ) ;
2012-07-04 16:25:06 +03:00
rproc_del ( rproc ) ;
2016-10-02 17:46:38 -07:00
rproc_free ( rproc ) ;
2020-03-24 13:00:26 +02:00
of_reserved_mem_device_release ( & pdev - > dev ) ;
2012-07-02 11:41:16 +03:00
return 0 ;
2011-10-20 18:53:35 +02:00
}
static struct platform_driver omap_rproc_driver = {
. probe = omap_rproc_probe ,
2012-12-21 15:14:44 -08:00
. remove = omap_rproc_remove ,
2011-10-20 18:53:35 +02:00
. driver = {
. name = " omap-rproc " ,
2020-03-24 13:00:22 +02:00
. of_match_table = omap_rproc_of_match ,
2011-10-20 18:53:35 +02:00
} ,
} ;
2011-12-13 14:41:47 +02:00
module_platform_driver ( omap_rproc_driver ) ;
2011-10-20 18:53:35 +02:00
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " OMAP Remote Processor control driver " ) ;