summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
diff options
context:
space:
mode:
authorSebastian Reichel <sebastian.reichel@collabora.com>2020-12-15 12:46:12 +0200
committerTomi Valkeinen <tomi.valkeinen@ti.com>2020-12-15 16:08:25 +0200
commitcf64148abcfd5ac1d6b1526950a48a497b180f61 (patch)
tree4017b6c3ff05e0a3b85552f97ad2fdd575837e4a /drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
parent85101487326a96fbe724eb1f05f4406ceb50dad9 (diff)
downloadlinux-cf64148abcfd5ac1d6b1526950a48a497b180f61.tar.bz2
drm/panel: Move OMAP's DSI command mode panel driver
The panel driver is no longer using any OMAP specific APIs, so let's move it into the generic panel directory. Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Cc: Thierry Reding <thierry.reding@gmail.com> Cc: Sam Ravnborg <sam@ravnborg.org> Acked-by: Sam Ravnborg <sam@ravnborg.org> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Link: https://patchwork.freedesktop.org/patch/msgid/20201215104657.802264-40-tomi.valkeinen@ti.com
Diffstat (limited to 'drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c')
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c637
1 files changed, 0 insertions, 637 deletions
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
deleted file mode 100644
index 21df1997e7d1..000000000000
--- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
+++ /dev/null
@@ -1,637 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Generic DSI Command Mode panel driver
- *
- * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com/
- * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- */
-
-#include <linux/backlight.h>
-#include <linux/delay.h>
-#include <linux/gpio/consumer.h>
-#include <linux/jiffies.h>
-#include <linux/module.h>
-#include <linux/sched/signal.h>
-#include <linux/slab.h>
-#include <linux/of_device.h>
-#include <linux/regulator/consumer.h>
-
-#include <drm/drm_connector.h>
-#include <drm/drm_mipi_dsi.h>
-#include <drm/drm_modes.h>
-#include <drm/drm_panel.h>
-
-#include <video/display_timing.h>
-#include <video/mipi_display.h>
-#include <video/of_display_timing.h>
-#include <video/videomode.h>
-
-#define DCS_READ_NUM_ERRORS 0x05
-#define DCS_GET_ID1 0xda
-#define DCS_GET_ID2 0xdb
-#define DCS_GET_ID3 0xdc
-
-#define DCS_REGULATOR_SUPPLY_NUM 2
-
-struct panel_drv_data {
- struct mipi_dsi_device *dsi;
- struct drm_panel panel;
- struct drm_display_mode mode;
-
- struct mutex lock;
-
- struct backlight_device *bldev;
- struct backlight_device *extbldev;
-
- unsigned long hw_guard_end; /* next value of jiffies when we can
- * issue the next sleep in/out command
- */
- unsigned long hw_guard_wait; /* max guard time in jiffies */
-
- /* panel HW configuration from DT or platform data */
- struct gpio_desc *reset_gpio;
-
- struct regulator_bulk_data supplies[DCS_REGULATOR_SUPPLY_NUM];
-
- bool use_dsi_backlight;
-
- int width_mm;
- int height_mm;
-
- /* runtime variables */
- bool enabled;
-
- bool intro_printed;
-};
-
-static inline struct panel_drv_data *panel_to_ddata(struct drm_panel *panel)
-{
- return container_of(panel, struct panel_drv_data, panel);
-}
-
-static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable);
-
-static void dsicm_bl_power(struct panel_drv_data *ddata, bool enable)
-{
- struct backlight_device *backlight;
-
- if (ddata->bldev)
- backlight = ddata->bldev;
- else if (ddata->extbldev)
- backlight = ddata->extbldev;
- else
- return;
-
- if (enable) {
- backlight->props.fb_blank = FB_BLANK_UNBLANK;
- backlight->props.state = ~(BL_CORE_FBBLANK | BL_CORE_SUSPENDED);
- backlight->props.power = FB_BLANK_UNBLANK;
- } else {
- backlight->props.fb_blank = FB_BLANK_NORMAL;
- backlight->props.power = FB_BLANK_POWERDOWN;
- backlight->props.state |= BL_CORE_FBBLANK | BL_CORE_SUSPENDED;
- }
-
- backlight_update_status(backlight);
-}
-
-static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec)
-{
- ddata->hw_guard_wait = msecs_to_jiffies(guard_msec);
- ddata->hw_guard_end = jiffies + ddata->hw_guard_wait;
-}
-
-static void hw_guard_wait(struct panel_drv_data *ddata)
-{
- unsigned long wait = ddata->hw_guard_end - jiffies;
-
- if ((long)wait > 0 && wait <= ddata->hw_guard_wait) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(wait);
- }
-}
-
-static int dsicm_dcs_read_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 *data)
-{
- return mipi_dsi_dcs_read(ddata->dsi, dcs_cmd, data, 1);
-}
-
-static int dsicm_dcs_write_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 param)
-{
- return mipi_dsi_dcs_write(ddata->dsi, dcs_cmd, &param, 1);
-}
-
-static int dsicm_sleep_in(struct panel_drv_data *ddata)
-
-{
- int r;
-
- hw_guard_wait(ddata);
-
- r = mipi_dsi_dcs_enter_sleep_mode(ddata->dsi);
- if (r)
- return r;
-
- hw_guard_start(ddata, 120);
-
- usleep_range(5000, 10000);
-
- return 0;
-}
-
-static int dsicm_sleep_out(struct panel_drv_data *ddata)
-{
- int r;
-
- hw_guard_wait(ddata);
-
- r = mipi_dsi_dcs_exit_sleep_mode(ddata->dsi);
- if (r)
- return r;
-
- hw_guard_start(ddata, 120);
-
- usleep_range(5000, 10000);
-
- return 0;
-}
-
-static int dsicm_get_id(struct panel_drv_data *ddata, u8 *id1, u8 *id2, u8 *id3)
-{
- int r;
-
- r = dsicm_dcs_read_1(ddata, DCS_GET_ID1, id1);
- if (r)
- return r;
- r = dsicm_dcs_read_1(ddata, DCS_GET_ID2, id2);
- if (r)
- return r;
- r = dsicm_dcs_read_1(ddata, DCS_GET_ID3, id3);
- if (r)
- return r;
-
- return 0;
-}
-
-static int dsicm_bl_update_status(struct backlight_device *dev)
-{
- struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
- int r = 0;
- int level;
-
- if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
- dev->props.power == FB_BLANK_UNBLANK)
- level = dev->props.brightness;
- else
- level = 0;
-
- dev_dbg(&ddata->dsi->dev, "update brightness to %d\n", level);
-
- mutex_lock(&ddata->lock);
-
- if (ddata->enabled) {
- if (!r)
- r = dsicm_dcs_write_1(
- ddata, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, level);
- }
-
- mutex_unlock(&ddata->lock);
-
- return r;
-}
-
-static int dsicm_bl_get_intensity(struct backlight_device *dev)
-{
- if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
- dev->props.power == FB_BLANK_UNBLANK)
- return dev->props.brightness;
-
- return 0;
-}
-
-static const struct backlight_ops dsicm_bl_ops = {
- .get_brightness = dsicm_bl_get_intensity,
- .update_status = dsicm_bl_update_status,
-};
-
-static ssize_t num_dsi_errors_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct panel_drv_data *ddata = dev_get_drvdata(dev);
- u8 errors = 0;
- int r = -ENODEV;
-
- mutex_lock(&ddata->lock);
-
- if (ddata->enabled)
- r = dsicm_dcs_read_1(ddata, DCS_READ_NUM_ERRORS, &errors);
-
- mutex_unlock(&ddata->lock);
-
- if (r)
- return r;
-
- return snprintf(buf, PAGE_SIZE, "%d\n", errors);
-}
-
-static ssize_t hw_revision_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct panel_drv_data *ddata = dev_get_drvdata(dev);
- u8 id1, id2, id3;
- int r = -ENODEV;
-
- mutex_lock(&ddata->lock);
-
- if (ddata->enabled)
- r = dsicm_get_id(ddata, &id1, &id2, &id3);
-
- mutex_unlock(&ddata->lock);
-
- if (r)
- return r;
-
- return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x\n", id1, id2, id3);
-}
-
-static DEVICE_ATTR_RO(num_dsi_errors);
-static DEVICE_ATTR_RO(hw_revision);
-
-static struct attribute *dsicm_attrs[] = {
- &dev_attr_num_dsi_errors.attr,
- &dev_attr_hw_revision.attr,
- NULL,
-};
-
-static const struct attribute_group dsicm_attr_group = {
- .attrs = dsicm_attrs,
-};
-
-static void dsicm_hw_reset(struct panel_drv_data *ddata)
-{
- gpiod_set_value(ddata->reset_gpio, 1);
- udelay(10);
- /* reset the panel */
- gpiod_set_value(ddata->reset_gpio, 0);
- /* assert reset */
- udelay(10);
- gpiod_set_value(ddata->reset_gpio, 1);
- /* wait after releasing reset */
- usleep_range(5000, 10000);
-}
-
-static int dsicm_power_on(struct panel_drv_data *ddata)
-{
- u8 id1, id2, id3;
- int r;
-
- dsicm_hw_reset(ddata);
-
- ddata->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
-
- r = dsicm_sleep_out(ddata);
- if (r)
- goto err;
-
- r = dsicm_get_id(ddata, &id1, &id2, &id3);
- if (r)
- goto err;
-
- r = dsicm_dcs_write_1(ddata, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0xff);
- if (r)
- goto err;
-
- r = dsicm_dcs_write_1(ddata, MIPI_DCS_WRITE_CONTROL_DISPLAY,
- (1<<2) | (1<<5)); /* BL | BCTRL */
- if (r)
- goto err;
-
- r = mipi_dsi_dcs_set_pixel_format(ddata->dsi, MIPI_DCS_PIXEL_FMT_24BIT);
- if (r)
- goto err;
-
- r = mipi_dsi_dcs_set_display_on(ddata->dsi);
- if (r)
- goto err;
-
- r = _dsicm_enable_te(ddata, true);
- if (r)
- goto err;
-
- ddata->enabled = true;
-
- if (!ddata->intro_printed) {
- dev_info(&ddata->dsi->dev, "panel revision %02x.%02x.%02x\n",
- id1, id2, id3);
- ddata->intro_printed = true;
- }
-
- ddata->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
-
- return 0;
-err:
- dev_err(&ddata->dsi->dev, "error while enabling panel, issuing HW reset\n");
-
- dsicm_hw_reset(ddata);
-
- return r;
-}
-
-static int dsicm_power_off(struct panel_drv_data *ddata)
-{
- int r;
-
- ddata->enabled = false;
-
- r = mipi_dsi_dcs_set_display_off(ddata->dsi);
- if (!r)
- r = dsicm_sleep_in(ddata);
-
- if (r) {
- dev_err(&ddata->dsi->dev,
- "error disabling panel, issuing HW reset\n");
- dsicm_hw_reset(ddata);
- }
-
- return r;
-}
-
-static int dsicm_prepare(struct drm_panel *panel)
-{
- struct panel_drv_data *ddata = panel_to_ddata(panel);
- int r;
-
- r = regulator_bulk_enable(ARRAY_SIZE(ddata->supplies), ddata->supplies);
- if (r)
- dev_err(&ddata->dsi->dev, "failed to enable supplies: %d\n", r);
-
- return r;
-}
-
-static int dsicm_enable(struct drm_panel *panel)
-{
- struct panel_drv_data *ddata = panel_to_ddata(panel);
- int r;
-
- mutex_lock(&ddata->lock);
-
- r = dsicm_power_on(ddata);
- if (r)
- goto err;
-
- mutex_unlock(&ddata->lock);
-
- dsicm_bl_power(ddata, true);
-
- return 0;
-err:
- dev_err(&ddata->dsi->dev, "enable failed (%d)\n", r);
- mutex_unlock(&ddata->lock);
- return r;
-}
-
-static int dsicm_unprepare(struct drm_panel *panel)
-{
- struct panel_drv_data *ddata = panel_to_ddata(panel);
- int r;
-
- r = regulator_bulk_disable(ARRAY_SIZE(ddata->supplies), ddata->supplies);
- if (r)
- dev_err(&ddata->dsi->dev, "failed to disable supplies: %d\n", r);
-
- return r;
-}
-
-static int dsicm_disable(struct drm_panel *panel)
-{
- struct panel_drv_data *ddata = panel_to_ddata(panel);
- int r;
-
- dsicm_bl_power(ddata, false);
-
- mutex_lock(&ddata->lock);
-
- r = dsicm_power_off(ddata);
-
- mutex_unlock(&ddata->lock);
-
- return r;
-}
-
-static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable)
-{
- struct mipi_dsi_device *dsi = ddata->dsi;
- int r;
-
- if (enable)
- r = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
- else
- r = mipi_dsi_dcs_set_tear_off(dsi);
-
- /* possible panel bug */
- msleep(100);
-
- return r;
-}
-
-static int dsicm_get_modes(struct drm_panel *panel,
- struct drm_connector *connector)
-{
- struct panel_drv_data *ddata = panel_to_ddata(panel);
- struct drm_display_mode *mode;
-
- mode = drm_mode_duplicate(connector->dev, &ddata->mode);
- if (!mode) {
- dev_err(&ddata->dsi->dev, "failed to add mode %ux%ux@%u kHz\n",
- ddata->mode.hdisplay, ddata->mode.vdisplay,
- ddata->mode.clock);
- return -ENOMEM;
- }
-
- drm_mode_set_name(mode);
- mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
-
- connector->display_info.width_mm = ddata->width_mm;
- connector->display_info.height_mm = ddata->height_mm;
-
- drm_mode_probed_add(connector, mode);
-
- return 1;
-}
-
-static const struct drm_panel_funcs dsicm_panel_funcs = {
- .unprepare = dsicm_unprepare,
- .disable = dsicm_disable,
- .prepare = dsicm_prepare,
- .enable = dsicm_enable,
- .get_modes = dsicm_get_modes,
-};
-
-static int dsicm_probe_of(struct mipi_dsi_device *dsi)
-{
- struct device_node *node = dsi->dev.of_node;
- struct backlight_device *backlight;
- struct panel_drv_data *ddata = mipi_dsi_get_drvdata(dsi);
- struct display_timing timing;
- struct videomode vm = {
- .hactive = 864,
- .vactive = 480,
- };
- int err;
-
- ddata->reset_gpio = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
- if (IS_ERR(ddata->reset_gpio)) {
- err = PTR_ERR(ddata->reset_gpio);
- dev_err(&dsi->dev, "reset gpio request failed: %d", err);
- return err;
- }
-
- err = of_get_display_timing(node, "panel-timing", &timing);
- if (!err) {
- videomode_from_timing(&timing, &vm);
- } else {
- dev_warn(&dsi->dev,
- "failed to get video timing, using defaults\n");
- }
-
- if (!vm.pixelclock)
- vm.pixelclock = vm.hactive * vm.vactive * 60;
- drm_display_mode_from_videomode(&vm, &ddata->mode);
-
- ddata->width_mm = 0;
- of_property_read_u32(node, "width-mm", &ddata->width_mm);
-
- ddata->height_mm = 0;
- of_property_read_u32(node, "height-mm", &ddata->height_mm);
-
- ddata->supplies[0].supply = "vpnl";
- ddata->supplies[1].supply = "vddi";
- err = devm_regulator_bulk_get(&dsi->dev, ARRAY_SIZE(ddata->supplies),
- ddata->supplies);
- if (err)
- return err;
-
- backlight = devm_of_find_backlight(&dsi->dev);
- if (IS_ERR(backlight))
- return PTR_ERR(backlight);
-
- /* If no backlight device is found assume native backlight support */
- if (backlight)
- ddata->extbldev = backlight;
- else
- ddata->use_dsi_backlight = true;
-
- return 0;
-}
-
-static int dsicm_probe(struct mipi_dsi_device *dsi)
-{
- struct panel_drv_data *ddata;
- struct backlight_device *bldev = NULL;
- struct device *dev = &dsi->dev;
- int r;
-
- dev_dbg(dev, "probe\n");
-
- ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
- if (!ddata)
- return -ENOMEM;
-
- mipi_dsi_set_drvdata(dsi, ddata);
- ddata->dsi = dsi;
-
- r = dsicm_probe_of(dsi);
- if (r)
- return r;
-
- mutex_init(&ddata->lock);
-
- dsicm_hw_reset(ddata);
-
- drm_panel_init(&ddata->panel, dev, &dsicm_panel_funcs,
- DRM_MODE_CONNECTOR_DSI);
-
- if (ddata->use_dsi_backlight) {
- struct backlight_properties props = { 0 };
- props.max_brightness = 255;
- props.type = BACKLIGHT_RAW;
-
- bldev = devm_backlight_device_register(dev, dev_name(dev),
- dev, ddata, &dsicm_bl_ops, &props);
- if (IS_ERR(bldev)) {
- r = PTR_ERR(bldev);
- goto err_bl;
- }
-
- ddata->bldev = bldev;
- }
-
- r = sysfs_create_group(&dev->kobj, &dsicm_attr_group);
- if (r) {
- dev_err(dev, "failed to create sysfs files\n");
- goto err_bl;
- }
-
- dsi->lanes = 2;
- dsi->format = MIPI_DSI_FMT_RGB888;
- dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS |
- MIPI_DSI_MODE_EOT_PACKET;
- dsi->hs_rate = 300000000;
- dsi->lp_rate = 10000000;
-
- drm_panel_add(&ddata->panel);
-
- r = mipi_dsi_attach(dsi);
- if (r < 0)
- goto err_dsi_attach;
-
- return 0;
-
-err_dsi_attach:
- drm_panel_remove(&ddata->panel);
- sysfs_remove_group(&dsi->dev.kobj, &dsicm_attr_group);
-err_bl:
- if (ddata->extbldev)
- put_device(&ddata->extbldev->dev);
-
- return r;
-}
-
-static int dsicm_remove(struct mipi_dsi_device *dsi)
-{
- struct panel_drv_data *ddata = mipi_dsi_get_drvdata(dsi);
-
- dev_dbg(&dsi->dev, "remove\n");
-
- mipi_dsi_detach(dsi);
-
- drm_panel_remove(&ddata->panel);
-
- sysfs_remove_group(&dsi->dev.kobj, &dsicm_attr_group);
-
- if (ddata->extbldev)
- put_device(&ddata->extbldev->dev);
-
- return 0;
-}
-
-static const struct of_device_id dsicm_of_match[] = {
- { .compatible = "panel-dsi-cm", },
- {},
-};
-
-MODULE_DEVICE_TABLE(of, dsicm_of_match);
-
-static struct mipi_dsi_driver dsicm_driver = {
- .probe = dsicm_probe,
- .remove = dsicm_remove,
- .driver = {
- .name = "panel-dsi-cm",
- .of_match_table = dsicm_of_match,
- },
-};
-module_mipi_dsi_driver(dsicm_driver);
-
-MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
-MODULE_DESCRIPTION("Generic DSI Command Mode Panel Driver");
-MODULE_LICENSE("GPL");