This adds a starting point for processing and defining generic bindings used by DSI panels. We just define one single bool property to force the panel into video mode for now.
Cc: devicetree@vger.kernel.org Suggested-by: Rob Herring robh@kernel.org Signed-off-by: Linus Walleij linus.walleij@linaro.org --- ChangeLog v3->v4: - Rename into display/dsi-controller.yaml - Require a virtual channel number for the DSI panel, as DSI have this 2-bit virtual address field. - Bring in some but not all properties from the existing MIPI DSI bindings. This schema can be used with simpler panels but not complex panels with multiple virtual channels for the moment. Let's handle it when we get there. - Add an example. ChangeLog v2->v3: - Make a more complete DSI panel binding including the controller and its address-cells and size-cells and a pattern for the panel nodes. The panel is one per DSI master, the reg property is compulsory but should always be 0 (as far as I can tell) as only one panel can be connected. The bus doesn't really have any addresses for the panel, the address/reg notation seems to be cargo-culted from the port graphs and is not necessary to parse some device trees, it is used to tell whether the node is a panel or not rather than any addressing. - I have no idea how many displays you can daisychain on a single DSI master, I just guess 15 will be enough. The MIPI-specs are memberwalled. Someone who knows can tell perhaps? ChangeLog v1->v2: - New patch after feedback. --- .../bindings/display/dsi-controller.yaml | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/dsi-controller.yaml
diff --git a/Documentation/devicetree/bindings/display/dsi-controller.yaml b/Documentation/devicetree/bindings/display/dsi-controller.yaml new file mode 100644 index 000000000000..2a6d872a40c5 --- /dev/null +++ b/Documentation/devicetree/bindings/display/dsi-controller.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/panel-dsi-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Common Properties for DSI Display Panels + +maintainers: + - Linus Walleij linus.walleij@linaro.org + +description: | + This document defines device tree properties common to DSI, Display + Serial Interface panels. It doesn't constitute a device tree binding + specification by itself but is meant to be referenced by device tree + bindings. + + When referenced from panel device tree bindings the properties defined in + this document are defined as follows. The panel device tree bindings are + responsible for defining whether each property is required or optional. + + Notice: this binding concerns DSI panels connected directly to a master + without any intermediate port graph to the panel. Each DSI master + can control exactly one panel. They should all just have a node "panel" + for their panel with their reg-property set to 0. + +properties: + $nodename: + pattern: "^dsi-controller(@.*)?$" + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^panel@[0-3]$": + type: object + + properties: + reg: + minimum: 0 + maximum: 3 + description: + The virtual channel number of a DSI peripheral. Must be in the range + from 0 to 3, as DSI uses a 2-bit addressing scheme. Some DSI + peripherals respond to more than a single virtual channel. In that + case the reg property can take multiple entries, one for each virtual + channel that the peripheral responds to. + + clock-master: + type: boolean + description: + Should be enabled if the host is being used in conjunction with + another DSI host to drive the same peripheral. Hardware supporting + such a configuration generally requires the data on both the busses + to be driven by the same clock. Only the DSI host instance + controlling this clock should contain this property. + + enforce-video-mode: + type: boolean + description: + The best option is usually to run a panel in command mode, as this + gives better control over the panel hardware. However for different + reasons like broken hardware, missing features or testing, it may be + useful to be able to force a command mode-capable panel into video + mode. + + required: + - reg + +examples: + - | + dsi-controller@55aa55aa { + compatible = "acme,foo"; + reg = <0x55aa55aa>; + #address-cells = <1>; + #size-cells = <0>; + panel@0 { + compatible = "acme,bar"; + reg = <0>; + vddi-supply = <&foo>; + reset-gpios = <&foo_gpio 0 GPIO_ACTIVE_LOW>; + }; + }; + +...
This adds device tree bindings for the Sony ACX424AKP panel. Let's use YAML.
Cc: devicetree@vger.kernel.org Signed-off-by: Linus Walleij linus.walleij@linaro.org --- ChangeLog v3->v4: - Adjust to adjusted DSI bindings. ChangeLog v2->v3: - Put the example inside a dsi-controller so we have a complete example that verifies to the DSI panel generic binding. ChangeLog v1->v2: - Suggest a stand-alone YAML bindings file for DSI panels in a separate patch, and use that to reference the boolean "enforce-video-mode" attribute for DSI panels --- .../display/panel/sony,acx424akp.yaml | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/sony,acx424akp.yaml
diff --git a/Documentation/devicetree/bindings/display/panel/sony,acx424akp.yaml b/Documentation/devicetree/bindings/display/panel/sony,acx424akp.yaml new file mode 100644 index 000000000000..a2f49b9a5958 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/sony,acx424akp.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/sony,acx424akp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sony ACX424AKP 4" 480x864 AMOLED panel + +maintainers: + - Linus Walleij linus.walleij@linaro.org + +allOf: + - $ref: panel-common.yaml# + - $ref: ../dsi-controller.yaml# + +properties: + compatible: + const: sony,acx424akp + reg: true + port: true + reset-gpios: true + vddi-supply: + description: regulator that supplies the vddi voltage + enforce-video-mode: true + +required: + - compatible + - reg + - port + - reset-gpios + - power-supply + +additionalProperties: false + +examples: + - | + dsi-controller@0 { + compatible = "foo"; + #address-cells = <1>; + #size-cells = <0>; + panel@0 { + compatible = "sony,acx424akp"; + reg = <0>; + vddi-supply = <&foo>; + reset-gpios = <&foo_gpio 0 GPIO_ACTIVE_LOW>; + }; + }; + +... \ No newline at end of file
On Thu, Oct 24, 2019 at 01:43:04PM +0200, Linus Walleij wrote:
This adds device tree bindings for the Sony ACX424AKP panel. Let's use YAML.
Also broken. Run 'make dt_binding_check'.
Cc: devicetree@vger.kernel.org Signed-off-by: Linus Walleij linus.walleij@linaro.org
ChangeLog v3->v4:
- Adjust to adjusted DSI bindings.
ChangeLog v2->v3:
- Put the example inside a dsi-controller so we have a complete example that verifies to the DSI panel generic binding.
ChangeLog v1->v2:
- Suggest a stand-alone YAML bindings file for DSI panels in a separate patch, and use that to reference the boolean "enforce-video-mode" attribute for DSI panels
.../display/panel/sony,acx424akp.yaml | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/sony,acx424akp.yaml
diff --git a/Documentation/devicetree/bindings/display/panel/sony,acx424akp.yaml b/Documentation/devicetree/bindings/display/panel/sony,acx424akp.yaml new file mode 100644 index 000000000000..a2f49b9a5958 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/sony,acx424akp.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/sony,acx424akp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: Sony ACX424AKP 4" 480x864 AMOLED panel
+maintainers:
- Linus Walleij linus.walleij@linaro.org
+allOf:
- $ref: panel-common.yaml#
- $ref: ../dsi-controller.yaml#
This is wrong now because it applies to the controller node, not the panel node. IOW, DSI controllers need to include it.
+properties:
- compatible:
- const: sony,acx424akp
- reg: true
- port: true
- reset-gpios: true
- vddi-supply:
description: regulator that supplies the vddi voltage
- enforce-video-mode: true
+required:
- compatible
- reg
- port
- reset-gpios
- power-supply
+additionalProperties: false
+examples:
- |
- dsi-controller@0 {
unit-address without 'reg'...
compatible = "foo";
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "sony,acx424akp";
reg = <0>;
vddi-supply = <&foo>;
reset-gpios = <&foo_gpio 0 GPIO_ACTIVE_LOW>;
};
- };
+... \ No newline at end of file
Should fix this...
-- 2.21.0
On Fri, Oct 25, 2019 at 9:25 PM Rob Herring robh@kernel.org wrote:
On Thu, Oct 24, 2019 at 01:43:04PM +0200, Linus Walleij wrote:
This adds device tree bindings for the Sony ACX424AKP panel. Let's use YAML.
Also broken. Run 'make dt_binding_check'.
That is what I'm doing.
make -f Makefile -j5 -l4 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KBUILD_OUTPUT=/home/linus/linux-stericsson/build-ux500 dt_binding_check CHKDT Documentation/devicetree/bindings/display/panel/sony,acx424akp.yaml CHKDT Documentation/devicetree/bindings/display/dsi-controller.yaml SCHEMA Documentation/devicetree/bindings/processed-schema.yaml (...)
I'm a bit unsure how this thing works. Are the several passes? Because later on this breaks because of an unrelated error in the bindings upstream: /home/linus/linux-stericsson/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml: properties:compatible:enum:0: {'const': 'regulator-fixed'} is not of type 'string' /home/linus/linux-stericsson/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml: properties:compatible:enum:1: {'const': 'regulator-fixed-clock'} is not of type 'string' (...)
This is v5.4-rc1.
Is there any way I can selectively make dt_bindings_check just target the files I wanna check as any brokenness upstream cause problems like this? (And I assume that will keep happening.)
Yours, Linus Walleij
On Wed, Oct 30, 2019 at 11:38 AM Linus Walleij linus.walleij@linaro.org wrote:
On Fri, Oct 25, 2019 at 9:25 PM Rob Herring robh@kernel.org wrote:
On Thu, Oct 24, 2019 at 01:43:04PM +0200, Linus Walleij wrote:
This adds device tree bindings for the Sony ACX424AKP panel. Let's use YAML.
Also broken. Run 'make dt_binding_check'.
That is what I'm doing.
make -f Makefile -j5 -l4 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KBUILD_OUTPUT=/home/linus/linux-stericsson/build-ux500 dt_binding_check CHKDT Documentation/devicetree/bindings/display/panel/sony,acx424akp.yaml CHKDT Documentation/devicetree/bindings/display/dsi-controller.yaml SCHEMA Documentation/devicetree/bindings/processed-schema.yaml (...)
I'm a bit unsure how this thing works. Are the several passes? Because later on this breaks because of an unrelated error in the bindings upstream: /home/linus/linux-stericsson/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml: properties:compatible:enum:0: {'const': 'regulator-fixed'} is not of type 'string' /home/linus/linux-stericsson/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml: properties:compatible:enum:1: {'const': 'regulator-fixed-clock'} is not of type 'string' (...)
This is v5.4-rc1.
Is there any way I can selectively make dt_bindings_check just target the files I wanna check as any brokenness upstream cause problems like this? (And I assume that will keep happening.)
I pass '-k' to make so we don't stop. You can also set DT_SCHEMA_FILES to the file you want to check. Linus' tree is fixed now (and next just broke :( ).
Yes, it will keep happening as long as maintainers don't run checks and/or take patches before I review them.
Rob
The Sony ACX424AKP is a command/videomode DSI panel for mobile devices. It is used on the ST-Ericsson HREF520 reference design. We support video mode by default, but it is possible to switch the panel into command mode by using the bool property "dsi-command-mode".
Signed-off-by: Linus Walleij linus.walleij@linaro.org --- ChangeLog v3->v4: - No changes just resending with the new binding updates. ChangeLog v2->v3: - No changes just resending with the new binding updates. ChangeLog v1->v2: - Fix up the ID read function to split into reading header, version and ID, store the version in the struct. - Get rid of a surplus semicolon found by the build robot while rewriting the above code. - Use unsigned int in probe() loop. - Set vrefresh to 60Hz, as good as any, the measured vrefresh in continous command mode is ~117 Hz. - Use a different for() idiom while retrying to read ID 5 times. - Drop the sync pulse setting, we are not using this, this panel uses an event. - Use the generic "enforce-video-mode" for video mode enforcement. --- drivers/gpu/drm/panel/Kconfig | 7 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-sony-acx424akp.c | 542 +++++++++++++++++++ include/video/mipi_display.h | 1 + 4 files changed, 551 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-sony-acx424akp.c
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index f152bc4eeb53..959df5bea7d2 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -316,6 +316,13 @@ config DRM_PANEL_SITRONIX_ST7789V Say Y here if you want to enable support for the Sitronix ST7789V controller for 240x320 LCD panels
+config DRM_PANEL_SONY_ACX424AKP + tristate "Sony ACX424AKP DSI command mode panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + select VIDEOMODE_HELPERS + config DRM_PANEL_SONY_ACX565AKM tristate "Sony ACX565AKM panel" depends on GPIOLIB && OF && SPI diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index b6cd39fe0f20..0b51793e3b43 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -33,6 +33,7 @@ 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_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 obj-$(CONFIG_DRM_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o diff --git a/drivers/gpu/drm/panel/panel-sony-acx424akp.c b/drivers/gpu/drm/panel/panel-sony-acx424akp.c new file mode 100644 index 000000000000..96a1450b699e --- /dev/null +++ b/drivers/gpu/drm/panel/panel-sony-acx424akp.c @@ -0,0 +1,542 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * MIPI-DSI Sony ACX424AKP panel driver. This is a 480x864 + * AMOLED panel with a command-only DSI interface. + * + * Copyright (C) Linaro Ltd. 2019 + * Author: Linus Walleij + * Based on code and know-how from Marcus Lorentzon + * Copyright (C) ST-Ericsson SA 2010 + */ + +#include <drm/drm_modes.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_panel.h> +#include <drm/drm_print.h> +#include <video/mipi_display.h> + +#include <linux/gpio/consumer.h> +#include <linux/regulator/consumer.h> +#include <linux/delay.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/backlight.h> + +#define ACX424_DCS_READ_ID1 0xDA +#define ACX424_DCS_READ_ID2 0xDB +#define ACX424_DCS_READ_ID3 0xDC + +#define DISPLAY_SONY_ACX424AKP_ID1 0x811b +#define DISPLAY_SONY_ACX424AKP_ID2 0x811a +#define DISPLAY_SONY_ACX424AKP_ID3 0x8000 + +struct acx424akp { + struct device *dev; + struct drm_panel panel; + struct backlight_device *bl; + struct regulator *supply; + struct gpio_desc *reset_gpio; + u8 version; + bool video_mode; +}; + +static const struct drm_display_mode sony_acx424akp_vid_mode = { + .clock = 330000, + .hdisplay = 480, + .hsync_start = 480 + 15, + .hsync_end = 480 + 15 + 0, + .htotal = 480 + 15 + 0 + 15, + .vdisplay = 864, + .vsync_start = 864 + 14, + .vsync_end = 864 + 14 + 1, + .vtotal = 864 + 14 + 1 + 11, + .vrefresh = 60, + .width_mm = 48, + .height_mm = 84, + .flags = DRM_MODE_FLAG_PVSYNC, +}; + +/* + * The timings are not very helpful as the display is used in + * command mode using the maximum HS frequency. + */ +static const struct drm_display_mode sony_acx424akp_cmd_mode = { + .clock = 420160, + .hdisplay = 480, + .hsync_start = 480 + 154, + .hsync_end = 480 + 154 + 16, + .htotal = 480 + 154 + 16 + 32, + .vdisplay = 864, + .vsync_start = 864 + 1, + .vsync_end = 864 + 1 + 1, + .vtotal = 864 + 1 + 1 + 1, + /* + * Some desired refresh rate, experiments at the maximum "pixel" + * clock speed (HS clock 420 MHz) yields around 117Hz. + */ + .vrefresh = 60, + .width_mm = 48, + .height_mm = 84, +}; + +static inline struct acx424akp *panel_to_acx424akp(struct drm_panel *panel) +{ + return container_of(panel, struct acx424akp, panel); +} + +#define FOSC 20 /* 20Mhz */ +#define SCALE_FACTOR_NS_DIV_MHZ 1000 + +static int acx424akp_set_brightness(struct backlight_device *bl) +{ + struct acx424akp *acx = bl_get_data(bl); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev); + int period_ns = 1023; + int duty_ns = bl->props.brightness; + u8 pwm_ratio; + u8 pwm_div; + u8 par; + int ret; + + /* Calculate the PWM duty cycle in n/256's */ + pwm_ratio = max(((duty_ns * 256) / period_ns) - 1, 1); + pwm_div = max(1, + ((FOSC * period_ns) / 256) / + SCALE_FACTOR_NS_DIV_MHZ); + + /* Set up PWM dutycycle ONE byte (differs from the standard) */ + DRM_DEV_DEBUG(acx->dev, "calculated duty cycle %02x\n", pwm_ratio); + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, + &pwm_ratio, 1); + if (ret < 0) { + DRM_DEV_ERROR(acx->dev, + "failed to set display PWM ratio (%d)\n", + ret); + return ret; + } + + /* + * Sequence to write PWMDIV: + * address data + * 0xF3 0xAA CMD2 Unlock + * 0x00 0x01 Enter CMD2 page 0 + * 0X7D 0x01 No reload MTP of CMD2 P1 + * 0x22 PWMDIV + * 0x7F 0xAA CMD2 page 1 lock + */ + par = 0xaa; + ret = mipi_dsi_dcs_write(dsi, 0xf3, &par, 1); + if (ret < 0) { + DRM_DEV_ERROR(acx->dev, + "failed to unlock CMD 2 (%d)\n", + ret); + return ret; + } + par = 0x01; + ret = mipi_dsi_dcs_write(dsi, 0x00, &par, 1); + if (ret < 0) { + DRM_DEV_ERROR(acx->dev, + "failed to enter page 1 (%d)\n", + ret); + return ret; + } + par = 0x01; + ret = mipi_dsi_dcs_write(dsi, 0x7d, &par, 1); + if (ret < 0) { + DRM_DEV_ERROR(acx->dev, + "failed to disable MTP reload (%d)\n", + ret); + return ret; + } + ret = mipi_dsi_dcs_write(dsi, 0x22, &pwm_div, 1); + if (ret < 0) { + DRM_DEV_ERROR(acx->dev, + "failed to set PWM divisor (%d)\n", + ret); + return ret; + } + par = 0xaa; + ret = mipi_dsi_dcs_write(dsi, 0x7f, &par, 1); + if (ret < 0) { + DRM_DEV_ERROR(acx->dev, + "failed to lock CMD 2 (%d)\n", + ret); + return ret; + } + + /* Enable backlight */ + par = 0x24; + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, + &par, 1); + if (ret < 0) { + DRM_DEV_ERROR(acx->dev, + "failed to enable display backlight (%d)\n", + ret); + return ret; + } + + return 0; +} + +static const struct backlight_ops acx424akp_bl_ops = { + .update_status = acx424akp_set_brightness, +}; + +static int acx424akp_read_id(struct acx424akp *acx) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev); + u8 header, version, id; + u16 val; + int ret; + + ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID1, &header, 1); + if (ret < 0) { + DRM_DEV_ERROR(acx->dev, "could not read ID header byte\n"); + return ret; + } + ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID2, &id, 1); + if (ret < 0) { + DRM_DEV_ERROR(acx->dev, "could not read device ID byte\n"); + return ret; + } + ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID3, &version, 1); + if (ret < 0) { + DRM_DEV_ERROR(acx->dev, "could not read version byte\n"); + return ret; + } + + if (header == 0x00) { + DRM_DEV_ERROR(acx->dev, "device ID header is zero\n"); + return -ENODEV; + } + + val = (id << 8) | version; + switch (val) { + case DISPLAY_SONY_ACX424AKP_ID1: + case DISPLAY_SONY_ACX424AKP_ID2: + case DISPLAY_SONY_ACX424AKP_ID3: + DRM_DEV_INFO(acx->dev, "panel ID %02x, version: %02x\n", + id, version); + break; + default: + DRM_DEV_INFO(acx->dev, "unknown panel ID %02x, version: %02x\n", + id, version); + break; + } + acx->version = version; + + return 0; +} + +static int acx424akp_power_on(struct acx424akp *acx) +{ + int ret; + + ret = regulator_enable(acx->supply); + if (ret) { + DRM_DEV_ERROR(acx->dev, "failed to enable supply (%d)\n", ret); + return ret; + } + + /* Assert RESET */ + gpiod_set_value_cansleep(acx->reset_gpio, 1); + udelay(20); + /* De-assert RESET */ + gpiod_set_value_cansleep(acx->reset_gpio, 0); + msleep(11); + + return 0; +} + +static int acx424akp_prepare(struct drm_panel *panel) +{ + struct acx424akp *acx = panel_to_acx424akp(panel); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev); + const u8 mddi = 3; + int ret; + + ret = acx424akp_power_on(acx); + if (ret) + return ret; + + /* Enabe tearing mode: send TE (tearing effect) at VBLANK */ + ret = mipi_dsi_dcs_set_tear_on(dsi, + MIPI_DSI_DCS_TEAR_MODE_VBLANK); + if (ret) { + DRM_DEV_ERROR(acx->dev, "failed to enable vblank TE (%d)\n", + ret); + return ret; + } + + /* Set MDDI */ + ret = mipi_dsi_dcs_write(dsi, MIPI_DSI_DCS_SET_MDDI, + &mddi, sizeof(mddi)); + if (ret < 0) { + DRM_DEV_ERROR(acx->dev, "failed to set MDDI (%d)\n", ret); + return ret; + } + + acx->bl->props.power = FB_BLANK_NORMAL; + + return 0; +} + +static void acx424akp_power_off(struct acx424akp *acx) +{ + /* Assert RESET */ + gpiod_set_value_cansleep(acx->reset_gpio, 1); + msleep(11); + + regulator_disable(acx->supply); +} + +static int acx424akp_unprepare(struct drm_panel *panel) +{ + struct acx424akp *acx = panel_to_acx424akp(panel); + + acx424akp_power_off(acx); + acx->bl->props.power = FB_BLANK_POWERDOWN; + + return 0; +} + +static int acx424akp_enable(struct drm_panel *panel) +{ + struct acx424akp *acx = panel_to_acx424akp(panel); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev); + int ret; + + /* Exit sleep mode */ + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret) { + DRM_DEV_ERROR(acx->dev, "failed to exit sleep mode (%d)\n", + ret); + return ret; + } + msleep(140); + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret) { + DRM_DEV_ERROR(acx->dev, "failed to turn display on (%d)\n", + ret); + return ret; + } + if (acx->video_mode) { + /* In video mode turn peripheral on */ + ret = mipi_dsi_turn_on_peripheral(dsi); + if (ret) { + dev_err(acx->dev, "failed to turn on peripheral\n"); + return ret; + } + } + + acx->bl->props.power = FB_BLANK_UNBLANK; + + return 0; +} + +static int acx424akp_disable(struct drm_panel *panel) +{ + struct acx424akp *acx = panel_to_acx424akp(panel); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev); + u8 par; + int ret; + + /* Disable backlight */ + par = 0x00; + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, + &par, 1); + if (ret) { + DRM_DEV_ERROR(acx->dev, + "failed to disable display backlight (%d)\n", + ret); + return ret; + } + + ret = mipi_dsi_dcs_set_display_off(dsi); + if (ret) { + DRM_DEV_ERROR(acx->dev, "failed to turn display off (%d)\n", + ret); + return ret; + } + + /* Enter sleep mode */ + ret = mipi_dsi_dcs_enter_sleep_mode(dsi); + if (ret) { + DRM_DEV_ERROR(acx->dev, "failed to enter sleep mode (%d)\n", + ret); + return ret; + } + msleep(85); + + acx->bl->props.power = FB_BLANK_NORMAL; + + return 0; +} + +static int acx424akp_get_modes(struct drm_panel *panel) +{ + struct acx424akp *acx = panel_to_acx424akp(panel); + struct drm_connector *connector = panel->connector; + struct drm_display_mode *mode; + + if (acx->video_mode) + mode = drm_mode_duplicate(panel->drm, + &sony_acx424akp_vid_mode); + else + mode = drm_mode_duplicate(panel->drm, + &sony_acx424akp_cmd_mode); + if (!mode) { + DRM_ERROR("bad mode or failed to add mode\n"); + return -EINVAL; + } + 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; /* Number of modes */ +} + +static const struct drm_panel_funcs acx424akp_drm_funcs = { + .disable = acx424akp_disable, + .unprepare = acx424akp_unprepare, + .prepare = acx424akp_prepare, + .enable = acx424akp_enable, + .get_modes = acx424akp_get_modes, +}; + +static int acx424akp_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct acx424akp *acx; + int ret; + unsigned int i; + + acx = devm_kzalloc(dev, sizeof(struct acx424akp), GFP_KERNEL); + if (!acx) + return -ENOMEM; + acx->video_mode = of_property_read_bool(dev->of_node, + "enforce-video-mode"); + + mipi_dsi_set_drvdata(dsi, acx); + acx->dev = dev; + + dsi->lanes = 2; + dsi->format = MIPI_DSI_FMT_RGB888; + /* + * FIXME: these come from the ST-Ericsson vendor driver for the + * HREF520 and seems to reflect limitations in the PLLs on that + * platform, if you have the datasheet, please cross-check the + * actual max rates. + */ + dsi->lp_rate = 19200000; + dsi->hs_rate = 420160000; + + if (acx->video_mode) + /* Burst mode using event for sync */ + dsi->mode_flags = + MIPI_DSI_MODE_VIDEO | + MIPI_DSI_MODE_VIDEO_BURST; + else + dsi->mode_flags = + MIPI_DSI_CLOCK_NON_CONTINUOUS | + MIPI_DSI_MODE_EOT_PACKET; + + acx->supply = devm_regulator_get(dev, "vddi"); + if (IS_ERR(acx->supply)) + return PTR_ERR(acx->supply); + + /* This asserts RESET by default */ + acx->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(acx->reset_gpio)) { + ret = PTR_ERR(acx->reset_gpio); + if (ret != -EPROBE_DEFER) + DRM_DEV_ERROR(dev, "failed to request GPIO (%d)\n", + ret); + return ret; + } + + drm_panel_init(&acx->panel); + acx->panel.dev = dev; + acx->panel.funcs = &acx424akp_drm_funcs; + + acx->bl = devm_backlight_device_register(dev, "acx424akp", dev, acx, + &acx424akp_bl_ops, NULL); + if (IS_ERR(acx->bl)) { + DRM_DEV_ERROR(dev, "failed to register backlight device\n"); + return PTR_ERR(acx->bl); + } + acx->bl->props.max_brightness = 1023; + acx->bl->props.brightness = 512; + acx->bl->props.power = FB_BLANK_POWERDOWN; + + ret = drm_panel_add(&acx->panel); + if (ret < 0) + return ret; + + ret = acx424akp_power_on(acx); + if (ret) { + DRM_DEV_ERROR(dev, "failed to power up display\n"); + goto out_remove; + } + + /* Try 5 times to read the device ID */ + for (i = 0; i < 5; i++) { + ret = acx424akp_read_id(acx); + if (!ret) + break; + } + + if (ret) { + DRM_DEV_ERROR(acx->dev, "failed to read panel ID (%d)\n", ret); + goto out_poweroff; + } + acx424akp_power_off(acx); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) + goto out_poweroff; + + return 0; + +out_poweroff: + acx424akp_power_off(acx); +out_remove: + drm_panel_remove(&acx->panel); + return ret; +} + +static int acx424akp_remove(struct mipi_dsi_device *dsi) +{ + struct acx424akp *acx = mipi_dsi_get_drvdata(dsi); + + mipi_dsi_detach(dsi); + drm_panel_remove(&acx->panel); + + return 0; +} + +static const struct of_device_id acx424akp_of_match[] = { + { .compatible = "sony,acx424akp" }, + { } +}; +MODULE_DEVICE_TABLE(of, acx424akp_of_match); + +static struct mipi_dsi_driver acx424akp_driver = { + .probe = acx424akp_probe, + .remove = acx424akp_remove, + .driver = { + .name = "panel-sony-acx424akp", + .of_match_table = acx424akp_of_match, + }, +}; +module_mipi_dsi_driver(acx424akp_driver); + +MODULE_AUTHOR("Linus Wallei linus.walleij@linaro.org"); +MODULE_DESCRIPTION("MIPI-DSI Sony acx424akp Panel Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/video/mipi_display.h b/include/video/mipi_display.h index cba57a678daf..cf99c6a519d5 100644 --- a/include/video/mipi_display.h +++ b/include/video/mipi_display.h @@ -125,6 +125,7 @@ enum { MIPI_DCS_GET_CABC_MIN_BRIGHTNESS = 0x5F, /* MIPI DCS 1.3 */ MIPI_DCS_READ_DDB_START = 0xA1, MIPI_DCS_READ_DDB_CONTINUE = 0xA8, + MIPI_DSI_DCS_SET_MDDI = 0xAE, };
/* MIPI DCS pixel formats */
On Thu, Oct 24, 2019 at 01:43:03PM +0200, Linus Walleij wrote:
This adds a starting point for processing and defining generic bindings used by DSI panels. We just define one single bool property to force the panel into video mode for now.
Cc: devicetree@vger.kernel.org Suggested-by: Rob Herring robh@kernel.org Signed-off-by: Linus Walleij linus.walleij@linaro.org
ChangeLog v3->v4:
- Rename into display/dsi-controller.yaml
- Require a virtual channel number for the DSI panel, as DSI have this 2-bit virtual address field.
- Bring in some but not all properties from the existing MIPI DSI bindings. This schema can be used with simpler panels but not complex panels with multiple virtual channels for the moment. Let's handle it when we get there.
- Add an example.
A broken example...
ChangeLog v2->v3:
- Make a more complete DSI panel binding including the controller and its address-cells and size-cells and a pattern for the panel nodes. The panel is one per DSI master, the reg property is compulsory but should always be 0 (as far as I can tell) as only one panel can be connected. The bus doesn't really have any addresses for the panel, the address/reg notation seems to be cargo-culted from the port graphs and is not necessary to parse some device trees, it is used to tell whether the node is a panel or not rather than any addressing.
- I have no idea how many displays you can daisychain on a single DSI master, I just guess 15 will be enough. The MIPI-specs are memberwalled. Someone who knows can tell perhaps?
ChangeLog v1->v2:
- New patch after feedback.
.../bindings/display/dsi-controller.yaml | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/dsi-controller.yaml
diff --git a/Documentation/devicetree/bindings/display/dsi-controller.yaml b/Documentation/devicetree/bindings/display/dsi-controller.yaml new file mode 100644 index 000000000000..2a6d872a40c5 --- /dev/null +++ b/Documentation/devicetree/bindings/display/dsi-controller.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/panel-dsi-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: Common Properties for DSI Display Panels
+maintainers:
- Linus Walleij linus.walleij@linaro.org
+description: |
- This document defines device tree properties common to DSI, Display
- Serial Interface panels. It doesn't constitute a device tree binding
- specification by itself but is meant to be referenced by device tree
- bindings.
- When referenced from panel device tree bindings the properties defined in
- this document are defined as follows. The panel device tree bindings are
- responsible for defining whether each property is required or optional.
- Notice: this binding concerns DSI panels connected directly to a master
- without any intermediate port graph to the panel. Each DSI master
- can control exactly one panel. They should all just have a node "panel"
- for their panel with their reg-property set to 0.
+properties:
- $nodename:
- pattern: "^dsi-controller(@.*)?$"
- "#address-cells":
- const: 1
- "#size-cells":
- const: 0
+patternProperties:
- "^panel@[0-3]$":
- type: object
- properties:
reg:
minimum: 0
maximum: 3
description:
The virtual channel number of a DSI peripheral. Must be in the range
from 0 to 3, as DSI uses a 2-bit addressing scheme. Some DSI
peripherals respond to more than a single virtual channel. In that
case the reg property can take multiple entries, one for each virtual
channel that the peripheral responds to.
clock-master:
type: boolean
description:
Should be enabled if the host is being used in conjunction with
another DSI host to drive the same peripheral. Hardware supporting
such a configuration generally requires the data on both the busses
to be driven by the same clock. Only the DSI host instance
controlling this clock should contain this property.
enforce-video-mode:
type: boolean
description:
The best option is usually to run a panel in command mode, as this
gives better control over the panel hardware. However for different
reasons like broken hardware, missing features or testing, it may be
useful to be able to force a command mode-capable panel into video
mode.
- required:
- reg
+examples:
- |
- dsi-controller@55aa55aa {
compatible = "acme,foo";
Eventually, I want to start reporting if compatible strings aren't documented (i.e. matched to a schema). This will break then...
reg = <0x55aa55aa>;
This will fail because a size cell is expected.
I'd just drop both properties here. A 'dsi-controller' node name is enough to select this schema.
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "acme,bar";
Just pick a real one. (Or drop the example because the binding for the real panel will have the same example).
reg = <0>;
vddi-supply = <&foo>;
reset-gpios = <&foo_gpio 0 GPIO_ACTIVE_LOW>;
};
- };
+...
2.21.0
On Fri, Oct 25, 2019 at 9:20 PM Rob Herring robh@kernel.org wrote:
[Me]
- dsi-controller@55aa55aa {
compatible = "acme,foo";
Eventually, I want to start reporting if compatible strings aren't documented (i.e. matched to a schema). This will break then...
OK I drop this.
reg = <0x55aa55aa>;
This will fail because a size cell is expected.
Do you mean it will fail the day we actually check reg properties to be properly formed under the circumstances?
Because: HOSTLD scripts/dtc/dtc CHKDT Documentation/devicetree/bindings/display/panel/sony,acx424akp.yaml CHKDT Documentation/devicetree/bindings/display/dsi-controller.yaml SCHEMA Documentation/devicetree/bindings/processed-schema.yaml (...)
It passes just fine.
I get a bit nervous since the schema is all about being strict about stuff so I get the feeling that "should have failed".
Yours, Linus Walleij
On Wed, Oct 30, 2019 at 8:50 AM Linus Walleij linus.walleij@linaro.org wrote:
On Fri, Oct 25, 2019 at 9:20 PM Rob Herring robh@kernel.org wrote:
[Me]
- dsi-controller@55aa55aa {
compatible = "acme,foo";
Eventually, I want to start reporting if compatible strings aren't documented (i.e. matched to a schema). This will break then...
OK I drop this.
reg = <0x55aa55aa>;
This will fail because a size cell is expected.
Do you mean it will fail the day we actually check reg properties to be properly formed under the circumstances?
Because: HOSTLD scripts/dtc/dtc CHKDT Documentation/devicetree/bindings/display/panel/sony,acx424akp.yaml CHKDT Documentation/devicetree/bindings/display/dsi-controller.yaml SCHEMA Documentation/devicetree/bindings/processed-schema.yaml (...)
It passes just fine.
Yes, but the examples are built and validated after this. With the other errors currently, you're erroring out before this happens.
I get a bit nervous since the schema is all about being strict about stuff so I get the feeling that "should have failed".
It's actually dtc that will complain here because it's aware of #*-cells values. Can't do that with schema.
Rob
dri-devel@lists.freedesktop.org