I want to sort out support for tinydrm in vc4, so I needed to get a tinydrm-appropriate panel working and this is what I had on hand. This is derived from a combination of ili9341.c from tinydrm and fb_hx8357d.c from staging's fbtft. The register header is copied directly from staging's fbtft, on the assumption that we will delete that copy later. Signed-off-by: Eric Anholt <eric@xxxxxxxxxx> --- MAINTAINERS | 7 + drivers/gpu/drm/tinydrm/Kconfig | 11 ++ drivers/gpu/drm/tinydrm/Makefile | 1 + drivers/gpu/drm/tinydrm/hx8357d.c | 261 ++++++++++++++++++++++++++++++ drivers/gpu/drm/tinydrm/hx8357d.h | 71 ++++++++ 5 files changed, 351 insertions(+) create mode 100644 drivers/gpu/drm/tinydrm/hx8357d.c create mode 100644 drivers/gpu/drm/tinydrm/hx8357d.h diff --git a/MAINTAINERS b/MAINTAINERS index 39c3f6682ace..e78971e20a11 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4623,6 +4623,13 @@ S: Maintained F: drivers/gpu/drm/tinydrm/ili9225.c F: Documentation/devicetree/bindings/display/ilitek,ili9225.txt +DRM DRIVER FOR HX8357D PANELS +M: Eric Anholt <eric@xxxxxxxxxx> +T: git git://anongit.freedesktop.org/drm/drm-misc +S: Maintained +F: drivers/gpu/drm/tinydrm/hx8357d.c +F: Documentation/devicetree/bindings/display/himax,hx8357d.txt + DRM DRIVER FOR INTEL I810 VIDEO CARDS S: Orphan / Obsolete F: drivers/gpu/drm/i810/ diff --git a/drivers/gpu/drm/tinydrm/Kconfig b/drivers/gpu/drm/tinydrm/Kconfig index 16f4b5c91f1b..2c408ac1a900 100644 --- a/drivers/gpu/drm/tinydrm/Kconfig +++ b/drivers/gpu/drm/tinydrm/Kconfig @@ -10,6 +10,17 @@ menuconfig DRM_TINYDRM config TINYDRM_MIPI_DBI tristate +config TINYDRM_HX8357D + tristate "DRM support for HX8357D display panels" + depends on DRM_TINYDRM && SPI + depends on BACKLIGHT_CLASS_DEVICE + select TINYDRM_MIPI_DBI + help + DRM driver for the following HX8357D panels: + * YX350HV15-T 3.5" 340x350 TFT (Adafruit 3.5") + + If M is selected the module will be called hx8357d. + config TINYDRM_ILI9225 tristate "DRM support for ILI9225 display panels" depends on DRM_TINYDRM && SPI diff --git a/drivers/gpu/drm/tinydrm/Makefile b/drivers/gpu/drm/tinydrm/Makefile index 14d99080665a..f823066f7743 100644 --- a/drivers/gpu/drm/tinydrm/Makefile +++ b/drivers/gpu/drm/tinydrm/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_TINYDRM) += core/ obj-$(CONFIG_TINYDRM_MIPI_DBI) += mipi-dbi.o # Displays +obj-$(CONFIG_TINYDRM_HX8357D) += hx8357d.o obj-$(CONFIG_TINYDRM_ILI9225) += ili9225.o obj-$(CONFIG_TINYDRM_ILI9341) += ili9341.o obj-$(CONFIG_TINYDRM_MI0283QT) += mi0283qt.o diff --git a/drivers/gpu/drm/tinydrm/hx8357d.c b/drivers/gpu/drm/tinydrm/hx8357d.c new file mode 100644 index 000000000000..51d4da624d57 --- /dev/null +++ b/drivers/gpu/drm/tinydrm/hx8357d.c @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * DRM driver for the HX8357D LCD controller + * + * Copyright 2018 Broadcom + * Copyright 2018 David Lechner <david@xxxxxxxxxxxxxx> + * Copyright 2016 Noralf Trønnes + * Copyright (C) 2015 Adafruit Industries + * Copyright (C) 2013 Christian Vogelgsang + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/spi/spi.h> + +#include <drm/drm_fb_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_modeset_helper.h> +#include <drm/tinydrm/mipi-dbi.h> +#include <drm/tinydrm/tinydrm-helpers.h> +#include <video/mipi_display.h> +#include "hx8357d.h" + +#define HX8357D_MADCTL_MY 0x80 +#define HX8357D_MADCTL_MX 0x40 +#define HX8357D_MADCTL_MV 0x20 +#define HX8357D_MADCTL_ML 0x10 +#define HX8357D_MADCTL_RGB 0x00 +#define HX8357D_MADCTL_BGR 0x08 +#define HX8357D_MADCTL_MH 0x04 + +static void yx240qv29_enable(struct drm_simple_display_pipe *pipe, + struct drm_crtc_state *crtc_state, + struct drm_plane_state *plane_state) +{ + struct tinydrm_device *tdev = pipe_to_tinydrm(pipe); + struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev); + u8 addr_mode; + int ret; + + DRM_DEBUG_KMS("\n"); + + ret = mipi_dbi_poweron_conditional_reset(mipi); + if (ret < 0) + return; + if (ret == 1) + goto out_enable; + + /* setextc */ + mipi_dbi_command(mipi, HX8357D_SETC, 0xFF, 0x83, 0x57); + msleep(150); + + /* setRGB which also enables SDO */ + mipi_dbi_command(mipi, HX8357_SETRGB, 0x00, 0x00, 0x06, 0x06); + + /* -1.52V */ + mipi_dbi_command(mipi, HX8357D_SETCOM, 0x25); + + /* Normal mode 70Hz, Idle mode 55 Hz */ + mipi_dbi_command(mipi, HX8357_SETOSC, 0x68); + + /* Set Panel - BGR, Gate direction swapped */ + mipi_dbi_command(mipi, HX8357_SETPANEL, 0x05); + + mipi_dbi_command(mipi, HX8357_SETPWR1, + 0x00, /* Not deep standby */ + 0x15, /* BT */ + 0x1C, /* VSPR */ + 0x1C, /* VSNR */ + 0x83, /* AP */ + 0xAA); /* FS */ + + mipi_dbi_command(mipi, HX8357D_SETSTBA, + 0x50, /* OPON normal */ + 0x50, /* OPON idle */ + 0x01, /* STBA */ + 0x3C, /* STBA */ + 0x1E, /* STBA */ + 0x08); /* GEN */ + + mipi_dbi_command(mipi, HX8357D_SETCYC, + 0x02, /* NW 0x02 */ + 0x40, /* RTN */ + 0x00, /* DIV */ + 0x2A, /* DUM */ + 0x2A, /* DUM */ + 0x0D, /* GDON */ + 0x78); /* GDOFF */ + + mipi_dbi_command(mipi, HX8357D_SETGAMMA, + 0x02, + 0x0A, + 0x11, + 0x1d, + 0x23, + 0x35, + 0x41, + 0x4b, + 0x4b, + 0x42, + 0x3A, + 0x27, + 0x1B, + 0x08, + 0x09, + 0x03, + 0x02, + 0x0A, + 0x11, + 0x1d, + 0x23, + 0x35, + 0x41, + 0x4b, + 0x4b, + 0x42, + 0x3A, + 0x27, + 0x1B, + 0x08, + 0x09, + 0x03, + 0x00, + 0x01); + + /* 16 bit */ + mipi_dbi_command(mipi, MIPI_DCS_SET_PIXEL_FORMAT, + MIPI_DCS_PIXEL_FMT_16BIT); + + /* TE off */ + mipi_dbi_command(mipi, MIPI_DCS_SET_TEAR_ON, 0x00); + + /* tear line */ + mipi_dbi_command(mipi, MIPI_DCS_SET_TEAR_SCANLINE, 0x00, 0x02); + + /* Exit Sleep */ + mipi_dbi_command(mipi, MIPI_DCS_EXIT_SLEEP_MODE); + msleep(150); + + /* display on */ + mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON); + usleep_range(5000, 7000); + +out_enable: + switch (mipi->rotation) { + default: + addr_mode = HX8357D_MADCTL_MX | HX8357D_MADCTL_MY; + break; + case 90: + addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MY; + break; + case 180: + addr_mode = 0; + break; + case 270: + addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MX; + break; + } + mipi_dbi_command(mipi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode); + mipi_dbi_enable_flush(mipi, crtc_state, plane_state); +} + +static const struct drm_simple_display_pipe_funcs hx8357d_pipe_funcs = { + .enable = yx240qv29_enable, + .disable = mipi_dbi_pipe_disable, + .update = tinydrm_display_pipe_update, + .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb, +}; + +static const struct drm_display_mode yx350hv15_mode = { + TINYDRM_MODE(320, 480, 60, 75), +}; + +DEFINE_DRM_GEM_CMA_FOPS(hx8357d_fops); + +static struct drm_driver hx8357d_driver = { + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC, + .fops = &hx8357d_fops, + TINYDRM_GEM_DRIVER_OPS, + .debugfs_init = mipi_dbi_debugfs_init, + .name = "hx8357d", + .desc = "HX8357D", + .date = "20181023", + .major = 1, + .minor = 0, +}; + +static const struct of_device_id hx8357d_of_match[] = { + { .compatible = "adafruit,yx350hv15" }, + { } +}; +MODULE_DEVICE_TABLE(of, hx8357d_of_match); + +static const struct spi_device_id hx8357d_id[] = { + { "hx8357d", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, hx8357d_id); + +static int hx8357d_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct mipi_dbi *mipi; + struct gpio_desc *dc; + u32 rotation = 0; + int ret; + + mipi = devm_kzalloc(dev, sizeof(*mipi), GFP_KERNEL); + if (!mipi) + return -ENOMEM; + + dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW); + if (IS_ERR(dc)) { + DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n"); + return PTR_ERR(dc); + } + + mipi->backlight = devm_of_find_backlight(dev); + if (IS_ERR(mipi->backlight)) + return PTR_ERR(mipi->backlight); + + device_property_read_u32(dev, "rotation", &rotation); + + ret = mipi_dbi_spi_init(spi, mipi, dc); + if (ret) + return ret; + + ret = mipi_dbi_init(&spi->dev, mipi, &hx8357d_pipe_funcs, + &hx8357d_driver, &yx350hv15_mode, rotation); + if (ret) + return ret; + + spi_set_drvdata(spi, mipi); + + return devm_tinydrm_register(&mipi->tinydrm); +} + +static void hx8357d_shutdown(struct spi_device *spi) +{ + struct mipi_dbi *mipi = spi_get_drvdata(spi); + + tinydrm_shutdown(&mipi->tinydrm); +} + +static struct spi_driver hx8357d_spi_driver = { + .driver = { + .name = "hx8357d", + .of_match_table = hx8357d_of_match, + }, + .id_table = hx8357d_id, + .probe = hx8357d_probe, + .shutdown = hx8357d_shutdown, +}; +module_spi_driver(hx8357d_spi_driver); + +MODULE_DESCRIPTION("HX8357D DRM driver"); +MODULE_AUTHOR("Eric Anholt <eric@xxxxxxxxxx>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/tinydrm/hx8357d.h b/drivers/gpu/drm/tinydrm/hx8357d.h new file mode 100644 index 000000000000..6180b093f94f --- /dev/null +++ b/drivers/gpu/drm/tinydrm/hx8357d.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: MIT */ +/* + * This is our library for the Adafruit ILI9341 Breakout and Shield + * ----> http://www.adafruit.com/products/1651 + * + * Check out the links above for our tutorials and wiring diagrams + * These displays use SPI to communicate, 4 or 5 pins are required to + * interface (RST is optional) + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * Written by Limor Fried/Ladyada for Adafruit Industries. + * MIT license, all text above must be included in any redistribution + */ + +#ifndef __HX8357_H__ +#define __HX8357_H__ + +#define HX8357D 0xD +#define HX8357B 0xB + +#define HX8357_TFTWIDTH 320 +#define HX8357_TFTHEIGHT 480 + +#define HX8357_SETOSC 0xB0 +#define HX8357_SETPWR1 0xB1 +#define HX8357B_SETDISPLAY 0xB2 +#define HX8357_SETRGB 0xB3 +#define HX8357D_SETCOM 0xB6 + +#define HX8357B_SETDISPMODE 0xB4 +#define HX8357D_SETCYC 0xB4 +#define HX8357B_SETOTP 0xB7 +#define HX8357D_SETC 0xB9 + +#define HX8357B_SET_PANEL_DRIVING 0xC0 +#define HX8357D_SETSTBA 0xC0 +#define HX8357B_SETDGC 0xC1 +#define HX8357B_SETID 0xC3 +#define HX8357B_SETDDB 0xC4 +#define HX8357B_SETDISPLAYFRAME 0xC5 +#define HX8357B_GAMMASET 0xC8 +#define HX8357B_SETCABC 0xC9 +#define HX8357_SETPANEL 0xCC + +#define HX8357B_SETPOWER 0xD0 +#define HX8357B_SETVCOM 0xD1 +#define HX8357B_SETPWRNORMAL 0xD2 + +#define HX8357B_RDID1 0xDA +#define HX8357B_RDID2 0xDB +#define HX8357B_RDID3 0xDC +#define HX8357B_RDID4 0xDD + +#define HX8357D_SETGAMMA 0xE0 + +#define HX8357B_SETGAMMA 0xC8 +#define HX8357B_SETPANELRELATED 0xE9 + +/* Color definitions */ +#define HX8357_BLACK 0x0000 +#define HX8357_BLUE 0x001F +#define HX8357_RED 0xF800 +#define HX8357_GREEN 0x07E0 +#define HX8357_CYAN 0x07FF +#define HX8357_MAGENTA 0xF81F +#define HX8357_YELLOW 0xFFE0 +#define HX8357_WHITE 0xFFFF + +#endif /* __HX8357_H__ */ -- 2.19.1