Commit 07ade844 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm/panel/for-4.5-rc1' of git://anongit.freedesktop.org/tegra/linux into drm-next

drm/panel: Changes for v4.5-rc1

This set of changes brings in a few more helpers for DSI support as well
as a couple of new drivers and support for some more simple panels.

* tag 'drm/panel/for-4.5-rc1' of git://anongit.freedesktop.org/tegra/linux:
  drm/panel: simple: Add QiaoDian qd43003c0-40
  of: Add vendor prefix for QiaoDian Xianshi
  drm/panel: add kernel doc for size attributes in panel_desc
  drm/panel: simple: Add support for Kyocera TCG121XGLP panel
  devicetree: add vendor prefix for Kyocera Corporation
  drm/bridge: Remove gratuitous blank line
  drm/bridge: dw-hdmi: Use dashes in filenames
  drm/panel: Add Sharp LS043T1LE01 MIPI DSI panel
  dt-bindings: Add Sharp LS043T1LE01 panel binding
  drm/dsi: Add Turn On/Shutdown Peripheral command helpers
  drm/panel: Add Panasonic VVX10F034N00 MIPI DSI panel
  dt-bindings: Add Panasonic VVX10F034N00 panel binding
  drm/panel: simple: Add support for Innolux G121X1-L03
  drm/panel: simple: Add support for BOE TV080WUM-NL0
  dt-bindings: Add BOE TV080WUM-NL0 panel binding
  of: Add vendor prefix for BOE Technology Group
  drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format
