From 9589a399895a8cc60e943e28d912a3a899b137b1 Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Thu, 6 Jul 2017 16:02:16 +0800 Subject: [PATCH] drm/rockchip: support backlight device Change-Id: Ib793b0dec8fe62027ca8e3085089d2e431b59eb5 Signed-off-by: Mark Yao --- .../display/rockchip/rockchip-backlight.txt | 29 + .../display/rockchip/rockchip-drm.txt | 2 + drivers/gpu/drm/rockchip/Kconfig | 8 + drivers/gpu/drm/rockchip/Makefile | 1 + .../gpu/drm/rockchip/rockchip_drm_backlight.c | 513 ++++++++++++++++++ .../gpu/drm/rockchip/rockchip_drm_backlight.h | 64 +++ drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 6 + drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 3 + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 25 + 9 files changed, 651 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-backlight.txt create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_backlight.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_backlight.h diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-backlight.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-backlight.txt new file mode 100644 index 000000000000..df06fb926bb3 --- /dev/null +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-backlight.txt @@ -0,0 +1,29 @@ +Rockchip DRM backlight device +================================ + +Rockchip display controller(see VOP bindings[0]) support CABC function, +and the CABC function required using VOP self pwm to control backlight, +This backlight device manager the backlight PWM, auto select correct +PWM for backlight. + +Required properties: +- compatible: Should be "rockchip,drm-backlight" + +Other properties are same to commom PWM backlight bindings[1]. + +[0]: Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt +[1]: Documentation/devicetree/bindings/leds/backlight/pwm-backlight.txt + +example: + +backlight { + compatible = "rockchip,drm-backlight"; + pwms = <&pwm 0 5000000>; + + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + + power-supply = <&vdd_bl_reg>; + enable-gpios = <&gpio 58 0>; +}; + diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.txt index 13d6495b4913..c408c50196ce 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.txt +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.txt @@ -12,6 +12,7 @@ Required properties: Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt Optional properties +- backlight: spacial backlight required by cabc function. - clocks: include clock specifiers corresponding to entries in the clock-names property. - clock-names: optional include @@ -25,6 +26,7 @@ example: display-subsystem { compatible = "rockchip,display-subsystem"; ports = <&vopl_out>, <&vopb_out>; + backlight = <&backlight> clocks = <&cru PLL_VPLL>, <&cru PLL_CPLL>; clock-names = "hdmi-tmds-pll", "default-vop-pll"; }; diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index fd749154e6c7..41d1edd5bea0 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -88,3 +88,11 @@ config ROCKCHIP_DRM_TVE help Choose this option to enable support for Rockchip TVE controllers. say Y to enable its driver. + +config ROCKCHIP_DRM_BACKLIGHT + tristate "Rockchip DRM Backlight" + depends on DRM_ROCKCHIP + help + This selects support for Rockchip backlight manager, + Vop cabc function request using vop self pwm devices, needed a + unique backlight devices to manager vop and soc pwm devices. diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 98f753458642..b7846651d4e2 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -15,5 +15,6 @@ obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o obj-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o obj-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o +obj-$(CONFIG_ROCKCHIP_DRM_BACKLIGHT) += rockchip_drm_backlight.o obj-$(CONFIG_DRM_ROCKCHIP) += rockchip_vop_reg.o rockchipdrm.o obj-$(CONFIG_ROCKCHIP_DRM_TVE) += rockchip_drm_tve.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_backlight.c b/drivers/gpu/drm/rockchip/rockchip_drm_backlight.c new file mode 100644 index 000000000000..8380b8c8ee62 --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_drm_backlight.c @@ -0,0 +1,513 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author:Mark Yao + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rockchip_drm_drv.h" +#include "rockchip_drm_backlight.h" + +struct sub_backlight { + struct pwm_device *pwm; + struct pinctrl *pinctrl; + struct pinctrl_state *dummy_state; + struct pinctrl_state *active_state; + struct drm_crtc *crtc; + struct device *dev; + + const struct rockchip_sub_backlight_ops *ops; + struct list_head list; +}; + +#define to_rockchip_backlight_device(x) \ + container_of((x), struct rockchip_drm_backlight, pwm_pdev) + +static DEFINE_MUTEX(backlight_lock); +static LIST_HEAD(backlight_list); + +static int compute_duty_cycle(struct rockchip_drm_backlight *bl, + int brightness, int period) +{ + unsigned int lth = bl->lth_brightness; + int duty_cycle; + + duty_cycle = bl->levels[brightness]; + + return (duty_cycle * (period - lth) / bl->scale) + lth; +} + +static void rockchip_pwm_power_on(struct rockchip_drm_backlight *bl, + struct pwm_device *pwm, int brightness) +{ + struct pwm_args pargs; + int duty_cycle; + + pwm_get_args(pwm, &pargs); + duty_cycle = compute_duty_cycle(bl, brightness, pargs.period); + pwm_config(pwm, duty_cycle, pargs.period); + pwm_enable(pwm); +} + +static void rockchip_pwm_power_off(struct rockchip_drm_backlight *bl, + struct pwm_device *pwm) +{ + struct pwm_args pargs; + struct pwm_state state; + + pwm_get_state(pwm, &state); + if (!state.enabled) + return; + + pwm_get_args(pwm, &pargs); + pwm_config(pwm, 0, pargs.period); + pwm_disable(pwm); +} + +static void rockchip_backlight_power_on(struct rockchip_drm_backlight *bl) +{ + int err; + + if (bl->enabled) + return; + + err = regulator_enable(bl->power_supply); + if (err < 0) + dev_err(bl->dev, "failed to enable power supply\n"); + + if (bl->enable_gpio) + gpiod_set_value(bl->enable_gpio, 1); + + bl->enabled = true; +} + +static void rockchip_backlight_power_off(struct rockchip_drm_backlight *bl) +{ + if (!bl->enabled) + return; + + if (bl->enable_gpio) + gpiod_set_value(bl->enable_gpio, 0); + + regulator_disable(bl->power_supply); + bl->enabled = false; +} + +static int backlight_parse_dt(struct rockchip_drm_backlight *bl) +{ + struct device_node *node = bl->dev->of_node; + struct device *dev = bl->dev; + struct property *prop; + size_t size; + int length; + u32 value; + int ret, i; + + if (!node) + return -ENODEV; + + bl->pwm = devm_pwm_get(dev, NULL); + if (IS_ERR(bl->pwm)) { + dev_err(dev, "unable to request PWM: %ld\n", + PTR_ERR(bl->pwm)); + return PTR_ERR(bl->pwm); + } + + if (!bl->pwm->chip->dev->pins) { + dev_err(dev, "failed to find pwm pinctrl\n"); + return -ENODEV; + } + bl->dummy_state = pinctrl_lookup_state(bl->pwm->chip->dev->pins->p, + "dummy"); + if (IS_ERR_OR_NULL(bl->dummy_state)) { + dev_err(dev, "failed to find pwm dummy state\n"); + return -ENODEV; + } + + bl->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_ASIS); + if (IS_ERR(bl->enable_gpio)) { + dev_err(dev, "unable to request enable gpio: %ld\n", + PTR_ERR(bl->enable_gpio)); + return PTR_ERR(bl->enable_gpio); + } + + bl->power_supply = devm_regulator_get(dev, "power"); + if (IS_ERR(bl->power_supply)) { + dev_err(dev, "unable to request power supply: %ld\n", + PTR_ERR(bl->power_supply)); + return PTR_ERR(bl->power_supply); + } + + /* determine the number of brightness levels */ + prop = of_find_property(node, "brightness-levels", &length); + if (!prop) + return -EINVAL; + + bl->max_brightness = length / sizeof(u32); + + if (bl->max_brightness <= 0) + return -EINVAL; + + /* read brightness levels from DT property */ + size = sizeof(*bl->levels) * bl->max_brightness; + + bl->levels = devm_kzalloc(dev, size, GFP_KERNEL); + if (!bl->levels) + return -ENOMEM; + + ret = of_property_read_u32_array(node, "brightness-levels", + bl->levels, + bl->max_brightness); + if (ret < 0) + return ret; + + ret = of_property_read_u32(node, "default-brightness-level", &value); + if (ret < 0) + return ret; + + bl->dft_brightness = value; + bl->max_brightness--; + + for (i = 0; i <= bl->max_brightness; i++) + if (bl->levels[i] > bl->scale) + bl->scale = bl->levels[i]; + + return 0; +} + +void rockchip_drm_backlight_update(struct drm_device *drm) +{ + struct rockchip_drm_private *private = drm->dev_private; + struct rockchip_drm_backlight *bl = private->backlight; + struct drm_connector *connector = bl->connector; + struct sub_backlight *sub = bl->sub; + struct rockchip_crtc_state *s; + struct drm_crtc *crtc; + bool backlight_changed = false; + + if (!connector) + return; + + crtc = connector->state->crtc; + if (!crtc) { + if (sub) { + bl->sub = NULL; + backlight_changed = true; + } + } else if (!sub || sub->dev->of_node != crtc->port) { + s = to_rockchip_crtc_state(crtc->state); + if (s->cabc_mode != ROCKCHIP_DRM_CABC_MODE_DISABLE) { + list_for_each_entry(sub, &backlight_list, list) { + if (sub->crtc == crtc) { + bl->sub = sub; + backlight_changed = true; + break; + } + } + } else if (bl->sub) { + bl->sub = NULL; + backlight_changed = true; + } + } + + if (backlight_changed) + backlight_update_status(bl->bd); +} +EXPORT_SYMBOL(rockchip_drm_backlight_update); + +int of_rockchip_drm_sub_backlight_register(struct device *dev, + struct drm_crtc *crtc, + const struct rockchip_sub_backlight_ops *ops) +{ + struct sub_backlight *sub; + struct pwm_device *pwm; + + pwm = devm_pwm_get(dev, NULL); + if (IS_ERR(pwm)) { + dev_err(dev, "unable to request PWM\n"); + return PTR_ERR(pwm); + } + + sub = devm_kzalloc(dev, sizeof(*sub), GFP_KERNEL); + if (!sub) + return -ENOMEM; + + sub->pinctrl = devm_pinctrl_get(pwm->chip->dev); + if (IS_ERR(sub->pinctrl)) { + dev_err(dev, "failed to find pwm pinctrl\n"); + return PTR_ERR(sub->pinctrl); + } + + sub->dummy_state = pinctrl_lookup_state(sub->pinctrl, "dummy"); + if (IS_ERR_OR_NULL(sub->dummy_state)) { + dev_err(dev, "failed to find pwm dummy state\n"); + return -ENODEV; + } + + sub->active_state = pinctrl_lookup_state(sub->pinctrl, "active"); + if (IS_ERR_OR_NULL(sub->active_state)) { + dev_err(dev, "failed to find pwm active state\n"); + return -ENODEV; + } + + pwm_adjust_config(pwm); + + sub->pwm = pwm; + sub->dev = dev; + sub->crtc = crtc; + sub->ops = ops; + + INIT_LIST_HEAD(&sub->list); + list_add_tail(&sub->list, &backlight_list); + + return 0; +} +EXPORT_SYMBOL(of_rockchip_drm_sub_backlight_register); + +static int rockchip_drm_backlight_bind(struct device *dev, + struct device *master, void *data) +{ + struct drm_device *drm_dev = data; + struct rockchip_drm_private *private = drm_dev->dev_private; + struct rockchip_drm_backlight *bl = dev_get_drvdata(dev); + struct drm_connector *connector; + struct drm_panel *panel; + struct device_node *backlight_np; + + private->backlight = bl; + + mutex_lock(&drm_dev->mode_config.mutex); + + drm_for_each_connector(connector, drm_dev) { + panel = drm_find_panel_by_connector(connector); + if (!panel && !panel->dev) + continue; + backlight_np = of_parse_phandle(panel->dev->of_node, + "backlight", 0); + if (backlight_np == dev->of_node) { + bl->connector = connector; + break; + } + } + + mutex_unlock(&drm_dev->mode_config.mutex); + + if (!bl->connector) { + dev_warn(dev, "failed to bind drm backlight\n"); + return -ENODEV; + } + + return 0; +} + +static void rockchip_drm_backlight_unbind(struct device *dev, + struct device *master, void *data) +{ + struct drm_device *drm_dev = data; + struct rockchip_drm_private *private = drm_dev->dev_private; + struct rockchip_drm_backlight *bl = dev_get_drvdata(dev); + + private->backlight = NULL; + bl->connector = NULL; +} + +static const struct component_ops rockchip_drm_backlight_component_ops = { + .bind = rockchip_drm_backlight_bind, + .unbind = rockchip_drm_backlight_unbind, +}; + +static int +rockchip_drm_backlight_update_status(struct backlight_device *backlight) +{ + int brightness = backlight->props.brightness; + struct rockchip_drm_backlight *bl = bl_get_data(backlight); + struct sub_backlight *sub = bl->sub; + struct sub_backlight *current_sub = bl->current_sub; + bool async; + + if (backlight->props.power != FB_BLANK_UNBLANK || + backlight->props.fb_blank != FB_BLANK_UNBLANK || + backlight->props.state & BL_CORE_FBBLANK) + brightness = 0; + + if (!sub || brightness <= 0) { + if (current_sub) + pinctrl_select_state(current_sub->pinctrl, + current_sub->dummy_state); + + if (brightness > 0) { + rockchip_pwm_power_on(bl, bl->pwm, brightness); + rockchip_backlight_power_on(bl); + } else { + rockchip_backlight_power_off(bl); + rockchip_pwm_power_off(bl, bl->pwm); + } + + pinctrl_pm_select_default_state(bl->pwm->chip->dev); + if (current_sub) { + rockchip_pwm_power_off(bl, current_sub->pwm); + + if (current_sub->ops->config_done) + current_sub->ops->config_done(current_sub->dev, + true); + } + + return 0; + } + + pinctrl_select_state(bl->pwm->chip->dev->pins->p, bl->dummy_state); + + async = !!current_sub; + if (current_sub && sub != current_sub) { + pinctrl_select_state(current_sub->pinctrl, + current_sub->dummy_state); + async = false; + } + + rockchip_pwm_power_on(bl, sub->pwm, brightness); + + if (current_sub && sub != current_sub) { + rockchip_pwm_power_on(bl, current_sub->pwm, brightness); + if (current_sub->ops->config_done) + current_sub->ops->config_done(current_sub->dev, true); + } + + if (sub->ops->config_done) + sub->ops->config_done(sub->dev, async); + + pinctrl_select_state(sub->pinctrl, sub->active_state); + + rockchip_backlight_power_on(bl); + + bl->current_sub = sub; + + return 0; +} + +static const struct backlight_ops rockchip_drm_backlight_ops = { + .update_status = rockchip_drm_backlight_update_status, +}; + +static int rockchip_drm_backlight_probe(struct platform_device *pdev) +{ + struct rockchip_drm_backlight *bl; + struct backlight_properties props; + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + int initial_blank = FB_BLANK_UNBLANK; + int ret; + + bl = devm_kzalloc(dev, sizeof(*bl), GFP_KERNEL); + if (!bl) + return -ENOMEM; + + bl->dev = dev; + ret = backlight_parse_dt(bl); + if (ret < 0) { + dev_err(&pdev->dev, "failed to find parse backlight dts\n"); + return ret; + } + + bl->enabled = false; + + if (bl->enable_gpio) { + /* + * If the driver is probed from the device tree and there is a + * phandle link pointing to the backlight node, it is safe to + * assume that another driver will enable the backlight at the + * appropriate time. Therefore, if it is disabled, keep it so. + */ + if (node && node->phandle && + gpiod_get_direction(bl->enable_gpio) == GPIOF_DIR_OUT && + gpiod_get_value(bl->enable_gpio) == 0) + initial_blank = FB_BLANK_POWERDOWN; + else + gpiod_direction_output(bl->enable_gpio, 1); + } + + if (node && node->phandle && !regulator_is_enabled(bl->power_supply)) + initial_blank = FB_BLANK_POWERDOWN; + + pwm_adjust_config(bl->pwm); + + memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_RAW; + props.max_brightness = bl->max_brightness; + bl->bd = backlight_device_register(dev_name(dev), dev, bl, + &rockchip_drm_backlight_ops, &props); + if (IS_ERR(bl->bd)) { + dev_err(&pdev->dev, "failed to register backlight\n"); + ret = PTR_ERR(bl->bd); + return ret; + } + + bl->bd->props.brightness = bl->dft_brightness; + bl->bd->props.power = initial_blank; + backlight_update_status(bl->bd); + + platform_set_drvdata(pdev, bl); + + ret = component_add(dev, &rockchip_drm_backlight_component_ops); + if (ret) + backlight_device_unregister(bl->bd); + + return ret; +} + +static int rockchip_drm_backlight_remove(struct platform_device *pdev) +{ + struct rockchip_drm_backlight *bl = platform_get_drvdata(pdev); + + backlight_device_unregister(bl->bd); + component_del(&pdev->dev, &rockchip_drm_backlight_component_ops); + + return 0; +} + +static const struct of_device_id rockchip_drm_backlight_dt_ids[] = { + {.compatible = "rockchip,drm-backlight", + .data = NULL }, + {} +}; +MODULE_DEVICE_TABLE(of, rockchip_drm_backlight_dt_ids); + +static struct platform_driver rockchip_drm_backlight_driver = { + .probe = rockchip_drm_backlight_probe, + .remove = rockchip_drm_backlight_remove, + .driver = { + .name = "drm-backlight", + .of_match_table = + of_match_ptr(rockchip_drm_backlight_dt_ids), + }, +}; + +module_platform_driver(rockchip_drm_backlight_driver); + +MODULE_AUTHOR("Mark Yao "); +MODULE_DESCRIPTION("Rockchip Drm Backlight Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_backlight.h b/drivers/gpu/drm/rockchip/rockchip_drm_backlight.h new file mode 100644 index 000000000000..7d1dfe95005d --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_drm_backlight.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author:Mark Yao + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef _ROCKCHIP_DRM_BACKLIGHT_H +#define _ROCKCHIP_DRM_BACKLIGHT_H + +#include + +struct rockchip_drm_backlight { + struct device *dev; + struct backlight_device *bd; + struct pinctrl *pinctrl; + struct pinctrl_state *dummy_state; + struct pwm_device *pwm; + + struct drm_connector *connector; + struct sub_backlight *current_sub, *sub; + + struct regulator *power_supply; + struct gpio_desc *enable_gpio; + bool enabled; + + unsigned int max_brightness; + unsigned int dft_brightness; + unsigned int lth_brightness; + unsigned int scale; + unsigned int *levels; +}; + +struct rockchip_sub_backlight_ops { + void (*config_done)(struct device *dev, bool async); +}; + +#ifdef CONFIG_ROCKCHIP_DRM_BACKLIGHT +int of_rockchip_drm_sub_backlight_register(struct device *dev, + struct drm_crtc *crtc, + const struct rockchip_sub_backlight_ops *ops); +void rockchip_drm_backlight_update(struct drm_device *drm); +#else +static inline int +of_rockchip_drm_sub_backlight_register(struct device *dev, + struct drm_crtc *crtc, + const struct rockchip_sub_backlight_ops *ops) +{ + return 0; +} + +static inline void rockchip_drm_backlight_update(struct drm_device *drm) +{ +} + +#endif +#endif diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 0e79f221f2c6..a38275f2c511 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -1497,6 +1497,12 @@ static int rockchip_drm_platform_probe(struct platform_device *pdev) of_node_put(port); } + port = of_parse_phandle(np, "backlight", 0); + if (port && of_device_is_available(port)) { + component_match_add(dev, &match, compare_of, port); + of_node_put(port); + } + return component_master_add_with_match(dev, &rockchip_drm_ops, match); } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index deb1b8374b0c..56e29bff7af0 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -23,6 +23,7 @@ #include "rockchip_drm_drv.h" #include "rockchip_drm_gem.h" +#include "rockchip_drm_backlight.h" #define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb) @@ -237,6 +238,8 @@ rockchip_atomic_commit_complete(struct rockchip_atomic_commit *commit) drm_atomic_helper_commit_modeset_enables(dev, state); + rockchip_drm_backlight_update(dev); + drm_atomic_helper_commit_planes(dev, state, true); drm_atomic_helper_wait_for_vblanks(dev, state); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 67ece59d3cf0..f45ce3277422 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -41,6 +41,7 @@ #include "rockchip_drm_gem.h" #include "rockchip_drm_fb.h" #include "rockchip_drm_vop.h" +#include "rockchip_drm_backlight.h" #define VOP_REG_SUPPORT(vop, reg) \ (!reg.major || (reg.major == VOP_MAJOR(vop->data->version) && \ @@ -3003,6 +3004,27 @@ int rockchip_drm_register_notifier_to_dmc(struct devfreq *devfreq) } EXPORT_SYMBOL(rockchip_drm_register_notifier_to_dmc); +static void vop_backlight_config_done(struct device *dev, bool async) +{ + struct vop *vop = dev_get_drvdata(dev); + + if (vop && vop->is_enabled) { + int dle; + + vop_cfg_done(vop); + if (!async) { + #define CTRL_GET(name) VOP_CTRL_GET(vop, name) + readx_poll_timeout(CTRL_GET, cfg_done, + dle, !dle, 5, 33333); + #undef CTRL_GET + } + } +} + +static const struct rockchip_sub_backlight_ops rockchip_sub_backlight_ops = { + .config_done = vop_backlight_config_done, +}; + static int vop_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); @@ -3138,6 +3160,9 @@ static int vop_bind(struct device *dev, struct device *master, void *data) pm_runtime_enable(&pdev->dev); + of_rockchip_drm_sub_backlight_register(dev, &vop->crtc, + &rockchip_sub_backlight_ops); + dmc_vop = vop; return 0; -- 2.34.1