drm/dp: Move panel DP AUX backlight support to drm_dp_helper

We were getting a depmod error:
  depmod: ERROR: Cycle detected: drm_kms_helper -> drm -> drm_kms_helper

It looks like the rule is that drm_kms_helper can call into drm, but
drm can't call into drm_kms_helper. That means we've got to move the
DP AUX backlight support into drm_dp_helper.

NOTE: as part of this, I didn't try to do any renames of the main
registration function. Even though it's in the drm_dp_helper, it still
feels very parallel to drm_panel_of_backlight().

Fixes: 10f7b40e4f ("drm/panel: add basic DP AUX backlight support")
Reported-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reported-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Reviewed-by: Rajeev Nandan <rajeevny@codeaurora.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210712075933.v2.1.I23eb4cc5a680341e7b3e791632a635566fa5806a@changeid
This commit is contained in:
Douglas Anderson 2021-07-12 08:00:44 -07:00
parent bbeb7461c7
commit 072ed3431f
4 changed files with 129 additions and 116 deletions

View File

@ -33,9 +33,17 @@
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include <drm/drm_dp_mst_helper.h>
#include <drm/drm_panel.h>
#include "drm_crtc_helper_internal.h"
struct dp_aux_backlight {
struct backlight_device *base;
struct drm_dp_aux *aux;
struct drm_edp_backlight_info info;
bool enabled;
};
/**
* DOC: dp helpers
*
@ -3462,3 +3470,108 @@ drm_edp_backlight_init(struct drm_dp_aux *aux, struct drm_edp_backlight_info *bl
return 0;
}
EXPORT_SYMBOL(drm_edp_backlight_init);
#if IS_BUILTIN(CONFIG_BACKLIGHT_CLASS_DEVICE) || \
(IS_MODULE(CONFIG_DRM_KMS_HELPER) && IS_MODULE(CONFIG_BACKLIGHT_CLASS_DEVICE))
static int dp_aux_backlight_update_status(struct backlight_device *bd)
{
struct dp_aux_backlight *bl = bl_get_data(bd);
u16 brightness = backlight_get_brightness(bd);
int ret = 0;
if (!backlight_is_blank(bd)) {
if (!bl->enabled) {
drm_edp_backlight_enable(bl->aux, &bl->info, brightness);
bl->enabled = true;
return 0;
}
ret = drm_edp_backlight_set_level(bl->aux, &bl->info, brightness);
} else {
if (bl->enabled) {
drm_edp_backlight_disable(bl->aux, &bl->info);
bl->enabled = false;
}
}
return ret;
}
static const struct backlight_ops dp_aux_bl_ops = {
.update_status = dp_aux_backlight_update_status,
};
/**
* drm_panel_dp_aux_backlight - create and use DP AUX backlight
* @panel: DRM panel
* @aux: The DP AUX channel to use
*
* Use this function to create and handle backlight if your panel
* supports backlight control over DP AUX channel using DPCD
* registers as per VESA's standard backlight control interface.
*
* When the panel is enabled backlight will be enabled after a
* successful call to &drm_panel_funcs.enable()
*
* When the panel is disabled backlight will be disabled before the
* call to &drm_panel_funcs.disable().
*
* A typical implementation for a panel driver supporting backlight
* control over DP AUX will call this function at probe time.
* Backlight will then be handled transparently without requiring
* any intervention from the driver.
*
* drm_panel_dp_aux_backlight() must be called after the call to drm_panel_init().
*
* Return: 0 on success or a negative error code on failure.
*/
int drm_panel_dp_aux_backlight(struct drm_panel *panel, struct drm_dp_aux *aux)
{
struct dp_aux_backlight *bl;
struct backlight_properties props = { 0 };
u16 current_level;
u8 current_mode;
u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE];
int ret;
if (!panel || !panel->dev || !aux)
return -EINVAL;
ret = drm_dp_dpcd_read(aux, DP_EDP_DPCD_REV, edp_dpcd,
EDP_DISPLAY_CTL_CAP_SIZE);
if (ret < 0)
return ret;
if (!drm_edp_backlight_supported(edp_dpcd)) {
DRM_DEV_INFO(panel->dev, "DP AUX backlight is not supported\n");
return 0;
}
bl = devm_kzalloc(panel->dev, sizeof(*bl), GFP_KERNEL);
if (!bl)
return -ENOMEM;
bl->aux = aux;
ret = drm_edp_backlight_init(aux, &bl->info, 0, edp_dpcd,
&current_level, &current_mode);
if (ret < 0)
return ret;
props.type = BACKLIGHT_RAW;
props.brightness = current_level;
props.max_brightness = bl->info.max;
bl->base = devm_backlight_device_register(panel->dev, "dp_aux_backlight",
panel->dev, bl,
&dp_aux_bl_ops, &props);
if (IS_ERR(bl->base))
return PTR_ERR(bl->base);
panel->backlight = bl->base;
return 0;
}
EXPORT_SYMBOL(drm_panel_dp_aux_backlight);
#endif

View File