parents 51bce5bc d2a6f0f5
Boe Corporation 8.0" WUXGA TFT LCD panel
Required properties:
- compatible: should be "boe,tv080wum-nl0"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
Innolux Corporation 12.1" G121X1-L03 XGA (1024x768) TFT LCD panel
Required properties:
- compatible: should be "innolux,g121x1-l03"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
Kyocera Corporation 12.1" XGA (1024x768) TFT LCD panel
Required properties:
- compatible: should be "kyo,tcg121xglp"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
Sharp Microelectronics 4.3" qHD TFT LCD panel
Required properties:
- compatible: should be "sharp,ls043t1le01-qhd"
- reg: DSI virtual channel of the peripheral
- power-supply: phandle of the regulator that provides the supply voltage
Optional properties:
- backlight: phandle of the backlight device attached to the panel
- reset-gpios: a GPIO spec for the reset pin
Example:
mdss_dsi@fd922800 {
panel@0 {
compatible = "sharp,ls043t1le01-qhd";
reg = <0>;
avdd-supply = <&pm8941_l22>;
backlight = <&pm8941_wled>;
reset-gpios = <&pm8941_gpios 19 GPIO_ACTIVE_HIGH>;
};
};
Panasonic 10" WUXGA TFT LCD panel
Required properties:
- compatible: should be "panasonic,vvx10f034n00"
- reg: DSI virtual channel of the peripheral
- power-supply: phandle of the regulator that provides the supply voltage
Optional properties:
- backlight: phandle of the backlight device attached to the panel
Example:
mdss_dsi@fd922800 {
panel@0 {
compatible = "panasonic,vvx10f034n00";
reg = <0>;
power-supply = <&vreg_vsp>;
backlight = <&lp8566_wled>;
};
};
QiaoDian XianShi Corporation 4"3 TFT LCD panel
Required properties:
- compatible: should be "qiaodian,qd43003c0-40"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
...@@ -33,6 +33,7 @@ auo AU Optronics Corporation ...@@ -33,6 +33,7 @@ auo AU Optronics Corporation
avago Avago Technologies avago Avago Technologies
avic Shanghai AVIC Optoelectronics Co., Ltd. avic Shanghai AVIC Optoelectronics Co., Ltd.
axis Axis Communications AB axis Axis Communications AB
boe BOE Technology Group Co., Ltd.
bosch Bosch Sensortec GmbH bosch Bosch Sensortec GmbH
boundary Boundary Devices Inc. boundary Boundary Devices Inc.
brcm Broadcom Corporation brcm Broadcom Corporation
...@@ -123,6 +124,7 @@ jedec JEDEC Solid State Technology Association ...@@ -123,6 +124,7 @@ jedec JEDEC Solid State Technology Association
karo Ka-Ro electronics GmbH karo Ka-Ro electronics GmbH
keymile Keymile GmbH keymile Keymile GmbH
kinetic Kinetic Technologies kinetic Kinetic Technologies
kyo Kyocera Corporation
lacie LaCie lacie LaCie
lantiq Lantiq Semiconductor lantiq Lantiq Semiconductor
lenovo Lenovo Group Ltd. lenovo Lenovo Group Ltd.
...@@ -180,6 +182,7 @@ qca Qualcomm Atheros, Inc. ...@@ -180,6 +182,7 @@ qca Qualcomm Atheros, Inc.
qcom Qualcomm Technologies, Inc qcom Qualcomm Technologies, Inc
qemu QEMU, a generic and open source machine emulator and virtualizer qemu QEMU, a generic and open source machine emulator and virtualizer
qi Qi Hardware qi Qi Hardware
qiaodian QiaoDian XianShi Corporation
qnap QNAP Systems, Inc. qnap QNAP Systems, Inc.
radxa Radxa radxa Radxa
raidsonic RaidSonic Technology GmbH raidsonic RaidSonic Technology GmbH
......
...@@ -22,7 +22,6 @@ config DRM_DW_HDMI_AHB_AUDIO ...@@ -22,7 +22,6 @@ config DRM_DW_HDMI_AHB_AUDIO
Designware HDMI block. This is used in conjunction with Designware HDMI block. This is used in conjunction with
the i.MX6 HDMI driver. the i.MX6 HDMI driver.
config DRM_NXP_PTN3460 config DRM_NXP_PTN3460
tristate "NXP PTN3460 DP/LVDS bridge" tristate "NXP PTN3460 DP/LVDS bridge"
depends on OF depends on OF
......
ccflags-y := -Iinclude/drm ccflags-y := -Iinclude/drm
obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw_hdmi-ahb-audio.o obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include <sound/pcm_drm_eld.h> #include <sound/pcm_drm_eld.h>
#include <sound/pcm_iec958.h> #include <sound/pcm_iec958.h>
#include "dw_hdmi-audio.h" #include "dw-hdmi-audio.h"
#define DRIVER_NAME "dw-hdmi-ahb-audio" #define DRIVER_NAME "dw-hdmi-ahb-audio"
......
...@@ -27,8 +27,8 @@ ...@@ -27,8 +27,8 @@
#include <drm/drm_encoder_slave.h> #include <drm/drm_encoder_slave.h>
#include <drm/bridge/dw_hdmi.h> #include <drm/bridge/dw_hdmi.h>
#include "dw_hdmi.h" #include "dw-hdmi.h"
#include "dw_hdmi-audio.h" #include "dw-hdmi-audio.h"
#define HDMI_EDID_LEN 512 #define HDMI_EDID_LEN 512
......
...@@ -365,6 +365,44 @@ int mipi_dsi_create_packet(struct mipi_dsi_packet *packet, ...@@ -365,6 +365,44 @@ int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
} }
EXPORT_SYMBOL(mipi_dsi_create_packet); EXPORT_SYMBOL(mipi_dsi_create_packet);
/**
* mipi_dsi_shutdown_peripheral() - sends a Shutdown Peripheral command
* @dsi: DSI peripheral device
*
* Return: 0 on success or a negative error code on failure.
*/
int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi)
{
struct mipi_dsi_msg msg = {
.channel = dsi->channel,
.type = MIPI_DSI_SHUTDOWN_PERIPHERAL,
.tx_buf = (u8 [2]) { 0, 0 },
.tx_len = 2,
};
return mipi_dsi_device_transfer(dsi, &msg);
}
EXPORT_SYMBOL(mipi_dsi_shutdown_peripheral);
/**
* mipi_dsi_turn_on_peripheral() - sends a Turn On Peripheral command
* @dsi: DSI peripheral device
*
* Return: 0 on success or a negative error code on failure.
*/
int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi)
{
struct mipi_dsi_msg msg = {
.channel = dsi->channel,
.type = MIPI_DSI_TURN_ON_PERIPHERAL,
.tx_buf = (u8 [2]) { 0, 0 },
.tx_len = 2,
};
return mipi_dsi_device_transfer(dsi, &msg);
}
EXPORT_SYMBOL(mipi_dsi_turn_on_peripheral);
/* /*
* mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of the * mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of the
* the payload in a long packet transmitted from the peripheral back to the * the payload in a long packet transmitted from the peripheral back to the
......
...@@ -31,6 +31,16 @@ config DRM_PANEL_LG_LG4573 ...@@ -31,6 +31,16 @@ config DRM_PANEL_LG_LG4573
Say Y here if you want to enable support for LG4573 RGB panel. Say Y here if you want to enable support for LG4573 RGB panel.
To compile this driver as a module, choose M here. To compile this driver as a module, choose M here.
config DRM_PANEL_PANASONIC_VVX10F034N00
tristate "Panasonic VVX10F034N00 1920x1200 video mode panel"
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
help
Say Y here if you want to enable support for Panasonic VVX10F034N00
WUXGA (1920x1200) Novatek NT1397-based DSI panel as found in some
Xperia Z2 tablets
config DRM_PANEL_SAMSUNG_S6E8AA0 config DRM_PANEL_SAMSUNG_S6E8AA0
tristate "Samsung S6E8AA0 DSI video mode panel" tristate "Samsung S6E8AA0 DSI video mode panel"
depends on OF depends on OF
...@@ -51,4 +61,13 @@ config DRM_PANEL_SHARP_LQ101R1SX01 ...@@ -51,4 +61,13 @@ config DRM_PANEL_SHARP_LQ101R1SX01
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called panel-sharp-lq101r1sx01. will be called panel-sharp-lq101r1sx01.
config DRM_PANEL_SHARP_LS043T1LE01
tristate "Sharp LS043T1LE01 qHD video mode panel"
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
help
Say Y here if you want to enable support for Sharp LS043T1LE01 qHD
(540x960) DSI panel as found on the Qualcomm APQ8074 Dragonboard
endmenu endmenu
obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o
/*
* Copyright (C) 2015 Red Hat
* Copyright (C) 2015 Sony Mobile Communications Inc.
* Author: Werner Johansson <werner.johansson@sonymobile.com>
*
* Based on AUO panel driver by Rob Clark <robdclark@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/backlight.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_panel.h>
#include <video/mipi_display.h>
/*
* When power is turned off to this panel a minimum off time of 500ms has to be
* observed before powering back on as there's no external reset pin. Keep
* track of earliest wakeup time and delay subsequent prepare call accordingly
*/
#define MIN_POFF_MS (500)
struct wuxga_nt_panel {
struct drm_panel base;
struct mipi_dsi_device *dsi;
struct backlight_device *backlight;
struct regulator *supply;
bool prepared;
bool enabled;
ktime_t earliest_wake;
const struct drm_display_mode *mode;
};
static inline struct wuxga_nt_panel *to_wuxga_nt_panel(struct drm_panel *panel)
{
return container_of(panel, struct wuxga_nt_panel, base);
}
static int wuxga_nt_panel_on(struct wuxga_nt_panel *wuxga_nt)
{
struct mipi_dsi_device *dsi = wuxga_nt->dsi;
int ret;
ret = mipi_dsi_turn_on_peripheral(dsi);
if (ret < 0)
return ret;
return 0;
}
static int wuxga_nt_panel_disable(struct drm_panel *panel)
{
struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
if (!wuxga_nt->enabled)
return 0;
mipi_dsi_shutdown_peripheral(wuxga_nt->dsi);
if (wuxga_nt->backlight) {
wuxga_nt->backlight->props.power = FB_BLANK_POWERDOWN;
wuxga_nt->backlight->props.state |= BL_CORE_FBBLANK;
backlight_update_status(wuxga_nt->backlight);
}
wuxga_nt->enabled = false;
return 0;
}
static int wuxga_nt_panel_unprepare(struct drm_panel *panel)
{
struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
if (!wuxga_nt->prepared)
return 0;
regulator_disable(wuxga_nt->supply);
wuxga_nt->earliest_wake = ktime_add_ms(ktime_get_real(), MIN_POFF_MS);
wuxga_nt->prepared = false;
return 0;
}
static int wuxga_nt_panel_prepare(struct drm_panel *panel)
{
struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
int ret;
s64 enablewait;
if (wuxga_nt->prepared)
return 0;
/*
* If the user re-enabled the panel before the required off-time then
* we need to wait the remaining period before re-enabling regulator
*/
enablewait = ktime_ms_delta(wuxga_nt->earliest_wake, ktime_get_real());
/* Sanity check, this should never happen */
if (enablewait > MIN_POFF_MS)
enablewait = MIN_POFF_MS;
if (enablewait > 0)
msleep(enablewait);
ret = regulator_enable(wuxga_nt->supply);
if (ret < 0)
return ret;
/*
* A minimum delay of 250ms is required after power-up until commands
* can be sent
*/
msleep(250);
ret = wuxga_nt_panel_on(wuxga_nt);
if (ret < 0) {
dev_err(panel->dev, "failed to set panel on: %d\n", ret);
goto poweroff;
}
wuxga_nt->prepared = true;
return 0;
poweroff:
regulator_disable(wuxga_nt->supply);
return ret;
}
static int wuxga_nt_panel_enable(struct drm_panel *panel)
{
struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
if (wuxga_nt->enabled)
return 0;
if (wuxga_nt->backlight) {
wuxga_nt->backlight->props.power = FB_BLANK_UNBLANK;
wuxga_nt->backlight->props.state &= ~BL_CORE_FBBLANK;
backlight_update_status(wuxga_nt->backlight);
}
wuxga_nt->enabled = true;
return 0;
}
static const struct drm_display_mode default_mode = {
.clock = 164402,
.hdisplay = 1920,
.hsync_start = 1920 + 152,
.hsync_end = 1920 + 152 + 52,
.htotal = 1920 + 152 + 52 + 20,
.vdisplay = 1200,
.vsync_start = 1200 + 24,
.vsync_end = 1200 + 24 + 6,
.vtotal = 1200 + 24 + 6 + 48,
.vrefresh = 60,
};
static int wuxga_nt_panel_get_modes(struct drm_panel *panel)
{
struct drm_display_mode *mode;
mode = drm_mode_duplicate(panel->drm, &default_mode);
if (!mode) {
dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
default_mode.hdisplay, default_mode.vdisplay,
default_mode.vrefresh);
return -ENOMEM;
}
drm_mode_set_name(mode);
drm_mode_probed_add(panel->connector, mode);
panel->connector->display_info.width_mm = 217;
panel->connector->display_info.height_mm = 136;
return 1;
}
static const struct drm_panel_funcs wuxga_nt_panel_funcs = {
.disable = wuxga_nt_panel_disable,
.unprepare = wuxga_nt_panel_unprepare,
.prepare = wuxga_nt_panel_prepare,
.enable = wuxga_nt_panel_enable,
.get_modes = wuxga_nt_panel_get_modes,
};
static const struct of_device_id wuxga_nt_of_match[] = {
{ .compatible = "panasonic,vvx10f034n00", },
{ }
};
MODULE_DEVICE_TABLE(of, wuxga_nt_of_match);
static int wuxga_nt_panel_add(struct wuxga_nt_panel *wuxga_nt)
{
struct device *dev = &wuxga_nt->dsi->dev;
struct device_node *np;
int ret;
wuxga_nt->mode = &default_mode;
wuxga_nt->supply = devm_regulator_get(dev, "power");
if (IS_ERR(wuxga_nt->supply))
return PTR_ERR(wuxga_nt->supply);
np = of_parse_phandle(dev->of_node, "backlight", 0);
if (np) {
wuxga_nt->backlight = of_find_backlight_by_node(np);
of_node_put(np);
if (!wuxga_nt->backlight)
return -EPROBE_DEFER;
}
drm_panel_init(&wuxga_nt->base);
wuxga_nt->base.funcs = &wuxga_nt_panel_funcs;
wuxga_nt->base.dev = &wuxga_nt->dsi->dev;
ret = drm_panel_add(&wuxga_nt->base);
if (ret < 0)
goto put_backlight;
return 0;
put_backlight:
if (wuxga_nt->backlight)
put_device(&wuxga_nt->backlight->dev);
return ret;
}
static void wuxga_nt_panel_del(struct wuxga_nt_panel *wuxga_nt)
{
if (wuxga_nt->base.dev)
drm_panel_remove(&wuxga_nt->base);
if (wuxga_nt->backlight)
put_device(&wuxga_nt->backlight->dev);
}
static int wuxga_nt_panel_probe(struct mipi_dsi_device *dsi)
{
struct wuxga_nt_panel *wuxga_nt;
int ret;
dsi->lanes = 4;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
MIPI_DSI_MODE_VIDEO_HSE |
MIPI_DSI_CLOCK_NON_CONTINUOUS |
MIPI_DSI_MODE_LPM;
wuxga_nt = devm_kzalloc(&dsi->dev, sizeof(*wuxga_nt), GFP_KERNEL);
if (!wuxga_nt)
return -ENOMEM;
mipi_dsi_set_drvdata(dsi, wuxga_nt);
wuxga_nt->dsi = dsi;
ret = wuxga_nt_panel_add(wuxga_nt);
if (ret < 0)
return ret;
return mipi_dsi_attach(dsi);
}
static int wuxga_nt_panel_remove(struct mipi_dsi_device *dsi)
{
struct wuxga_nt_panel *wuxga_nt = mipi_dsi_get_drvdata(dsi);
int ret;
ret = wuxga_nt_panel_disable(&wuxga_nt->base);
if (ret < 0)
dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
ret = mipi_dsi_detach(dsi);
if (ret < 0)
dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
drm_panel_detach(&wuxga_nt->base);
wuxga_nt_panel_del(wuxga_nt);
return 0;
}
static void wuxga_nt_panel_shutdown(struct mipi_dsi_device *dsi)
{
struct wuxga_nt_panel *wuxga_nt = mipi_dsi_get_drvdata(dsi);
wuxga_nt_panel_disable(&wuxga_nt->base);
}
static struct mipi_dsi_driver wuxga_nt_panel_driver = {
.driver = {
.name = "panel-panasonic-vvx10f034n00",
.of_match_table = wuxga_nt_of_match,
},
.probe = wuxga_nt_panel_probe,
.remove = wuxga_nt_panel_remove,
.shutdown = wuxga_nt_panel_shutdown,
};
module_mipi_dsi_driver(wuxga_nt_panel_driver);
MODULE_AUTHOR("Werner Johansson <werner.johansson@sonymobile.com>");
MODULE_DESCRIPTION("Panasonic VVX10F034N00 Novatek NT1397-based WUXGA (1920x1200) video mode panel driver");
MODULE_LICENSE("GPL v2");
/*
* Copyright (C) 2015 Red Hat
* Copyright (C) 2015 Sony Mobile Communications Inc.
* Author: Werner Johansson <werner.johansson@sonymobile.com>
*
* Based on AUO panel driver by Rob Clark <robdclark@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/backlight.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_panel.h>
#include <video/mipi_display.h>
struct sharp_nt_panel {
struct drm_panel base;
struct mipi_dsi_device *dsi;
struct backlight_device *backlight;
struct regulator *supply;
struct gpio_desc *reset_gpio;
bool prepared;
bool enabled;
const struct drm_display_mode *mode;
};
static inline struct sharp_nt_panel *to_sharp_nt_panel(struct drm_panel *panel)
{
return container_of(panel, struct sharp_nt_panel, base);
}
static int sharp_nt_panel_init(struct sharp_nt_panel *sharp_nt)
{
struct mipi_dsi_device *dsi = sharp_nt->dsi;
int ret;
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0)
return ret;
msleep(120);
/* Novatek two-lane operation */
ret = mipi_dsi_dcs_write(dsi, 0xae, (u8[]){ 0x03 }, 1);
if (ret < 0)
return ret;
/* Set both MCU and RGB I/F to 24bpp */
ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT |
(MIPI_DCS_PIXEL_FMT_24BIT << 4));
if (ret < 0)
return ret;
return 0;
}
static int sharp_nt_panel_on(struct sharp_nt_panel *sharp_nt)
{
struct mipi_dsi_device *dsi = sharp_nt->dsi;
int ret;
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0)
return ret;
return 0;
}
static int sharp_nt_panel_off(struct sharp_nt_panel *sharp_nt)
{
struct mipi_dsi_device *dsi = sharp_nt->dsi;
int ret;
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret < 0)
return ret;
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret < 0)
return ret;
return 0;
}
static int sharp_nt_panel_disable(struct drm_panel *panel)
{
struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
if (!sharp_nt->enabled)
return 0;
if (sharp_nt->backlight) {
sharp_nt->backlight->props.power = FB_BLANK_POWERDOWN;
backlight_update_status(sharp_nt->backlight);
}
sharp_nt->enabled = false;
return 0;
}
static int sharp_nt_panel_unprepare(struct drm_panel *panel)
{
struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
int ret;
if (!sharp_nt->prepared)
return 0;
ret = sharp_nt_panel_off(sharp_nt);
if (ret < 0) {
dev_err(panel->dev, "failed to set panel off: %d\n", ret);
return ret;
}
regulator_disable(sharp_nt->supply);
if (sharp_nt->reset_gpio)
gpiod_set_value(sharp_nt->reset_gpio, 0);
sharp_nt->prepared = false;
return 0;
}
static int sharp_nt_panel_prepare(struct drm_panel *panel)
{
struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
int ret;
if (sharp_nt->prepared)
return 0;
ret = regulator_enable(sharp_nt->supply);
if (ret < 0)
return ret;
msleep(20);
if (sharp_nt->reset_gpio) {
gpiod_set_value(sharp_nt->reset_gpio, 1);
msleep(1);
gpiod_set_value(sharp_nt->reset_gpio, 0);
msleep(1);
gpiod_set_value(sharp_nt->reset_gpio, 1);
msleep(10);
}
ret = sharp_nt_panel_init(sharp_nt);
if (ret < 0) {
dev_err(panel->dev, "failed to init panel: %d\n", ret);
goto poweroff;
}
ret = sharp_nt_panel_on(sharp_nt);
if (ret < 0) {
dev_err(panel->dev, "failed to set panel on: %d\n", ret);
goto poweroff;
}
sharp_nt->prepared = true;
return 0;
poweroff:
regulator_disable(sharp_nt->supply);
if (sharp_nt->reset_gpio)
gpiod_set_value(sharp_nt->reset_gpio, 0);
return ret;
}
static int sharp_nt_panel_enable(struct drm_panel *panel)
{
struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
if (sharp_nt->enabled)
return 0;
if (sharp_nt->backlight) {
sharp_nt->backlight->props.power = FB_BLANK_UNBLANK;
backlight_update_status(sharp_nt->backlight);
}
sharp_nt->enabled = true;
return 0;
}
static const struct drm_display_mode default_mode = {
.clock = 41118,
.hdisplay = 540,
.hsync_start = 540 + 48,
.hsync_end = 540 + 48 + 80,
.htotal = 540 + 48 + 80 + 32,
.vdisplay = 960,
.vsync_start = 960 + 3,
.vsync_end = 960 + 3 + 15,
.vtotal = 960 + 3 + 15 + 1,
.vrefresh = 60,
};
static int sharp_nt_panel_get_modes(struct drm_panel *panel)
{
struct drm_display_mode *mode;
mode = drm_mode_duplicate(panel->drm, &default_mode);
if (!mode) {
dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
default_mode.hdisplay, default_mode.vdisplay,
default_mode.vrefresh);
return -ENOMEM;
}
drm_mode_set_name(mode);
drm_mode_probed_add(panel->connector, mode);
panel->connector->display_info.width_mm = 54;
panel->connector->display_info.height_mm = 95;
return 1;
}
static const struct drm_panel_funcs sharp_nt_panel_funcs = {
.disable = sharp_nt_panel_disable,
.unprepare = sharp_nt_panel_unprepare,
.prepare = sharp_nt_panel_prepare,
.enable = sharp_nt_panel_enable,
.get_modes = sharp_nt_panel_get_modes,
};
static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt)
{
struct device *dev = &sharp_nt->dsi->dev;
struct device_node *np;
int ret;
sharp_nt->mode = &default_mode;
sharp_nt->supply = devm_regulator_get(dev, "avdd");
if (IS_ERR(sharp_nt->supply))
return PTR_ERR(sharp_nt->supply);
sharp_nt->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(sharp_nt->reset_gpio)) {
dev_err(dev, "cannot get reset-gpios %ld\n",
PTR_ERR(sharp_nt->reset_gpio));
sharp_nt->reset_gpio = NULL;
} else {
gpiod_set_value(sharp_nt->reset_gpio, 0);
}
np = of_parse_phandle(dev->of_node, "backlight", 0);
if (np) {
sharp_nt->backlight = of_find_backlight_by_node(np);
of_node_put(np);
if (!sharp_nt->backlight)
return -EPROBE_DEFER;
}
drm_panel_init(&sharp_nt->base);
sharp_nt->base.funcs = &sharp_nt_panel_funcs;
sharp_nt->base.dev = &sharp_nt->dsi->dev;
ret = drm_panel_add(&sharp_nt->base);
if (ret < 0)
goto put_backlight;
return 0;
put_backlight:
if (sharp_nt->backlight)
put_device(&sharp_nt->backlight->dev);
return ret;
}
static void sharp_nt_panel_del(struct sharp_nt_panel *sharp_nt)
{
if (sharp_nt->base.dev)
drm_panel_remove(&sharp_nt->base);
if (sharp_nt->backlight)
put_device(&sharp_nt->backlight->dev);
}
static int sharp_nt_panel_probe(struct mipi_dsi_device *dsi)
{
struct sharp_nt_panel *sharp_nt;
int ret;
dsi->lanes = 2;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
MIPI_DSI_MODE_VIDEO_HSE |
MIPI_DSI_CLOCK_NON_CONTINUOUS |
MIPI_DSI_MODE_EOT_PACKET;
sharp_nt = devm_kzalloc(&dsi->dev, sizeof(*sharp_nt), GFP_KERNEL);
if (!sharp_nt)
return -ENOMEM;
mipi_dsi_set_drvdata(dsi, sharp_nt);
sharp_nt->dsi = dsi;
ret = sharp_nt_panel_add(sharp_nt);
if (ret < 0)
return ret;
return mipi_dsi_attach(dsi);
}
static int sharp_nt_panel_remove(struct mipi_dsi_device *dsi)
{
struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi);
int ret;
ret = sharp_nt_panel_disable(&sharp_nt->base);
if (ret < 0)
dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
ret = mipi_dsi_detach(dsi);
if (ret < 0)
dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
drm_panel_detach(&sharp_nt->base);
sharp_nt_panel_del(sharp_nt);
return 0;
}
static void sharp_nt_panel_shutdown(struct mipi_dsi_device *dsi)
{
struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi);
sharp_nt_panel_disable(&sharp_nt->base);
}
static const struct of_device_id sharp_nt_of_match[] = {
{ .compatible = "sharp,ls043t1le01-qhd", },
{ }
};
MODULE_DEVICE_TABLE(of, sharp_nt_of_match);
static struct mipi_dsi_driver sharp_nt_panel_driver = {
.driver = {
.name = "panel-sharp-ls043t1le01-qhd",
.of_match_table = sharp_nt_of_match,
},
.probe = sharp_nt_panel_probe,
.remove = sharp_nt_panel_remove,
.shutdown = sharp_nt_panel_shutdown,
};
module_mipi_dsi_driver(sharp_nt_panel_driver);
MODULE_AUTHOR("Werner Johansson <werner.johansson@sonymobile.com>");
MODULE_DESCRIPTION("Sharp LS043T1LE01 NT35565-based qHD (540x960) video mode panel driver");
MODULE_LICENSE("GPL v2");
...@@ -44,6 +44,10 @@ struct panel_desc { ...@@ -44,6 +44,10 @@ struct panel_desc {
unsigned int bpc; unsigned int bpc;
/**
* @width: width (in millimeters) of the panel's active display area
* @height: height (in millimeters) of the panel's active display area
*/
struct { struct {
unsigned int width; unsigned int width;
unsigned int height; unsigned int height;
...@@ -832,6 +836,34 @@ static const struct panel_desc innolux_g121i1_l01 = { ...@@ -832,6 +836,34 @@ static const struct panel_desc innolux_g121i1_l01 = {
}, },
}; };
static const struct drm_display_mode innolux_g121x1_l03_mode = {
.clock = 65000,
.hdisplay = 1024,
.hsync_start = 1024 + 0,
.hsync_end = 1024 + 1,
.htotal = 1024 + 0 + 1 + 320,
.vdisplay = 768,
.vsync_start = 768 + 38,
.vsync_end = 768 + 38 + 1,
.vtotal = 768 + 38 + 1 + 0,
.vrefresh = 60,
};
static const struct panel_desc innolux_g121x1_l03 = {
.modes = &innolux_g121x1_l03_mode,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 246,
.height = 185,
},
.delay = {
.enable = 200,
.unprepare = 200,
.disable = 400,
},
};
static const struct drm_display_mode innolux_n116bge_mode = { static const struct drm_display_mode innolux_n116bge_mode = {
.clock = 76420, .clock = 76420,
.hdisplay = 1366, .hdisplay = 1366,
...@@ -902,6 +934,30 @@ static const struct panel_desc innolux_zj070na_01p = { ...@@ -902,6 +934,30 @@ static const struct panel_desc innolux_zj070na_01p = {
}, },
}; };
static const struct display_timing kyo_tcg121xglp_timing = {
.pixelclock = { 52000000, 65000000, 71000000 },
.hactive = { 1024, 1024, 1024 },
.hfront_porch = { 2, 2, 2 },
.hback_porch = { 2, 2, 2 },
.hsync_len = { 86, 124, 244 },
.vactive = { 768, 768, 768 },
.vfront_porch = { 2, 2, 2 },
.vback_porch = { 2, 2, 2 },
.vsync_len = { 6, 34, 73 },
.flags = DISPLAY_FLAGS_DE_HIGH,
};
static const struct panel_desc kyo_tcg121xglp = {
.timings = &kyo_tcg121xglp_timing,
.num_timings = 1,
.bpc = 8,
.size = {
.width = 246,
.height = 184,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
};
static const struct drm_display_mode lg_lb070wv8_mode = { static const struct drm_display_mode lg_lb070wv8_mode = {
.clock = 33246, .clock = 33246,
.hdisplay = 800, .hdisplay = 800,
...@@ -1027,6 +1083,30 @@ static const struct panel_desc ortustech_com43h4m85ulc = { ...@@ -1027,6 +1083,30 @@ static const struct panel_desc ortustech_com43h4m85ulc = {
.bus_format = MEDIA_BUS_FMT_RGB888_1X24, .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
}; };
static const struct drm_display_mode qd43003c0_40_mode = {
.clock = 9000,
.hdisplay = 480,
.hsync_start = 480 + 8,
.hsync_end = 480 + 8 + 4,
.htotal = 480 + 8 + 4 + 39,
.vdisplay = 272,
.vsync_start = 272 + 4,
.vsync_end = 272 + 4 + 10,
.vtotal = 272 + 4 + 10 + 2,
.vrefresh = 60,
};
static const struct panel_desc qd43003c0_40 = {
.modes = &qd43003c0_40_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 95,
.height = 53,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
};
static const struct drm_display_mode samsung_ltn101nt05_mode = { static const struct drm_display_mode samsung_ltn101nt05_mode = {
.clock = 54030, .clock = 54030,
.hdisplay = 1024, .hdisplay = 1024,
...@@ -1157,6 +1237,9 @@ static const struct of_device_id platform_of_match[] = { ...@@ -1157,6 +1237,9 @@ static const struct of_device_id platform_of_match[] = {
}, { }, {
.compatible ="innolux,g121i1-l01", .compatible ="innolux,g121i1-l01",
.data = &innolux_g121i1_l01 .data = &innolux_g121i1_l01
}, {
.compatible = "innolux,g121x1-l03",
.data = &innolux_g121x1_l03,
}, { }, {
.compatible = "innolux,n116bge", .compatible = "innolux,n116bge",
.data = &innolux_n116bge, .data = &innolux_n116bge,
...@@ -1166,6 +1249,9 @@ static const struct of_device_id platform_of_match[] = { ...@@ -1166,6 +1249,9 @@ static const struct of_device_id platform_of_match[] = {
}, { }, {
.compatible = "innolux,zj070na-01p", .compatible = "innolux,zj070na-01p",
.data = &innolux_zj070na_01p, .data = &innolux_zj070na_01p,
}, {
.compatible = "kyo,tcg121xglp",
.data = &kyo_tcg121xglp,
}, { }, {
.compatible = "lg,lb070wv8", .compatible = "lg,lb070wv8",
.data = &lg_lb070wv8, .data = &lg_lb070wv8,
...@@ -1181,6 +1267,9 @@ static const struct of_device_id platform_of_match[] = { ...@@ -1181,6 +1267,9 @@ static const struct of_device_id platform_of_match[] = {
}, { }, {
.compatible = "ortustech,com43h4m85ulc", .compatible = "ortustech,com43h4m85ulc",
.data = &ortustech_com43h4m85ulc, .data = &ortustech_com43h4m85ulc,
}, {
.compatible = "qiaodian,qd43003c0-40",
.data = &qd43003c0_40,
}, { }, {
.compatible = "samsung,ltn101nt05", .compatible = "samsung,ltn101nt05",
.data = &samsung_ltn101nt05, .data = &samsung_ltn101nt05,
...@@ -1263,6 +1352,36 @@ static const struct panel_desc_dsi auo_b080uan01 = { ...@@ -1263,6 +1352,36 @@ static const struct panel_desc_dsi auo_b080uan01 = {
.lanes = 4, .lanes = 4,
}; };
static const struct drm_display_mode boe_tv080wum_nl0_mode = {
.clock = 160000,
.hdisplay = 1200,
.hsync_start = 1200 + 120,
.hsync_end = 1200 + 120 + 20,
.htotal = 1200 + 120 + 20 + 21,
.vdisplay = 1920,
.vsync_start = 1920 + 21,
.vsync_end = 1920 + 21 + 3,
.vtotal = 1920 + 21 + 3 + 18,
.vrefresh = 60,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
};
static const struct panel_desc_dsi boe_tv080wum_nl0 = {
.desc = {
.modes = &boe_tv080wum_nl0_mode,
.num_modes = 1,
.size = {
.width = 107,
.height = 172,
},
},
.flags = MIPI_DSI_MODE_VIDEO |
MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
.format = MIPI_DSI_FMT_RGB888,
.lanes = 4,
};
static const struct drm_display_mode lg_ld070wx3_sl01_mode = { static const struct drm_display_mode lg_ld070wx3_sl01_mode = {
.clock = 71000, .clock = 71000,
.hdisplay = 800, .hdisplay = 800,
...@@ -1348,10 +1467,14 @@ static const struct panel_desc_dsi panasonic_vvx10f004b00 = { ...@@ -1348,10 +1467,14 @@ static const struct panel_desc_dsi panasonic_vvx10f004b00 = {
.lanes = 4, .lanes = 4,
}; };
static const struct of_device_id dsi_of_match[] = { static const struct of_device_id dsi_of_match[] = {
{ {
.compatible = "auo,b080uan01", .compatible = "auo,b080uan01",
.data = &auo_b080uan01 .data = &auo_b080uan01
}, {
.compatible = "boe,tv080wum-nl0",
.data = &boe_tv080wum_nl0
}, { }, {
.compatible = "lg,ld070wx3-sl01", .compatible = "lg,ld070wx3-sl01",
.data = &lg_ld070wx3_sl01 .data = &lg_ld070wx3_sl01
......
...@@ -163,9 +163,36 @@ static inline struct mipi_dsi_device *to_mipi_dsi_device(struct device *dev) ...@@ -163,9 +163,36 @@ static inline struct mipi_dsi_device *to_mipi_dsi_device(struct device *dev)
return container_of(dev, struct mipi_dsi_device, dev); return container_of(dev, struct mipi_dsi_device, dev);
} }
/**
* mipi_dsi_pixel_format_to_bpp - obtain the number of bits per pixel for any
* given pixel format defined by the MIPI DSI
* specification
* @fmt: MIPI DSI pixel format
*
* Returns: The number of bits per pixel of the given pixel format.
*/
static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt)
{
switch (fmt) {
case MIPI_DSI_FMT_RGB888:
case MIPI_DSI_FMT_RGB666:
return 24;
case MIPI_DSI_FMT_RGB666_PACKED:
return 18;
case MIPI_DSI_FMT_RGB565:
return 16;
}
return -EINVAL;
}
struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np); struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np);
int mipi_dsi_attach(struct mipi_dsi_device *dsi); int mipi_dsi_attach(struct mipi_dsi_device *dsi);
int mipi_dsi_detach(struct mipi_dsi_device *dsi); int mipi_dsi_detach(struct mipi_dsi_device *dsi);
int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi);
int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi);
int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi, int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
u16 value); u16 value);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment