drm/rockchip: support backlight device
authorMark Yao <mark.yao@rock-chips.com>
Thu, 6 Jul 2017 08:02:16 +0000 (16:02 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Fri, 21 Jul 2017 04:52:08 +0000 (12:52 +0800)
Change-Id: Ib793b0dec8fe62027ca8e3085089d2e431b59eb5
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
Documentation/devicetree/bindings/display/rockchip/rockchip-backlight.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/rockchip/rockchip-drm.txt
drivers/gpu/drm/rockchip/Kconfig
drivers/gpu/drm/rockchip/Makefile
drivers/gpu/drm/rockchip/rockchip_drm_backlight.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_backlight.h [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
drivers/gpu/drm/rockchip/rockchip_drm_fb.c
drivers/gpu/drm/rockchip/rockchip_drm_vop.c

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-backlight.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-backlight.txt
new file mode 100644 (file)
index 0000000..df06fb9
--- /dev/null
@@ -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>;
+};
+
index 13d6495b4913e3b390d5c7e5248380de064a58e9..c408c50196ce55905bc928d1e145563b10697c4f 100644 (file)
@@ -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";
 };
index fd749154e6c768f396b14edd84de830546c02c5c..41d1edd5bea00d16b5d10143b227f12f4694a37e 100644 (file)
@@ -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.
index 98f753458642bafc977eea2254c5fbef1c27de92..b7846651d4e2305a036189c0d7d14d3cd6bd4494 100644 (file)
@@ -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 (file)
index 0000000..8380b8c
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:Mark Yao <mark.yao@rock-chips.com>
+ *
+ * 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 <drm/drm.h>
+#include <drm/drmP.h>
+#include <drm/drm_panel.h>
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/pwm_backlight.h>
+#include <uapi/drm/rockchip_drm.h>
+
+#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 <mark.yao@rock-chips.com>");
+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 (file)
index 0000000..7d1dfe9
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:Mark Yao <mark.yao@rock-chips.com>
+ *
+ * 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 <linux/pwm_backlight.h>
+
+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
index 0e79f221f2c63e6ed68ac2e1ccae50094fdc7415..a38275f2c5116408037b1b5ab363889abee9ba3a 100644 (file)
@@ -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);
 }
 
index deb1b8374b0c301c5569fa286fbf23eb0271bb8c..56e29bff7af0526a01ee93679f034974217eca50 100644 (file)
@@ -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);
index 67ece59d3cf0b0fd0a7dafcd24b1b5930e9f7bc9..f45ce327742211b232e4a6a2fe1731715ea45ce2 100644 (file)
@@ -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;