2019-06-01 11:08:42 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2006-01-21 01:08:59 +03:00
2005-04-17 02:20:36 +04:00
/*
* drm_sysfs . c - Modifications to drm_sysfs_class . c to support
* extra sysfs attribute from DRM . Normal drm_sysfs_class
* does not allow adding attributes .
*
* Copyright ( c ) 2004 Jon Smirl < jonsmirl @ gmail . com >
* Copyright ( c ) 2003 - 2004 Greg Kroah - Hartman < greg @ kroah . com >
* Copyright ( c ) 2003 - 2004 IBM Corp .
*/
2021-08-18 00:51:55 +03:00
# include <linux/acpi.h>
drm/sysfs: Link DRM connectors to corresponding Type-C connectors
Create a symlink pointing to USB Type-C connector for DRM connectors
when they are created. The link will be created only if the firmware is
able to describe the connection beween the two connectors.
Currently, even if a display uses a USB Type-C port, there is no way for
the userspace to find which port is used for which display. With the
symlink, display information would be accessible from Type-C connectors
and port information would be accessible from DRM connectors.
Associating the two subsystems, userspace would have potential to expose
and utilize more complex information. ChromeOS intend to use this
information for metrics collection. For example, we want to tell which
port is deriving which displays. Also, combined with USB PD information,
we can tell whether user is charging their device through display.
Chromium patch for parsing the symlink from the kernel is at
http://crrev.com/c/4317207.
We already have a framework in typec port-mapper.c where it goes through
component devices and runs the bind functions for those with matching
_PLD (physical location of device).
https://elixir.bootlin.com/linux/v5.18.1/source/drivers/usb/typec/
port-mapper.c
Since _PLD is ACPI specific field, this linking would only work on ACPI
x86 as long as _PLD field for Type-C connectors and DRM connectors are
correctly added to the firmware.
Currently, USB ports and USB4 ports are added as components to create a
symlink with Type C connector.
USB:
https://lore.kernel.org/all/20211223082349.45616-1-heikki.krogerus
@linux.intel.com/
USB4:
https://lore.kernel.org/all/20220418175932.1809770-3-wonchung@google.com/
So, we follow the same pattern in this patch.
Signed-off-by: Won Chung <wonchung@google.com>
Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Manasi Navare <navaremanasi@chromium.org>
Signed-off-by: Manasi Navare <navaremanasi@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20230427165813.2844530-1-wonchung@google.com
2023-04-27 19:58:13 +03:00
# include <linux/component.h>
2005-04-17 02:20:36 +04:00
# include <linux/device.h>
# include <linux/err.h>
2011-08-31 02:16:33 +04:00
# include <linux/export.h>
2019-05-26 20:35:35 +03:00
# include <linux/gfp.h>
2019-07-26 20:22:55 +03:00
# include <linux/i2c.h>
2019-05-26 20:35:35 +03:00
# include <linux/kdev_t.h>
drm/sysfs: Link DRM connectors to corresponding Type-C connectors
Create a symlink pointing to USB Type-C connector for DRM connectors
when they are created. The link will be created only if the firmware is
able to describe the connection beween the two connectors.
Currently, even if a display uses a USB Type-C port, there is no way for
the userspace to find which port is used for which display. With the
symlink, display information would be accessible from Type-C connectors
and port information would be accessible from DRM connectors.
Associating the two subsystems, userspace would have potential to expose
and utilize more complex information. ChromeOS intend to use this
information for metrics collection. For example, we want to tell which
port is deriving which displays. Also, combined with USB PD information,
we can tell whether user is charging their device through display.
Chromium patch for parsing the symlink from the kernel is at
http://crrev.com/c/4317207.
We already have a framework in typec port-mapper.c where it goes through
component devices and runs the bind functions for those with matching
_PLD (physical location of device).
https://elixir.bootlin.com/linux/v5.18.1/source/drivers/usb/typec/
port-mapper.c
Since _PLD is ACPI specific field, this linking would only work on ACPI
x86 as long as _PLD field for Type-C connectors and DRM connectors are
correctly added to the firmware.
Currently, USB ports and USB4 ports are added as components to create a
symlink with Type C connector.
USB:
https://lore.kernel.org/all/20211223082349.45616-1-heikki.krogerus
@linux.intel.com/
USB4:
https://lore.kernel.org/all/20220418175932.1809770-3-wonchung@google.com/
So, we follow the same pattern in this patch.
Signed-off-by: Won Chung <wonchung@google.com>
Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Manasi Navare <navaremanasi@chromium.org>
Signed-off-by: Manasi Navare <navaremanasi@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20230427165813.2844530-1-wonchung@google.com
2023-04-27 19:58:13 +03:00
# include <linux/property.h>
2019-05-26 20:35:35 +03:00
# include <linux/slab.h>
2022-10-31 16:31:07 +03:00
# include <drm/drm_accel.h>
2019-05-26 20:35:35 +03:00
# include <drm/drm_connector.h>
# include <drm/drm_device.h>
# include <drm/drm_file.h>
# include <drm/drm_modes.h>
# include <drm/drm_print.h>
# include <drm/drm_property.h>
2012-10-02 21:01:07 +04:00
# include <drm/drm_sysfs.h>
2019-05-26 20:35:35 +03:00
2014-09-10 14:43:53 +04:00
# include "drm_internal.h"
2019-08-01 14:41:16 +03:00
# include "drm_crtc_internal.h"
2005-04-17 02:20:36 +04:00
2013-10-11 08:07:25 +04:00
# define to_drm_minor(d) dev_get_drvdata(d)
# define to_drm_connector(d) dev_get_drvdata(d)
2007-11-22 07:02:38 +03:00
2017-04-04 12:52:55 +03:00
/**
* DOC : overview
*
* DRM provides very little additional support to drivers for sysfs
* interactions , beyond just all the standard stuff . Drivers who want to expose
* additional sysfs properties and property groups can attach them at either
* & drm_device . dev or & drm_connector . kdev .
*
* Registration is automatically handled when calling drm_dev_register ( ) , or
* drm_connector_register ( ) in case of hot - plugged connectors . Unregistration is
* also automatically handled by drm_dev_unregister ( ) and
* drm_connector_unregister ( ) .
*/
2009-08-20 13:02:31 +04:00
static struct device_type drm_sysfs_device_minor = {
. name = " drm_minor "
} ;
2021-08-18 00:51:54 +03:00
static struct device_type drm_sysfs_device_connector = {
. name = " drm_connector " ,
} ;
2015-09-09 15:21:30 +03:00
struct class * drm_class ;
2021-08-18 00:51:55 +03:00
# ifdef CONFIG_ACPI
static bool drm_connector_acpi_bus_match ( struct device * dev )
{
return dev - > type = = & drm_sysfs_device_connector ;
}
static struct acpi_device * drm_connector_acpi_find_companion ( struct device * dev )
{
struct drm_connector * connector = to_drm_connector ( dev ) ;
return to_acpi_device_node ( connector - > fwnode ) ;
}
static struct acpi_bus_type drm_connector_acpi_bus = {
. name = " drm_connector " ,
. match = drm_connector_acpi_bus_match ,
. find_companion = drm_connector_acpi_find_companion ,
} ;
static void drm_sysfs_acpi_register ( void )
{
register_acpi_bus_type ( & drm_connector_acpi_bus ) ;
}
static void drm_sysfs_acpi_unregister ( void )
{
unregister_acpi_bus_type ( & drm_connector_acpi_bus ) ;
}
# else
static void drm_sysfs_acpi_register ( void ) { }
static void drm_sysfs_acpi_unregister ( void ) { }
# endif
2022-11-23 15:25:20 +03:00
static char * drm_devnode ( const struct device * dev , umode_t * mode )
2009-04-30 17:23:42 +04:00
{
return kasprintf ( GFP_KERNEL , " dri/%s " , dev_name ( dev ) ) ;
}
drm/sysfs: Link DRM connectors to corresponding Type-C connectors
Create a symlink pointing to USB Type-C connector for DRM connectors
when they are created. The link will be created only if the firmware is
able to describe the connection beween the two connectors.
Currently, even if a display uses a USB Type-C port, there is no way for
the userspace to find which port is used for which display. With the
symlink, display information would be accessible from Type-C connectors
and port information would be accessible from DRM connectors.
Associating the two subsystems, userspace would have potential to expose
and utilize more complex information. ChromeOS intend to use this
information for metrics collection. For example, we want to tell which
port is deriving which displays. Also, combined with USB PD information,
we can tell whether user is charging their device through display.
Chromium patch for parsing the symlink from the kernel is at
http://crrev.com/c/4317207.
We already have a framework in typec port-mapper.c where it goes through
component devices and runs the bind functions for those with matching
_PLD (physical location of device).
https://elixir.bootlin.com/linux/v5.18.1/source/drivers/usb/typec/
port-mapper.c
Since _PLD is ACPI specific field, this linking would only work on ACPI
x86 as long as _PLD field for Type-C connectors and DRM connectors are
correctly added to the firmware.
Currently, USB ports and USB4 ports are added as components to create a
symlink with Type C connector.
USB:
https://lore.kernel.org/all/20211223082349.45616-1-heikki.krogerus
@linux.intel.com/
USB4:
https://lore.kernel.org/all/20220418175932.1809770-3-wonchung@google.com/
So, we follow the same pattern in this patch.
Signed-off-by: Won Chung <wonchung@google.com>
Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Manasi Navare <navaremanasi@chromium.org>
Signed-off-by: Manasi Navare <navaremanasi@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20230427165813.2844530-1-wonchung@google.com
2023-04-27 19:58:13 +03:00
static int typec_connector_bind ( struct device * dev ,
struct device * typec_connector , void * data )
{
int ret ;
ret = sysfs_create_link ( & dev - > kobj , & typec_connector - > kobj , " typec_connector " ) ;
if ( ret )
return ret ;
ret = sysfs_create_link ( & typec_connector - > kobj , & dev - > kobj , " drm_connector " ) ;
if ( ret )
sysfs_remove_link ( & dev - > kobj , " typec_connector " ) ;
return ret ;
}
static void typec_connector_unbind ( struct device * dev ,
struct device * typec_connector , void * data )
{
sysfs_remove_link ( & typec_connector - > kobj , " drm_connector " ) ;
sysfs_remove_link ( & dev - > kobj , " typec_connector " ) ;
}
static const struct component_ops typec_connector_ops = {
. bind = typec_connector_bind ,
. unbind = typec_connector_unbind ,
} ;
drm: drop obsolete drm_core.h
The drm_core.h header contains a set of constants meant to be used
throughout DRM. However, as it turns out, they're each used just once and
don't bring any benefit. They're also grossly mis-named and lack
name-spacing. This patch inlines them, or moves them into drm_internal.h
as appropriate:
- CORE_AUTHOR and CORE_DESC are inlined into corresponding MODULE_*()
macros. It's just confusing having to follow 2 pointers when trying to
find the definition of these fields. Grep'ping for MODULE_AUTHOR()
should reveal the full information, if there's no strong reason not to.
- CORE_NAME, CORE_DATE, CORE_MAJOR, CORE_MINOR, and CORE_PATCHLEVEL are
inlined into the sysfs 'version' attribute. They're stripped
everywhere else (which is just some printk() statements). CORE_NAME
just doesn't make *any* sense, as we hard-code it in many places,
anyway. The other constants are outdated and just serve
binary-compatibility purposes. Hence, inline them in 'version' sysfs
attribute (we might even try dropping it..).
- DRM_IF_MAJOR and DRM_IF_MINOR are moved into drm_internal.h as they're
only used by the global ioctl handlers. Furthermore, versioning
interfaces breaks backports and as such is deprecated, anyway. We just
keep them for historic reasons. I doubt anyone will ever modify them
again.
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/20160901124837.680-6-dh.herrmann@gmail.com
2016-09-01 15:48:36 +03:00
static CLASS_ATTR_STRING ( version , S_IRUGO , " drm 1.1.0 20060810 " ) ;
2005-04-17 02:20:36 +04:00
/**
2015-09-09 15:21:30 +03:00
* drm_sysfs_init - initialize sysfs helpers
*
* This is used to create the DRM class , which is the implicit parent of any
* other top - level DRM sysfs objects .
2005-04-17 02:20:36 +04:00
*
2015-09-09 15:21:30 +03:00
* You must call drm_sysfs_destroy ( ) to release the allocated resources .
2005-04-17 02:20:36 +04:00
*
2015-09-09 15:21:30 +03:00
* Return : 0 on success , negative error code on failure .
2005-04-17 02:20:36 +04:00
*/
2015-09-09 15:21:30 +03:00
int drm_sysfs_init ( void )
2005-04-17 02:20:36 +04:00
{
2006-10-11 01:23:37 +04:00
int err ;
2006-01-21 01:08:59 +03:00
2023-03-13 21:18:35 +03:00
drm_class = class_create ( " drm " ) ;
2015-09-09 15:21:30 +03:00
if ( IS_ERR ( drm_class ) )
return PTR_ERR ( drm_class ) ;
2007-11-22 07:02:38 +03:00
2015-09-09 15:21:30 +03:00
err = class_create_file ( drm_class , & class_attr_version . attr ) ;
if ( err ) {
class_destroy ( drm_class ) ;
drm_class = NULL ;
return err ;
}
2006-10-11 01:23:37 +04:00
2015-09-09 15:21:30 +03:00
drm_class - > devnode = drm_devnode ;
2021-08-18 00:51:55 +03:00
drm_sysfs_acpi_register ( ) ;
2015-09-09 15:21:30 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/**
2007-11-22 07:02:38 +03:00
* drm_sysfs_destroy - destroys DRM class
2005-04-17 02:20:36 +04:00
*
2007-11-22 07:02:38 +03:00
* Destroy the DRM device class .
2005-04-17 02:20:36 +04:00
*/
2007-11-22 07:02:38 +03:00
void drm_sysfs_destroy ( void )
2005-04-17 02:20:36 +04:00
{
2015-09-09 15:21:29 +03:00
if ( IS_ERR_OR_NULL ( drm_class ) )
2005-04-17 02:20:36 +04:00
return ;
2021-08-18 00:51:55 +03:00
drm_sysfs_acpi_unregister ( ) ;
2010-01-05 14:48:09 +03:00
class_remove_file ( drm_class , & class_attr_version . attr ) ;
2007-11-22 07:02:38 +03:00
class_destroy ( drm_class ) ;
2012-07-06 21:06:42 +04:00
drm_class = NULL ;
2005-04-17 02:20:36 +04:00
}
2021-08-18 00:51:54 +03:00
static void drm_sysfs_release ( struct device * dev )
{
kfree ( dev ) ;
}
2008-11-08 01:05:41 +03:00
/*
* Connector properties
*/
2015-03-06 15:36:42 +03:00
static ssize_t status_store ( struct device * device ,
2008-11-08 01:05:41 +03:00
struct device_attribute * attr ,
2015-03-06 15:36:42 +03:00
const char * buf , size_t count )
2008-11-08 01:05:41 +03:00
{
struct drm_connector * connector = to_drm_connector ( device ) ;
2015-03-06 15:36:42 +03:00
struct drm_device * dev = connector - > dev ;
2015-11-19 19:46:50 +03:00
enum drm_connector_force old_force ;
2011-03-15 14:40:00 +03:00
int ret ;
2015-03-06 15:36:42 +03:00
ret = mutex_lock_interruptible ( & dev - > mode_config . mutex ) ;
2011-03-15 14:40:00 +03:00
if ( ret )
return ret ;
2008-11-08 01:05:41 +03:00
2015-11-19 19:46:50 +03:00
old_force = connector - > force ;
2015-03-06 15:36:42 +03:00
2015-11-19 19:46:50 +03:00
if ( sysfs_streq ( buf , " detect " ) )
2015-03-06 15:36:42 +03:00
connector - > force = 0 ;
2015-11-19 19:46:50 +03:00
else if ( sysfs_streq ( buf , " on " ) )
2015-03-06 15:36:42 +03:00
connector - > force = DRM_FORCE_ON ;
2015-11-19 19:46:50 +03:00
else if ( sysfs_streq ( buf , " on-digital " ) )
2015-03-06 15:36:42 +03:00
connector - > force = DRM_FORCE_ON_DIGITAL ;
2015-11-19 19:46:50 +03:00
else if ( sysfs_streq ( buf , " off " ) )
2015-03-06 15:36:42 +03:00
connector - > force = DRM_FORCE_OFF ;
2015-11-19 19:46:50 +03:00
else
2015-03-06 15:36:42 +03:00
ret = - EINVAL ;
2015-11-19 19:46:50 +03:00
if ( old_force ! = connector - > force | | ! connector - > force ) {
DRM_DEBUG_KMS ( " [CONNECTOR:%d:%s] force updated from %d to %d or reprobing \n " ,
2015-03-06 15:36:42 +03:00
connector - > base . id ,
connector - > name ,
2015-11-19 19:46:50 +03:00
old_force , connector - > force ) ;
2015-03-06 15:36:42 +03:00
2015-11-19 19:46:50 +03:00
connector - > funcs - > fill_modes ( connector ,
dev - > mode_config . max_width ,
dev - > mode_config . max_height ) ;
2015-03-06 15:36:42 +03:00
}
mutex_unlock ( & dev - > mode_config . mutex ) ;
2015-06-06 01:27:30 +03:00
return ret ? ret : count ;
2015-03-06 15:36:42 +03:00
}
static ssize_t status_show ( struct device * device ,
struct device_attribute * attr ,
char * buf )
{
struct drm_connector * connector = to_drm_connector ( device ) ;
2016-03-30 12:45:13 +03:00
enum drm_connector_status status ;
status = READ_ONCE ( connector - > status ) ;
2011-03-15 14:40:00 +03:00
2021-03-22 04:19:38 +03:00
return sysfs_emit ( buf , " %s \n " ,
drm_get_connector_status_name ( status ) ) ;
2008-11-08 01:05:41 +03:00
}
static ssize_t dpms_show ( struct device * device ,
struct device_attribute * attr ,
char * buf )
{
struct drm_connector * connector = to_drm_connector ( device ) ;
2015-09-29 10:56:53 +03:00
int dpms ;
2008-11-08 01:05:41 +03:00
2015-09-29 10:56:53 +03:00
dpms = READ_ONCE ( connector - > dpms ) ;
2008-11-08 01:05:41 +03:00
2021-03-22 04:19:38 +03:00
return sysfs_emit ( buf , " %s \n " , drm_get_dpms_name ( dpms ) ) ;
2008-11-08 01:05:41 +03:00
}
static ssize_t enabled_show ( struct device * device ,
struct device_attribute * attr ,
char * buf )
{
struct drm_connector * connector = to_drm_connector ( device ) ;
2016-03-30 12:45:13 +03:00
bool enabled ;
enabled = READ_ONCE ( connector - > encoder ) ;
2008-11-08 01:05:41 +03:00
2021-03-22 04:19:38 +03:00
return sysfs_emit ( buf , enabled ? " enabled \n " : " disabled \n " ) ;
2008-11-08 01:05:41 +03:00
}
2010-05-13 05:28:57 +04:00
static ssize_t edid_show ( struct file * filp , struct kobject * kobj ,
struct bin_attribute * attr , char * buf , loff_t off ,
size_t count )
2008-11-08 01:05:41 +03:00
{
2016-01-13 17:48:41 +03:00
struct device * connector_dev = kobj_to_dev ( kobj ) ;
2008-11-08 01:05:41 +03:00
struct drm_connector * connector = to_drm_connector ( connector_dev ) ;
unsigned char * edid ;
size_t size ;
2015-10-02 14:01:02 +03:00
ssize_t ret = 0 ;
2008-11-08 01:05:41 +03:00
2015-10-02 14:01:02 +03:00
mutex_lock ( & connector - > dev - > mode_config . mutex ) ;
2008-11-08 01:05:41 +03:00
if ( ! connector - > edid_blob_ptr )
2015-10-02 14:01:02 +03:00
goto unlock ;
2008-11-08 01:05:41 +03:00
edid = connector - > edid_blob_ptr - > data ;
size = connector - > edid_blob_ptr - > length ;
if ( ! edid )
2015-10-02 14:01:02 +03:00
goto unlock ;
2008-11-08 01:05:41 +03:00
if ( off > = size )
2015-10-02 14:01:02 +03:00
goto unlock ;
2008-11-08 01:05:41 +03:00
if ( off + count > size )
count = size - off ;
memcpy ( buf , edid + off , count ) ;
2015-10-02 14:01:02 +03:00
ret = count ;
unlock :
mutex_unlock ( & connector - > dev - > mode_config . mutex ) ;
return ret ;
2008-11-08 01:05:41 +03:00
}
static ssize_t modes_show ( struct device * device ,
struct device_attribute * attr ,
char * buf )
{
struct drm_connector * connector = to_drm_connector ( device ) ;
struct drm_display_mode * mode ;
int written = 0 ;
2015-10-02 14:01:02 +03:00
mutex_lock ( & connector - > dev - > mode_config . mutex ) ;
2008-11-08 01:05:41 +03:00
list_for_each_entry ( mode , & connector - > modes , head ) {
2020-03-11 10:35:40 +03:00
written + = scnprintf ( buf + written , PAGE_SIZE - written , " %s \n " ,
2008-11-08 01:05:41 +03:00
mode - > name ) ;
}
2015-10-02 14:01:02 +03:00
mutex_unlock ( & connector - > dev - > mode_config . mutex ) ;
2008-11-08 01:05:41 +03:00
return written ;
}
2023-03-29 04:44:55 +03:00
static ssize_t connector_id_show ( struct device * device ,
struct device_attribute * attr ,
char * buf )
{
struct drm_connector * connector = to_drm_connector ( device ) ;
return sysfs_emit ( buf , " %d \n " , connector - > base . id ) ;
}
2015-03-06 15:36:42 +03:00
static DEVICE_ATTR_RW ( status ) ;
2015-02-04 13:58:53 +03:00
static DEVICE_ATTR_RO ( enabled ) ;
static DEVICE_ATTR_RO ( dpms ) ;
static DEVICE_ATTR_RO ( modes ) ;
2023-03-29 04:44:55 +03:00
static DEVICE_ATTR_RO ( connector_id ) ;
2015-02-04 13:58:53 +03:00
static struct attribute * connector_dev_attrs [ ] = {
& dev_attr_status . attr ,
& dev_attr_enabled . attr ,
& dev_attr_dpms . attr ,
& dev_attr_modes . attr ,
2023-03-29 04:44:55 +03:00
& dev_attr_connector_id . attr ,
2015-02-04 13:58:53 +03:00
NULL
2008-11-08 01:05:41 +03:00
} ;
static struct bin_attribute edid_attr = {
. attr . name = " edid " ,
2009-05-31 07:42:26 +04:00
. attr . mode = 0444 ,
2010-03-30 01:43:23 +04:00
. size = 0 ,
2008-11-08 01:05:41 +03:00
. read = edid_show ,
} ;
2015-02-04 13:58:53 +03:00
static struct bin_attribute * connector_bin_attrs [ ] = {
& edid_attr ,
NULL
} ;
static const struct attribute_group connector_dev_group = {
. attrs = connector_dev_attrs ,
. bin_attrs = connector_bin_attrs ,
} ;
static const struct attribute_group * connector_dev_groups [ ] = {
& connector_dev_group ,
NULL
} ;
2008-11-08 01:05:41 +03:00
int drm_sysfs_connector_add ( struct drm_connector * connector )
{
struct drm_device * dev = connector - > dev ;
2021-08-18 00:51:54 +03:00
struct device * kdev ;
int r ;
2008-11-08 01:05:41 +03:00
2013-10-11 08:07:25 +04:00
if ( connector - > kdev )
return 0 ;
2008-11-08 01:05:41 +03:00
2021-08-18 00:51:54 +03:00
kdev = kzalloc ( sizeof ( * kdev ) , GFP_KERNEL ) ;
if ( ! kdev )
return - ENOMEM ;
device_initialize ( kdev ) ;
kdev - > class = drm_class ;
kdev - > type = & drm_sysfs_device_connector ;
kdev - > parent = dev - > primary - > kdev ;
kdev - > groups = connector_dev_groups ;
kdev - > release = drm_sysfs_release ;
dev_set_drvdata ( kdev , connector ) ;
r = dev_set_name ( kdev , " card%d-%s " , dev - > primary - > index , connector - > name ) ;
if ( r )
goto err_free ;
2008-11-08 01:05:41 +03:00
DRM_DEBUG ( " adding \" %s \" to sysfs \n " ,
2014-06-03 15:56:20 +04:00
connector - > name ) ;
2008-11-08 01:05:41 +03:00
2021-08-18 00:51:54 +03:00
r = device_add ( kdev ) ;
if ( r ) {
drm_err ( dev , " failed to register connector device: %d \n " , r ) ;
goto err_free ;
2008-11-08 01:05:41 +03:00
}
2021-08-18 00:51:54 +03:00
connector - > kdev = kdev ;
drm/sysfs: Link DRM connectors to corresponding Type-C connectors
Create a symlink pointing to USB Type-C connector for DRM connectors
when they are created. The link will be created only if the firmware is
able to describe the connection beween the two connectors.
Currently, even if a display uses a USB Type-C port, there is no way for
the userspace to find which port is used for which display. With the
symlink, display information would be accessible from Type-C connectors
and port information would be accessible from DRM connectors.
Associating the two subsystems, userspace would have potential to expose
and utilize more complex information. ChromeOS intend to use this
information for metrics collection. For example, we want to tell which
port is deriving which displays. Also, combined with USB PD information,
we can tell whether user is charging their device through display.
Chromium patch for parsing the symlink from the kernel is at
http://crrev.com/c/4317207.
We already have a framework in typec port-mapper.c where it goes through
component devices and runs the bind functions for those with matching
_PLD (physical location of device).
https://elixir.bootlin.com/linux/v5.18.1/source/drivers/usb/typec/
port-mapper.c
Since _PLD is ACPI specific field, this linking would only work on ACPI
x86 as long as _PLD field for Type-C connectors and DRM connectors are
correctly added to the firmware.
Currently, USB ports and USB4 ports are added as components to create a
symlink with Type C connector.
USB:
https://lore.kernel.org/all/20211223082349.45616-1-heikki.krogerus
@linux.intel.com/
USB4:
https://lore.kernel.org/all/20220418175932.1809770-3-wonchung@google.com/
So, we follow the same pattern in this patch.
Signed-off-by: Won Chung <wonchung@google.com>
Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Manasi Navare <navaremanasi@chromium.org>
Signed-off-by: Manasi Navare <navaremanasi@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20230427165813.2844530-1-wonchung@google.com
2023-04-27 19:58:13 +03:00
if ( dev_fwnode ( kdev ) ) {
r = component_add ( kdev , & typec_connector_ops ) ;
if ( r )
drm_err ( dev , " failed to add component to create link to typec connector \n " ) ;
}
2019-07-26 20:22:55 +03:00
if ( connector - > ddc )
return sysfs_create_link ( & connector - > kdev - > kobj ,
& connector - > ddc - > dev . kobj , " ddc " ) ;
drm/sysfs: Link DRM connectors to corresponding Type-C connectors
Create a symlink pointing to USB Type-C connector for DRM connectors
when they are created. The link will be created only if the firmware is
able to describe the connection beween the two connectors.
Currently, even if a display uses a USB Type-C port, there is no way for
the userspace to find which port is used for which display. With the
symlink, display information would be accessible from Type-C connectors
and port information would be accessible from DRM connectors.
Associating the two subsystems, userspace would have potential to expose
and utilize more complex information. ChromeOS intend to use this
information for metrics collection. For example, we want to tell which
port is deriving which displays. Also, combined with USB PD information,
we can tell whether user is charging their device through display.
Chromium patch for parsing the symlink from the kernel is at
http://crrev.com/c/4317207.
We already have a framework in typec port-mapper.c where it goes through
component devices and runs the bind functions for those with matching
_PLD (physical location of device).
https://elixir.bootlin.com/linux/v5.18.1/source/drivers/usb/typec/
port-mapper.c
Since _PLD is ACPI specific field, this linking would only work on ACPI
x86 as long as _PLD field for Type-C connectors and DRM connectors are
correctly added to the firmware.
Currently, USB ports and USB4 ports are added as components to create a
symlink with Type C connector.
USB:
https://lore.kernel.org/all/20211223082349.45616-1-heikki.krogerus
@linux.intel.com/
USB4:
https://lore.kernel.org/all/20220418175932.1809770-3-wonchung@google.com/
So, we follow the same pattern in this patch.
Signed-off-by: Won Chung <wonchung@google.com>
Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Manasi Navare <navaremanasi@chromium.org>
Signed-off-by: Manasi Navare <navaremanasi@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20230427165813.2844530-1-wonchung@google.com
2023-04-27 19:58:13 +03:00
2008-11-08 01:05:41 +03:00
return 0 ;
2021-08-18 00:51:54 +03:00
err_free :
put_device ( kdev ) ;
return r ;
2008-11-08 01:05:41 +03:00
}
void drm_sysfs_connector_remove ( struct drm_connector * connector )
{
2013-10-11 08:07:25 +04:00
if ( ! connector - > kdev )
2012-02-20 18:15:02 +04:00
return ;
2019-07-26 20:22:55 +03:00
if ( connector - > ddc )
sysfs_remove_link ( & connector - > kdev - > kobj , " ddc " ) ;
drm/sysfs: Link DRM connectors to corresponding Type-C connectors
Create a symlink pointing to USB Type-C connector for DRM connectors
when they are created. The link will be created only if the firmware is
able to describe the connection beween the two connectors.
Currently, even if a display uses a USB Type-C port, there is no way for
the userspace to find which port is used for which display. With the
symlink, display information would be accessible from Type-C connectors
and port information would be accessible from DRM connectors.
Associating the two subsystems, userspace would have potential to expose
and utilize more complex information. ChromeOS intend to use this
information for metrics collection. For example, we want to tell which
port is deriving which displays. Also, combined with USB PD information,
we can tell whether user is charging their device through display.
Chromium patch for parsing the symlink from the kernel is at
http://crrev.com/c/4317207.
We already have a framework in typec port-mapper.c where it goes through
component devices and runs the bind functions for those with matching
_PLD (physical location of device).
https://elixir.bootlin.com/linux/v5.18.1/source/drivers/usb/typec/
port-mapper.c
Since _PLD is ACPI specific field, this linking would only work on ACPI
x86 as long as _PLD field for Type-C connectors and DRM connectors are
correctly added to the firmware.
Currently, USB ports and USB4 ports are added as components to create a
symlink with Type C connector.
USB:
https://lore.kernel.org/all/20211223082349.45616-1-heikki.krogerus
@linux.intel.com/
USB4:
https://lore.kernel.org/all/20220418175932.1809770-3-wonchung@google.com/
So, we follow the same pattern in this patch.
Signed-off-by: Won Chung <wonchung@google.com>
Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Manasi Navare <navaremanasi@chromium.org>
Signed-off-by: Manasi Navare <navaremanasi@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20230427165813.2844530-1-wonchung@google.com
2023-04-27 19:58:13 +03:00
if ( dev_fwnode ( connector - > kdev ) )
component_del ( connector - > kdev , & typec_connector_ops ) ;
2008-11-08 01:05:41 +03:00
DRM_DEBUG ( " removing \" %s \" from sysfs \n " ,
2014-06-03 15:56:20 +04:00
connector - > name ) ;
2008-11-08 01:05:41 +03:00
2013-10-11 08:07:25 +04:00
device_unregister ( connector - > kdev ) ;
connector - > kdev = NULL ;
2008-11-08 01:05:41 +03:00
}
2018-11-29 12:42:26 +03:00
void drm_sysfs_lease_event ( struct drm_device * dev )
{
char * event_string = " LEASE=1 " ;
char * envp [ ] = { event_string , NULL } ;
DRM_DEBUG ( " generating lease event \n " ) ;
kobject_uevent_env ( & dev - > primary - > kdev - > kobj , KOBJ_CHANGE , envp ) ;
}
2008-11-08 01:05:41 +03:00
/**
* drm_sysfs_hotplug_event - generate a DRM uevent
* @ dev : DRM device
*
* Send a uevent for the DRM device specified by @ dev . Currently we only
* set HOTPLUG = 1 in the uevent environment , but this could be expanded to
* deal with other types of events .
2019-08-01 14:41:16 +03:00
*
* Any new uapi should be using the drm_sysfs_connector_status_event ( )
* for uevents on connector status change .
2008-11-08 01:05:41 +03:00
*/
void drm_sysfs_hotplug_event ( struct drm_device * dev )
{
char * event_string = " HOTPLUG=1 " ;
char * envp [ ] = { event_string , NULL } ;
DRM_DEBUG ( " generating hotplug event \n " ) ;
2013-10-11 08:07:25 +04:00
kobject_uevent_env ( & dev - > primary - > kdev - > kobj , KOBJ_CHANGE , envp ) ;
2008-11-08 01:05:41 +03:00
}
2009-04-01 01:11:15 +04:00
EXPORT_SYMBOL ( drm_sysfs_hotplug_event ) ;
2008-11-08 01:05:41 +03:00
2021-10-18 11:47:25 +03:00
/**
* drm_sysfs_connector_hotplug_event - generate a DRM uevent for any connector
* change
* @ connector : connector which has changed
*
* Send a uevent for the DRM connector specified by @ connector . This will send
* a uevent with the properties HOTPLUG = 1 and CONNECTOR .
*/
void drm_sysfs_connector_hotplug_event ( struct drm_connector * connector )
{
struct drm_device * dev = connector - > dev ;
char hotplug_str [ ] = " HOTPLUG=1 " , conn_id [ 21 ] ;
char * envp [ ] = { hotplug_str , conn_id , NULL } ;
snprintf ( conn_id , sizeof ( conn_id ) ,
" CONNECTOR=%u " , connector - > base . id ) ;
drm_dbg_kms ( connector - > dev ,
" [CONNECTOR:%d:%s] generating connector hotplug event \n " ,
connector - > base . id , connector - > name ) ;
kobject_uevent_env ( & dev - > primary - > kdev - > kobj , KOBJ_CHANGE , envp ) ;
}
EXPORT_SYMBOL ( drm_sysfs_connector_hotplug_event ) ;
2019-08-01 14:41:16 +03:00
/**
2023-06-20 20:42:42 +03:00
* drm_sysfs_connector_property_event - generate a DRM uevent for connector
* property change
* @ connector : connector on which property changed
* @ property : connector property which has changed .
2019-08-01 14:41:16 +03:00
*
2023-06-20 20:42:42 +03:00
* Send a uevent for the specified DRM connector and property . Currently we
2019-08-01 14:41:16 +03:00
* set HOTPLUG = 1 and connector id along with the attached property id
2023-06-20 20:42:42 +03:00
* related to the change .
2019-08-01 14:41:16 +03:00
*/
2023-06-20 20:42:42 +03:00
void drm_sysfs_connector_property_event ( struct drm_connector * connector ,
struct drm_property * property )
2019-08-01 14:41:16 +03:00
{
struct drm_device * dev = connector - > dev ;
char hotplug_str [ ] = " HOTPLUG=1 " , conn_id [ 21 ] , prop_id [ 21 ] ;
char * envp [ 4 ] = { hotplug_str , conn_id , prop_id , NULL } ;
WARN_ON ( ! drm_mode_obj_find_prop_id ( & connector - > base ,
property - > base . id ) ) ;
snprintf ( conn_id , ARRAY_SIZE ( conn_id ) ,
" CONNECTOR=%u " , connector - > base . id ) ;
snprintf ( prop_id , ARRAY_SIZE ( prop_id ) ,
" PROPERTY=%u " , property - > base . id ) ;
2023-06-20 20:42:42 +03:00
drm_dbg_kms ( connector - > dev ,
" [CONNECTOR:%d:%s] generating connector property event for [PROP:%d:%s] \n " ,
connector - > base . id , connector - > name ,
property - > base . id , property - > name ) ;
2019-08-01 14:41:16 +03:00
kobject_uevent_env ( & dev - > primary - > kdev - > kobj , KOBJ_CHANGE , envp ) ;
}
2023-06-20 20:42:42 +03:00
EXPORT_SYMBOL ( drm_sysfs_connector_property_event ) ;
2019-08-01 14:41:16 +03:00
2014-07-23 13:38:38 +04:00
struct device * drm_sysfs_minor_alloc ( struct drm_minor * minor )
2005-04-17 02:20:36 +04:00
{
2014-07-23 13:38:38 +04:00
const char * minor_str ;
struct device * kdev ;
2013-11-21 14:50:50 +04:00
int r ;
2007-11-22 07:02:38 +03:00
2014-07-23 13:38:38 +04:00
kdev = kzalloc ( sizeof ( * kdev ) , GFP_KERNEL ) ;
if ( ! kdev )
return ERR_PTR ( - ENOMEM ) ;
device_initialize ( kdev ) ;
2022-10-31 16:31:07 +03:00
if ( minor - > type = = DRM_MINOR_ACCEL ) {
minor_str = " accel%d " ;
accel_set_device_instance_params ( kdev , minor - > index ) ;
} else {
if ( minor - > type = = DRM_MINOR_RENDER )
minor_str = " renderD%d " ;
else
minor_str = " card%d " ;
kdev - > devt = MKDEV ( DRM_MAJOR , minor - > index ) ;
kdev - > class = drm_class ;
kdev - > type = & drm_sysfs_device_minor ;
}
2014-07-23 13:38:38 +04:00
kdev - > parent = minor - > dev - > dev ;
kdev - > release = drm_sysfs_release ;
dev_set_drvdata ( kdev , minor ) ;
r = dev_set_name ( kdev , minor_str , minor - > index ) ;
2013-11-21 14:50:50 +04:00
if ( r < 0 )
2014-07-23 13:38:38 +04:00
goto err_free ;
2013-11-21 14:50:50 +04:00
2014-07-23 13:38:38 +04:00
return kdev ;
2005-04-17 02:20:36 +04:00
2014-07-23 13:38:38 +04:00
err_free :
put_device ( kdev ) ;
return ERR_PTR ( r ) ;
2005-04-17 02:20:36 +04:00
}
2009-08-17 18:28:37 +04:00
/**
2017-04-04 12:52:55 +03:00
* drm_class_device_register - register new device with the DRM sysfs class
* @ dev : device to register
2009-08-17 18:28:37 +04:00
*
2017-04-04 12:52:55 +03:00
* Registers a new & struct device within the DRM sysfs class . Essentially only
* used by ttm to have a place for its global settings . Drivers should never use
* this .
2009-08-17 18:28:37 +04:00
*/
int drm_class_device_register ( struct device * dev )
{
2012-07-06 21:06:42 +04:00
if ( ! drm_class | | IS_ERR ( drm_class ) )
return - ENOENT ;
2009-08-17 18:28:37 +04:00
dev - > class = drm_class ;
return device_register ( dev ) ;
}
EXPORT_SYMBOL_GPL ( drm_class_device_register ) ;
2017-04-04 12:52:55 +03:00
/**
* drm_class_device_unregister - unregister device with the DRM sysfs class
* @ dev : device to unregister
*
* Unregisters a & struct device from the DRM sysfs class . Essentially only used
* by ttm to have a place for its global settings . Drivers should never use
* this .
*/
2009-08-17 18:28:37 +04:00
void drm_class_device_unregister ( struct device * dev )
{
return device_unregister ( dev ) ;
}
EXPORT_SYMBOL_GPL ( drm_class_device_unregister ) ;