Thread (22 messages) 22 messages, 4 authors, 2014-09-19

[PATCH 3/9] drm: add driver for panels used by the Rockchip DRM

STALE4398d

From: mark yao <hidden>
Date: 2014-08-04 04:50:05
Also in: dri-devel, linux-api, lkml
Subsystem: arm/rockchip soc support, drm drivers, drm drivers and misc gpu patches, drm drivers for rockchip, the rest · Maintainers: Heiko Stuebner, David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Sandy Huang, Andy Yan, Linus Torvalds

Revision v1 of 16 in this series.

Revisions (16)
  1. v1 current
  2. v2 [diff vs current]
  3. v3 [diff vs current]
  4. v4 [diff vs current]
  5. v5 [diff vs current]
  6. v6 [diff vs current]
  7. v7 [diff vs current]
  8. v7 [diff vs current]
  9. v8 [diff vs current]
  10. v9 [diff vs current]
  11. v10 [diff vs current]
  12. v11 [diff vs current]
  13. v12 [diff vs current]
  14. v13 [diff vs current]
  15. v14 [diff vs current]
  16. v15 [diff vs current]
Signed-off-by: mark yao <redacted>
---
 drivers/gpu/drm/rockchip/Makefile         |    3 +-
 drivers/gpu/drm/rockchip/rockchip_panel.c |  297 +++++++++++++++++++++++++++++
 2 files changed, 299 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_panel.c
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index 45c9d50..a5e5132 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -5,7 +5,8 @@
 ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/rockchip
 
 rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_gem.o \
-		rockchip_drm_fb.o rockchip_drm_fbdev.o
+		rockchip_drm_fb.o rockchip_drm_fbdev.o \
+		rockchip_panel.o
 
 obj-$(CONFIG_DRM_ROCKCHIP_CONNECTOR) += rockchip_drm_connector.o
 obj-$(CONFIG_DRM_ROCKCHIP_LCDC) += rockchip_drm_lcdc.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_panel.c b/drivers/gpu/drm/rockchip/rockchip_panel.c
new file mode 100644
index 0000000..87401a2
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_panel.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
+ *
+ * based on panel-simple.c
+ *
+ * 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 <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <video/of_videomode.h>
+#include <video/videomode.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_panel.h>
+
+#include "rockchip_drm_drv.h"
+
+/* TODO: convert to gpiod_*() API once it's been merged */
+#define GPIO_ACTIVE_LOW	(1 << 0)
+
+struct pwr_gpio {
+	struct list_head head;
+	unsigned long enable_gpio_flags;
+	int enable_gpio;
+};
+
+struct rockchip_panel {
+	struct drm_panel base;
+	bool enabled;
+
+	struct drm_display_mode mode;
+	struct rockchip_panel_special priv;
+
+	struct list_head pwrlist;
+};
+
+static inline struct rockchip_panel *to_rockchip_panel(struct drm_panel *panel)
+{
+	return container_of(panel, struct rockchip_panel, base);
+}
+
+static int rockchip_panel_disable(struct drm_panel *panel)
+{
+	struct rockchip_panel *p = to_rockchip_panel(panel);
+	struct pwr_gpio *pwr;
+	struct list_head *pos;
+
+	if (!p->enabled)
+		return 0;
+
+	list_for_each(pos, &p->pwrlist) {
+		pwr = list_entry(pos, struct pwr_gpio, head);
+		if (gpio_is_valid(pwr->enable_gpio)) {
+			if (pwr->enable_gpio_flags & GPIO_ACTIVE_LOW)
+				gpio_set_value(pwr->enable_gpio, 1);
+			else
+				gpio_set_value(pwr->enable_gpio, 0);
+		}
+	}
+
+	p->enabled = false;
+
+	return 0;
+}
+
+static int rockchip_panel_enable(struct drm_panel *panel)
+{
+	struct rockchip_panel *p = to_rockchip_panel(panel);
+	struct pwr_gpio *pwr;
+	struct list_head *pos;
+
+	if (p->enabled)
+		return 0;
+
+	list_for_each(pos, &p->pwrlist) {
+		pwr = list_entry(pos, struct pwr_gpio, head);
+		if (gpio_is_valid(pwr->enable_gpio)) {
+			if (pwr->enable_gpio_flags & GPIO_ACTIVE_LOW)
+				gpio_set_value(pwr->enable_gpio, 0);
+			else
+				gpio_set_value(pwr->enable_gpio, 1);
+		}
+	}
+
+	p->enabled = true;
+
+	return 0;
+}
+
+static int rockchip_panel_get_modes(struct drm_panel *panel)
+{
+	struct rockchip_panel *p = to_rockchip_panel(panel);
+	struct drm_device *drm = panel->drm;
+	struct drm_connector *connector = panel->connector;
+	const struct drm_display_mode *m = &p->mode;
+	struct drm_display_mode *mode;
+
+	mode = drm_mode_duplicate(drm, m);
+	if (!mode) {
+		dev_err(drm->dev, "failed to add mode %ux%u@%u\n",
+			m->hdisplay, m->vdisplay, m->vrefresh);
+		return 0;
+	}
+
+	drm_mode_set_name(mode);
+	drm_mode_probed_add(connector, mode);
+
+	return 1;
+}
+
+static const struct drm_panel_funcs rockchip_panel_funcs = {
+	.disable = rockchip_panel_disable,
+	.enable = rockchip_panel_enable,
+	.get_modes = rockchip_panel_get_modes,
+};
+
+static int rockchip_name_to_face(const char *s)
+{
+	if (!s)
+		return 0;
+
+	if (strncmp(s, "r8g8b8", 6) == 0)
+		return ROCKCHIP_OUTFACE_P888;
+	else if (strncmp(s, "r6g6b6", 6) == 0)
+		return ROCKCHIP_OUTFACE_P666;
+	else if (strncmp(s, "r5g6b5", 6) == 0)
+		return ROCKCHIP_OUTFACE_P565;
+
+	DRM_ERROR("unsupport display output face[%s]\n", s);
+
+	return 0;
+}
+
+static int rockchip_panel_probe(struct platform_device *pdev)
+{
+	struct rockchip_panel *panel;
+	struct device *dev = &pdev->dev;
+	struct rockchip_panel_special *priv;
+	struct device_node *dn = dev->of_node;
+	struct device_node *np;
+	enum of_gpio_flags flags;
+	struct videomode vm;
+	const char *name;
+	struct pwr_gpio *pwr;
+	struct list_head *pos;
+	int value;
+	int err, i;
+	int num_gpio;
+
+	panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
+	if (!panel)
+		return -ENOMEM;
+
+	priv = &panel->priv;
+
+	INIT_LIST_HEAD(&panel->pwrlist);
+	num_gpio = of_gpio_named_count(dn, "enable-gpios");
+	for (i = 0; i < num_gpio; i++) {
+		pwr = kmalloc(sizeof(*pwr), GFP_KERNEL);
+		pwr->enable_gpio = of_get_named_gpio_flags(dn,
+							   "enable-gpios", i,
+							   &flags);
+		if (flags & OF_GPIO_ACTIVE_LOW)
+			pwr->enable_gpio_flags |= GPIO_ACTIVE_LOW;
+
+		if (gpio_is_valid(pwr->enable_gpio)) {
+			err = gpio_request(pwr->enable_gpio, NULL);
+			if (err < 0) {
+				dev_err(dev, "failed to request GPIO#%u: %d\n",
+					pwr->enable_gpio, err);
+				gpio_free(pwr->enable_gpio);
+				kfree(pwr);
+				continue;
+			}
+			value = (pwr->enable_gpio_flags & GPIO_ACTIVE_LOW) != 0;
+			err = gpio_direction_output(pwr->enable_gpio, value);
+			if (err < 0) {
+				dev_err(dev, "failed to setup GPIO%u: %d\n",
+					pwr->enable_gpio, err);
+				gpio_free(pwr->enable_gpio);
+				kfree(pwr);
+				continue;
+			}
+
+			list_add_tail(&pwr->head, &panel->pwrlist);
+		}
+	}
+
+	if (of_property_read_bool(dn, "color-swap-rb"))
+		priv->color_swap = ROCKCHIP_COLOR_SWAP_RB;
+
+	if (of_property_read_bool(dn, "color-swap-rg"))
+		priv->color_swap |= ROCKCHIP_COLOR_SWAP_RG;
+
+	if (of_property_read_bool(dn, "color-swap-gb"))
+		priv->color_swap |= ROCKCHIP_COLOR_SWAP_GB;
+
+	if (of_property_read_string(dn, "rockchip,output-face", &name))
+		/* default set it as RGB screen */
+		priv->out_face = ROCKCHIP_OUTFACE_P666;
+	else
+		priv->out_face = rockchip_name_to_face(name);
+
+	priv->pwr18 = of_property_read_bool(dn, "lcd-vcc18");
+	priv->dither = of_property_read_bool(dn, "output-dither");
+
+	np = of_get_child_by_name(dn, "display-timings");
+	if (!np) {
+		DRM_ERROR("can't find display timings\n");
+		return 0;
+	}
+
+	of_node_put(np);
+	memset(&vm, 0, sizeof(vm));
+
+	err = of_get_videomode(dn, &vm, 0);
+	if (err < 0)
+		return err;
+
+	drm_display_mode_from_videomode(&vm, &panel->mode);
+	panel->mode.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+
+	priv->flags = vm.flags;
+	panel->mode.private = (void *)priv;
+
+	drm_panel_init(&panel->base);
+	panel->base.dev = dev;
+	panel->base.funcs = &rockchip_panel_funcs;
+
+	err = drm_panel_add(&panel->base);
+	if (err < 0)
+		goto free_gpio;
+
+	dev_set_drvdata(dev, panel);
+
+	return 0;
+
+free_gpio:
+	list_for_each(pos, &panel->pwrlist) {
+		pwr = list_entry(pos, struct pwr_gpio, head);
+		if (gpio_is_valid(pwr->enable_gpio))
+			gpio_free(pwr->enable_gpio);
+		kfree(pwr);
+	}
+	return err;
+}
+
+static const struct of_device_id platform_of_match[] = {
+	{
+		.compatible = "rockchip,panel",
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(of, platform_of_match);
+
+static int rockchip_panel_remove(struct platform_device *pdev)
+{
+	struct rockchip_panel *panel = dev_get_drvdata(&pdev->dev);
+	struct pwr_gpio *pwr;
+	struct list_head *pos;
+
+	drm_panel_detach(&panel->base);
+	drm_panel_remove(&panel->base);
+
+	list_for_each(pos, &panel->pwrlist) {
+		pwr = list_entry(pos, struct pwr_gpio, head);
+		if (gpio_is_valid(pwr->enable_gpio))
+			gpio_free(pwr->enable_gpio);
+		kfree(pwr);
+	}
+
+	return 0;
+}
+
+struct platform_driver rockchip_panel_platform_driver = {
+	.driver = {
+		.name = "rockchip,panel",
+		.owner = THIS_MODULE,
+		.of_match_table = platform_of_match,
+	},
+	.probe = rockchip_panel_probe,
+	.remove = rockchip_panel_remove,
+};
-- 
1.7.9.5
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help