2017-12-05 14:29:31 -06:00
/*
* OMAP Display Subsystem Base
*
* Copyright ( C ) 2015 - 2017 Texas Instruments Incorporated - http : //www.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 .
*/
2015-11-05 17:19:32 +02:00
# include <linux/kernel.h>
2018-02-28 23:49:24 +02:00
# include <linux/list.h>
2015-11-05 17:19:32 +02:00
# include <linux/module.h>
2018-02-28 23:49:24 +02:00
# include <linux/mutex.h>
2016-05-03 22:07:10 +03:00
# include <linux/of.h>
# include <linux/of_graph.h>
2018-02-13 14:00:41 +02:00
# include "dss.h"
2016-05-03 22:07:10 +03:00
# include "omapdss.h"
2015-11-05 17:19:32 +02:00
2018-02-13 14:00:40 +02:00
static struct dss_device * dss_device ;
2015-11-05 17:23:14 +02:00
2018-02-13 14:00:40 +02:00
struct dss_device * omapdss_get_dss ( void )
2015-11-05 17:23:14 +02:00
{
2018-02-13 14:00:40 +02:00
return dss_device ;
2015-11-05 17:23:14 +02:00
}
2018-02-13 14:00:40 +02:00
EXPORT_SYMBOL ( omapdss_get_dss ) ;
2015-11-05 17:23:14 +02:00
2018-02-13 14:00:40 +02:00
void omapdss_set_dss ( struct dss_device * dss )
2015-11-05 17:23:14 +02:00
{
2018-02-13 14:00:40 +02:00
dss_device = dss ;
2015-11-05 17:23:14 +02:00
}
2018-02-13 14:00:40 +02:00
EXPORT_SYMBOL ( omapdss_set_dss ) ;
2015-11-05 17:23:14 +02:00
2018-02-13 14:00:42 +02:00
struct dispc_device * dispc_get_dispc ( struct dss_device * dss )
{
return dss - > dispc ;
}
EXPORT_SYMBOL ( dispc_get_dispc ) ;
2018-02-13 14:00:41 +02:00
const struct dispc_ops * dispc_get_ops ( struct dss_device * dss )
2015-11-05 19:36:02 +02:00
{
2018-02-13 14:00:41 +02:00
return dss - > dispc_ops ;
2015-11-05 19:36:02 +02:00
}
EXPORT_SYMBOL ( dispc_get_ops ) ;
2018-02-28 23:49:24 +02:00
/* -----------------------------------------------------------------------------
* OMAP DSS Devices Handling
*/
static LIST_HEAD ( omapdss_devices_list ) ;
static DEFINE_MUTEX ( omapdss_devices_lock ) ;
void omapdss_device_register ( struct omap_dss_device * dssdev )
{
mutex_lock ( & omapdss_devices_lock ) ;
list_add_tail ( & dssdev - > list , & omapdss_devices_list ) ;
mutex_unlock ( & omapdss_devices_lock ) ;
}
2018-03-02 01:25:32 +02:00
EXPORT_SYMBOL_GPL ( omapdss_device_register ) ;
2018-02-28 23:49:24 +02:00
void omapdss_device_unregister ( struct omap_dss_device * dssdev )
{
mutex_lock ( & omapdss_devices_lock ) ;
list_del ( & dssdev - > list ) ;
mutex_unlock ( & omapdss_devices_lock ) ;
}
2018-03-02 01:25:32 +02:00
EXPORT_SYMBOL_GPL ( omapdss_device_unregister ) ;
2018-02-28 23:49:24 +02:00
2018-02-28 23:53:16 +02:00
static bool omapdss_device_is_registered ( struct device_node * node )
{
struct omap_dss_device * dssdev ;
bool found = false ;
mutex_lock ( & omapdss_devices_lock ) ;
list_for_each_entry ( dssdev , & omapdss_devices_list , list ) {
if ( dssdev - > dev - > of_node = = node ) {
found = true ;
break ;
}
}
mutex_unlock ( & omapdss_devices_lock ) ;
return found ;
}
2018-03-01 23:35:55 +02:00
struct omap_dss_device * omapdss_find_device_by_port ( struct device_node * src ,
unsigned int port )
{
struct omap_dss_device * dssdev ;
list_for_each_entry ( dssdev , & omapdss_devices_list , list ) {
if ( dssdev - > dev - > of_node = = src & & dssdev - > port_num = = port )
return omap_dss_get_device ( dssdev ) ;
}
return NULL ;
}
2018-02-28 17:30:30 +02:00
int omapdss_device_connect ( struct omap_dss_device * src ,
struct omap_dss_device * dst )
{
2018-02-28 17:30:30 +02:00
int ret ;
2018-02-28 17:30:30 +02:00
dev_dbg ( src - > dev , " connect \n " ) ;
if ( omapdss_device_is_connected ( src ) )
return - EBUSY ;
2018-02-28 17:30:30 +02:00
if ( src - > driver )
2018-02-28 17:30:30 +02:00
ret = src - > driver - > connect ( src ) ;
2018-02-28 17:30:30 +02:00
else
2018-02-28 17:30:30 +02:00
ret = src - > ops - > connect ( src , dst ) ;
if ( ret < 0 )
return ret ;
if ( dst ) {
dst - > src = src ;
src - > dst = dst ;
}
return 0 ;
2018-02-28 17:30:30 +02:00
}
EXPORT_SYMBOL_GPL ( omapdss_device_connect ) ;
void omapdss_device_disconnect ( struct omap_dss_device * src ,
struct omap_dss_device * dst )
{
2018-02-28 17:30:30 +02:00
dev_dbg ( src - > dev , " disconnect \n " ) ;
if ( ! src - > id & & ! omapdss_device_is_connected ( src ) ) {
WARN_ON ( ! src - > driver ) ;
return ;
}
2018-02-28 17:30:30 +02:00
if ( dst ) {
if ( WARN_ON ( dst ! = src - > dst ) )
return ;
dst - > src = NULL ;
src - > dst = NULL ;
}
2018-02-28 17:30:30 +02:00
if ( src - > driver )
src - > driver - > disconnect ( src ) ;
else
src - > ops - > disconnect ( src , dst ) ;
}
EXPORT_SYMBOL_GPL ( omapdss_device_disconnect ) ;
2018-02-28 23:49:24 +02:00
/* -----------------------------------------------------------------------------
* Components Handling
*/
static struct list_head omapdss_comp_list ;
struct omapdss_comp_node {
struct list_head list ;
struct device_node * node ;
bool dss_core_component ;
} ;
2016-05-03 22:07:10 +03:00
static bool omapdss_list_contains ( const struct device_node * node )
{
struct omapdss_comp_node * comp ;
list_for_each_entry ( comp , & omapdss_comp_list , list ) {
if ( comp - > node = = node )
return true ;
}
return false ;
}
static void omapdss_walk_device ( struct device * dev , struct device_node * node ,
bool dss_core )
{
struct device_node * n ;
struct omapdss_comp_node * comp = devm_kzalloc ( dev , sizeof ( * comp ) ,
GFP_KERNEL ) ;
if ( comp ) {
comp - > node = node ;
comp - > dss_core_component = dss_core ;
list_add ( & comp - > list , & omapdss_comp_list ) ;
}
/*
* of_graph_get_remote_port_parent ( ) prints an error if there is no
* port / ports node . To avoid that , check first that there ' s the node .
*/
n = of_get_child_by_name ( node , " ports " ) ;
if ( ! n )
n = of_get_child_by_name ( node , " port " ) ;
if ( ! n )
return ;
of_node_put ( n ) ;
n = NULL ;
while ( ( n = of_graph_get_next_endpoint ( node , n ) ) ! = NULL ) {
struct device_node * pn = of_graph_get_remote_port_parent ( n ) ;
if ( ! pn )
continue ;
if ( ! of_device_is_available ( pn ) | | omapdss_list_contains ( pn ) ) {
of_node_put ( pn ) ;
continue ;
}
omapdss_walk_device ( dev , pn , false ) ;
}
}
void omapdss_gather_components ( struct device * dev )
{
struct device_node * child ;
INIT_LIST_HEAD ( & omapdss_comp_list ) ;
omapdss_walk_device ( dev , dev - > of_node , true ) ;
for_each_available_child_of_node ( dev - > of_node , child ) {
if ( ! of_find_property ( child , " compatible " , NULL ) )
continue ;
omapdss_walk_device ( dev , child , true ) ;
}
}
EXPORT_SYMBOL ( omapdss_gather_components ) ;
static bool omapdss_component_is_loaded ( struct omapdss_comp_node * comp )
{
if ( comp - > dss_core_component )
return true ;
2018-02-28 23:53:16 +02:00
if ( omapdss_device_is_registered ( comp - > node ) )
2016-05-03 22:07:10 +03:00
return true ;
return false ;
}
bool omapdss_stack_is_ready ( void )
{
struct omapdss_comp_node * comp ;
list_for_each_entry ( comp , & omapdss_comp_list , list ) {
if ( ! omapdss_component_is_loaded ( comp ) )
return false ;
}
return true ;
}
EXPORT_SYMBOL ( omapdss_stack_is_ready ) ;
2015-11-05 17:19:32 +02:00
MODULE_AUTHOR ( " Tomi Valkeinen <tomi.valkeinen@ti.com> " ) ;
MODULE_DESCRIPTION ( " OMAP Display Subsystem Base " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;