@ -26,20 +26,12 @@
#include <linux/module.h>
#include <drm/drm_crtc.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
static DEFINE_MUTEX(panel_lock);
static LIST_HEAD(panel_list);
struct dp_aux_backlight {
struct backlight_device *base;
struct drm_dp_aux *aux;
struct drm_edp_backlight_info info;
bool enabled;
};
/**
* DOC: drm panel
*
@ -350,106 +342,6 @@ int drm_panel_of_backlight(struct drm_panel *panel)
return 0;
}
EXPORT_SYMBOL(drm_panel_of_backlight);
static int dp_aux_backlight_update_status(struct backlight_device *bd)
{
struct dp_aux_backlight *bl = bl_get_data(bd);
u16 brightness = backlight_get_brightness(bd);
int ret = 0;
if (!backlight_is_blank(bd)) {
if (!bl->enabled) {
drm_edp_backlight_enable(bl->aux, &bl->info, brightness);
bl->enabled = true;
return 0;
}
ret = drm_edp_backlight_set_level(bl->aux, &bl->info, brightness);
} else {
if (bl->enabled) {
drm_edp_backlight_disable(bl->aux, &bl->info);
bl->enabled = false;
}
}
return ret;
}
static const struct backlight_ops dp_aux_bl_ops = {
.update_status = dp_aux_backlight_update_status,
};
/**
* drm_panel_dp_aux_backlight - create and use DP AUX backlight
* @panel: DRM panel
* @aux: The DP AUX channel to use
*
* Use this function to create and handle backlight if your panel
* supports backlight control over DP AUX channel using DPCD
* registers as per VESA's standard backlight control interface.
*
* When the panel is enabled backlight will be enabled after a
* successful call to &drm_panel_funcs.enable()
*
* When the panel is disabled backlight will be disabled before the
* call to &drm_panel_funcs.disable().
*
* A typical implementation for a panel driver supporting backlight
* control over DP AUX will call this function at probe time.
* Backlight will then be handled transparently without requiring
* any intervention from the driver.
*
* drm_panel_dp_aux_backlight() must be called after the call to drm_panel_init().
*
* Return: 0 on success or a negative error code on failure.
*/
int drm_panel_dp_aux_backlight(struct drm_panel *panel, struct drm_dp_aux *aux)
{
struct dp_aux_backlight *bl;
struct backlight_properties props = { 0 };
u16 current_level;
u8 current_mode;
u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE];
int ret;
if (!panel || !panel->dev || !aux)
return -EINVAL;
ret = drm_dp_dpcd_read(aux, DP_EDP_DPCD_REV, edp_dpcd,
EDP_DISPLAY_CTL_CAP_SIZE);
if (ret < 0)
return ret;
if (!drm_edp_backlight_supported(edp_dpcd)) {
DRM_DEV_INFO(panel->dev, "DP AUX backlight is not supported\n");
return 0;
}
bl = devm_kzalloc(panel->dev, sizeof(*bl), GFP_KERNEL);
if (!bl)
return -ENOMEM;
bl->aux = aux;
ret = drm_edp_backlight_init(aux, &bl->info, 0, edp_dpcd,
&current_level, &current_mode);
if (ret < 0)
return ret;
props.type = BACKLIGHT_RAW;
props.brightness = current_level;
props.max_brightness = bl->info.max;
bl->base = devm_backlight_device_register(panel->dev, "dp_aux_backlight",
panel->dev, bl,
&dp_aux_bl_ops, &props);
if (IS_ERR(bl->base))
return PTR_ERR(bl->base);
panel->backlight = bl->base;
return 0;
}
EXPORT_SYMBOL(drm_panel_dp_aux_backlight);
#endif
MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");

View File

@ -30,6 +30,7 @@
struct drm_device;
struct drm_dp_aux;
struct drm_panel;
/*
* Unless otherwise noted, all values are from the DP 1.1a spec. Note that
@ -2200,6 +2201,21 @@ int drm_edp_backlight_enable(struct drm_dp_aux *aux, const struct drm_edp_backli
u16 level);
int drm_edp_backlight_disable(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl);
#if IS_ENABLED(CONFIG_DRM_KMS_HELPER) && (IS_BUILTIN(CONFIG_BACKLIGHT_CLASS_DEVICE) || \
(IS_MODULE(CONFIG_DRM_KMS_HELPER) && IS_MODULE(CONFIG_BACKLIGHT_CLASS_DEVICE)))
int drm_panel_dp_aux_backlight(struct drm_panel *panel, struct drm_dp_aux *aux);
#else
static inline int drm_panel_dp_aux_backlight(struct drm_panel *panel,
struct drm_dp_aux *aux)
{
return 0;
}
#endif
#ifdef CONFIG_DRM_DP_CEC
void drm_dp_cec_irq(struct drm_dp_aux *aux);
void drm_dp_cec_register_connector(struct drm_dp_aux *aux,

View File

@ -32,7 +32,6 @@ struct backlight_device;
struct device_node;
struct drm_connector;
struct drm_device;
struct drm_dp_aux;
struct drm_panel;
struct display_timing;
@ -209,18 +208,11 @@ static inline int of_drm_get_panel_orientation(const struct device_node *np,
#if IS_ENABLED(CONFIG_DRM_PANEL) && (IS_BUILTIN(CONFIG_BACKLIGHT_CLASS_DEVICE) || \
(IS_MODULE(CONFIG_DRM) && IS_MODULE(CONFIG_BACKLIGHT_CLASS_DEVICE)))
int drm_panel_of_backlight(struct drm_panel *panel);
int drm_panel_dp_aux_backlight(struct drm_panel *panel, struct drm_dp_aux *aux);
#else
static inline int drm_panel_of_backlight(struct drm_panel *panel)
{
return 0;
}
static inline int drm_panel_dp_aux_backlight(struct drm_panel *panel,
struct drm_dp_aux *aux)
{
return 0;
}
#endif
#endif