This patchset adds support for the LCD panel of PinePhone.
The first 3 patches are for the panel itself, and the last 2 patches are for enabling it on PinePhone.
I've tested this on PinePhone 1.0 and 1.2.
Please take a look.
thank you and regards, Ondrej Jirman
Changes in v3: - Panel driver renamed to the name of the LCD controller - Re-organize the driver slightly to more easily support more panels based on the same controller. - Add patch to enable the touchscreen to complete the LCD support on PinePhone. - Dropped the "DSI fix" patch (the driver seems to work for me without it) - Improved brightness levels handling: - PinePhone 1.0 uses default levels generated by the driver - On PinePhone 1.1 duty cycles < 20% lead to black screen, so default levels can't be used. Martijn Braam came up with a list of duty cycle values that lead to perception of linear brigtness level <-> light intensity on PinePhone 1.1 - There was some feedback on v2 about this being similar to st7701. It's only similar in name. Most of the "user commands" are different, so I opted to keep this in a new driver instead of creating st770x.
Anyone who likes to check the differences, here are datasheets:
- https://megous.com/dl/tmp/ST7703_DS_v01_20160128.pdf - https://megous.com/dl/tmp/ST7701.pdf
Changes in v2: - DT Example fix. - DT Format fix. - Raised copyright info to 2020. - Sort panel operation functions. - Sort inclusion.
-- For phone owners: --
There's an open question on how to set the backlight brightness values on post 1.0 revision phone, since lower duty cycles (< 10-20%) lead to backlight being black. It would be nice if more people can test the various backlight levels on 1.1 and 1.2 revision with this change in dts:
brightness-levels = <0 1000>; num-interpolated-steps = <1000>;
and report at what brightness level the backlight turns on. So far it seems this has a wide range. Lowest useable duty cycle for me is ~7% on 1.2 and for Martijn ~20% on 1.1.
Icenowy Zheng (4): dt-bindings: vendor-prefixes: Add Xingbangda dt-bindings: panel: Add binding for Xingbangda XBD599 panel drm: panel: Add Xingbangda XBD599 panel (ST7703 controller) arm64: dts: sun50i-a64-pinephone: Enable LCD support on PinePhone
Ondrej Jirman (1): arm64: dts: sun50i-a64-pinephone: Add touchscreen support
.../display/panel/sitronix,st7703.yaml | 63 +++ .../devicetree/bindings/vendor-prefixes.yaml | 2 + .../allwinner/sun50i-a64-pinephone-1.1.dts | 19 + .../dts/allwinner/sun50i-a64-pinephone.dtsi | 54 +++ drivers/gpu/drm/panel/Kconfig | 10 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-sitronix-st7703.c | 386 ++++++++++++++++++ 7 files changed, 535 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/sitronix,st7703.yaml create mode 100644 drivers/gpu/drm/panel/panel-sitronix-st7703.c
From: Icenowy Zheng icenowy@aosc.io
Shenzhen Xingbangda Display Technology Co., Ltd is a company which produces LCD modules. It supplies the LCD panels for the PinePhone.
Add the vendor prefix of it.
Signed-off-by: Icenowy Zheng icenowy@aosc.io Signed-off-by: Ondrej Jirman megous@megous.com --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 442579a4c837..7504440dba36 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1139,6 +1139,8 @@ patternProperties: description: Xiaomi Technology Co., Ltd. "^xillybus,.*": description: Xillybus Ltd. + "^xingbangda,.*": + description: Shenzhen Xingbangda Display Technology Co., Ltd "^xinpeng,.*": description: Shenzhen Xinpeng Technology Co., Ltd "^xlnx,.*":
On Wed, 13 May 2020 23:24:47 +0200, Ondrej Jirman wrote:
From: Icenowy Zheng icenowy@aosc.io
Shenzhen Xingbangda Display Technology Co., Ltd is a company which produces LCD modules. It supplies the LCD panels for the PinePhone.
Add the vendor prefix of it.
Signed-off-by: Icenowy Zheng icenowy@aosc.io Signed-off-by: Ondrej Jirman megous@megous.com
Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+)
Acked-by: Rob Herring robh@kernel.org
From: Icenowy Zheng icenowy@aosc.io
Xingbangda XBD599 is a 5.99" 720x1440 MIPI-DSI LCD panel. It is based on Sitronix ST7703 LCD controller.
Add its device tree binding.
Signed-off-by: Icenowy Zheng icenowy@aosc.io Signed-off-by: Ondrej Jirman megous@megous.com --- .../display/panel/sitronix,st7703.yaml | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/sitronix,st7703.yaml
diff --git a/Documentation/devicetree/bindings/display/panel/sitronix,st7703.yaml b/Documentation/devicetree/bindings/display/panel/sitronix,st7703.yaml new file mode 100644 index 000000000000..6e1606db4ab4 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/sitronix,st7703.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/sitronix,st7703.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sitronix ST7703 MIPI DSI panel + +maintainers: + - Icenowy Zheng icenowy@aosc.io + - Ondrej Jirman megous@megous.com + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + items: + - enum: + - xingbangda,xbd599 + - const: sitronix,st7703 + + reg: + description: DSI virtual channel used by that screen + maxItems: 1 + + vcc-supply: + description: regulator that supplies the VCC voltage + + iovcc-supply: + description: regulator that supplies the IOVCC voltage + + reset-gpios: true + + backlight: true + +required: + - compatible + - reg + - vcc-supply + - iovcc-supply + - reset-gpios + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + dsi { + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "xingbangda,xbd599", "sitronix,st7703"; + reg = <0>; + reset-gpios = <&pio 3 24 GPIO_ACTIVE_HIGH>; /* LCD-RST: PD24 */ + iovcc-supply = <®_dldo2>; + vcc-supply = <®_ldo_io0>; + backlight = <&backlight>; + }; + }; +
On Wed, May 13, 2020 at 11:24 PM Ondrej Jirman megous@megous.com wrote:
From: Icenowy Zheng icenowy@aosc.io
Xingbangda XBD599 is a 5.99" 720x1440 MIPI-DSI LCD panel. It is based on Sitronix ST7703 LCD controller.
Add its device tree binding.
Signed-off-by: Icenowy Zheng icenowy@aosc.io Signed-off-by: Ondrej Jirman megous@megous.com
Reviewed-by: Linus Walleij linus.walleij@linaro.org
Yours, Linus Walleij
On Wed, 13 May 2020 23:24:48 +0200, Ondrej Jirman wrote:
From: Icenowy Zheng icenowy@aosc.io
Xingbangda XBD599 is a 5.99" 720x1440 MIPI-DSI LCD panel. It is based on Sitronix ST7703 LCD controller.
Add its device tree binding.
Signed-off-by: Icenowy Zheng icenowy@aosc.io Signed-off-by: Ondrej Jirman megous@megous.com
.../display/panel/sitronix,st7703.yaml | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/sitronix,st7703.yaml
Reviewed-by: Rob Herring robh@kernel.org
From: Icenowy Zheng icenowy@aosc.io
Xingbangda XBD599 is a 5.99" 720x1440 MIPI-DSI IPS LCD panel made by Xingbangda, which is used on PinePhone final assembled phones.
It is based on Sitronix ST7703 LCD controller.
Add support for it.
Signed-off-by: Icenowy Zheng icenowy@aosc.io Signed-off-by: Ondrej Jirman megous@megous.com --- drivers/gpu/drm/panel/Kconfig | 10 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-sitronix-st7703.c | 386 ++++++++++++++++++ 3 files changed, 397 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-sitronix-st7703.c
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 39055c1f0e2f..b7bc157b0612 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -395,6 +395,16 @@ config DRM_PANEL_SITRONIX_ST7701 ST7701 controller for 480X864 LCD panels with MIPI/RGB/SPI system interfaces.
+config DRM_PANEL_SITRONIX_ST7703 + tristate "Sitronix ST7703 panel driver" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for the Sitronix + ST7703 controller for 720X1440 LCD panels with MIPI/RGB/SPI + system interfaces. + config DRM_PANEL_SITRONIX_ST7789V tristate "Sitronix ST7789V panel" depends on OF && SPI diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index de74f282c433..47f4789a8685 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o obj-$(CONFIG_DRM_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7701) += panel-sitronix-st7701.o +obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7703) += panel-sitronix-st7703.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o obj-$(CONFIG_DRM_PANEL_SONY_ACX424AKP) += panel-sony-acx424akp.o obj-$(CONFIG_DRM_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7703.c b/drivers/gpu/drm/panel/panel-sitronix-st7703.c new file mode 100644 index 000000000000..092dd73c86d0 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-sitronix-st7703.c @@ -0,0 +1,386 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DRM driver for Sitronix ST7703 MIPI DSI panel + * + * Copyright (C) 2020 Ondrej Jirman megous@megous.com + * Copyright (C) 2019-2020 Icenowy Zheng icenowy@aosc.io + * + * Based on panel-rocktech-jh057n00900.c, which is: + * Copyright (C) Purism SPC 2019 + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/regulator/consumer.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> +#include <drm/drm_print.h> + +/* Manufacturer specific Commands send via DSI */ +#define ST7703_CMD_ALL_PIXEL_OFF 0x22 +#define ST7703_CMD_ALL_PIXEL_ON 0x23 +#define ST7703_CMD_SETDISP 0xB2 +#define ST7703_CMD_SETRGBIF 0xB3 +#define ST7703_CMD_SETCYC 0xB4 +#define ST7703_CMD_SETBGP 0xB5 +#define ST7703_CMD_SETVCOM 0xB6 +#define ST7703_CMD_SETOTP 0xB7 +#define ST7703_CMD_SETPOWER_EXT 0xB8 +#define ST7703_CMD_SETEXTC 0xB9 +#define ST7703_CMD_SETMIPI 0xBA +#define ST7703_CMD_SETVDC 0xBC +#define ST7703_CMD_SETSCR 0xC0 +#define ST7703_CMD_SETPOWER 0xC1 +#define ST7703_CMD_UNK_C6 0xC6 +#define ST7703_CMD_SETPANEL 0xCC +#define ST7703_CMD_SETGAMMA 0xE0 +#define ST7703_CMD_SETEQ 0xE3 +#define ST7703_CMD_SETGIP1 0xE9 +#define ST7703_CMD_SETGIP2 0xEA + +struct st7703_panel_desc { + const struct drm_display_mode *mode; + unsigned int lanes; + unsigned long flags; + enum mipi_dsi_pixel_format format; + const char *const *supply_names; + unsigned int num_supplies; +}; + +struct st7703 { + struct device *dev; + struct drm_panel panel; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data *supplies; + const struct st7703_panel_desc *desc; + bool prepared; +}; + +static inline struct st7703 *panel_to_st7703(struct drm_panel *panel) +{ + return container_of(panel, struct st7703, panel); +} + +#define dsi_dcs_write_seq(dsi, cmd, seq...) do { \ + static const u8 d[] = { seq }; \ + int ret; \ + ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d)); \ + if (ret < 0) \ + return ret; \ + } while (0) + +static int st7703_init_sequence(struct st7703 *ctx) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + struct device *dev = ctx->dev; + int ret; + + /* + * Init sequence was supplied by the panel vendor. + */ + dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, + 0xF1, 0x12, 0x83); + dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI, + 0x33, 0x81, 0x05, 0xF9, 0x0E, 0x0E, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25, + 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02, 0x4F, 0x11, + 0x00, 0x00, 0x37); + dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT, + 0x25, 0x22, 0x20, 0x03); + dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF, + 0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00, + 0x00, 0x00); + dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR, + 0x73, 0x73, 0x50, 0x50, 0x00, 0xC0, 0x08, 0x70, + 0x00); + dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E); + dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B); + dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80); + dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0xF0); + dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ, + 0x00, 0x00, 0x0B, 0x0B, 0x10, 0x10, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10); + dsi_dcs_write_seq(dsi, 0xC6, 0x01, 0x00, 0xFF, 0xFF, 0x00); + dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, + 0x74, 0x00, 0x32, 0x32, 0x77, 0xF1, 0xFF, 0xFF, + 0xCC, 0xCC, 0x77, 0x77); + dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, 0x07, 0x07); + dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, 0x2C, 0x2C); + dsi_dcs_write_seq(dsi, 0xBF, 0x02, 0x11, 0x00); + + dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1, + 0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12, + 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38, + 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64, + 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2, + 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13, + 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A, + 0xA5, 0x00, 0x00, 0x00, 0x00); + dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA, + 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35, + 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12, + 0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, + 0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, + 0x12, 0x18); + msleep(20); + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret < 0) { + DRM_DEV_ERROR(dev, "Failed to exit sleep mode\n"); + return ret; + } + msleep(250); + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret) + return ret; + msleep(50); + + DRM_DEV_DEBUG_DRIVER(dev, "Panel init sequence done\n"); + return 0; +} + +static int st7703_prepare(struct drm_panel *panel) +{ + struct st7703 *ctx = panel_to_st7703(panel); + int ret; + + if (ctx->prepared) + return 0; + + ret = regulator_bulk_enable(ctx->desc->num_supplies, ctx->supplies); + if (ret) + return ret; + + DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n"); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(20, 40); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + msleep(20); + + ctx->prepared = true; + + return 0; +} + +static int st7703_enable(struct drm_panel *panel) +{ + struct st7703 *ctx = panel_to_st7703(panel); + int ret; + + ret = st7703_init_sequence(ctx); + if (ret < 0) { + DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n", + ret); + return ret; + } + + return 0; +} + +static int st7703_disable(struct drm_panel *panel) +{ + struct st7703 *ctx = panel_to_st7703(panel); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + + return mipi_dsi_dcs_set_display_off(dsi); +} + +static int st7703_unprepare(struct drm_panel *panel) +{ + struct st7703 *ctx = panel_to_st7703(panel); + + if (!ctx->prepared) + return 0; + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ctx->desc->num_supplies, ctx->supplies); + ctx->prepared = false; + + return 0; +} + +static int st7703_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct st7703 *ctx = panel_to_st7703(panel); + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, ctx->desc->mode); + if (!mode) { + DRM_DEV_ERROR(ctx->dev, "Failed to add mode\n"); + return -ENOMEM; + } + + drm_mode_set_name(mode); + + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + drm_mode_probed_add(connector, mode); + + return 1; +} + +static const struct drm_panel_funcs st7703_drm_funcs = { + .prepare = st7703_prepare, + .enable = st7703_enable, + .disable = st7703_disable, + .unprepare = st7703_unprepare, + .get_modes = st7703_get_modes, +}; + +static const struct drm_display_mode xbd599_mode = { + .hdisplay = 720, + .hsync_start = 720 + 40, + .hsync_end = 720 + 40 + 40, + .htotal = 720 + 40 + 40 + 40, + .vdisplay = 1440, + .vsync_start = 1440 + 18, + .vsync_end = 1440 + 18 + 10, + .vtotal = 1440 + 18 + 10 + 17, + .vrefresh = 60, + .clock = 69000, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + + .width_mm = 68, + .height_mm = 136, + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, +}; + +static const char * const xbd599_supply_names[] = { + "iovcc", + "vcc", +}; + +static const struct st7703_panel_desc xbd599_desc = { + .mode = &xbd599_mode, + .lanes = 4, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE, + .format = MIPI_DSI_FMT_RGB888, + .supply_names = xbd599_supply_names, + .num_supplies = ARRAY_SIZE(xbd599_supply_names), +}; + +static int st7703_probe(struct mipi_dsi_device *dsi) +{ + const struct st7703_panel_desc *desc; + struct device *dev = &dsi->dev; + struct st7703 *ctx; + int i, ret; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->dev = dev; + ctx->desc = desc = of_device_get_match_data(dev); + + dsi->mode_flags = desc->flags; + dsi->format = desc->format; + dsi->lanes = desc->lanes; + + ctx->supplies = devm_kcalloc(&dsi->dev, desc->num_supplies, + sizeof(*ctx->supplies), + GFP_KERNEL); + if (!ctx->supplies) + return -ENOMEM; + + for (i = 0; i < desc->num_supplies; i++) + ctx->supplies[i].supply = desc->supply_names[i]; + + ret = devm_regulator_bulk_get(&dsi->dev, desc->num_supplies, + ctx->supplies); + if (ret < 0) + return ret; + + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ctx->reset_gpio)) { + DRM_DEV_ERROR(dev, "Can't get reset gpio\n"); + return PTR_ERR(ctx->reset_gpio); + } + + mipi_dsi_set_drvdata(dsi, ctx); + + drm_panel_init(&ctx->panel, &dsi->dev, &st7703_drm_funcs, + DRM_MODE_CONNECTOR_DSI); + + ret = drm_panel_of_backlight(&ctx->panel); + if (ret) + return ret; + + drm_panel_add(&ctx->panel); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + DRM_DEV_ERROR(dev, "mipi_dsi_attach failed. Is host ready?\n"); + drm_panel_remove(&ctx->panel); + return ret; + } + + return 0; +} + +static void st7703_shutdown(struct mipi_dsi_device *dsi) +{ + struct st7703 *ctx = mipi_dsi_get_drvdata(dsi); + int ret; + + ret = drm_panel_unprepare(&ctx->panel); + if (ret < 0) + DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", + ret); +} + +static int st7703_remove(struct mipi_dsi_device *dsi) +{ + struct st7703 *ctx = mipi_dsi_get_drvdata(dsi); + int ret; + + st7703_shutdown(dsi); + + ret = mipi_dsi_detach(dsi); + if (ret < 0) + DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n", + ret); + + drm_panel_remove(&ctx->panel); + + return 0; +} + +static const struct of_device_id st7703_of_match[] = { + { .compatible = "xingbangda,xbd599", .data = &xbd599_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, st7703_of_match); + +static struct mipi_dsi_driver st7703_driver = { + .probe = st7703_probe, + .remove = st7703_remove, + .shutdown = st7703_shutdown, + .driver = { + .name = "st7703", + .of_match_table = st7703_of_match, + }, +}; +module_mipi_dsi_driver(st7703_driver); + +MODULE_AUTHOR("Icenowy Zheng icenowy@aosc.io"); +MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 MIPI DSI panel"); +MODULE_LICENSE("GPL v2");
Hi Ondrej,
I see you took over this driver submission from Icenowy.
On Wed, May 13, 2020 at 11:24 PM Ondrej Jirman megous@megous.com wrote:
From: Icenowy Zheng icenowy@aosc.io
Xingbangda XBD599 is a 5.99" 720x1440 MIPI-DSI IPS LCD panel made by Xingbangda, which is used on PinePhone final assembled phones.
It is based on Sitronix ST7703 LCD controller.
Add support for it.
Signed-off-by: Icenowy Zheng icenowy@aosc.io Signed-off-by: Ondrej Jirman megous@megous.com
(...)
create mode 100644 drivers/gpu/drm/panel/panel-sitronix-st7703.c
Nice!
/*
* Init sequence was supplied by the panel vendor.
*/
dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC,
0xF1, 0x12, 0x83);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI,
0x33, 0x81, 0x05, 0xF9, 0x0E, 0x0E, 0x20, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25,
0x00, 0x91, 0x0a, 0x00, 0x00, 0x02, 0x4F, 0x11,
0x00, 0x00, 0x37);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT,
0x25, 0x22, 0x20, 0x03);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF,
0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
0x00, 0x00);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR,
0x73, 0x73, 0x50, 0x50, 0x00, 0xC0, 0x08, 0x70,
0x00);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0xF0);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ,
0x00, 0x00, 0x0B, 0x0B, 0x10, 0x10, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
dsi_dcs_write_seq(dsi, 0xC6, 0x01, 0x00, 0xFF, 0xFF, 0x00);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER,
0x74, 0x00, 0x32, 0x32, 0x77, 0xF1, 0xFF, 0xFF,
0xCC, 0xCC, 0x77, 0x77);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, 0x07, 0x07);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, 0x2C, 0x2C);
dsi_dcs_write_seq(dsi, 0xBF, 0x02, 0x11, 0x00);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1,
0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2,
0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
0xA5, 0x00, 0x00, 0x00, 0x00);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA,
0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
0x12, 0x18);
msleep(20);
This stuff is really hard or impossible to understand without the datasheet.
In my previous review I wrote:
It appears that the Himax HX8363 is using the same display controller if you look at the datasheet: http://www.datasheet-pdf.com/PDF/HX8369-A-Datasheet-Himax-729024 There you find an explanation to some of the commands.
That means, try to get rid of as much of the magic bytes as you can and use proper #defines. I know it takes some work but the result is so much more useful and readable.
Further I wrote:
You should definately insert code to read the MTP bytes: 0xDA manufacturer 0xDB driver version 0xDC LCD module/driver And print these, se e.g. my newly added NT35510 driver or the Sony ACX424AKP driver.
So please do that.
Yours, Linus Walleij
Hello Linus,
On Tue, May 26, 2020 at 01:32:25PM +0200, Linus Walleij wrote:
Hi Ondrej,
[...]
dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1,
0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2,
0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
0xA5, 0x00, 0x00, 0x00, 0x00);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA,
0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
0x12, 0x18);
msleep(20);
This stuff is really hard or impossible to understand without the datasheet.
In my previous review I wrote:
It appears that the Himax HX8363 is using the same display controller if you look at the datasheet: http://www.datasheet-pdf.com/PDF/HX8369-A-Datasheet-Himax-729024 There you find an explanation to some of the commands.
It is st7703, and we have a fairly complete datasheet available publicly. I posted links in the cover letter.
That means, try to get rid of as much of the magic bytes as you can and use proper #defines. I know it takes some work but the result is so much more useful and readable.
I've added some descriptions from the datasheet as comments next to the values in v4.
Thank you and regards, o.
Further I wrote:
You should definately insert code to read the MTP bytes: 0xDA manufacturer 0xDB driver version 0xDC LCD module/driver And print these, se e.g. my newly added NT35510 driver or the Sony ACX424AKP driver.
So please do that.
Yours, Linus Walleij
-- You received this message because you are subscribed to the Google Groups "linux-sunxi" group. To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com. To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/CACRpkdZpiQ7E_v-Gfk6vFcUEiMazv....
On 5/13/20 4:24 PM, Ondrej Jirman wrote:
From: Icenowy Zheng icenowy@aosc.io
Xingbangda XBD599 is a 5.99" 720x1440 MIPI-DSI IPS LCD panel made by Xingbangda, which is used on PinePhone final assembled phones.
It is based on Sitronix ST7703 LCD controller.
Add support for it.
Signed-off-by: Icenowy Zheng icenowy@aosc.io Signed-off-by: Ondrej Jirman megous@megous.com
drivers/gpu/drm/panel/Kconfig | 10 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-sitronix-st7703.c | 386 ++++++++++++++++++ 3 files changed, 397 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-sitronix-st7703.c
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 39055c1f0e2f..b7bc157b0612 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -395,6 +395,16 @@ config DRM_PANEL_SITRONIX_ST7701 ST7701 controller for 480X864 LCD panels with MIPI/RGB/SPI system interfaces.
+config DRM_PANEL_SITRONIX_ST7703
- tristate "Sitronix ST7703 panel driver"
- depends on OF
- depends on DRM_MIPI_DSI
- depends on BACKLIGHT_CLASS_DEVICE
- help
Say Y here if you want to enable support for the Sitronix
ST7703 controller for 720X1440 LCD panels with MIPI/RGB/SPI
system interfaces.
config DRM_PANEL_SITRONIX_ST7789V tristate "Sitronix ST7789V panel" depends on OF && SPI diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index de74f282c433..47f4789a8685 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o obj-$(CONFIG_DRM_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7701) += panel-sitronix-st7701.o +obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7703) += panel-sitronix-st7703.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o obj-$(CONFIG_DRM_PANEL_SONY_ACX424AKP) += panel-sony-acx424akp.o obj-$(CONFIG_DRM_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7703.c b/drivers/gpu/drm/panel/panel-sitronix-st7703.c new file mode 100644 index 000000000000..092dd73c86d0 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-sitronix-st7703.c @@ -0,0 +1,386 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- DRM driver for Sitronix ST7703 MIPI DSI panel
- Copyright (C) 2020 Ondrej Jirman megous@megous.com
- Copyright (C) 2019-2020 Icenowy Zheng icenowy@aosc.io
- Based on panel-rocktech-jh057n00900.c, which is:
- Copyright (C) Purism SPC 2019
- */
+#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/regulator/consumer.h>
+#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> +#include <drm/drm_print.h>
+/* Manufacturer specific Commands send via DSI */ +#define ST7703_CMD_ALL_PIXEL_OFF 0x22 +#define ST7703_CMD_ALL_PIXEL_ON 0x23 +#define ST7703_CMD_SETDISP 0xB2 +#define ST7703_CMD_SETRGBIF 0xB3 +#define ST7703_CMD_SETCYC 0xB4 +#define ST7703_CMD_SETBGP 0xB5 +#define ST7703_CMD_SETVCOM 0xB6 +#define ST7703_CMD_SETOTP 0xB7 +#define ST7703_CMD_SETPOWER_EXT 0xB8 +#define ST7703_CMD_SETEXTC 0xB9 +#define ST7703_CMD_SETMIPI 0xBA +#define ST7703_CMD_SETVDC 0xBC +#define ST7703_CMD_SETSCR 0xC0 +#define ST7703_CMD_SETPOWER 0xC1 +#define ST7703_CMD_UNK_C6 0xC6 +#define ST7703_CMD_SETPANEL 0xCC +#define ST7703_CMD_SETGAMMA 0xE0 +#define ST7703_CMD_SETEQ 0xE3 +#define ST7703_CMD_SETGIP1 0xE9 +#define ST7703_CMD_SETGIP2 0xEA
+struct st7703_panel_desc {
- const struct drm_display_mode *mode;
- unsigned int lanes;
- unsigned long flags;
- enum mipi_dsi_pixel_format format;
- const char *const *supply_names;
- unsigned int num_supplies;
+};
+struct st7703 {
- struct device *dev;
- struct drm_panel panel;
- struct gpio_desc *reset_gpio;
- struct regulator_bulk_data *supplies;
- const struct st7703_panel_desc *desc;
- bool prepared;
+};
+static inline struct st7703 *panel_to_st7703(struct drm_panel *panel) +{
- return container_of(panel, struct st7703, panel);
+}
+#define dsi_dcs_write_seq(dsi, cmd, seq...) do { \
static const u8 d[] = { seq }; \
int ret; \
ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d)); \
if (ret < 0) \
return ret; \
- } while (0)
+static int st7703_init_sequence(struct st7703 *ctx) +{
- struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
- struct device *dev = ctx->dev;
- int ret;
- /*
* Init sequence was supplied by the panel vendor.
*/
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC,
0xF1, 0x12, 0x83);
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI,
0x33, 0x81, 0x05, 0xF9, 0x0E, 0x0E, 0x20, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25,
0x00, 0x91, 0x0a, 0x00, 0x00, 0x02, 0x4F, 0x11,
0x00, 0x00, 0x37);
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT,
0x25, 0x22, 0x20, 0x03);
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF,
0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
0x00, 0x00);
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR,
0x73, 0x73, 0x50, 0x50, 0x00, 0xC0, 0x08, 0x70,
0x00);
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0xF0);
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ,
0x00, 0x00, 0x0B, 0x0B, 0x10, 0x10, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
- dsi_dcs_write_seq(dsi, 0xC6, 0x01, 0x00, 0xFF, 0xFF, 0x00);
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER,
0x74, 0x00, 0x32, 0x32, 0x77, 0xF1, 0xFF, 0xFF,
0xCC, 0xCC, 0x77, 0x77);
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, 0x07, 0x07);
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, 0x2C, 0x2C);
- dsi_dcs_write_seq(dsi, 0xBF, 0x02, 0x11, 0x00);
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1,
0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2,
0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
0xA5, 0x00, 0x00, 0x00, 0x00);
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA,
0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
0x12, 0x18);
- msleep(20);
- ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
- if (ret < 0) {
DRM_DEV_ERROR(dev, "Failed to exit sleep mode\n");
return ret;
- }
- msleep(250);
- ret = mipi_dsi_dcs_set_display_on(dsi);
Since you have the complementary call to mipi_dsi_dcs_set_display_off in st7703_disable, I would suggest calling this from st7703_enable, after the call to st7703_init_sequence. [but see below about moving all of this to prepare.]
- if (ret)
return ret;
- msleep(50);
This is the last step of the init sequence. According to table 8-1 of the manual, T10 needs no delay. What is this delay for?
- DRM_DEV_DEBUG_DRIVER(dev, "Panel init sequence done\n");
- return 0;
+}
+static int st7703_prepare(struct drm_panel *panel) +{
- struct st7703 *ctx = panel_to_st7703(panel);
- int ret;
- if (ctx->prepared)
return 0;
- ret = regulator_bulk_enable(ctx->desc->num_supplies, ctx->supplies);
- if (ret)
return ret;
- DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n");
- gpiod_set_value_cansleep(ctx->reset_gpio, 1);
- usleep_range(20, 40);
- gpiod_set_value_cansleep(ctx->reset_gpio, 0);
- msleep(20);
- ctx->prepared = true;
- return 0;
+}
+static int st7703_enable(struct drm_panel *panel) +{
- struct st7703 *ctx = panel_to_st7703(panel);
- int ret;
- ret = st7703_init_sequence(ctx);
v1 had this function called from prepare, not enable. From reading the comments in drm_panel.h, that seems to be the right place for it.
- if (ret < 0) {
DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n",
ret);
return ret;
- }
- return 0;
+}
+static int st7703_disable(struct drm_panel *panel) +{
- struct st7703 *ctx = panel_to_st7703(panel);
- struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
- return mipi_dsi_dcs_set_display_off(dsi);
The datasheet suggests in "5.6 Power on/off Sequence" that there also needs to be a call to mipi_dsi_dcs_enter_sleep_mode() here.
+}
+static int st7703_unprepare(struct drm_panel *panel) +{
- struct st7703 *ctx = panel_to_st7703(panel);
- if (!ctx->prepared)
return 0;
- gpiod_set_value_cansleep(ctx->reset_gpio, 1);
- regulator_bulk_disable(ctx->desc->num_supplies, ctx->supplies);
- ctx->prepared = false;
- return 0;
+}
+static int st7703_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
+{
- struct st7703 *ctx = panel_to_st7703(panel);
- struct drm_display_mode *mode;
- mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
- if (!mode) {
DRM_DEV_ERROR(ctx->dev, "Failed to add mode\n");
return -ENOMEM;
- }
- drm_mode_set_name(mode);
- mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
This line...
- connector->display_info.width_mm = mode->width_mm;
- connector->display_info.height_mm = mode->height_mm;
- drm_mode_probed_add(connector, mode);
- return 1;
+}
+static const struct drm_panel_funcs st7703_drm_funcs = {
- .prepare = st7703_prepare,
- .enable = st7703_enable,
- .disable = st7703_disable,
- .unprepare = st7703_unprepare,
- .get_modes = st7703_get_modes,
+};
+static const struct drm_display_mode xbd599_mode = {
- .hdisplay = 720,
- .hsync_start = 720 + 40,
- .hsync_end = 720 + 40 + 40,
- .htotal = 720 + 40 + 40 + 40,
- .vdisplay = 1440,
- .vsync_start = 1440 + 18,
- .vsync_end = 1440 + 18 + 10,
- .vtotal = 1440 + 18 + 10 + 17,
- .vrefresh = 60,
- .clock = 69000,
- .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
- .width_mm = 68,
- .height_mm = 136,
- .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
...duplicates this line. I'm not sure which is the better place to put it; panel drivers seem evenly split. But it doesn't need to be in both places.
Cheers, Samuel
+};
+static const char * const xbd599_supply_names[] = {
- "iovcc",
- "vcc",
+};
+static const struct st7703_panel_desc xbd599_desc = {
- .mode = &xbd599_mode,
- .lanes = 4,
- .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
- .format = MIPI_DSI_FMT_RGB888,
- .supply_names = xbd599_supply_names,
- .num_supplies = ARRAY_SIZE(xbd599_supply_names),
+};
+static int st7703_probe(struct mipi_dsi_device *dsi) +{
- const struct st7703_panel_desc *desc;
- struct device *dev = &dsi->dev;
- struct st7703 *ctx;
- int i, ret;
- ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
return -ENOMEM;
- ctx->dev = dev;
- ctx->desc = desc = of_device_get_match_data(dev);
- dsi->mode_flags = desc->flags;
- dsi->format = desc->format;
- dsi->lanes = desc->lanes;
- ctx->supplies = devm_kcalloc(&dsi->dev, desc->num_supplies,
sizeof(*ctx->supplies),
GFP_KERNEL);
- if (!ctx->supplies)
return -ENOMEM;
- for (i = 0; i < desc->num_supplies; i++)
ctx->supplies[i].supply = desc->supply_names[i];
- ret = devm_regulator_bulk_get(&dsi->dev, desc->num_supplies,
ctx->supplies);
- if (ret < 0)
return ret;
- ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
- if (IS_ERR(ctx->reset_gpio)) {
DRM_DEV_ERROR(dev, "Can't get reset gpio\n");
return PTR_ERR(ctx->reset_gpio);
- }
- mipi_dsi_set_drvdata(dsi, ctx);
- drm_panel_init(&ctx->panel, &dsi->dev, &st7703_drm_funcs,
DRM_MODE_CONNECTOR_DSI);
- ret = drm_panel_of_backlight(&ctx->panel);
- if (ret)
return ret;
- drm_panel_add(&ctx->panel);
- ret = mipi_dsi_attach(dsi);
- if (ret < 0) {
DRM_DEV_ERROR(dev, "mipi_dsi_attach failed. Is host ready?\n");
drm_panel_remove(&ctx->panel);
return ret;
- }
- return 0;
+}
+static void st7703_shutdown(struct mipi_dsi_device *dsi) +{
- struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
- int ret;
- ret = drm_panel_unprepare(&ctx->panel);
- if (ret < 0)
DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n",
ret);
+}
+static int st7703_remove(struct mipi_dsi_device *dsi) +{
- struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
- int ret;
- st7703_shutdown(dsi);
- ret = mipi_dsi_detach(dsi);
- if (ret < 0)
DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n",
ret);
- drm_panel_remove(&ctx->panel);
- return 0;
+}
+static const struct of_device_id st7703_of_match[] = {
- { .compatible = "xingbangda,xbd599", .data = &xbd599_desc },
- { /* sentinel */ }
+}; +MODULE_DEVICE_TABLE(of, st7703_of_match);
+static struct mipi_dsi_driver st7703_driver = {
- .probe = st7703_probe,
- .remove = st7703_remove,
- .shutdown = st7703_shutdown,
- .driver = {
.name = "st7703",
.of_match_table = st7703_of_match,
- },
+}; +module_mipi_dsi_driver(st7703_driver);
+MODULE_AUTHOR("Icenowy Zheng icenowy@aosc.io"); +MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 MIPI DSI panel"); +MODULE_LICENSE("GPL v2");
From: Icenowy Zheng icenowy@aosc.io
PinePhone uses PWM backlight and a XBD599 LCD panel over DSI for display.
Backlight levels curve was optimized by Martijn Braam using a lux meter.
Add its device nodes.
Signed-off-by: Icenowy Zheng icenowy@aosc.io Signed-off-by: Martijn Braam martijn@brixit.nl Signed-off-by: Ondrej Jirman megous@megous.com --- .../allwinner/sun50i-a64-pinephone-1.1.dts | 19 ++++++++++ .../dts/allwinner/sun50i-a64-pinephone.dtsi | 35 +++++++++++++++++++ 2 files changed, 54 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts index 06a775c41664..3e99a87e9ce5 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts @@ -9,3 +9,22 @@ / { model = "Pine64 PinePhone Braveheart (1.1)"; compatible = "pine64,pinephone-1.1", "allwinner,sun50i-a64"; }; + +&backlight { + power-supply = <®_ldo_io0>; + /* + * PWM backlight circuit on this PinePhone revision was changed since + * 1.0, and the lowest PWM duty cycle that doesn't lead to backlight + * being off is around 20%. Duty cycle for the lowest brightness level + * also varries quite a bit between individual boards, so the lowest + * value here was chosen as a safe default. + */ + brightness-levels = < + 774 793 814 842 + 882 935 1003 1088 + 1192 1316 1462 1633 + 1830 2054 2309 2596 + 2916 3271 3664 4096>; + num-interpolated-steps = <50>; + default-brightness-level = <400>; +}; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi index cefda145c3c9..e60b57f8ac14 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi @@ -16,6 +16,13 @@ aliases { serial0 = &uart0; };
+ backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&r_pwm 0 50000 PWM_POLARITY_INVERTED>; + enable-gpios = <&pio 7 10 GPIO_ACTIVE_HIGH>; /* PH10 */ + /* Backlight configuration differs per PinePhone revision. */ + }; + chosen { stdout-path = "serial0:115200n8"; }; @@ -84,6 +91,30 @@ &dai { status = "okay"; };
+&de { + status = "okay"; +}; + +&dphy { + status = "okay"; +}; + +&dsi { + vcc-dsi-supply = <®_dldo1>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + panel@0 { + compatible = "xingbangda,xbd599", "sitronix,st7703"; + reg = <0>; + reset-gpios = <&pio 3 23 GPIO_ACTIVE_LOW>; /* PD23 */ + iovcc-supply = <®_dldo2>; + vcc-supply = <®_ldo_io0>; + backlight = <&backlight>; + }; +}; + &ehci0 { status = "okay"; }; @@ -188,6 +219,10 @@ &r_pio { */ };
+&r_pwm { + status = "okay"; +}; + &r_rsb { status = "okay";
Hi!
PinePhone uses PWM backlight and a XBD599 LCD panel over DSI for display.
Backlight levels curve was optimized by Martijn Braam using a lux meter.
If it was possible to preserve lux values for individual settings in the comment somewhere... that would be nice :-).
One day, it would be nice to have brightness settings in lux, so I could easily set matching levels on multiple devices, for example...
Best regards,
Pavel
+&backlight {
- power-supply = <®_ldo_io0>;
- /*
* PWM backlight circuit on this PinePhone revision was changed since
* 1.0, and the lowest PWM duty cycle that doesn't lead to backlight
* being off is around 20%. Duty cycle for the lowest brightness level
* also varries quite a bit between individual boards, so the lowest
* value here was chosen as a safe default.
*/
- brightness-levels = <
774 793 814 842
882 935 1003 1088
1192 1316 1462 1633
1830 2054 2309 2596
2916 3271 3664 4096>;
- num-interpolated-steps = <50>;
- default-brightness-level = <400>;
Pinephone has a Goodix GT917S capacitive touchscreen controller on I2C0 bus. Add support for it.
Signed-off-by: Ondrej Jirman megous@megous.com --- .../dts/allwinner/sun50i-a64-pinephone.dtsi | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi index e60b57f8ac14..6b2ff431cddb 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi @@ -123,6 +123,25 @@ &ehci1 { status = "okay"; };
+&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + status = "okay"; + + touchscreen@5d { + compatible = "goodix,gt917s", "goodix,gt911"; + reg = <0x5d>; + interrupt-parent = <&pio>; + interrupts = <7 4 IRQ_TYPE_LEVEL_HIGH>; /* PH4 */ + irq-gpios = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */ + reset-gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>; /* PH11 */ + AVDD28-supply = <®_ldo_io0>; + VDDIO-supply = <®_ldo_io0>; + touchscreen-size-x = <720>; + touchscreen-size-y = <1440>; + }; +}; + &i2c1 { status = "okay";
dri-devel@lists.freedesktop.org