From patchwork Wed Apr 13 22:19:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Holland X-Patchwork-Id: 12812736 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 08A75C433FE for ; Wed, 13 Apr 2022 22:19:34 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id F021B10F134; Wed, 13 Apr 2022 22:19:28 +0000 (UTC) Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by gabe.freedesktop.org (Postfix) with ESMTPS id 2770A10F12E for ; Wed, 13 Apr 2022 22:19:25 +0000 (UTC) Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.nyi.internal (Postfix) with ESMTP id 773CB5C01F8; Wed, 13 Apr 2022 18:19:24 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute5.internal (MEProxy); Wed, 13 Apr 2022 18:19:24 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sholland.org; h= cc:cc:content-transfer-encoding:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm2; t=1649888364; x=1649974764; bh=t3 R9K4RmpPHgFV2MCz+ahY35ugv1/r5JX9ttGYH/p/s=; b=N+/kv28XEg7cqCbiqW +pxb2lwnBU9wmAVqImOnBSGM6WsUogv+MVcj58IxCD0hv22fukH8eyBCi0+tkGAy zL5gGcPeF8rkgjdpTJlVjvNKfPu29vfnuj0o86hhvi1tHfCzx4mgtcSGRCUmG/Zz b7LhKiXdEJMT+gGqOnC4YDiPWMJR+MFgVkwDLeCdqF5qz2cAoXIyzzCp7ByF9DaE JkmoslCswHsptydVxVyqpDn+JiJBlDRtcSBrefLO5iMViqA/shxPf0x8+h2kY6X/ vkiRO/YJBWVZt5V+72gAvHlcmgoi5bjc5TC0dNuTZhoVOcKFd9bdpl6WB+6lwUWJ KAzw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1649888364; x=1649974764; bh=t3R9K4RmpPHgFV2MCz+ahY35ugv1/r5JX9t tGYH/p/s=; b=hEfVZV3vugr1D11KTaj8Wdd4Be/EOWwCeBqZW5PuCcqls8jxMWL X96i3gmapN05hcJ1xKnz6ce8RPbitCbIiCY4VaKFQ4A0uRJG7xuWxYFM90WAzXbG E5GbOn1djKtTI26X3Q5NdwzKcTzXm4ZNGsDbBJm10iJ3WQ5DXkurqG69CvwyQdup 0sSajJIDZrr6wDeszGG2SgCeBygrW04M3MEQdk9Ji3dRhvy9rahZR4cAepDiBrps 3Rw0OrUFbqxUSXNhaoOD1f1jgBWlfyDi9MByhETjQ1ii2SNQUVEyGP8PpVILeP9I GiTXcIklWmXxhDBRLrlTM9GBiC2lvSHR4Dw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudelvddgtdelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefurghmuhgv lhcujfholhhlrghnugcuoehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhgqeenucggtf frrghtthgvrhhnpeduhfejfedvhffgfeehtefghfeiiefgfeehgfdvvdevfeegjeehjedv gfejheeuieenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhroh hmpehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhg X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 13 Apr 2022 18:19:22 -0400 (EDT) From: Samuel Holland To: =?utf-8?q?Heiko_St=C3=BCbner?= , Sandy Huang , dri-devel@lists.freedesktop.org Subject: [RFC PATCH 01/16] drm: Add a helper library for EPD drivers Date: Wed, 13 Apr 2022 17:19:01 -0500 Message-Id: <20220413221916.50995-2-samuel@sholland.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220413221916.50995-1-samuel@sholland.org> References: <20220413221916.50995-1-samuel@sholland.org> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Airlie , =?utf-8?q?Ond=C5=99ej_Jirman?= , Thierry Reding , Michael Riesch , Sam Ravnborg , Samuel Holland , Nicolas Frattaroli , linux-rockchip@lists.infradead.org, Andreas Kemnade , Geert Uytterhoeven , Liang Chen , devicetree@vger.kernel.org, Thomas Zimmermann , Alistair Francis , Rob Herring , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peter Geis , Krzysztof Kozlowski Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Currently, this library is focused on LUTs and LUT files, specifically the PVI wbf-format files shipped with E-Ink displays. It provides helpers to load and validate LUT files, and extract LUTs from them. Since EPD controllers need the LUTs in various formats, this library allows drivers to declare their desired format. It will then convert LUTs to that format before returning them. Signed-off-by: Samuel Holland --- drivers/gpu/drm/Kconfig | 6 + drivers/gpu/drm/Makefile | 2 + drivers/gpu/drm/drm_epd_helper.c | 663 +++++++++++++++++++++++++++++++ include/drm/drm_epd_helper.h | 104 +++++ 4 files changed, 775 insertions(+) create mode 100644 drivers/gpu/drm/drm_epd_helper.c create mode 100644 include/drm/drm_epd_helper.h diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index f1422bee3dcc..ad96cf605444 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -198,6 +198,12 @@ config DRM_DP_CEC Note: not all adapters support this feature, and even for those that do support this they often do not hook up the CEC pin. +config DRM_EPD_HELPER + tristate + depends on DRM + help + Choose this if you need the EPD (LUT, etc.) helper functions + config DRM_TTM tristate depends on DRM && MMU diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index c2ef5f9fce54..49380ccfe9d6 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -33,6 +33,8 @@ drm-$(CONFIG_DRM_PRIVACY_SCREEN) += drm_privacy_screen.o drm_privacy_screen_x86. obj-$(CONFIG_DRM_NOMODESET) += drm_nomodeset.o +obj-$(CONFIG_DRM_EPD_HELPER) += drm_epd_helper.o + drm_cma_helper-y := drm_gem_cma_helper.o drm_cma_helper-$(CONFIG_DRM_KMS_HELPER) += drm_fb_cma_helper.o obj-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_cma_helper.o diff --git a/drivers/gpu/drm/drm_epd_helper.c b/drivers/gpu/drm/drm_epd_helper.c new file mode 100644 index 000000000000..433a6728ef3e --- /dev/null +++ b/drivers/gpu/drm/drm_epd_helper.c @@ -0,0 +1,663 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * Electrophoretic Display Helper Library + * + * Copyright (C) 2022 Samuel Holland + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include +#include +#include +#include + +/** + * DOC: overview + * + * This library provides functions for working with the lookup tables (LUTs) + * used by electrophoretic displays (EPDs). It fills in a LUT buffer based on + * the selected waveform, the panel temperature, and the buffer format needed + * by the driver. + */ + +struct pvi_wbf_offset { + u8 b[3]; +}; + +struct pvi_wbf_pointer { + struct pvi_wbf_offset offset; + u8 checksum; +}; + +struct pvi_wbf_file_header { + __le32 checksum; // 0x00 + __le32 file_size; // 0x04 + __le32 serial; // 0x08 + u8 run_type; // 0x0c + u8 fpl_platform; // 0x0d + __le16 fpl_lot; // 0x0e + u8 mode_version; // 0x10 + u8 wf_version; // 0x11 + u8 wf_subversion; // 0x12 + u8 wf_type; // 0x13 + u8 panel_size; // 0x14 + u8 amepd_part_number; // 0x15 + u8 wf_rev; // 0x16 + u8 frame_rate_bcd; // 0x17 + u8 frame_rate_hex; // 0x18 + u8 vcom_offset; // 0x19 + u8 unknown[2]; // 0x1a + struct pvi_wbf_offset xwia; // 0x1c + u8 cs1; // 0x1f + struct pvi_wbf_offset wmta; // 0x20 + u8 fvsn; // 0x23 + u8 luts; // 0x24 + u8 mode_count; // 0x25 + u8 temp_range_count; // 0x26 + u8 advanced_wf_flags; // 0x27 + u8 eb; // 0x28 + u8 sb; // 0x29 + u8 reserved[5]; // 0x2a + u8 cs2; // 0x2f + u8 temp_range_table[]; // 0x30 +}; +static_assert(sizeof(struct pvi_wbf_file_header) == 0x30); + +struct pvi_wbf_mode_info { + u8 versions[2]; + u8 format; + u8 modes[DRM_EPD_WF_MAX]; +}; + +static const struct pvi_wbf_mode_info pvi_wbf_mode_info_table[] = { + { + .versions = { + 0x09, + }, + .format = DRM_EPD_LUT_4BIT_PACKED, + .modes = { + [DRM_EPD_WF_RESET] = 0, + [DRM_EPD_WF_DU] = 1, + [DRM_EPD_WF_DU4] = 1, + [DRM_EPD_WF_GC16] = 2, + [DRM_EPD_WF_GL16] = 3, + [DRM_EPD_WF_GLR16] = 3, + [DRM_EPD_WF_GLD16] = 3, + [DRM_EPD_WF_A2] = 4, + [DRM_EPD_WF_GCC16] = 3, + }, + }, + { + .versions = { + 0x12, + }, + .format = DRM_EPD_LUT_4BIT_PACKED, + .modes = { + [DRM_EPD_WF_RESET] = 0, + [DRM_EPD_WF_DU] = 1, + [DRM_EPD_WF_DU4] = 7, + [DRM_EPD_WF_GC16] = 3, + [DRM_EPD_WF_GL16] = 3, + [DRM_EPD_WF_GLR16] = 5, + [DRM_EPD_WF_GLD16] = 6, + [DRM_EPD_WF_A2] = 4, + [DRM_EPD_WF_GCC16] = 5, + }, + }, + { + .versions = { + 0x16, + }, + .format = DRM_EPD_LUT_5BIT_PACKED, + .modes = { + [DRM_EPD_WF_RESET] = 0, + [DRM_EPD_WF_DU] = 1, + [DRM_EPD_WF_DU4] = 1, + [DRM_EPD_WF_GC16] = 2, + [DRM_EPD_WF_GL16] = 3, + [DRM_EPD_WF_GLR16] = 4, + [DRM_EPD_WF_GLD16] = 4, + [DRM_EPD_WF_A2] = 6, + [DRM_EPD_WF_GCC16] = 5, + }, + }, + { + .versions = { + 0x18, + 0x20, + }, + .format = DRM_EPD_LUT_5BIT_PACKED, + .modes = { + [DRM_EPD_WF_RESET] = 0, + [DRM_EPD_WF_DU] = 1, + [DRM_EPD_WF_DU4] = 1, + [DRM_EPD_WF_GC16] = 2, + [DRM_EPD_WF_GL16] = 3, + [DRM_EPD_WF_GLR16] = 4, + [DRM_EPD_WF_GLD16] = 5, + [DRM_EPD_WF_A2] = 6, + [DRM_EPD_WF_GCC16] = 4, + }, + }, + { + .versions = { + 0x19, + 0x43, + }, + .format = DRM_EPD_LUT_5BIT_PACKED, + .modes = { + [DRM_EPD_WF_RESET] = 0, + [DRM_EPD_WF_DU] = 1, + [DRM_EPD_WF_DU4] = 7, + [DRM_EPD_WF_GC16] = 2, + [DRM_EPD_WF_GL16] = 3, + [DRM_EPD_WF_GLR16] = 4, + [DRM_EPD_WF_GLD16] = 5, + [DRM_EPD_WF_A2] = 6, + [DRM_EPD_WF_GCC16] = 4, + }, + }, + { + .versions = { + 0x23, + }, + .format = DRM_EPD_LUT_4BIT_PACKED, + .modes = { + [DRM_EPD_WF_RESET] = 0, + [DRM_EPD_WF_DU] = 1, + [DRM_EPD_WF_DU4] = 5, + [DRM_EPD_WF_GC16] = 2, + [DRM_EPD_WF_GL16] = 3, + [DRM_EPD_WF_GLR16] = 3, + [DRM_EPD_WF_GLD16] = 3, + [DRM_EPD_WF_A2] = 4, + [DRM_EPD_WF_GCC16] = 3, + }, + }, + { + .versions = { + 0x54, + }, + .format = DRM_EPD_LUT_4BIT_PACKED, + .modes = { + [DRM_EPD_WF_RESET] = 0, + [DRM_EPD_WF_DU] = 1, + [DRM_EPD_WF_DU4] = 1, + [DRM_EPD_WF_GC16] = 2, + [DRM_EPD_WF_GL16] = 3, + [DRM_EPD_WF_GLR16] = 4, + [DRM_EPD_WF_GLD16] = 4, + [DRM_EPD_WF_A2] = 5, + [DRM_EPD_WF_GCC16] = 4, + }, + }, +}; + +static const void *pvi_wbf_apply_offset(const struct drm_epd_lut_file *file, + const struct pvi_wbf_offset *offset) +{ + u32 bytes = offset->b[0] | offset->b[1] << 8 | offset->b[2] << 16; + + if (bytes >= file->fw->size) + return NULL; + + return (const void *)file->header + bytes; +} + +static const void *pvi_wbf_dereference(const struct drm_epd_lut_file *file, + const struct pvi_wbf_pointer *ptr) +{ + u8 sum = ptr->offset.b[0] + ptr->offset.b[1] + ptr->offset.b[2]; + + if (ptr->checksum != sum) + return NULL; + + return pvi_wbf_apply_offset(file, &ptr->offset); +} + +static int pvi_wbf_get_mode_index(const struct drm_epd_lut_file *file, + enum drm_epd_waveform waveform) +{ + if (waveform >= DRM_EPD_WF_MAX) + return -EINVAL; + + return file->mode_info->modes[waveform]; +} + +static int pvi_wbf_get_mode_info(struct drm_epd_lut_file *file) +{ + u8 mode_version = file->header->mode_version; + const struct pvi_wbf_mode_info *mode_info; + int i, v; + + for (i = 0; i < ARRAY_SIZE(pvi_wbf_mode_info_table); i++) { + mode_info = &pvi_wbf_mode_info_table[i]; + + for (v = 0; v < ARRAY_SIZE(mode_info->versions); v++) { + if (mode_info->versions[v] == mode_version) { + file->mode_info = mode_info; + return 0; + } + } + } + + drm_err(file->dev, "Unknown PVI waveform version 0x%02x\n", + mode_version); + + return -EOPNOTSUPP; +} + +static int pvi_wbf_get_temp_index(const struct drm_epd_lut_file *file, + int temperature) +{ + const struct pvi_wbf_file_header *header = file->header; + int i; + + for (i = 0; i < header->temp_range_count; i++) + if (temperature < header->temp_range_table[i]) + return i - 1; + + return header->temp_range_count - 1; +} + +static int pvi_wbf_validate_header(struct drm_epd_lut_file *file) +{ + const struct pvi_wbf_file_header *header = file->header; + int ret; + + if (le32_to_cpu(header->file_size) > file->fw->size) + return -EINVAL; + + ret = pvi_wbf_get_mode_info(file); + if (ret) + return ret; + + drm_info(file->dev, "Loaded %d-bit PVI waveform version 0x%02x\n", + file->mode_info->format == DRM_EPD_LUT_5BIT_PACKED ? 5 : 4, + header->mode_version); + + return 0; +} + +static void drm_epd_lut_file_free(struct drm_device *dev, void *res) +{ + struct drm_epd_lut_file *file = res; + + release_firmware(file->fw); +} + +/** + * drmm_epd_lut_file_init - Initialize a managed EPD LUT file + * + * @dev: The DRM device owning this LUT file + * @file: The LUT file to initialize + * @file_name: The filesystem name of the LUT file + * + * Return: negative errno on failure, 0 otherwise + */ +int drmm_epd_lut_file_init(struct drm_device *dev, + struct drm_epd_lut_file *file, + const char *file_name) +{ + int ret; + + ret = request_firmware(&file->fw, file_name, dev->dev); + if (ret) + return ret; + + ret = drmm_add_action_or_reset(dev, drm_epd_lut_file_free, file); + if (ret) + return ret; + + file->dev = dev; + file->header = (const void *)file->fw->data; + + ret = pvi_wbf_validate_header(file); + if (ret) + return ret; + + /* Only 5-bit waveform files are supported by drm_epd_lut_convert. */ + if (file->mode_info->format != DRM_EPD_LUT_5BIT_PACKED) + return -EOPNOTSUPP; + + return 0; +} +EXPORT_SYMBOL(drmm_epd_lut_file_init); + +/** + * drm_epd_lut_size_shift - Get the size of a LUT phase in power-of-2 bytes + * + * @format: One of the LUT buffer formats + * + * Return: buffer size shift amount + */ +static int drm_epd_lut_size_shift(enum drm_epd_lut_format format) +{ + switch (format) { + case DRM_EPD_LUT_4BIT: + /* (4 bits/pixel)^2 / 1 pixel/byte */ + return 4 + 4; + case DRM_EPD_LUT_4BIT_PACKED: + /* (4 bits/pixel)^2 / 4 pixels/byte */ + return 4 + 4 - 2; + case DRM_EPD_LUT_5BIT: + /* (5 bits/pixel)^2 / 1 pixel/byte */ + return 5 + 5; + case DRM_EPD_LUT_5BIT_PACKED: + /* (5 bits/pixel)^2 / 4 pixels/byte */ + return 5 + 5 - 2; + } + + unreachable(); +} + +static int pvi_wbf_decode_lut(struct drm_epd_lut *lut, const u8 *lut_data) +{ + + unsigned int copies, max_bytes, size_shift, state, total_bytes; + struct drm_device *dev = lut->file->dev; + const u8 *in = lut_data; + u8 *out = lut->buf; + u8 token; + + size_shift = drm_epd_lut_size_shift(lut->file->mode_info->format); + max_bytes = lut->max_phases << size_shift; + total_bytes = 0; + state = 1; + + /* Read tokens until reaching the end-of-input marker. */ + while ((token = *in++) != 0xff) { + /* Special handling for the state switch token. */ + if (token == 0xfc) { + state = !state; + token = *in++; + } + + /* + * State 0 is a sequence of data bytes. + * State 1 is a sequence of [data byte, extra copies] pairs. + */ + copies = 1 + (state ? *in++ : 0); + + total_bytes += copies; + if (total_bytes > max_bytes) { + drm_err(dev, "LUT contains too many phases\n"); + lut->num_phases = 0; + return -EILSEQ; + } + + while (copies--) + *out++ = token; + } + + lut->num_phases = total_bytes >> size_shift; + if (total_bytes != lut->num_phases << size_shift) { + drm_err(dev, "LUT contains a partial phase\n"); + lut->num_phases = 0; + return -EILSEQ; + } + + drm_dbg_core(dev, "LUT contains %d phases (%ld => %ld bytes)\n", + lut->num_phases, in - lut_data, out - lut->buf); + + return 0; +} + +static int pvi_wbf_get_lut(struct drm_epd_lut *lut, + int mode_index, int temp_index) +{ + const struct pvi_wbf_pointer *mode_table, *temp_table; + const struct drm_epd_lut_file *file = lut->file; + const u8 *lut_data; + int ret; + + mode_table = pvi_wbf_apply_offset(file, &file->header->wmta); + if (!mode_table) + return -EFAULT; + + temp_table = pvi_wbf_dereference(file, &mode_table[mode_index]); + if (!temp_table) + return -EFAULT; + + lut_data = pvi_wbf_dereference(file, &temp_table[temp_index]); + if (!lut_data) + return -EFAULT; + + ret = pvi_wbf_decode_lut(lut, lut_data); + if (ret) + return ret; + + return 0; +} + +static void drm_epd_lut_convert(const struct drm_epd_lut *lut) +{ + enum drm_epd_lut_format from = lut->file->mode_info->format; + enum drm_epd_lut_format to = lut->format; + u8 *buf = lut->buf; + size_t x, y; + + if (to == from) + return; + + switch (to) { + case DRM_EPD_LUT_4BIT: + for (y = 0; y < 16 * lut->num_phases; ++y) { + for (x = 8; x--;) { + u8 byte = buf[16 * y + x]; + + buf[16 * y + 2 * x + 0] = (byte >> 0) & 0x03; + buf[16 * y + 2 * x + 1] = (byte >> 4) & 0x03; + } + } + for (; y < 16 * lut->max_phases; ++y) { + for (x = 8; x--;) { + buf[16 * y + 2 * x + 0] = 0; + buf[16 * y + 2 * x + 1] = 0; + } + } + break; + case DRM_EPD_LUT_4BIT_PACKED: + for (y = 0; y < 16 * lut->num_phases; ++y) { + for (x = 4; x--;) { + u8 lo_byte = buf[16 * y + 2 * x + 0] & 0x33; + u8 hi_byte = buf[16 * y + 2 * x + 1] & 0x33; + + /* Copy bits 4:5 => bits 2:3. */ + lo_byte |= lo_byte >> 2; + hi_byte |= hi_byte >> 2; + + buf[4 * y + x] = (lo_byte & 0xf) | + (hi_byte << 4); + } + } + for (; y < 16 * lut->max_phases; ++y) { + for (x = 4; x--;) + buf[4 * y + x] = 0; + } + break; + case DRM_EPD_LUT_5BIT: + memset(buf + 256 * lut->num_phases, 0, + 256 * (lut->max_phases - lut->num_phases)); + for (x = 256 * lut->num_phases; x--;) { + u8 byte = buf[x]; + + buf[4 * x + 0] = (byte >> 0) & 0x03; + buf[4 * x + 1] = (byte >> 2) & 0x03; + buf[4 * x + 2] = (byte >> 4) & 0x03; + buf[4 * x + 3] = (byte >> 6) & 0x03; + } + break; + case DRM_EPD_LUT_5BIT_PACKED: + /* Nothing to do. */ + break; + } +} + +static int drm_epd_lut_update(struct drm_epd_lut *lut, + int mode_index, int temp_index) +{ + int ret; + + ret = pvi_wbf_get_lut(lut, mode_index, temp_index); + if (ret) + return ret; + + drm_epd_lut_convert(lut); + + return 0; +} + +/** + * drm_epd_lut_set_temperature - Update the LUT due to panel temperature change + * + * @lut: The LUT structure + * @temperateure: The current panel temperature in degrees Celsius + * + * Return: negative errno on failure, 1 if LUT was changed, 0 otherwise + */ +int drm_epd_lut_set_temperature(struct drm_epd_lut *lut, + int temperature) +{ + int temp_index; + int ret; + + temp_index = pvi_wbf_get_temp_index(lut->file, temperature); + if (temp_index < 0) + return -ENOENT; + + if (temp_index == lut->temp_index) + return 0; + + drm_dbg_core(lut->file->dev, "LUT temperature changed (%d)\n", + temperature); + + ret = drm_epd_lut_update(lut, lut->mode_index, temp_index); + if (ret) + return ret; + + lut->temp_index = temp_index; + + return 1; +} +EXPORT_SYMBOL(drm_epd_lut_set_temperature); + +/** + * drm_epd_lut_set_waveform - Update the LUT due to waveform selection change + * + * @lut: The LUT structure + * @waveform: The desired waveform + * + * Return: negative errno on failure, 1 if LUT was changed, 0 otherwise + */ +int drm_epd_lut_set_waveform(struct drm_epd_lut *lut, + enum drm_epd_waveform waveform) +{ + int mode_index; + int ret; + + mode_index = pvi_wbf_get_mode_index(lut->file, waveform); + if (mode_index < 0) + return -ENOENT; + + if (mode_index == lut->mode_index) + return 0; + + drm_dbg_core(lut->file->dev, "LUT waveform changed (%d)\n", + waveform); + + ret = drm_epd_lut_update(lut, mode_index, lut->temp_index); + if (ret) + return ret; + + lut->mode_index = mode_index; + + return 1; +} +EXPORT_SYMBOL(drm_epd_lut_set_waveform); + +static void drm_epd_lut_free(struct drm_device *dev, void *res) +{ + struct drm_epd_lut *lut = res; + + vfree(lut->buf); +} + +/** + * drmm_epd_lut_init - Initialize a managed EPD LUT from a LUT file + * + * @dev: The DRM device owning this LUT + * @lut: The LUT to initialize + * @file_name: The file name of the waveform firmware + * @format: The LUT buffer format needed by the driver + * @max_phases: The maximum number of waveform phases supported by the driver + * + * Return: negative errno on failure, 0 otherwise + */ +int drmm_epd_lut_init(struct drm_epd_lut_file *file, + struct drm_epd_lut *lut, + enum drm_epd_lut_format format, + unsigned int max_phases) +{ + size_t max_order; + int ret; + + /* Allocate a buffer large enough to convert the LUT in place. */ + max_order = max(drm_epd_lut_size_shift(file->mode_info->format), + drm_epd_lut_size_shift(format)); + lut->buf = vmalloc(max_phases << max_order); + if (!lut->buf) + return -ENOMEM; + + ret = drmm_add_action_or_reset(file->dev, drm_epd_lut_free, lut); + if (ret) + return ret; + + lut->file = file; + lut->format = format; + lut->max_phases = max_phases; + lut->num_phases = 0; + + /* Set sane initial values for the waveform and temperature. */ + lut->mode_index = pvi_wbf_get_mode_index(file, DRM_EPD_WF_RESET); + if (lut->mode_index < 0) + return -ENOENT; + + lut->temp_index = pvi_wbf_get_temp_index(file, 25); + if (lut->temp_index < 0) + return -ENOENT; + + ret = drm_epd_lut_update(lut, lut->mode_index, lut->temp_index); + if (ret) + return ret; + + return 0; +} +EXPORT_SYMBOL(drmm_epd_lut_init); + +MODULE_AUTHOR("Samuel Holland "); +MODULE_DESCRIPTION("DRM EPD waveform LUT library"); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/include/drm/drm_epd_helper.h b/include/drm/drm_epd_helper.h new file mode 100644 index 000000000000..290f5d48c0cb --- /dev/null +++ b/include/drm/drm_epd_helper.h @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ + +#ifndef __DRM_EPD_HELPER_H__ +#define __DRM_EPD_HELPER_H__ + +#define DRM_EPD_DEFAULT_TEMPERATURE 25 + +struct drm_device; +struct firmware; +struct pvi_wbf_file_header; +struct pvi_wbf_mode_info; + +/** + * enum drm_epd_waveform - Identifiers for waveforms used to drive EPD pixels + * + * @DRM_EPD_WF_RESET: Used to initialize the panel, ends with white + * @DRM_EPD_WF_A2: Fast transitions between black and white only + * @DRM_EPD_WF_DU: Transitions 16-level grayscale to monochrome + * @DRM_EPD_WF_DU4: Transitions 16-level grayscale to 4-level grayscale + * @DRM_EPD_WF_GC16: High-quality but flashy 16-level grayscale + * @DRM_EPD_WF_GCC16: Less flashy 16-level grayscale + * @DRM_EPD_WF_GL16: Less flashy 16-level grayscale + * @DRM_EPD_WF_GLR16: Less flashy 16-level grayscale, plus anti-ghosting + * @DRM_EPD_WF_GLD16: Less flashy 16-level grayscale, plus anti-ghosting + */ +enum drm_epd_waveform { + DRM_EPD_WF_RESET, + DRM_EPD_WF_A2, + DRM_EPD_WF_DU, + DRM_EPD_WF_DU4, + DRM_EPD_WF_GC16, + DRM_EPD_WF_GCC16, + DRM_EPD_WF_GL16, + DRM_EPD_WF_GLR16, + DRM_EPD_WF_GLD16, + DRM_EPD_WF_MAX +}; + +/** + * enum drm_epd_lut_format - EPD LUT buffer format + * + * @DRM_EPD_LUT_4BIT: 4-bit grayscale indexes, 1 byte per element + * @DRM_EPD_LUT_4BIT_PACKED: 4-bit grayscale indexes, 2 bits per element + * @DRM_EPD_LUT_5BIT: 5-bit grayscale indexes, 1 byte per element + * @DRM_EPD_LUT_5BIT_PACKED: 5-bit grayscale indexes, 2 bits per element + */ +enum drm_epd_lut_format { + DRM_EPD_LUT_4BIT, + DRM_EPD_LUT_4BIT_PACKED, + DRM_EPD_LUT_5BIT, + DRM_EPD_LUT_5BIT_PACKED, +}; + +/** + * struct drm_epd_lut_file - Describes a file containing EPD LUTs + * + * @dev: The DRM device owning this LUT file + * @fw: The firmware object holding the raw file contents + * @header: Vendor-specific LUT file header + * @mode_info: Vendor-specific information about available waveforms + */ +struct drm_epd_lut_file { + struct drm_device *dev; + const struct firmware *fw; + const struct pvi_wbf_file_header *header; + const struct pvi_wbf_mode_info *mode_info; +}; + +/** + * struct drm_epd_lut - Describes a particular LUT buffer + * + * @buf: The LUT, in the format requested by the driver + * @file: The file where this LUT was loaded from + * @format: The LUT buffer format needed by the driver + * @max_phases: The maximum number of waveform phases supported by the driver + * @num_phases: The number of waveform phases in the current LUT + * @mode_index: Private identifier for the current waveform + * @temp_index: Private identifier for the current temperature + */ +struct drm_epd_lut { + u8 *buf; + const struct drm_epd_lut_file *file; + enum drm_epd_lut_format format; + unsigned int max_phases; + unsigned int num_phases; + int mode_index; + int temp_index; +}; + +int drmm_epd_lut_file_init(struct drm_device *dev, + struct drm_epd_lut_file *file, + const char *file_name); + +int drmm_epd_lut_init(struct drm_epd_lut_file *file, + struct drm_epd_lut *lut, + enum drm_epd_lut_format format, + unsigned int max_phases); + +int drm_epd_lut_set_temperature(struct drm_epd_lut *lut, + int temperature); +int drm_epd_lut_set_waveform(struct drm_epd_lut *lut, + enum drm_epd_waveform waveform); + +#endif /* __DRM_EPD_HELPER_H__ */ From patchwork Wed Apr 13 22:19:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Holland X-Patchwork-Id: 12812735 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id ED283C433F5 for ; Wed, 13 Apr 2022 22:19:30 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 3883410F132; Wed, 13 Apr 2022 22:19:28 +0000 (UTC) Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by gabe.freedesktop.org (Postfix) with ESMTPS id 4287B10F132 for ; Wed, 13 Apr 2022 22:19:27 +0000 (UTC) Received: from compute2.internal (compute2.nyi.internal [10.202.2.46]) by mailout.nyi.internal (Postfix) with ESMTP id 928445C029A; Wed, 13 Apr 2022 18:19:26 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute2.internal (MEProxy); Wed, 13 Apr 2022 18:19:26 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sholland.org; h= cc:cc:content-transfer-encoding:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm2; t=1649888366; x=1649974766; bh=DL jgBEQ1+1vq/nXxADtpNaSm7RE9fz3MOj06zwzz+gk=; b=tGxVfhfS18dInH3xbp 5sviT7voXBlvIfsRKOFqahGWxhmQ0I45KaxXfmZrHrvHAI05e1mxWLpAcwrTVpE9 l3a2QvebuXT9NEDuEezPLQ0nB722xgb3y6501RJVOo69DNmP+9Dg1wGY1oDbnRBZ zMn6SHaJT4E5Pwvjqixxh2K80zMdS/3Z2etec2NBayR/DE/AEbZFBI1Ao+u5fP4w OBrC0QKxFuerB3CDqoNN6A4srQ9s3g4mCvmgDhm6/yXANvKt0ZRc4U2CrgWi1FQN u40mCxuovnafzAF0kapGjr/WOtXT775Rk3z7LsVDMCUAVkLAgkYLmKvoKATXJ2WN J3zw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1649888366; x=1649974766; bh=DLjgBEQ1+1vq/nXxADtpNaSm7RE9fz3MOj0 6zwzz+gk=; b=eURCH2ejrVMvU8WXiCnab0H5zIEDr6JEIyVuXiSKv3CudCl48P6 0LwWY57vou4hK7qbUaxAk4P31aGRd8p0CgKQg1QHgk/wHBFIasUqKwLNJVREf4uy 0YYkediuIGp29mM79xkN6LbUMANoKLMeAvdeTI/S5IKxhDQjo3XXhnyMGpblWpwS Q8JRniJQn0OzYPhuxUX5zpT0dtnE+8aehBaypiJns0b+coPG2yPqEvXQlp8437W/ vaAJAP2z49t4RFJg8Hvx2QaN9F9pBx5PdLQ5GY2dFr2wxwm1Gmf9peRg70tWviNo N0MkLfh9OLevW1TeGUAyQZhc9iq4W9HFgLA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudelvddguddtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefurghmuhgv lhcujfholhhlrghnugcuoehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhgqeenucggtf frrghtthgvrhhnpeelueelgeettdfggfeuffevkefhuddtteeigfevhfdtffdtjefgteeg leeggedvudenucffohhmrghinhepuggvvhhitggvthhrvggvrdhorhhgnecuvehluhhsth gvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepshgrmhhuvghlsehshhho lhhlrghnugdrohhrgh X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 13 Apr 2022 18:19:25 -0400 (EDT) From: Samuel Holland To: =?utf-8?q?Heiko_St=C3=BCbner?= , Sandy Huang , dri-devel@lists.freedesktop.org Subject: [RFC PATCH 02/16] dt-bindings: display: rockchip: Add EBC binding Date: Wed, 13 Apr 2022 17:19:02 -0500 Message-Id: <20220413221916.50995-3-samuel@sholland.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220413221916.50995-1-samuel@sholland.org> References: <20220413221916.50995-1-samuel@sholland.org> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Airlie , =?utf-8?q?Ond=C5=99ej_Jirman?= , Thierry Reding , Michael Riesch , Sam Ravnborg , Samuel Holland , Nicolas Frattaroli , linux-rockchip@lists.infradead.org, Andreas Kemnade , Geert Uytterhoeven , Liang Chen , devicetree@vger.kernel.org, Thomas Zimmermann , Alistair Francis , Rob Herring , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peter Geis , Krzysztof Kozlowski Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" The Rockchip E-Book Controller (EBC) is a controller for Electrophoretic Displays (EPDs). It is self-contained; it does not interact directly with the VOP or the RGA. While two of the regulator consumers here actually power the display panel, not the EBC hardware, they are consumed here because they are only needed during display refreshes. They do not match the normal panel prepare/enable lifecycle. Signed-off-by: Samuel Holland --- .../display/rockchip/rockchip,rk3568-ebc.yaml | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip,rk3568-ebc.yaml diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3568-ebc.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3568-ebc.yaml new file mode 100644 index 000000000000..957ca874ab02 --- /dev/null +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3568-ebc.yaml @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/rockchip/rockchip,rk3568-ebc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip SoC E-Book Controller (EBC) + +description: + Rockchip EBC is a controller for Electrophoretic Displays (EPDs). + +maintainers: + - Samuel Holland + +properties: + compatible: + enum: + - rockchip,rk3568-ebc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: AHB register clock + - description: Pixel clock + + clock-names: + items: + - const: hclk + - const: dclk + + resets: + items: + - description: hclk domain reset + - description: dclk domain reset + + reset-names: + items: + - const: hclk + - const: dclk + + io-channels: + maxItems: 1 + description: I/O channel for panel temperature measurement + + panel-supply: + description: Regulator supplying the panel's logic voltage + + power-domains: + maxItems: 1 + + vcom-supply: + description: Regulator supplying the panel's compensation voltage + + vdrive-supply: + description: Regulator supplying the panel's gate and source drivers + + port: + $ref: /schemas/graph.yaml#/properties/port + description: OF graph port for the attached display panel + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - resets + - reset-names + - power-domains + - panel-supply + - vcom-supply + - vdrive-supply + +additionalProperties: false + +examples: + - | + #include + #include + #include + + ebc: ebc@fdec0000 { + compatible = "rockchip,rk3568-ebc"; + reg = <0x0 0xfdec0000 0x0 0x5000>; + interrupts = ; + clocks = <&cru HCLK_EBC>, <&cru DCLK_EBC>; + clock-names = "hclk", "dclk"; + resets = <&cru SRST_H_EBC>, <&cru SRST_D_EBC>; + reset-names = "hclk", "dclk"; + power-domains = <&power RK3568_PD_RGA>; + + panel-supply = <&v3p3>; + vcom-supply = <&vcom>; + vdrive-supply = <&vdrive>; + + port { + ebc_out_panel: endpoint { + remote-endpoint = <&panel_in_ebc>; + }; + }; + }; From patchwork Wed Apr 13 22:19:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Holland X-Patchwork-Id: 12812738 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id BFE59C433EF for ; Wed, 13 Apr 2022 22:19:38 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id C1D6110F135; Wed, 13 Apr 2022 22:19:33 +0000 (UTC) Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by gabe.freedesktop.org (Postfix) with ESMTPS id 3D22B10F133 for ; Wed, 13 Apr 2022 22:19:29 +0000 (UTC) Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.nyi.internal (Postfix) with ESMTP id 88BA75C02A2; Wed, 13 Apr 2022 18:19:28 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute5.internal (MEProxy); Wed, 13 Apr 2022 18:19:28 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sholland.org; h= cc:cc:content-transfer-encoding:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm2; t=1649888368; x=1649974768; bh=6N qnJ9jKDQ/Xs7NgHGQxK5zygVx2tcQm+rl1IErNHA0=; b=a851i311nxtGUGtaje ScJ+eeFgcEb/7Y/AlDmMtI8g44vKG38oWKO9UdyIbWivhJyAxDZo/ArZ8cDE3VsU IYBRXtmjQ6NPJ/kG7OHG/XHRg+GnxBxMWrjdqjgE5Cd2yAlObp5VQxdGIdEj9AiU vXvEY5WWrclwPkUJLJfHaXIs0rxZNlqDhzslG+HtoXY7Il0/MdOl0mSpYT3VwezX BH3eHiw78BzpvJA1FsiPkhnLEeR81Hy1QnV2yckUnsOVO7kqdBtLxjlLn28x2wc7 2cJAiKUJLgtBYUjfAtKUvQJsLORbgSWftlBfxPViXjhZVGp3yZo7fi6OllYgJOAI 7T1A== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1649888368; x=1649974768; bh=6NqnJ9jKDQ/Xs7NgHGQxK5zygVx2tcQm+rl 1IErNHA0=; b=Padv7h6gqp/NJaBPdkO9MFAkBteb8Oo24lDb3Jmq1ZJGPEUCzqh FP5K21hLr1gYtpJQ5IFX7pjbZ5pfVxG864TP2cXuNwgrS8OvVBRp9j6bkbfp4kbp dAV71Tm+3ikA4hU46Ve51f7//0CMhhJeI5LjnNqNflKVxsOL9om/3WalAV7TX1HF RdI8NDSqWoDEbwczA6eO0iXb7IpMZLcYT7u2dAwWo8/AmtaY/WJJnxJ0cfxYoRx7 X/GQp9/X+qlpTwXtrX+4ghXhZkMUHn2ryfOZnbvBbUs6o0l6fapVUso3YQB/szxm OiCPF/XE+9ViV6vDdGgwDdfLc9EDcrDa6Ow== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudelvddgtdelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefurghmuhgv lhcujfholhhlrghnugcuoehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhgqeenucggtf frrghtthgvrhhnpeduhfejfedvhffgfeehtefghfeiiefgfeehgfdvvdevfeegjeehjedv gfejheeuieenucevlhhushhtvghrufhiiigvpedunecurfgrrhgrmhepmhgrihhlfhhroh hmpehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhg X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 13 Apr 2022 18:19:27 -0400 (EDT) From: Samuel Holland To: =?utf-8?q?Heiko_St=C3=BCbner?= , Sandy Huang , dri-devel@lists.freedesktop.org Subject: [RFC PATCH 03/16] drm/rockchip: Add EBC platform driver skeleton Date: Wed, 13 Apr 2022 17:19:03 -0500 Message-Id: <20220413221916.50995-4-samuel@sholland.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220413221916.50995-1-samuel@sholland.org> References: <20220413221916.50995-1-samuel@sholland.org> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Airlie , =?utf-8?q?Ond=C5=99ej_Jirman?= , Thierry Reding , Michael Riesch , Sam Ravnborg , Samuel Holland , Nicolas Frattaroli , linux-rockchip@lists.infradead.org, Andreas Kemnade , Geert Uytterhoeven , Liang Chen , devicetree@vger.kernel.org, Thomas Zimmermann , Alistair Francis , Rob Herring , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peter Geis , Krzysztof Kozlowski Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" The Rockchip E-Book Controller (EBC) is a timing controller (TCON) responsible for sending timing signals and pixel update waveforms to an electrophoretic display (EPD). The EBC has several modes of operation. In direct mode, it reads precomputed source driver polarity data from a series of buffers in RAM. In the other modes, it reads pixel luminance data from RAM, and uses a lookup table (LUT) to compute the source driver polarity for each phase within the waveform. This commit adds a platform driver skeleton for the EBC, containing the IRQ handler and runtime PM hooks. The EBC only needs to be powered up when the display is actively being refreshed. regcache is used to allow configuration changes (i.e. modeset) while the EBC is powered down. While two of the regulator consumers here actually power the display panel, not the EBC hardware, they are consumed here because again they are only needed during display refreshes. They do not match the normal panel prepare/enable lifecycle. Signed-off-by: Samuel Holland --- drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/rockchip/Kconfig | 11 + drivers/gpu/drm/rockchip/Makefile | 2 + drivers/gpu/drm/rockchip/rockchip_ebc.c | 324 ++++++++++++++++++++++++ 4 files changed, 338 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/rockchip/rockchip_ebc.c diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 49380ccfe9d6..e940f81a2acf 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -93,7 +93,7 @@ obj-$(CONFIG_DRM_VGEM) += vgem/ obj-$(CONFIG_DRM_VKMS) += vkms/ obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/ obj-$(CONFIG_DRM_EXYNOS) +=exynos/ -obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/ +obj-y +=rockchip/ obj-$(CONFIG_DRM_GMA500) += gma500/ obj-$(CONFIG_DRM_UDL) += udl/ obj-$(CONFIG_DRM_AST) += ast/ diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index fa5cfda4e90e..9d3273a5fd97 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -91,3 +91,14 @@ config ROCKCHIP_RK3066_HDMI for the RK3066 HDMI driver. If you want to enable HDMI on RK3066 based SoC, you should select this option. endif + +config DRM_ROCKCHIP_EBC + tristate "DRM Support for Rockchip EBC" + depends on DRM + select DRM_GEM_SHMEM_HELPER + select DRM_KMS_HELPER + help + This selects DRM/KMS support for the Rockchip E-Book Controller (EBC). + Choose this option if you have a Rockchip SoC and an electrophoretic + display. This hardware and driver is separate from the normal Rockchip + display hardware and DRM driver. diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 1a56f696558c..e3accc526438 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -16,3 +16,5 @@ rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o rockchipdrm-$(CONFIG_ROCKCHIP_RK3066_HDMI) += rk3066_hdmi.o obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o + +obj-$(CONFIG_DRM_ROCKCHIP_EBC) += rockchip_ebc.o diff --git a/drivers/gpu/drm/rockchip/rockchip_ebc.c b/drivers/gpu/drm/rockchip/rockchip_ebc.c new file mode 100644 index 000000000000..5ed66c6cd2f0 --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_ebc.c @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021-2022 Samuel Holland + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define EBC_DSP_START 0x0000 +#define EBC_DSP_START_DSP_OUT_LOW BIT(31) +#define EBC_DSP_START_DSP_SDCE_WIDTH(x) ((x) << 16) +#define EBC_DSP_START_DSP_EINK_MODE BIT(13) +#define EBC_DSP_START_SW_BURST_CTRL BIT(12) +#define EBC_DSP_START_DSP_FRM_TOTAL(x) ((x) << 2) +#define EBC_DSP_START_DSP_RST BIT(1) +#define EBC_DSP_START_DSP_FRM_START BIT(0) +#define EBC_EPD_CTRL 0x0004 +#define EBC_EPD_CTRL_EINK_MODE_SWAP BIT(31) +#define EBC_EPD_CTRL_DSP_GD_END(x) ((x) << 16) +#define EBC_EPD_CTRL_DSP_GD_ST(x) ((x) << 8) +#define EBC_EPD_CTRL_DSP_THREE_WIN_MODE BIT(7) +#define EBC_EPD_CTRL_DSP_SDDW_MODE BIT(6) +#define EBC_EPD_CTRL_EPD_AUO BIT(5) +#define EBC_EPD_CTRL_EPD_PWR(x) ((x) << 2) +#define EBC_EPD_CTRL_EPD_GDRL BIT(1) +#define EBC_EPD_CTRL_EPD_SDSHR BIT(0) +#define EBC_DSP_CTRL 0x0008 +#define EBC_DSP_CTRL_DSP_SWAP_MODE(x) ((x) << 30) +#define EBC_DSP_CTRL_DSP_DIFF_MODE BIT(29) +#define EBC_DSP_CTRL_DSP_LUT_MODE BIT(28) +#define EBC_DSP_CTRL_DSP_VCOM_MODE BIT(27) +#define EBC_DSP_CTRL_DSP_GDOE_POL BIT(26) +#define EBC_DSP_CTRL_DSP_GDSP_POL BIT(25) +#define EBC_DSP_CTRL_DSP_GDCLK_POL BIT(24) +#define EBC_DSP_CTRL_DSP_SDCE_POL BIT(23) +#define EBC_DSP_CTRL_DSP_SDOE_POL BIT(22) +#define EBC_DSP_CTRL_DSP_SDLE_POL BIT(21) +#define EBC_DSP_CTRL_DSP_SDCLK_POL BIT(20) +#define EBC_DSP_CTRL_DSP_SDCLK_DIV(x) ((x) << 16) +#define EBC_DSP_CTRL_DSP_BACKGROUND(x) ((x) << 0) +#define EBC_DSP_HTIMING0 0x000c +#define EBC_DSP_HTIMING0_DSP_HTOTAL(x) ((x) << 16) +#define EBC_DSP_HTIMING0_DSP_HS_END(x) ((x) << 0) +#define EBC_DSP_HTIMING1 0x0010 +#define EBC_DSP_HTIMING1_DSP_HACT_END(x) ((x) << 16) +#define EBC_DSP_HTIMING1_DSP_HACT_ST(x) ((x) << 0) +#define EBC_DSP_VTIMING0 0x0014 +#define EBC_DSP_VTIMING0_DSP_VTOTAL(x) ((x) << 16) +#define EBC_DSP_VTIMING0_DSP_VS_END(x) ((x) << 0) +#define EBC_DSP_VTIMING1 0x0018 +#define EBC_DSP_VTIMING1_DSP_VACT_END(x) ((x) << 16) +#define EBC_DSP_VTIMING1_DSP_VACT_ST(x) ((x) << 0) +#define EBC_DSP_ACT_INFO 0x001c +#define EBC_DSP_ACT_INFO_DSP_HEIGHT(x) ((x) << 16) +#define EBC_DSP_ACT_INFO_DSP_WIDTH(x) ((x) << 0) +#define EBC_WIN_CTRL 0x0020 +#define EBC_WIN_CTRL_WIN2_FIFO_THRESHOLD(x) ((x) << 19) +#define EBC_WIN_CTRL_WIN_EN BIT(18) +#define EBC_WIN_CTRL_AHB_INCR_NUM_REG(x) ((x) << 13) +#define EBC_WIN_CTRL_AHB_BURST_REG(x) ((x) << 10) +#define EBC_WIN_CTRL_WIN_FIFO_THRESHOLD(x) ((x) << 2) +#define EBC_WIN_CTRL_WIN_FMT_Y4 (0x0 << 0) +#define EBC_WIN_CTRL_WIN_FMT_Y8 (0x1 << 0) +#define EBC_WIN_CTRL_WIN_FMT_XRGB8888 (0x2 << 0) +#define EBC_WIN_CTRL_WIN_FMT_RGB565 (0x3 << 0) +#define EBC_WIN_MST0 0x0024 +#define EBC_WIN_MST1 0x0028 +#define EBC_WIN_VIR 0x002c +#define EBC_WIN_VIR_WIN_VIR_HEIGHT(x) ((x) << 16) +#define EBC_WIN_VIR_WIN_VIR_WIDTH(x) ((x) << 0) +#define EBC_WIN_ACT 0x0030 +#define EBC_WIN_ACT_WIN_ACT_HEIGHT(x) ((x) << 16) +#define EBC_WIN_ACT_WIN_ACT_WIDTH(x) ((x) << 0) +#define EBC_WIN_DSP 0x0034 +#define EBC_WIN_DSP_WIN_DSP_HEIGHT(x) ((x) << 16) +#define EBC_WIN_DSP_WIN_DSP_WIDTH(x) ((x) << 0) +#define EBC_WIN_DSP_ST 0x0038 +#define EBC_WIN_DSP_ST_WIN_DSP_YST(x) ((x) << 16) +#define EBC_WIN_DSP_ST_WIN_DSP_XST(x) ((x) << 0) +#define EBC_INT_STATUS 0x003c +#define EBC_INT_STATUS_DSP_FRM_INT_NUM(x) ((x) << 12) +#define EBC_INT_STATUS_LINE_FLAG_INT_CLR BIT(11) +#define EBC_INT_STATUS_DSP_FRM_INT_CLR BIT(10) +#define EBC_INT_STATUS_DSP_END_INT_CLR BIT(9) +#define EBC_INT_STATUS_FRM_END_INT_CLR BIT(8) +#define EBC_INT_STATUS_LINE_FLAG_INT_MSK BIT(7) +#define EBC_INT_STATUS_DSP_FRM_INT_MSK BIT(6) +#define EBC_INT_STATUS_DSP_END_INT_MSK BIT(5) +#define EBC_INT_STATUS_FRM_END_INT_MSK BIT(4) +#define EBC_INT_STATUS_LINE_FLAG_INT_ST BIT(3) +#define EBC_INT_STATUS_DSP_FRM_INT_ST BIT(2) +#define EBC_INT_STATUS_DSP_END_INT_ST BIT(1) +#define EBC_INT_STATUS_FRM_END_INT_ST BIT(0) +#define EBC_VCOM0 0x0040 +#define EBC_VCOM1 0x0044 +#define EBC_VCOM2 0x0048 +#define EBC_VCOM3 0x004c +#define EBC_CONFIG_DONE 0x0050 +#define EBC_CONFIG_DONE_REG_CONFIG_DONE BIT(0) +#define EBC_VNUM 0x0054 +#define EBC_VNUM_DSP_VCNT(x) ((x) << 16) +#define EBC_VNUM_LINE_FLAG_NUM(x) ((x) << 0) +#define EBC_WIN_MST2 0x0058 +#define EBC_LUT_DATA 0x1000 + +#define EBC_NUM_LUT_REGS 0x1000 +#define EBC_NUM_SUPPLIES 3 + +#define EBC_SUSPEND_DELAY_MS 2000 + +struct rockchip_ebc { + struct clk *dclk; + struct clk *hclk; + struct completion display_end; + struct regmap *regmap; + struct regulator_bulk_data supplies[EBC_NUM_SUPPLIES]; +}; + +static int rockchip_ebc_runtime_suspend(struct device *dev) +{ + struct rockchip_ebc *ebc = dev_get_drvdata(dev); + + regcache_cache_only(ebc->regmap, true); + + clk_disable_unprepare(ebc->dclk); + clk_disable_unprepare(ebc->hclk); + regulator_bulk_disable(EBC_NUM_SUPPLIES, ebc->supplies); + + return 0; +} + +static int rockchip_ebc_runtime_resume(struct device *dev) +{ + struct rockchip_ebc *ebc = dev_get_drvdata(dev); + int ret; + + ret = regulator_bulk_enable(EBC_NUM_SUPPLIES, ebc->supplies); + if (ret) + return ret; + + ret = clk_prepare_enable(ebc->hclk); + if (ret) + goto err_disable_supplies; + + ret = clk_prepare_enable(ebc->dclk); + if (ret) + goto err_disable_hclk; + + regcache_cache_only(ebc->regmap, false); + regcache_mark_dirty(ebc->regmap); + regcache_sync(ebc->regmap); + + regmap_write(ebc->regmap, EBC_INT_STATUS, + EBC_INT_STATUS_DSP_END_INT_CLR | + EBC_INT_STATUS_LINE_FLAG_INT_MSK | + EBC_INT_STATUS_DSP_FRM_INT_MSK | + EBC_INT_STATUS_FRM_END_INT_MSK); + + return 0; + +err_disable_hclk: + clk_disable_unprepare(ebc->hclk); +err_disable_supplies: + regulator_bulk_disable(EBC_NUM_SUPPLIES, ebc->supplies); + + return ret; +} + +static const struct dev_pm_ops rockchip_ebc_dev_pm_ops = { + SET_RUNTIME_PM_OPS(rockchip_ebc_runtime_suspend, + rockchip_ebc_runtime_resume, NULL) +}; + +static bool rockchip_ebc_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case EBC_DSP_START: + case EBC_INT_STATUS: + case EBC_CONFIG_DONE: + case EBC_VNUM: + return true; + default: + /* Do not cache the LUT registers. */ + return reg > EBC_WIN_MST2; + } +} + +static const struct regmap_config rockchip_ebc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .volatile_reg = rockchip_ebc_volatile_reg, + .max_register = 0x4ffc, /* end of EBC_LUT_DATA */ + .cache_type = REGCACHE_FLAT, +}; + +static const char *const rockchip_ebc_supplies[EBC_NUM_SUPPLIES] = { + "panel", + "vcom", + "vdrive", +}; + +static irqreturn_t rockchip_ebc_irq(int irq, void *dev_id) +{ + struct rockchip_ebc *ebc = dev_id; + unsigned int status; + + regmap_read(ebc->regmap, EBC_INT_STATUS, &status); + + if (status & EBC_INT_STATUS_DSP_END_INT_ST) { + status |= EBC_INT_STATUS_DSP_END_INT_CLR; + complete(&ebc->display_end); + } + + regmap_write(ebc->regmap, EBC_INT_STATUS, status); + + return IRQ_HANDLED; +} + +static int rockchip_ebc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rockchip_ebc *ebc; + void __iomem *base; + int i, ret; + + ebc = devm_kzalloc(dev, sizeof(*ebc), GFP_KERNEL); + if (!ebc) + return -ENOMEM; + + platform_set_drvdata(pdev, ebc); + init_completion(&ebc->display_end); + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + ebc->regmap = devm_regmap_init_mmio(dev, base, + &rockchip_ebc_regmap_config); + if (IS_ERR(ebc->regmap)) + return PTR_ERR(ebc->regmap); + + regcache_cache_only(ebc->regmap, true); + + ebc->dclk = devm_clk_get(dev, "dclk"); + if (IS_ERR(ebc->dclk)) + return dev_err_probe(dev, PTR_ERR(ebc->dclk), + "Failed to get dclk\n"); + + ebc->hclk = devm_clk_get(dev, "hclk"); + if (IS_ERR(ebc->hclk)) + return dev_err_probe(dev, PTR_ERR(ebc->hclk), + "Failed to get hclk\n"); + + for (i = 0; i < EBC_NUM_SUPPLIES; i++) + ebc->supplies[i].supply = rockchip_ebc_supplies[i]; + + ret = devm_regulator_bulk_get(dev, EBC_NUM_SUPPLIES, ebc->supplies); + if (ret) + return dev_err_probe(dev, ret, "Failed to get supplies\n"); + + ret = devm_request_irq(dev, platform_get_irq(pdev, 0), + rockchip_ebc_irq, 0, dev_name(dev), ebc); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to request IRQ\n"); + + pm_runtime_set_autosuspend_delay(dev, EBC_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(dev); + pm_runtime_enable(dev); + if (!pm_runtime_enabled(dev)) { + ret = rockchip_ebc_runtime_resume(&pdev->dev); + if (ret) + return ret; + } + + return 0; +} + +static int rockchip_ebc_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + + pm_runtime_disable(dev); + if (!pm_runtime_status_suspended(dev)) + rockchip_ebc_runtime_suspend(dev); + + return 0; +} + +static void rockchip_ebc_shutdown(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + + if (!pm_runtime_status_suspended(dev)) + rockchip_ebc_runtime_suspend(dev); +} + +static const struct of_device_id rockchip_ebc_of_match[] = { + { .compatible = "rockchip,rk3568-ebc" }, + { } +}; +MODULE_DEVICE_TABLE(of, rockchip_ebc_of_match); + +static struct platform_driver rockchip_ebc_driver = { + .probe = rockchip_ebc_probe, + .remove = rockchip_ebc_remove, + .shutdown = rockchip_ebc_shutdown, + .driver = { + .name = "rockchip-ebc", + .of_match_table = rockchip_ebc_of_match, + .pm = &rockchip_ebc_dev_pm_ops, + }, +}; +module_platform_driver(rockchip_ebc_driver); + +MODULE_AUTHOR("Samuel Holland "); +MODULE_DESCRIPTION("Rockchip EBC driver"); +MODULE_LICENSE("GPL"); From patchwork Wed Apr 13 22:19:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Holland X-Patchwork-Id: 12812737 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 8A4BCC433F5 for ; Wed, 13 Apr 2022 22:19:36 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 9DDCC10F133; Wed, 13 Apr 2022 22:19:33 +0000 (UTC) Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by gabe.freedesktop.org (Postfix) with ESMTPS id 28CAF10F133 for ; Wed, 13 Apr 2022 22:19:31 +0000 (UTC) Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.nyi.internal (Postfix) with ESMTP id 769015C031C; Wed, 13 Apr 2022 18:19:30 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute4.internal (MEProxy); Wed, 13 Apr 2022 18:19:30 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sholland.org; h= cc:cc:content-transfer-encoding:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm2; t=1649888370; x=1649974770; bh=li VdDnZWRFN/01EDWJ04iBIR5q+lQrzOvuZ68gkGyyw=; b=oDd7p6QrclsdB2kEr+ b4VXLYx8zVfp6/GGPo20iFE9nO19iLxL60kn/u+BFK43vwaL2BEIAcUicxjZHxNE OltBlAHGzFxh57XwjsNHlsHstZwc2PYrHsXBm5TZkXO0h31lro2PHOUPmkzOvrYD XBNy4Q0wgJQLnLltqB6YGQhT9TezApB6qXSl0+6u0eXjljLGKstN3rQ4ZAH/+XAg C9swaIMLkCb0IG2ohUCBEhrNSubzOCxiE1cU67Yp3ooxrqTPZLYWuAxKKsDMXlVI xEh9redb5YACaA6M9Yojq/vChXeADcP1dzuZ9Qn832n0wCPJWYeZDBd9nwQBrV14 2+HQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1649888370; x=1649974770; bh=liVdDnZWRFN/01EDWJ04iBIR5q+lQrzOvuZ 68gkGyyw=; b=m5N3aDVtE1a1pPJ6sChRefOD8H8bwexJlBtFeBquBiTqGWJf3hr XX0CeZnFDLknqQMb4B/OlNM8pCEgCsvxhEcWwcxdbqRSFjbHIp4Ui+sod4gphPzi /RT7YwkPbeLri8BKZasQf0pdkchph/5c0M0ru/SH6lf7KFo4IJ/MIAAztUzkhLrS lnFiRJmKMwlDTPDBiIV7f5g6ZG2DHEr000Kyeipm0vVqXATApe5XjE3kFoZEnqJP sWlfnGk1UhB8jKILM79N8wcWnq3RsfY1rnOQ/QstXHIk8VEA+UpFVBCZfUmk+y1X ICvmIvrkjUYYJvXwVPSkkpmCu15ZbonD8hg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudelvddgtdelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefurghmuhgv lhcujfholhhlrghnugcuoehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhgqeenucggtf frrghtthgvrhhnpeduhfejfedvhffgfeehtefghfeiiefgfeehgfdvvdevfeegjeehjedv gfejheeuieenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhroh hmpehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhg X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 13 Apr 2022 18:19:29 -0400 (EDT) From: Samuel Holland To: =?utf-8?q?Heiko_St=C3=BCbner?= , Sandy Huang , dri-devel@lists.freedesktop.org Subject: [RFC PATCH 04/16] drm/rockchip: ebc: Add DRM driver skeleton Date: Wed, 13 Apr 2022 17:19:04 -0500 Message-Id: <20220413221916.50995-5-samuel@sholland.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220413221916.50995-1-samuel@sholland.org> References: <20220413221916.50995-1-samuel@sholland.org> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Airlie , =?utf-8?q?Ond=C5=99ej_Jirman?= , Thierry Reding , Michael Riesch , Sam Ravnborg , Samuel Holland , Nicolas Frattaroli , linux-rockchip@lists.infradead.org, Andreas Kemnade , Geert Uytterhoeven , Liang Chen , devicetree@vger.kernel.org, Thomas Zimmermann , Alistair Francis , Rob Herring , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peter Geis , Krzysztof Kozlowski Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" The Rockchip E-Book Controller (EBC) has a relatively simple and self- contained display pipeline. The pipeline consists of a single CRTC, encoder, and bridge, with the bridge normally attached to a panel. Initially, there is also a single plane. Since all blitting is done in software, the driver could eventually support any number of planes. For example, it could expose one plane for each supported waveform. However, EPD controller hardware has some unique properties which complicate using drm_simple_display_pipe: - EPDs operate on relative pixel values, not absolute pixel values. This requires the driver to maintain multiple shadow buffers for the "previous" and "next" framebuffer contents. - It also means that disabling the CRTC (i.e. clearing the screen) requires access to these shadow buffers, as it requires knowing the previous contents of the framebuffer. And of course it requires a buffer for the blank image. - Atomically managing these shadow buffers needs reference counting in .atomic_check. However, drm_simple_display_pipe_funcs::check is only called while the plane is visible, complicating this. - Furthermore, because all plane blitting/blending must be done in software, the number and location of these planes is arbitrary. drm_simple_display_pipe enforces an unnecessary limitation that a single plane covers the entire CRTC. For these reasons, drm_simple_display_pipe is not used. This commit adds the structure for this pipeline. The atomic helper callbacks are left empty. They will be filled in incrementally by the next several commits. Both the CRTC and the pipe need extra state information, so this commit adds the state hook boilerplate. Additionally, the plane takes advantage of the shadow plane helpers. Signed-off-by: Samuel Holland --- drivers/gpu/drm/rockchip/rockchip_ebc.c | 359 +++++++++++++++++++++++- 1 file changed, 356 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_ebc.c b/drivers/gpu/drm/rockchip/rockchip_ebc.c index 5ed66c6cd2f0..f75fd23adda2 100644 --- a/drivers/gpu/drm/rockchip/rockchip_ebc.c +++ b/drivers/gpu/drm/rockchip/rockchip_ebc.c @@ -12,6 +12,17 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #define EBC_DSP_START 0x0000 #define EBC_DSP_START_DSP_OUT_LOW BIT(31) #define EBC_DSP_START_DSP_SDCE_WIDTH(x) ((x) << 16) @@ -118,10 +129,332 @@ struct rockchip_ebc { struct clk *dclk; struct clk *hclk; struct completion display_end; + struct drm_crtc crtc; + struct drm_device drm; + struct drm_encoder encoder; + struct drm_plane plane; struct regmap *regmap; struct regulator_bulk_data supplies[EBC_NUM_SUPPLIES]; }; +DEFINE_DRM_GEM_FOPS(rockchip_ebc_fops); + +static const struct drm_driver rockchip_ebc_drm_driver = { + .lastclose = drm_fb_helper_lastclose, + DRM_GEM_SHMEM_DRIVER_OPS, + .major = 0, + .minor = 3, + .name = "rockchip-ebc", + .desc = "Rockchip E-Book Controller", + .date = "20220303", + .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET, + .fops = &rockchip_ebc_fops, +}; + +static const struct drm_mode_config_funcs rockchip_ebc_mode_config_funcs = { + .fb_create = drm_gem_fb_create_with_dirty, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +/* + * CRTC + */ + +struct ebc_crtc_state { + struct drm_crtc_state base; +}; + +static inline struct ebc_crtc_state * +to_ebc_crtc_state(struct drm_crtc_state *crtc_state) +{ + return container_of(crtc_state, struct ebc_crtc_state, base); +} + +static inline struct rockchip_ebc *crtc_to_ebc(struct drm_crtc *crtc) +{ + return container_of(crtc, struct rockchip_ebc, crtc); +} + +static void rockchip_ebc_crtc_mode_set_nofb(struct drm_crtc *crtc) +{ +} + +static int rockchip_ebc_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + return 0; +} + +static void rockchip_ebc_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ +} + +static void rockchip_ebc_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ +} + +static void rockchip_ebc_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ +} + +static const struct drm_crtc_helper_funcs rockchip_ebc_crtc_helper_funcs = { + .mode_set_nofb = rockchip_ebc_crtc_mode_set_nofb, + .atomic_check = rockchip_ebc_crtc_atomic_check, + .atomic_flush = rockchip_ebc_crtc_atomic_flush, + .atomic_enable = rockchip_ebc_crtc_atomic_enable, + .atomic_disable = rockchip_ebc_crtc_atomic_disable, +}; + +static void rockchip_ebc_crtc_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *crtc_state); + +static void rockchip_ebc_crtc_reset(struct drm_crtc *crtc) +{ + struct ebc_crtc_state *ebc_crtc_state; + + if (crtc->state) + rockchip_ebc_crtc_destroy_state(crtc, crtc->state); + + ebc_crtc_state = kzalloc(sizeof(*ebc_crtc_state), GFP_KERNEL); + if (!ebc_crtc_state) + return; + + __drm_atomic_helper_crtc_reset(crtc, &ebc_crtc_state->base); +} + +static struct drm_crtc_state * +rockchip_ebc_crtc_duplicate_state(struct drm_crtc *crtc) +{ + struct ebc_crtc_state *ebc_crtc_state; + + if (!crtc->state) + return NULL; + + ebc_crtc_state = kzalloc(sizeof(*ebc_crtc_state), GFP_KERNEL); + if (!ebc_crtc_state) + return NULL; + + __drm_atomic_helper_crtc_duplicate_state(crtc, &ebc_crtc_state->base); + + return &ebc_crtc_state->base; +} + +static void rockchip_ebc_crtc_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *crtc_state) +{ + struct ebc_crtc_state *ebc_crtc_state = to_ebc_crtc_state(crtc_state); + + __drm_atomic_helper_crtc_destroy_state(&ebc_crtc_state->base); + + kfree(ebc_crtc_state); +} + +static const struct drm_crtc_funcs rockchip_ebc_crtc_funcs = { + .reset = rockchip_ebc_crtc_reset, + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .atomic_duplicate_state = rockchip_ebc_crtc_duplicate_state, + .atomic_destroy_state = rockchip_ebc_crtc_destroy_state, +}; + +/* + * Plane + */ + +struct ebc_plane_state { + struct drm_shadow_plane_state base; +}; + +static inline struct ebc_plane_state * +to_ebc_plane_state(struct drm_plane_state *plane_state) +{ + return container_of(plane_state, struct ebc_plane_state, base.base); +} + +static inline struct rockchip_ebc *plane_to_ebc(struct drm_plane *plane) +{ + return container_of(plane, struct rockchip_ebc, plane); +} + +static int rockchip_ebc_plane_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *plane_state; + struct drm_crtc_state *crtc_state; + int ret; + + plane_state = drm_atomic_get_new_plane_state(state, plane); + if (!plane_state->crtc) + return 0; + + crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc); + ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + true, true); + if (ret) + return ret; + + return 0; +} + +static void rockchip_ebc_plane_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *state) +{ +} + +static const struct drm_plane_helper_funcs rockchip_ebc_plane_helper_funcs = { + .prepare_fb = drm_gem_prepare_shadow_fb, + .cleanup_fb = drm_gem_cleanup_shadow_fb, + .atomic_check = rockchip_ebc_plane_atomic_check, + .atomic_update = rockchip_ebc_plane_atomic_update, +}; + +static void rockchip_ebc_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *plane_state); + +static void rockchip_ebc_plane_reset(struct drm_plane *plane) +{ + struct ebc_plane_state *ebc_plane_state; + + if (plane->state) + rockchip_ebc_plane_destroy_state(plane, plane->state); + + ebc_plane_state = kzalloc(sizeof(*ebc_plane_state), GFP_KERNEL); + if (!ebc_plane_state) + return; + + __drm_gem_reset_shadow_plane(plane, &ebc_plane_state->base); +} + +static struct drm_plane_state * +rockchip_ebc_plane_duplicate_state(struct drm_plane *plane) +{ + struct ebc_plane_state *ebc_plane_state; + + if (!plane->state) + return NULL; + + ebc_plane_state = kzalloc(sizeof(*ebc_plane_state), GFP_KERNEL); + if (!ebc_plane_state) + return NULL; + + __drm_gem_duplicate_shadow_plane_state(plane, &ebc_plane_state->base); + + return &ebc_plane_state->base.base; +} + +static void rockchip_ebc_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *plane_state) +{ + struct ebc_plane_state *ebc_plane_state = to_ebc_plane_state(plane_state); + + __drm_gem_destroy_shadow_plane_state(&ebc_plane_state->base); + + kfree(ebc_plane_state); +} + +static const struct drm_plane_funcs rockchip_ebc_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = rockchip_ebc_plane_reset, + .atomic_duplicate_state = rockchip_ebc_plane_duplicate_state, + .atomic_destroy_state = rockchip_ebc_plane_destroy_state, +}; + +static const u32 rockchip_ebc_plane_formats[] = { + DRM_FORMAT_XRGB8888, +}; + +static const u64 rockchip_ebc_plane_format_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +static int rockchip_ebc_drm_init(struct rockchip_ebc *ebc) +{ + struct drm_device *drm = &ebc->drm; + struct drm_bridge *bridge; + int ret; + + ret = drmm_mode_config_init(drm); + if (ret) + return ret; + + drm->mode_config.max_width = DRM_SHADOW_PLANE_MAX_WIDTH; + drm->mode_config.max_height = DRM_SHADOW_PLANE_MAX_HEIGHT; + drm->mode_config.funcs = &rockchip_ebc_mode_config_funcs; + drm->mode_config.quirk_addfb_prefer_host_byte_order = true; + + drm_plane_helper_add(&ebc->plane, &rockchip_ebc_plane_helper_funcs); + ret = drm_universal_plane_init(drm, &ebc->plane, 0, + &rockchip_ebc_plane_funcs, + rockchip_ebc_plane_formats, + ARRAY_SIZE(rockchip_ebc_plane_formats), + rockchip_ebc_plane_format_modifiers, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + + drm_plane_enable_fb_damage_clips(&ebc->plane); + + drm_crtc_helper_add(&ebc->crtc, &rockchip_ebc_crtc_helper_funcs); + ret = drm_crtc_init_with_planes(drm, &ebc->crtc, &ebc->plane, NULL, + &rockchip_ebc_crtc_funcs, NULL); + if (ret) + return ret; + + ebc->encoder.possible_crtcs = drm_crtc_mask(&ebc->crtc); + ret = drm_simple_encoder_init(drm, &ebc->encoder, DRM_MODE_ENCODER_NONE); + if (ret) + return ret; + + bridge = devm_drm_of_get_bridge(drm->dev, drm->dev->of_node, 0, 0); + if (IS_ERR(bridge)) + return PTR_ERR(bridge); + + ret = drm_bridge_attach(&ebc->encoder, bridge, NULL, 0); + if (ret) + return ret; + + drm_mode_config_reset(drm); + + ret = drm_dev_register(drm, 0); + if (ret) + return ret; + + drm_fbdev_generic_setup(drm, 0); + + return 0; +} + +static int __maybe_unused rockchip_ebc_suspend(struct device *dev) +{ + struct rockchip_ebc *ebc = dev_get_drvdata(dev); + int ret; + + ret = drm_mode_config_helper_suspend(&ebc->drm); + if (ret) + return ret; + + return pm_runtime_force_suspend(dev); +} + +static int __maybe_unused rockchip_ebc_resume(struct device *dev) +{ + struct rockchip_ebc *ebc = dev_get_drvdata(dev); + + pm_runtime_force_resume(dev); + + return drm_mode_config_helper_resume(&ebc->drm); +} + static int rockchip_ebc_runtime_suspend(struct device *dev) { struct rockchip_ebc *ebc = dev_get_drvdata(dev); @@ -173,6 +506,7 @@ static int rockchip_ebc_runtime_resume(struct device *dev) } static const struct dev_pm_ops rockchip_ebc_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(rockchip_ebc_suspend, rockchip_ebc_resume) SET_RUNTIME_PM_OPS(rockchip_ebc_runtime_suspend, rockchip_ebc_runtime_resume, NULL) }; @@ -230,9 +564,10 @@ static int rockchip_ebc_probe(struct platform_device *pdev) void __iomem *base; int i, ret; - ebc = devm_kzalloc(dev, sizeof(*ebc), GFP_KERNEL); - if (!ebc) - return -ENOMEM; + ebc = devm_drm_dev_alloc(dev, &rockchip_ebc_drm_driver, + struct rockchip_ebc, drm); + if (IS_ERR(ebc)) + return PTR_ERR(ebc); platform_set_drvdata(pdev, ebc); init_completion(&ebc->display_end); @@ -279,13 +614,28 @@ static int rockchip_ebc_probe(struct platform_device *pdev) return ret; } + ret = rockchip_ebc_drm_init(ebc); + if (ret) + goto err_disable_pm; + return 0; + +err_disable_pm: + pm_runtime_disable(dev); + if (!pm_runtime_status_suspended(dev)) + rockchip_ebc_runtime_suspend(dev); + + return ret; } static int rockchip_ebc_remove(struct platform_device *pdev) { + struct rockchip_ebc *ebc = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; + drm_dev_unregister(&ebc->drm); + drm_atomic_helper_shutdown(&ebc->drm); + pm_runtime_disable(dev); if (!pm_runtime_status_suspended(dev)) rockchip_ebc_runtime_suspend(dev); @@ -295,8 +645,11 @@ static int rockchip_ebc_remove(struct platform_device *pdev) static void rockchip_ebc_shutdown(struct platform_device *pdev) { + struct rockchip_ebc *ebc = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; + drm_atomic_helper_shutdown(&ebc->drm); + if (!pm_runtime_status_suspended(dev)) rockchip_ebc_runtime_suspend(dev); } From patchwork Wed Apr 13 22:19:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Holland X-Patchwork-Id: 12812743 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 24CE8C433EF for ; Wed, 13 Apr 2022 22:19:53 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 81D0910F153; Wed, 13 Apr 2022 22:19:51 +0000 (UTC) Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by gabe.freedesktop.org (Postfix) with ESMTPS id 0F61610F133 for ; Wed, 13 Apr 2022 22:19:33 +0000 (UTC) Received: from compute2.internal (compute2.nyi.internal [10.202.2.46]) by mailout.nyi.internal (Postfix) with ESMTP id 5BB705C0323; Wed, 13 Apr 2022 18:19:32 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute2.internal (MEProxy); Wed, 13 Apr 2022 18:19:32 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sholland.org; h= cc:cc:content-transfer-encoding:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm2; t=1649888372; x=1649974772; bh=ng rt2MEr4z8GI4+zoah18/U0+SvzTpZZW+sSchHQgqw=; b=wawPN8qUvHr63z4xdi brOCkbGn2zalS6uDCaKgPSyte/dRJ5M30t8pB3soZGxm3Q1h6DflqbxxneDl+cCb MdM0gCdoqQpbpLJONcBljJpxDxh5LpR/B571L928u/BxOpXHenoWiiUkUhb3/A5m pXxoBndI3JhFE06UuaXws8gre97ife0VMXwvBdDI9QQwMg4UdqfD+4RGHUz5a0pl jAzukMjW8P5O15FjbGKZvDtkx5B2eUBulw9wyV17Jh9bM6e7mcQd20oBTTejBTot wlRCuyq80MbfCloxCIqQ97aRYL+a2fv8yVV5w0/dMT9bUIinnPwNEOeoKZenKTuu JQ3A== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1649888372; x=1649974772; bh=ngrt2MEr4z8GI4+zoah18/U0+SvzTpZZW+s SchHQgqw=; b=BingKrHdYkk6l9I/ljL5wiPGYo5TN6UWOXSYOg66m6kAnXSSYg/ 8NhLba5YrkIbhocG+K7iwKgAuxJMdJU52X0sS74aokKeccgNCwRN+m26K4kVWk3i FRFtuNPClNOZCjC8J28EYWzwmKaj3PMD+1fruHcMDXFjKVvatAMG8yTDUfhmEP2E fYxx9sfimHFAlFLkUaM3/ZT5y1l7XzzQ4BNy9qU4lZp7+eimCTV4gJdwQJBRvw9I nkEPWhJhHoM5xwFUjc1NUvopJVPs5EooLKJgKj17kY4pyem3XuIng9VdN536NQGL ERxfB18fO9Cj9NxH6F/oc6k99JyuIroxA1w== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudelvddguddtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefurghmuhgv lhcujfholhhlrghnugcuoehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhgqeenucggtf frrghtthgvrhhnpeduhfejfedvhffgfeehtefghfeiiefgfeehgfdvvdevfeegjeehjedv gfejheeuieenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhroh hmpehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhg X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 13 Apr 2022 18:19:31 -0400 (EDT) From: Samuel Holland To: =?utf-8?q?Heiko_St=C3=BCbner?= , Sandy Huang , dri-devel@lists.freedesktop.org Subject: [RFC PATCH 05/16] drm/rockchip: ebc: Add CRTC mode setting Date: Wed, 13 Apr 2022 17:19:05 -0500 Message-Id: <20220413221916.50995-6-samuel@sholland.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220413221916.50995-1-samuel@sholland.org> References: <20220413221916.50995-1-samuel@sholland.org> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Airlie , =?utf-8?q?Ond=C5=99ej_Jirman?= , Thierry Reding , Michael Riesch , Sam Ravnborg , Samuel Holland , Nicolas Frattaroli , linux-rockchip@lists.infradead.org, Andreas Kemnade , Geert Uytterhoeven , Liang Chen , devicetree@vger.kernel.org, Thomas Zimmermann , Alistair Francis , Rob Herring , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peter Geis , Krzysztof Kozlowski Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" EPDs require some additional timing data beyond what is normally provided by drm_display_mode, as that struct is designed for CRTs/LCDs. For example, EPDs care about the width and position of the gate driver (vertical) clock pulse within a line. EPDs also update some number of pixels in parallel, based on the interface width, which of course varies by panel. Only two data bits are used for each pixel, to choose between driving it positive, negative, or neither direction. Color depth is thus not limited by interface width, but by time (the number of phases in the active waveform). This additional timing information is packed inside drm_display_mode as hskew and DRM_MODE_FLAG_CLKDIV2. This allows getting the complete mode from a DRM bridge. Signed-off-by: Samuel Holland --- drivers/gpu/drm/rockchip/rockchip_ebc.c | 102 ++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_ebc.c b/drivers/gpu/drm/rockchip/rockchip_ebc.c index f75fd23adda2..5f9502313657 100644 --- a/drivers/gpu/drm/rockchip/rockchip_ebc.c +++ b/drivers/gpu/drm/rockchip/rockchip_ebc.c @@ -135,6 +135,7 @@ struct rockchip_ebc { struct drm_plane plane; struct regmap *regmap; struct regulator_bulk_data supplies[EBC_NUM_SUPPLIES]; + u32 dsp_start; }; DEFINE_DRM_GEM_FOPS(rockchip_ebc_fops); @@ -178,11 +179,112 @@ static inline struct rockchip_ebc *crtc_to_ebc(struct drm_crtc *crtc) static void rockchip_ebc_crtc_mode_set_nofb(struct drm_crtc *crtc) { + struct rockchip_ebc *ebc = crtc_to_ebc(crtc); + struct drm_display_mode mode = crtc->state->adjusted_mode; + struct drm_display_mode sdck; + u16 hsync_width, vsync_width; + u16 hact_start, vact_start; + u16 pixels_per_sdck; + bool bus_16bit; + + /* + * Hardware needs horizontal timings in SDCK (source driver clock) + * cycles, not pixels. Bus width is either 8 bits (normal) or 16 bits + * (DRM_MODE_FLAG_CLKDIV2), and each pixel uses two data bits. + */ + bus_16bit = !!(mode.flags & DRM_MODE_FLAG_CLKDIV2); + pixels_per_sdck = bus_16bit ? 8 : 4; + sdck.hdisplay = mode.hdisplay / pixels_per_sdck; + sdck.hsync_start = mode.hsync_start / pixels_per_sdck; + sdck.hsync_end = mode.hsync_end / pixels_per_sdck; + sdck.htotal = mode.htotal / pixels_per_sdck; + sdck.hskew = mode.hskew / pixels_per_sdck; + + /* + * Linux timing order is display/fp/sync/bp. Hardware timing order is + * sync/bp/display/fp, aka sync/start/display/end. + */ + hact_start = sdck.htotal - sdck.hsync_start; + vact_start = mode.vtotal - mode.vsync_start; + + hsync_width = sdck.hsync_end - sdck.hsync_start; + vsync_width = mode.vsync_end - mode.vsync_start; + + clk_set_rate(ebc->dclk, mode.clock * 1000); + + ebc->dsp_start = EBC_DSP_START_DSP_SDCE_WIDTH(sdck.hdisplay) | + EBC_DSP_START_SW_BURST_CTRL; + regmap_write(ebc->regmap, EBC_EPD_CTRL, + EBC_EPD_CTRL_DSP_GD_END(sdck.htotal - sdck.hskew) | + EBC_EPD_CTRL_DSP_GD_ST(hsync_width + sdck.hskew) | + EBC_EPD_CTRL_DSP_SDDW_MODE * bus_16bit); + regmap_write(ebc->regmap, EBC_DSP_CTRL, + /* no swap */ + EBC_DSP_CTRL_DSP_SWAP_MODE(bus_16bit ? 2 : 3) | + EBC_DSP_CTRL_DSP_SDCLK_DIV(pixels_per_sdck - 1)); + regmap_write(ebc->regmap, EBC_DSP_HTIMING0, + EBC_DSP_HTIMING0_DSP_HTOTAL(sdck.htotal) | + /* sync end == sync width */ + EBC_DSP_HTIMING0_DSP_HS_END(hsync_width)); + regmap_write(ebc->regmap, EBC_DSP_HTIMING1, + EBC_DSP_HTIMING1_DSP_HACT_END(hact_start + sdck.hdisplay) | + /* minus 1 for fixed delay in timing sequence */ + EBC_DSP_HTIMING1_DSP_HACT_ST(hact_start - 1)); + regmap_write(ebc->regmap, EBC_DSP_VTIMING0, + EBC_DSP_VTIMING0_DSP_VTOTAL(mode.vtotal) | + /* sync end == sync width */ + EBC_DSP_VTIMING0_DSP_VS_END(vsync_width)); + regmap_write(ebc->regmap, EBC_DSP_VTIMING1, + EBC_DSP_VTIMING1_DSP_VACT_END(vact_start + mode.vdisplay) | + EBC_DSP_VTIMING1_DSP_VACT_ST(vact_start)); + regmap_write(ebc->regmap, EBC_DSP_ACT_INFO, + EBC_DSP_ACT_INFO_DSP_HEIGHT(mode.vdisplay) | + EBC_DSP_ACT_INFO_DSP_WIDTH(mode.hdisplay)); + regmap_write(ebc->regmap, EBC_WIN_CTRL, + /* FIFO depth - 16 */ + EBC_WIN_CTRL_WIN2_FIFO_THRESHOLD(496) | + EBC_WIN_CTRL_WIN_EN | + /* INCR16 */ + EBC_WIN_CTRL_AHB_BURST_REG(7) | + /* FIFO depth - 16 */ + EBC_WIN_CTRL_WIN_FIFO_THRESHOLD(240) | + EBC_WIN_CTRL_WIN_FMT_Y4); + + /* To keep things simple, always use a window size matching the CRTC. */ + regmap_write(ebc->regmap, EBC_WIN_VIR, + EBC_WIN_VIR_WIN_VIR_HEIGHT(mode.vdisplay) | + EBC_WIN_VIR_WIN_VIR_WIDTH(mode.hdisplay)); + regmap_write(ebc->regmap, EBC_WIN_ACT, + EBC_WIN_ACT_WIN_ACT_HEIGHT(mode.vdisplay) | + EBC_WIN_ACT_WIN_ACT_WIDTH(mode.hdisplay)); + regmap_write(ebc->regmap, EBC_WIN_DSP, + EBC_WIN_DSP_WIN_DSP_HEIGHT(mode.vdisplay) | + EBC_WIN_DSP_WIN_DSP_WIDTH(mode.hdisplay)); + regmap_write(ebc->regmap, EBC_WIN_DSP_ST, + EBC_WIN_DSP_ST_WIN_DSP_YST(vact_start) | + EBC_WIN_DSP_ST_WIN_DSP_XST(hact_start)); } static int rockchip_ebc_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) { + struct rockchip_ebc *ebc = crtc_to_ebc(crtc); + struct drm_crtc_state *crtc_state; + + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + if (!crtc_state->mode_changed) + return 0; + + if (crtc_state->enable) { + struct drm_display_mode *mode = &crtc_state->adjusted_mode; + long rate = mode->clock * 1000; + + rate = clk_round_rate(ebc->dclk, rate); + if (rate < 0) + return rate; + mode->clock = rate / 1000; + } + return 0; } From patchwork Wed Apr 13 22:19:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Holland X-Patchwork-Id: 12812741 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 96B30C433F5 for ; Wed, 13 Apr 2022 22:19:44 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 5DFD310F13F; Wed, 13 Apr 2022 22:19:40 +0000 (UTC) Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by gabe.freedesktop.org (Postfix) with ESMTPS id F0CC910F136 for ; Wed, 13 Apr 2022 22:19:34 +0000 (UTC) Received: from compute2.internal (compute2.nyi.internal [10.202.2.46]) by mailout.nyi.internal (Postfix) with ESMTP id 4C4035C0322; Wed, 13 Apr 2022 18:19:34 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute2.internal (MEProxy); Wed, 13 Apr 2022 18:19:34 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sholland.org; h= cc:cc:content-transfer-encoding:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm2; t=1649888374; x=1649974774; bh=nV Ty+l52zCL3CGPsMmkYpIgGpQIKDxR1HFzp1d9DKBM=; b=dVbHkFYEUIWKj3ST7L IBX+AJR97Rtc0cw/qe/xx1IbNAWDzL7cJxz92447dAJ+2XEMH9GU5LnFkNHnneLG SFhR4LUP/MXzeomdimp7OCR8XFDBurxwSK/quHj86LkjRORQYoS4hvfXFakfi8VE CvqOK6ihp9rGtzdL4mkrHJtEZTTImSV8tEdThzKo9Yo7k+uB+DYWO0tw5NGiij6W jif+GY0AaIlBqQX2sFudpXcaOPE752aKTneA6XMeMyMkS4TY3ZNYTKF/CZFfi1Qi SFr40Chx1xag+xteKy77K0SbfqP3GdJQ+fYwazt/FQcS3fbjPdhvyUAqqIR1c2E7 GyMw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1649888374; x=1649974774; bh=nVTy+l52zCL3CGPsMmkYpIgGpQIKDxR1HFz p1d9DKBM=; b=T5bbug34WLzjJT60oKKAjH1Uv5gPeFjPhVnLKH6/meLNcIczDt9 nSx/qeeOrXFwLv3M/oQKGA64u6ziulT4CyG79Fepyy0WaPk48PO65ZPo+svzfJ2D Di2RzPO33aiXdNSS66Vi0Rxgi4dpH0j9p8N3v7UST129BFiB110/FQBCKos38aow 2YtT1RykvcUk0ZyloPOvXMTL4WFl57qBCJDJvKKU5FsRG+ncL2LrFtm0ZmCGG1qi Do86lfvwo8tFbcAQ8I8Y7EDyYI5mnW/zsmlYaUPOdNuHEvGE4FHCIaz0pCpc5nbv +zI85V/NHO+/5FRlF36zhvV7u4n34c+PpRw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudelvddguddtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefurghmuhgv lhcujfholhhlrghnugcuoehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhgqeenucggtf frrghtthgvrhhnpeduhfejfedvhffgfeehtefghfeiiefgfeehgfdvvdevfeegjeehjedv gfejheeuieenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhroh hmpehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhg X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 13 Apr 2022 18:19:33 -0400 (EDT) From: Samuel Holland To: =?utf-8?q?Heiko_St=C3=BCbner?= , Sandy Huang , dri-devel@lists.freedesktop.org Subject: [RFC PATCH 06/16] drm/rockchip: ebc: Add CRTC refresh thread Date: Wed, 13 Apr 2022 17:19:06 -0500 Message-Id: <20220413221916.50995-7-samuel@sholland.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220413221916.50995-1-samuel@sholland.org> References: <20220413221916.50995-1-samuel@sholland.org> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Airlie , =?utf-8?q?Ond=C5=99ej_Jirman?= , Thierry Reding , Michael Riesch , Sam Ravnborg , Samuel Holland , Nicolas Frattaroli , linux-rockchip@lists.infradead.org, Andreas Kemnade , Geert Uytterhoeven , Liang Chen , devicetree@vger.kernel.org, Thomas Zimmermann , Alistair Francis , Rob Herring , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peter Geis , Krzysztof Kozlowski Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" EPD refreshes are extremely slow; they take anywhere between hundreds of milliseconds and several seconds. To avoid blocking userspace, perform these refreshes on a separate thread. The thread will also take care of initializing the display before first use and clearing it when the CRTC is disabled. Signed-off-by: Samuel Holland --- drivers/gpu/drm/rockchip/rockchip_ebc.c | 82 ++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_ebc.c b/drivers/gpu/drm/rockchip/rockchip_ebc.c index 5f9502313657..ebe60d5e011a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_ebc.c +++ b/drivers/gpu/drm/rockchip/rockchip_ebc.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -135,9 +136,15 @@ struct rockchip_ebc { struct drm_plane plane; struct regmap *regmap; struct regulator_bulk_data supplies[EBC_NUM_SUPPLIES]; + struct task_struct *refresh_thread; u32 dsp_start; + bool reset_complete; }; +static bool skip_reset; +module_param(skip_reset, bool, 0444); +MODULE_PARM_DESC(skip_reset, "skip the initial display reset"); + DEFINE_DRM_GEM_FOPS(rockchip_ebc_fops); static const struct drm_driver rockchip_ebc_drm_driver = { @@ -172,6 +179,42 @@ to_ebc_crtc_state(struct drm_crtc_state *crtc_state) return container_of(crtc_state, struct ebc_crtc_state, base); } +static int rockchip_ebc_refresh_thread(void *data) +{ + struct rockchip_ebc *ebc = data; + + while (!kthread_should_stop()) { + /* + * LUTs use both the old and the new pixel values as inputs. + * However, the initial contents of the display are unknown. + * The special RESET waveform will initialize the display to + * known contents (white) regardless of its current contents. + */ + if (!ebc->reset_complete) { + ebc->reset_complete = true; + drm_dbg(&ebc->drm, "display reset\n"); + } + + while (!kthread_should_park()) { + drm_dbg(&ebc->drm, "display update\n"); + + set_current_state(TASK_IDLE); + schedule(); + __set_current_state(TASK_RUNNING); + } + + /* + * Clear the display before disabling the CRTC. Use the + * highest-quality waveform to minimize visible artifacts. + */ + drm_dbg(&ebc->drm, "display clear\n"); + + kthread_parkme(); + } + + return 0; +} + static inline struct rockchip_ebc *crtc_to_ebc(struct drm_crtc *crtc) { return container_of(crtc, struct rockchip_ebc, crtc); @@ -296,11 +339,23 @@ static void rockchip_ebc_crtc_atomic_flush(struct drm_crtc *crtc, static void rockchip_ebc_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) { + struct rockchip_ebc *ebc = crtc_to_ebc(crtc); + struct drm_crtc_state *crtc_state; + + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + if (crtc_state->mode_changed) + kthread_unpark(ebc->refresh_thread); } static void rockchip_ebc_crtc_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state) { + struct rockchip_ebc *ebc = crtc_to_ebc(crtc); + struct drm_crtc_state *crtc_state; + + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + if (crtc_state->mode_changed) + kthread_park(ebc->refresh_thread); } static const struct drm_crtc_helper_funcs rockchip_ebc_crtc_helper_funcs = { @@ -408,6 +463,14 @@ static int rockchip_ebc_plane_atomic_check(struct drm_plane *plane, static void rockchip_ebc_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state) { + struct rockchip_ebc *ebc = plane_to_ebc(plane); + struct drm_plane_state *plane_state; + + plane_state = drm_atomic_get_new_plane_state(state, plane); + if (!plane_state->crtc) + return; + + wake_up_process(ebc->refresh_thread); } static const struct drm_plane_helper_funcs rockchip_ebc_plane_helper_funcs = { @@ -673,6 +736,7 @@ static int rockchip_ebc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ebc); init_completion(&ebc->display_end); + ebc->reset_complete = skip_reset; base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) @@ -716,12 +780,26 @@ static int rockchip_ebc_probe(struct platform_device *pdev) return ret; } + ebc->refresh_thread = kthread_create(rockchip_ebc_refresh_thread, + ebc, "ebc-refresh/%s", + dev_name(dev)); + if (IS_ERR(ebc->refresh_thread)) { + ret = dev_err_probe(dev, PTR_ERR(ebc->refresh_thread), + "Failed to start refresh thread\n"); + goto err_disable_pm; + } + + kthread_park(ebc->refresh_thread); + sched_set_fifo(ebc->refresh_thread); + ret = rockchip_ebc_drm_init(ebc); if (ret) - goto err_disable_pm; + goto err_stop_kthread; return 0; +err_stop_kthread: + kthread_stop(ebc->refresh_thread); err_disable_pm: pm_runtime_disable(dev); if (!pm_runtime_status_suspended(dev)) @@ -738,6 +816,8 @@ static int rockchip_ebc_remove(struct platform_device *pdev) drm_dev_unregister(&ebc->drm); drm_atomic_helper_shutdown(&ebc->drm); + kthread_stop(ebc->refresh_thread); + pm_runtime_disable(dev); if (!pm_runtime_status_suspended(dev)) rockchip_ebc_runtime_suspend(dev); From patchwork Wed Apr 13 22:19:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Holland X-Patchwork-Id: 12812740 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C2DB9C433FE for ; Wed, 13 Apr 2022 22:19:42 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id A1DD610F142; Wed, 13 Apr 2022 22:19:39 +0000 (UTC) Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by gabe.freedesktop.org (Postfix) with ESMTPS id D748810F136 for ; Wed, 13 Apr 2022 22:19:36 +0000 (UTC) Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.nyi.internal (Postfix) with ESMTP id 2ED0C5C02A7; Wed, 13 Apr 2022 18:19:36 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute5.internal (MEProxy); Wed, 13 Apr 2022 18:19:36 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sholland.org; h= cc:cc:content-transfer-encoding:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm2; t=1649888376; x=1649974776; bh=l5 vU5WVwRKKm13piTZRihQEkEUzFfrdwYn8dVCn/ts4=; b=RhC4uciPnKD/nHp08D rkLH3SIALFBBE73efUXxMXrQflRgBa2qt9+Seupl4Eb6Tg1iRzG7D/K5avrx02ja CLvdHpaOC5ggGnL7APMAP4R23FPyhCHKB6Ry55ydGc7J0W5CDvkA5nAOI/leoBBs b/MP9vnLdU9yUdSXO7+Pkc8YWe9Gide2gjosvr8UFrAXvVxyIGUWXGXBIX53WYyF 4RK74vG1OsORMiixKNyejncrlyI+mjYMXgwd8UFJZF+Oy+aH1kjmRU35Ngt64M/l 17LD3NXTE/xzKQiYGUrWS3U+bBn0cALMJxzt8kqXSNmdtCApUsy+VpGijI13XccI YP8w== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1649888376; x=1649974776; bh=l5vU5WVwRKKm13piTZRihQEkEUzFfrdwYn8 dVCn/ts4=; b=ZP64vNZlztWAPDchOWL+nFnpNOVOIXM8fuw8FZxBiymWB5DwYdw r2zR081fRDlGhYq9rOFaYdQCPDzCTVSlpJLvFbuMh5aA/ozx7F0s20fHe/+bxumT Ox5wC3ZIf3ewo1ZmB90dlG0dmyKCzrw6yTzmGo37Vi/Er6L6+ubyVCjqRtNCesmS 6CDYk8yPZMXI7Ij+r2CPVZtZTqobBHQLONC5EhwyUOLY1Yhc4kRF9ZXO9Y9431WT AcVx00xaaE+JsxaLk/Q5UVcE7XTPtFaUeh89KPed+UNJZRs91p/YgJu5u/hJpAdC 6U3bn5gGCMpH0fTZe3rhUvLuGEAT22+D3Zw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudelvddgtdelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefurghmuhgv lhcujfholhhlrghnugcuoehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhgqeenucggtf frrghtthgvrhhnpeduhfejfedvhffgfeehtefghfeiiefgfeehgfdvvdevfeegjeehjedv gfejheeuieenucevlhhushhtvghrufhiiigvpedvnecurfgrrhgrmhepmhgrihhlfhhroh hmpehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhg X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 13 Apr 2022 18:19:35 -0400 (EDT) From: Samuel Holland To: =?utf-8?q?Heiko_St=C3=BCbner?= , Sandy Huang , dri-devel@lists.freedesktop.org Subject: [RFC PATCH 07/16] drm/rockchip: ebc: Add CRTC buffer management Date: Wed, 13 Apr 2022 17:19:07 -0500 Message-Id: <20220413221916.50995-8-samuel@sholland.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220413221916.50995-1-samuel@sholland.org> References: <20220413221916.50995-1-samuel@sholland.org> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Airlie , =?utf-8?q?Ond=C5=99ej_Jirman?= , Thierry Reding , Michael Riesch , Sam Ravnborg , Samuel Holland , Nicolas Frattaroli , linux-rockchip@lists.infradead.org, Andreas Kemnade , Geert Uytterhoeven , Liang Chen , devicetree@vger.kernel.org, Thomas Zimmermann , Alistair Francis , Rob Herring , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peter Geis , Krzysztof Kozlowski Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" This commit adds the "context" structure which holds all buffers needed to refresh the display. It is allocated separately from the CRTC state because it is reused as long as no mode change occurs. There are three buffers holding Y4 (grayscale 4 bits/pixel) pixel data: - "prev" - contents of the display at the beginning of a refresh. - "next" - contents of the display at the end of that refresh. When a refresh finishes, the "next" buffer is copied into "prev". - "final" - contents of the display at the end of the final refresh. This buffer is necessary because a refresh waveform cannot be modified or interrupted once it is started. If a pixel's value is changed while it is already being refreshed, the "next" buffer cannot be updated until the first waveform completes. At that time, the "final" buffer is copied into "next", and another refresh is started. The name "final" refers to the write-combining behavior of this buffer; any number of plane updates can change this buffer while waiting for the current refresh to complete. Then there are two buffers holding "phase" data. These are only used during partial refreshes. The phase represents the time component (the X coordinate) of the waveform. Since the EBC supports a maximum of 256 phases in a waveform, the phase number requires one byte per pixel. The driver swaps between two buffers to minimize the delay between phases, as these buffers must be updated for every phase in the waveform. Signed-off-by: Samuel Holland --- drivers/gpu/drm/rockchip/rockchip_ebc.c | 166 +++++++++++++++++++++++- 1 file changed, 163 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_ebc.c b/drivers/gpu/drm/rockchip/rockchip_ebc.c index ebe60d5e011a..095d66e67c2f 100644 --- a/drivers/gpu/drm/rockchip/rockchip_ebc.c +++ b/drivers/gpu/drm/rockchip/rockchip_ebc.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -141,6 +142,10 @@ struct rockchip_ebc { bool reset_complete; }; +static int default_waveform = DRM_EPD_WF_GC16; +module_param(default_waveform, int, 0644); +MODULE_PARM_DESC(default_waveform, "waveform to use for display updates"); + static bool skip_reset; module_param(skip_reset, bool, 0444); MODULE_PARM_DESC(skip_reset, "skip the initial display reset"); @@ -165,12 +170,86 @@ static const struct drm_mode_config_funcs rockchip_ebc_mode_config_funcs = { .atomic_commit = drm_atomic_helper_commit, }; +/** + * struct rockchip_ebc_ctx - context for performing display refreshes + * + * @kref: Reference count, maintained as part of the CRTC's atomic state + * @prev: Display contents (Y4) before this refresh + * @next: Display contents (Y4) after this refresh + * @final: Display contents (Y4) after all pending refreshes + * @phase: Buffers for selecting a phase from the EBC's LUT, 1 byte/pixel + * @gray4_pitch: Horizontal line length of a Y4 pixel buffer in bytes + * @gray4_size: Size of a Y4 pixel buffer in bytes + * @phase_pitch: Horizontal line length of a phase buffer in bytes + * @phase_size: Size of a phase buffer in bytes + */ +struct rockchip_ebc_ctx { + struct kref kref; + u8 *prev; + u8 *next; + u8 *final; + u8 *phase[2]; + u32 gray4_pitch; + u32 gray4_size; + u32 phase_pitch; + u32 phase_size; +}; + +static void rockchip_ebc_ctx_free(struct rockchip_ebc_ctx *ctx) +{ + kfree(ctx->prev); + kfree(ctx->next); + kfree(ctx->final); + kfree(ctx->phase[0]); + kfree(ctx->phase[1]); + kfree(ctx); +} + +static struct rockchip_ebc_ctx *rockchip_ebc_ctx_alloc(u32 width, u32 height) +{ + u32 gray4_size = width * height / 2; + u32 phase_size = width * height; + struct rockchip_ebc_ctx *ctx; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return NULL; + + ctx->prev = kmalloc(gray4_size, GFP_KERNEL); + ctx->next = kmalloc(gray4_size, GFP_KERNEL); + ctx->final = kmalloc(gray4_size, GFP_KERNEL); + ctx->phase[0] = kmalloc(phase_size, GFP_KERNEL); + ctx->phase[1] = kmalloc(phase_size, GFP_KERNEL); + if (!ctx->prev || !ctx->next || !ctx->final || + !ctx->phase[0] || !ctx->phase[1]) { + rockchip_ebc_ctx_free(ctx); + return NULL; + } + + kref_init(&ctx->kref); + ctx->gray4_pitch = width / 2; + ctx->gray4_size = gray4_size; + ctx->phase_pitch = width; + ctx->phase_size = phase_size; + + return ctx; +} + +static void rockchip_ebc_ctx_release(struct kref *kref) +{ + struct rockchip_ebc_ctx *ctx = + container_of(kref, struct rockchip_ebc_ctx, kref); + + return rockchip_ebc_ctx_free(ctx); +} + /* * CRTC */ struct ebc_crtc_state { struct drm_crtc_state base; + struct rockchip_ebc_ctx *ctx; }; static inline struct ebc_crtc_state * @@ -179,11 +258,70 @@ to_ebc_crtc_state(struct drm_crtc_state *crtc_state) return container_of(crtc_state, struct ebc_crtc_state, base); } +static void rockchip_ebc_global_refresh(struct rockchip_ebc *ebc, + const struct rockchip_ebc_ctx *ctx) +{ + struct drm_device *drm = &ebc->drm; + u32 gray4_size = ctx->gray4_size; + + drm_dbg(drm, "global refresh\n"); + + memcpy(ctx->prev, ctx->next, gray4_size); +} + +static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc, + struct rockchip_ebc_ctx *ctx) +{ + struct drm_device *drm = &ebc->drm; + + drm_dbg(drm, "partial refresh\n"); +} + +static void rockchip_ebc_refresh(struct rockchip_ebc *ebc, + struct rockchip_ebc_ctx *ctx, + bool global_refresh, + enum drm_epd_waveform waveform) +{ + if (global_refresh) + rockchip_ebc_global_refresh(ebc, ctx); + else + rockchip_ebc_partial_refresh(ebc, ctx); +} + static int rockchip_ebc_refresh_thread(void *data) { struct rockchip_ebc *ebc = data; + struct rockchip_ebc_ctx *ctx; while (!kthread_should_stop()) { + /* The context will change each time the thread is unparked. */ + ctx = to_ebc_crtc_state(READ_ONCE(ebc->crtc.state))->ctx; + + /* + * Initialize the buffers before use. This is deferred to the + * kthread to avoid slowing down atomic_check. + * + * ctx->prev and ctx->next are set to 0xff, all white, because: + * 1) the display is set to white by the reset waveform, and + * 2) the driver maintains the invariant that the display is + * all white whenever the CRTC is disabled. + * + * ctx->final is initialized by the first plane update. + * + * ctx->phase is set to 0xff, the number of the last possible + * phase, because the LUT for that phase is known to be all + * zeroes. (The last real phase in a waveform is zero in order + * to discharge the display, and unused phases in the LUT are + * zeroed out.) This prevents undesired driving of the display + * in 3-window mode between when the framebuffer is blitted + * (and thus prev != next) and when the refresh thread starts + * counting phases for that region. + */ + memset(ctx->prev, 0xff, ctx->gray4_size); + memset(ctx->next, 0xff, ctx->gray4_size); + memset(ctx->phase[0], 0xff, ctx->phase_size); + memset(ctx->phase[1], 0xff, ctx->phase_size); + /* * LUTs use both the old and the new pixel values as inputs. * However, the initial contents of the display are unknown. @@ -192,11 +330,11 @@ static int rockchip_ebc_refresh_thread(void *data) */ if (!ebc->reset_complete) { ebc->reset_complete = true; - drm_dbg(&ebc->drm, "display reset\n"); + rockchip_ebc_refresh(ebc, ctx, true, DRM_EPD_WF_RESET); } while (!kthread_should_park()) { - drm_dbg(&ebc->drm, "display update\n"); + rockchip_ebc_refresh(ebc, ctx, false, default_waveform); set_current_state(TASK_IDLE); schedule(); @@ -207,7 +345,8 @@ static int rockchip_ebc_refresh_thread(void *data) * Clear the display before disabling the CRTC. Use the * highest-quality waveform to minimize visible artifacts. */ - drm_dbg(&ebc->drm, "display clear\n"); + memset(ctx->next, 0xff, ctx->gray4_size); + rockchip_ebc_refresh(ebc, ctx, true, DRM_EPD_WF_GC16); kthread_parkme(); } @@ -312,7 +451,9 @@ static int rockchip_ebc_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) { struct rockchip_ebc *ebc = crtc_to_ebc(crtc); + struct ebc_crtc_state *ebc_crtc_state; struct drm_crtc_state *crtc_state; + struct rockchip_ebc_ctx *ctx; crtc_state = drm_atomic_get_new_crtc_state(state, crtc); if (!crtc_state->mode_changed) @@ -320,14 +461,26 @@ static int rockchip_ebc_crtc_atomic_check(struct drm_crtc *crtc, if (crtc_state->enable) { struct drm_display_mode *mode = &crtc_state->adjusted_mode; + long rate = mode->clock * 1000; rate = clk_round_rate(ebc->dclk, rate); if (rate < 0) return rate; mode->clock = rate / 1000; + + ctx = rockchip_ebc_ctx_alloc(mode->hdisplay, mode->vdisplay); + if (!ctx) + return -ENOMEM; + } else { + ctx = NULL; } + ebc_crtc_state = to_ebc_crtc_state(crtc_state); + if (ebc_crtc_state->ctx) + kref_put(&ebc_crtc_state->ctx->kref, rockchip_ebc_ctx_release); + ebc_crtc_state->ctx = ctx; + return 0; } @@ -397,6 +550,10 @@ rockchip_ebc_crtc_duplicate_state(struct drm_crtc *crtc) __drm_atomic_helper_crtc_duplicate_state(crtc, &ebc_crtc_state->base); + ebc_crtc_state->ctx = to_ebc_crtc_state(crtc->state)->ctx; + if (ebc_crtc_state->ctx) + kref_get(&ebc_crtc_state->ctx->kref); + return &ebc_crtc_state->base; } @@ -405,6 +562,9 @@ static void rockchip_ebc_crtc_destroy_state(struct drm_crtc *crtc, { struct ebc_crtc_state *ebc_crtc_state = to_ebc_crtc_state(crtc_state); + if (ebc_crtc_state->ctx) + kref_put(&ebc_crtc_state->ctx->kref, rockchip_ebc_ctx_release); + __drm_atomic_helper_crtc_destroy_state(&ebc_crtc_state->base); kfree(ebc_crtc_state); From patchwork Wed Apr 13 22:19:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Holland X-Patchwork-Id: 12812739 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id EB9A1C433F5 for ; Wed, 13 Apr 2022 22:19:40 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 79D7C10F136; Wed, 13 Apr 2022 22:19:39 +0000 (UTC) Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by gabe.freedesktop.org (Postfix) with ESMTPS id A596D10F136 for ; Wed, 13 Apr 2022 22:19:38 +0000 (UTC) Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.nyi.internal (Postfix) with ESMTP id 017155C0337; Wed, 13 Apr 2022 18:19:38 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute5.internal (MEProxy); Wed, 13 Apr 2022 18:19:38 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sholland.org; h= cc:cc:content-transfer-encoding:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm2; t=1649888377; x=1649974777; bh=tY YXooyzfoVASIVFw46sk2jtQuSFQj7O0CjADjvQKS4=; b=fnbQiRCWZKoa6P2AFl UCN2cUs8hriQsg+DTZJBhg6fKGCwumuG62IEDgTeIiEx9yd5Y1F2hMRzmAcFysU5 cS5hbbwRvTDrqSiI42YGA1xc24+rimiICmi7tDg7maQ+IZmLT79JX6fRm2/kIlnX AdnUOwD50xQ/TZGy5Gk/gMqwVhyiKLYduZRYZ36jurBvH52iY4pT3Nl2aod3hUc5 6iGJqiTgMBuhEAHhi1wcQ/oUMksynJiu0PMEoflM0ten8rn0ZVXh2BO+hHQiVrIB +4BmFZAJ1a7YP5ChIryCqaxBdjOabDNj1b7qNr4rtu3rdHfBlbYicnlssHQHBNvl 0AXQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1649888377; x=1649974777; bh=tYYXooyzfoVASIVFw46sk2jtQuSFQj7O0Cj ADjvQKS4=; b=JN/u/DVSKTUMgkOEo/iiZMZiOEglinf5P/JGht+fnQMEX2vTL6r O8uAgoyL3b3P8vqeTD6RQk37E9K/+khwTK14Lb31637ClNaOGPkF+em+6t7aBayA eJ/b0tyMz8afdMlBiDmDzZLzCIoHbYvyrFE3iy7fAqjgzemvzHdEPcIhlEwhDlez VKMjbIU8z3XpSxUByu4aKmIosWw+sncCKB2cxPzO32OYF1vrtoEOFEmeU6yHDszL BoNSU8UuuTaEEqA8kMhNz815ly6AKTi5c1Ep8EoYIDNrc1/Ecr2OZ6GBMpO0Z7BJ 2B0/IA6LoAqWwKojy5gqAufaOx4Q9tQ/8MA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudelvddgtdelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefurghmuhgv lhcujfholhhlrghnugcuoehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhgqeenucggtf frrghtthgvrhhnpeduhfejfedvhffgfeehtefghfeiiefgfeehgfdvvdevfeegjeehjedv gfejheeuieenucevlhhushhtvghrufhiiigvpedvnecurfgrrhgrmhepmhgrihhlfhhroh hmpehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhg X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 13 Apr 2022 18:19:37 -0400 (EDT) From: Samuel Holland To: =?utf-8?q?Heiko_St=C3=BCbner?= , Sandy Huang , dri-devel@lists.freedesktop.org Subject: [RFC PATCH 08/16] drm/rockchip: ebc: Add LUT loading Date: Wed, 13 Apr 2022 17:19:08 -0500 Message-Id: <20220413221916.50995-9-samuel@sholland.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220413221916.50995-1-samuel@sholland.org> References: <20220413221916.50995-1-samuel@sholland.org> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Airlie , =?utf-8?q?Ond=C5=99ej_Jirman?= , Thierry Reding , Michael Riesch , Sam Ravnborg , Samuel Holland , Nicolas Frattaroli , linux-rockchip@lists.infradead.org, Andreas Kemnade , Geert Uytterhoeven , Liang Chen , devicetree@vger.kernel.org, Thomas Zimmermann , Alistair Francis , Rob Herring , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peter Geis , Krzysztof Kozlowski Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" The EBC contains a 16 KiB SRAM which stores the current LUT. It needs to be programmed any time the LUT changes or the hardware block is enabled. Since both of these triggers can happen at the same time, use a flag to avoid writing the LUT twice. Signed-off-by: Samuel Holland --- drivers/gpu/drm/rockchip/Kconfig | 3 +- drivers/gpu/drm/rockchip/rockchip_ebc.c | 76 +++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 9d3273a5fd97..efe4476e336d 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -94,7 +94,8 @@ endif config DRM_ROCKCHIP_EBC tristate "DRM Support for Rockchip EBC" - depends on DRM + depends on DRM && IIO + select DRM_EPD_HELPER select DRM_GEM_SHMEM_HELPER select DRM_KMS_HELPER help diff --git a/drivers/gpu/drm/rockchip/rockchip_ebc.c b/drivers/gpu/drm/rockchip/rockchip_ebc.c index 095d66e67c2f..ca3173b28d1c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_ebc.c +++ b/drivers/gpu/drm/rockchip/rockchip_ebc.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -122,6 +123,7 @@ #define EBC_WIN_MST2 0x0058 #define EBC_LUT_DATA 0x1000 +#define EBC_MAX_PHASES 256 #define EBC_NUM_LUT_REGS 0x1000 #define EBC_NUM_SUPPLIES 3 @@ -134,11 +136,15 @@ struct rockchip_ebc { struct drm_crtc crtc; struct drm_device drm; struct drm_encoder encoder; + struct drm_epd_lut lut; + struct drm_epd_lut_file lut_file; struct drm_plane plane; + struct iio_channel *temperature_channel; struct regmap *regmap; struct regulator_bulk_data supplies[EBC_NUM_SUPPLIES]; struct task_struct *refresh_thread; u32 dsp_start; + bool lut_changed; bool reset_complete; }; @@ -282,10 +288,59 @@ static void rockchip_ebc_refresh(struct rockchip_ebc *ebc, bool global_refresh, enum drm_epd_waveform waveform) { + struct drm_device *drm = &ebc->drm; + struct device *dev = drm->dev; + int ret, temperature; + + /* Resume asynchronously while preparing to refresh. */ + ret = pm_runtime_get(dev); + if (ret < 0) { + drm_err(drm, "Failed to request resume: %d\n", ret); + return; + } + + ret = iio_read_channel_processed(ebc->temperature_channel, &temperature); + if (ret < 0) { + drm_err(drm, "Failed to get temperature: %d\n", ret); + } else { + /* Convert from millicelsius to celsius. */ + temperature /= 1000; + + ret = drm_epd_lut_set_temperature(&ebc->lut, temperature); + if (ret < 0) + drm_err(drm, "Failed to set LUT temperature: %d\n", ret); + else if (ret) + ebc->lut_changed = true; + } + + ret = drm_epd_lut_set_waveform(&ebc->lut, waveform); + if (ret < 0) + drm_err(drm, "Failed to set LUT waveform: %d\n", ret); + else if (ret) + ebc->lut_changed = true; + + /* Wait for the resume to complete before writing any registers. */ + ret = pm_runtime_resume(dev); + if (ret < 0) { + drm_err(drm, "Failed to resume: %d\n", ret); + pm_runtime_put(dev); + return; + } + + /* This flag may have been set above, or by the runtime PM callback. */ + if (ebc->lut_changed) { + ebc->lut_changed = false; + regmap_bulk_write(ebc->regmap, EBC_LUT_DATA, + ebc->lut.buf, EBC_NUM_LUT_REGS); + } + if (global_refresh) rockchip_ebc_global_refresh(ebc, ctx); else rockchip_ebc_partial_refresh(ebc, ctx); + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); } static int rockchip_ebc_refresh_thread(void *data) @@ -708,6 +763,15 @@ static int rockchip_ebc_drm_init(struct rockchip_ebc *ebc) struct drm_bridge *bridge; int ret; + ret = drmm_epd_lut_file_init(drm, &ebc->lut_file, "rockchip/ebc.wbf"); + if (ret) + return ret; + + ret = drmm_epd_lut_init(&ebc->lut_file, &ebc->lut, + DRM_EPD_LUT_4BIT_PACKED, EBC_MAX_PHASES); + if (ret) + return ret; + ret = drmm_mode_config_init(drm); if (ret) return ret; @@ -810,6 +874,13 @@ static int rockchip_ebc_runtime_resume(struct device *dev) if (ret) goto err_disable_hclk; + /* + * Do not restore the LUT registers here, because the temperature or + * waveform may have changed since the last refresh. Instead, have the + * refresh thread program the LUT during the next refresh. + */ + ebc->lut_changed = true; + regcache_cache_only(ebc->regmap, false); regcache_mark_dirty(ebc->regmap); regcache_sync(ebc->regmap); @@ -919,6 +990,11 @@ static int rockchip_ebc_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(ebc->hclk), "Failed to get hclk\n"); + ebc->temperature_channel = devm_iio_channel_get(dev, NULL); + if (IS_ERR(ebc->temperature_channel)) + return dev_err_probe(dev, PTR_ERR(ebc->temperature_channel), + "Failed to get temperature I/O channel\n"); + for (i = 0; i < EBC_NUM_SUPPLIES; i++) ebc->supplies[i].supply = rockchip_ebc_supplies[i]; From patchwork Wed Apr 13 22:19:09 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Holland X-Patchwork-Id: 12812745 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 54BB5C433F5 for ; Wed, 13 Apr 2022 22:19:55 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id EB99D10F158; Wed, 13 Apr 2022 22:19:51 +0000 (UTC) Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by gabe.freedesktop.org (Postfix) with ESMTPS id F2ADF10F147 for ; Wed, 13 Apr 2022 22:19:40 +0000 (UTC) Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.nyi.internal (Postfix) with ESMTP id E12FD5C0325; Wed, 13 Apr 2022 18:19:39 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute5.internal (MEProxy); Wed, 13 Apr 2022 18:19:39 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sholland.org; h= cc:cc:content-transfer-encoding:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm2; t=1649888379; x=1649974779; bh=Dm EyWFCtmS1CP/NJfSjamUUamIi9FMNiWBV0XLSX5tI=; b=mk4goxXUJrAIBWW089 dPCf4FzqENNN0V90qnVFG3Nb+06XXWnUrXuZ+EZ6KlLvmQlaXV9aLyBEheUsB0ew L5IA+VDexu9UDz6dGM6mmgxkKvzzLYGjP3cMHo+hVZIF9kC4V64sjU8qx/jOcs5L jlN3BOhlSz0a0f8q0SsMtOtEcWU+yNnikHz1LQO4RRSxkHIRCE10BA5ek86yu7kT YGh49nlDZ1paW0U8O6XzmoK5UGs8+a9UjY3n4SLqsWmX0JGaC9H0+lMli/eqGBVM cVPioWFJsFXzAiGrvp8NspW1xYpvIJB3aadgENPWLfBujOblEA6ajcicj3TfRgLF hqAA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1649888379; x=1649974779; bh=DmEyWFCtmS1CP/NJfSjamUUamIi9FMNiWBV 0XLSX5tI=; b=p2cP5wLcgSeBDjXtnvHzgbPSPk4yR/i4fCkA7ZcCtNYo63XOpfs MCD6IQpVv1+Dvi4dKKDfk+b8QKvo5zbtk2n5xvgts/v2zX/asrYoVUsHHdKl9HFe JMyLH2eL4Wed7wNTe/mHykvgiIexwOTkhsl1xC7ch91CbBfLRCmRojvmG3ULGkcE 81bnvhj5CVzIrQwrXEOlTtS2CmAek3tdrY1DYseSt/Qy+M/F9XzVk7cV+73LN0j7 LXhmz0c/y0R+OnY/q2gBsADIuhWFUhCq+nKEuOlqY/X61x3YGdggRtcCqiea/L4Y VKkfy76tni9n76SXAE+h/l2bjLPG34bnGXw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudelvddgtdelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefurghmuhgv lhcujfholhhlrghnugcuoehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhgqeenucggtf frrghtthgvrhhnpeduhfejfedvhffgfeehtefghfeiiefgfeehgfdvvdevfeegjeehjedv gfejheeuieenucevlhhushhtvghrufhiiigvpedvnecurfgrrhgrmhepmhgrihhlfhhroh hmpehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhg X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 13 Apr 2022 18:19:38 -0400 (EDT) From: Samuel Holland To: =?utf-8?q?Heiko_St=C3=BCbner?= , Sandy Huang , dri-devel@lists.freedesktop.org Subject: [RFC PATCH 09/16] drm/rockchip: ebc: Implement global refreshes Date: Wed, 13 Apr 2022 17:19:09 -0500 Message-Id: <20220413221916.50995-10-samuel@sholland.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220413221916.50995-1-samuel@sholland.org> References: <20220413221916.50995-1-samuel@sholland.org> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Airlie , =?utf-8?q?Ond=C5=99ej_Jirman?= , Thierry Reding , Michael Riesch , Sam Ravnborg , Samuel Holland , Nicolas Frattaroli , linux-rockchip@lists.infradead.org, Andreas Kemnade , Geert Uytterhoeven , Liang Chen , devicetree@vger.kernel.org, Thomas Zimmermann , Alistair Francis , Rob Herring , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peter Geis , Krzysztof Kozlowski Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" The global refresh mode is used to initialize and clear the screen. It is the most efficient refresh mode. It uses two pixel buffers (old and new) and a frame count. The frame count is set to the number of phases in the waveform. The hardware then looks up the combination of (old pixel value, new pixel value, frame number) in the LUT and sends the resulting polarity value to the display. Signed-off-by: Samuel Holland --- drivers/gpu/drm/rockchip/rockchip_ebc.c | 48 ++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_ebc.c b/drivers/gpu/drm/rockchip/rockchip_ebc.c index ca3173b28d1c..cb6dc567e94c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_ebc.c +++ b/drivers/gpu/drm/rockchip/rockchip_ebc.c @@ -127,6 +127,7 @@ #define EBC_NUM_LUT_REGS 0x1000 #define EBC_NUM_SUPPLIES 3 +#define EBC_REFRESH_TIMEOUT msecs_to_jiffies(3000) #define EBC_SUSPEND_DELAY_MS 2000 struct rockchip_ebc { @@ -269,8 +270,23 @@ static void rockchip_ebc_global_refresh(struct rockchip_ebc *ebc, { struct drm_device *drm = &ebc->drm; u32 gray4_size = ctx->gray4_size; + struct device *dev = drm->dev; - drm_dbg(drm, "global refresh\n"); + dma_sync_single_for_device(dev, virt_to_phys(ctx->next), + gray4_size, DMA_TO_DEVICE); + dma_sync_single_for_device(dev, virt_to_phys(ctx->prev), + gray4_size, DMA_TO_DEVICE); + + reinit_completion(&ebc->display_end); + regmap_write(ebc->regmap, EBC_CONFIG_DONE, + EBC_CONFIG_DONE_REG_CONFIG_DONE); + regmap_write(ebc->regmap, EBC_DSP_START, + ebc->dsp_start | + EBC_DSP_START_DSP_FRM_TOTAL(ebc->lut.num_phases - 1) | + EBC_DSP_START_DSP_FRM_START); + if (!wait_for_completion_timeout(&ebc->display_end, + EBC_REFRESH_TIMEOUT)) + drm_err(drm, "Refresh timed out!\n"); memcpy(ctx->prev, ctx->next, gray4_size); } @@ -289,6 +305,7 @@ static void rockchip_ebc_refresh(struct rockchip_ebc *ebc, enum drm_epd_waveform waveform) { struct drm_device *drm = &ebc->drm; + u32 dsp_ctrl = 0, epd_ctrl = 0; struct device *dev = drm->dev; int ret, temperature; @@ -334,11 +351,40 @@ static void rockchip_ebc_refresh(struct rockchip_ebc *ebc, ebc->lut.buf, EBC_NUM_LUT_REGS); } + regmap_write(ebc->regmap, EBC_DSP_START, + ebc->dsp_start); + + /* + * The hardware has a separate bit for each mode, with some priority + * scheme between them. For clarity, only set one bit at a time. + */ + if (global_refresh) { + dsp_ctrl |= EBC_DSP_CTRL_DSP_LUT_MODE; + } else { + epd_ctrl |= EBC_EPD_CTRL_DSP_THREE_WIN_MODE; + } + regmap_update_bits(ebc->regmap, EBC_EPD_CTRL, + EBC_EPD_CTRL_DSP_THREE_WIN_MODE, + epd_ctrl); + regmap_update_bits(ebc->regmap, EBC_DSP_CTRL, + EBC_DSP_CTRL_DSP_LUT_MODE, + dsp_ctrl); + + regmap_write(ebc->regmap, EBC_WIN_MST0, + virt_to_phys(ctx->next)); + regmap_write(ebc->regmap, EBC_WIN_MST1, + virt_to_phys(ctx->prev)); + if (global_refresh) rockchip_ebc_global_refresh(ebc, ctx); else rockchip_ebc_partial_refresh(ebc, ctx); + /* Drive the output pins low once the refresh is complete. */ + regmap_write(ebc->regmap, EBC_DSP_START, + ebc->dsp_start | + EBC_DSP_START_DSP_OUT_LOW); + pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); } From patchwork Wed Apr 13 22:19:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Holland X-Patchwork-Id: 12812746 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id AD7B6C433EF for ; Wed, 13 Apr 2022 22:19:56 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 22D5010F15A; Wed, 13 Apr 2022 22:19:52 +0000 (UTC) Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by gabe.freedesktop.org (Postfix) with ESMTPS id 9973B10F146 for ; Wed, 13 Apr 2022 22:19:42 +0000 (UTC) Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id E983F5C033A; Wed, 13 Apr 2022 18:19:41 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Wed, 13 Apr 2022 18:19:41 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sholland.org; h= cc:cc:content-transfer-encoding:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm2; t=1649888381; x=1649974781; bh=7b bIqqy2mMtv+LMNn04scZFEsK5Ygh9hQ+hXBLs4DCI=; b=De+yP95f0xqDeVLgAN i0kBEYBFk47F+1kVQkC2z3T/1xVRXqi83dqUEXMoyIhuEnGvqmHND+UKhlpLNa6K ZZ6BlXpFYniLjetsBoi2ge4SgaCs6VH9IbjN/8eH7JjVe+VEFPtcT5ViOxDA1/QY HYClCuLWVPlzk1zfnvYAXNssRzD8byhMMJRGerXNszdvlBcJYbD2DQmEb8Rg5Bhc VFY2mHhPRAX5uCwgQiOfj5UGvYlwYOdjXyzkkQ+I/8CeFxJ7EGcumh4tLwfV+RbY nYIB79MSKpl2JdGk8v9uQA+ATWaeIPFHnU6fIGr756PNCuhcbxPTnk2062uhUU5/ 5fiw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1649888381; x=1649974781; bh=7bbIqqy2mMtv+LMNn04scZFEsK5Ygh9hQ+h XBLs4DCI=; b=HJcnNONuVResbsVXjNVr3+qBWtwl2lp518gpSXHsuQVfYa311gu WQZTPiy+Irpdchd5Y2OMRK5rcAc/4G9M/q0k9Wd9v9/056aC3KwfBeaYsPx/rUH2 10tqr27CyrtRDVMaZbM6qeC2JNkXwRpXZ9npa668xkA0nnrOifOdbXdLMGsna3tq B/pzt02CepHZLtWEWK7DfPkCx8mIoalbsKg/CBlT155nB9VpwZuV8gfqusrxBrA8 zSQ6lHCxYY+Y8DIB6aHzJ+tEH28JTeVU0FR4/5id0VE6Ioy9B/9P9ycbT4lVjLl0 k3LrioKlZJi0mPdmdZK/q6ubTYH2pMuzqcg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudelvddguddtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefurghmuhgv lhcujfholhhlrghnugcuoehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhgqeenucggtf frrghtthgvrhhnpeduhfejfedvhffgfeehtefghfeiiefgfeehgfdvvdevfeegjeehjedv gfejheeuieenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhroh hmpehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhg X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 13 Apr 2022 18:19:40 -0400 (EDT) From: Samuel Holland To: =?utf-8?q?Heiko_St=C3=BCbner?= , Sandy Huang , dri-devel@lists.freedesktop.org Subject: [RFC PATCH 10/16] drm/rockchip: ebc: Implement partial refreshes Date: Wed, 13 Apr 2022 17:19:10 -0500 Message-Id: <20220413221916.50995-11-samuel@sholland.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220413221916.50995-1-samuel@sholland.org> References: <20220413221916.50995-1-samuel@sholland.org> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Airlie , =?utf-8?q?Ond=C5=99ej_Jirman?= , Thierry Reding , Michael Riesch , Sam Ravnborg , Samuel Holland , Nicolas Frattaroli , linux-rockchip@lists.infradead.org, Andreas Kemnade , Geert Uytterhoeven , Liang Chen , devicetree@vger.kernel.org, Thomas Zimmermann , Alistair Francis , Rob Herring , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peter Geis , Krzysztof Kozlowski Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Several areas of the display can be refreshed concurrently, but only if they do not overlap. This commit adds a queue of damaged areas, and schedules them for refresh based on collision with other areas. While the queue is unbounded, there is logic to quickly drop duplicate areas. Because three-window mode disables the hardware's frame counter, a separate buffer is required for each frame. (In other words, there is no automatic increment.) To minimize overhead, swap between two buffers for phase numbers. This requires extending the loop for one extra frame to clear the phase numbers in both buffers when an area completes. (This extra frame is a no-op and is not sent to the hardware.) Signed-off-by: Samuel Holland --- drivers/gpu/drm/rockchip/rockchip_ebc.c | 346 +++++++++++++++++++++++- 1 file changed, 344 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_ebc.c b/drivers/gpu/drm/rockchip/rockchip_ebc.c index cb6dc567e94c..c3e4b65bdee6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_ebc.c +++ b/drivers/gpu/drm/rockchip/rockchip_ebc.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -123,10 +124,14 @@ #define EBC_WIN_MST2 0x0058 #define EBC_LUT_DATA 0x1000 +#define EBC_FRAME_PENDING (-1U) + #define EBC_MAX_PHASES 256 + #define EBC_NUM_LUT_REGS 0x1000 #define EBC_NUM_SUPPLIES 3 +#define EBC_FRAME_TIMEOUT msecs_to_jiffies(25) #define EBC_REFRESH_TIMEOUT msecs_to_jiffies(3000) #define EBC_SUSPEND_DELAY_MS 2000 @@ -177,10 +182,25 @@ static const struct drm_mode_config_funcs rockchip_ebc_mode_config_funcs = { .atomic_commit = drm_atomic_helper_commit, }; +/** + * struct rockchip_ebc_area - describes a damaged area of the display + * + * @list: Used to put this area in the state/context/refresh thread list + * @clip: The rectangular clip of this damage area + * @frame_begin: The frame number when this damage area starts being refreshed + */ +struct rockchip_ebc_area { + struct list_head list; + struct drm_rect clip; + u32 frame_begin; +}; + /** * struct rockchip_ebc_ctx - context for performing display refreshes * * @kref: Reference count, maintained as part of the CRTC's atomic state + * @queue: Queue of damaged areas to be refreshed + * @queue_lock: Lock protecting access to @queue * @prev: Display contents (Y4) before this refresh * @next: Display contents (Y4) after this refresh * @final: Display contents (Y4) after all pending refreshes @@ -192,6 +212,8 @@ static const struct drm_mode_config_funcs rockchip_ebc_mode_config_funcs = { */ struct rockchip_ebc_ctx { struct kref kref; + struct list_head queue; + spinlock_t queue_lock; u8 *prev; u8 *next; u8 *final; @@ -204,6 +226,10 @@ struct rockchip_ebc_ctx { static void rockchip_ebc_ctx_free(struct rockchip_ebc_ctx *ctx) { + struct rockchip_ebc_area *area; + + list_for_each_entry(area, &ctx->queue, list) + kfree(area); kfree(ctx->prev); kfree(ctx->next); kfree(ctx->final); @@ -234,6 +260,8 @@ static struct rockchip_ebc_ctx *rockchip_ebc_ctx_alloc(u32 width, u32 height) } kref_init(&ctx->kref); + INIT_LIST_HEAD(&ctx->queue); + spin_lock_init(&ctx->queue_lock); ctx->gray4_pitch = width / 2; ctx->gray4_size = gray4_size; ctx->phase_pitch = width; @@ -291,12 +319,204 @@ static void rockchip_ebc_global_refresh(struct rockchip_ebc *ebc, memcpy(ctx->prev, ctx->next, gray4_size); } +static bool rockchip_ebc_schedule_area(struct list_head *areas, + struct rockchip_ebc_area *area, + u32 current_frame, u32 num_phases) +{ + struct rockchip_ebc_area *other; + u32 frame_begin = current_frame; + + list_for_each_entry(other, areas, list) { + struct drm_rect intersection; + u32 other_end; + + /* Only consider areas before this one in the list. */ + if (other == area) + break; + + /* Skip areas that finish refresh before this area begins. */ + other_end = other->frame_begin + num_phases; + if (other_end <= frame_begin) + continue; + + /* If there is no collision, the areas are independent. */ + intersection = area->clip; + if (!drm_rect_intersect(&intersection, &other->clip)) + continue; + + /* If the other area already started, wait until it finishes. */ + if (other->frame_begin < current_frame) { + frame_begin = other_end; + continue; + } + + /* + * If the other area has not started yet, and completely + * contains this area, then this area is redundant. + */ + if (drm_rect_equals(&area->clip, &intersection)) + return false; + + /* Otherwise, start at the same time as the other area. */ + frame_begin = other->frame_begin; + } + + area->frame_begin = frame_begin; + + return true; +} + +static void rockchip_ebc_blit_phase(const struct rockchip_ebc_ctx *ctx, + u8 *dst, u8 phase, + const struct drm_rect *clip) +{ + unsigned int pitch = ctx->phase_pitch; + unsigned int width = clip->x2 - clip->x1; + unsigned int y; + u8 *dst_line; + + dst_line = dst + clip->y1 * pitch + clip->x1; + + for (y = clip->y1; y < clip->y2; y++) { + memset(dst_line, phase, width); + + dst_line += pitch; + } +} + +static void rockchip_ebc_blit_pixels(const struct rockchip_ebc_ctx *ctx, + u8 *dst, const u8 *src, + const struct drm_rect *clip) +{ + unsigned int x1_bytes = clip->x1 / 2; + unsigned int x2_bytes = clip->x2 / 2; + unsigned int pitch = ctx->gray4_pitch; + unsigned int width = x2_bytes - x1_bytes; + const u8 *src_line; + unsigned int y; + u8 *dst_line; + + dst_line = dst + clip->y1 * pitch + x1_bytes; + src_line = src + clip->y1 * pitch + x1_bytes; + + for (y = clip->y1; y < clip->y2; y++) { + memcpy(dst_line, src_line, width); + + dst_line += pitch; + src_line += pitch; + } +} + static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc, struct rockchip_ebc_ctx *ctx) { + dma_addr_t next_handle = virt_to_phys(ctx->next); + dma_addr_t prev_handle = virt_to_phys(ctx->prev); + struct rockchip_ebc_area *area, *next_area; + u32 last_phase = ebc->lut.num_phases - 1; struct drm_device *drm = &ebc->drm; + u32 gray4_size = ctx->gray4_size; + struct device *dev = drm->dev; + LIST_HEAD(areas); + u32 frame; + + for (frame = 0;; frame++) { + /* Swap phase buffers to minimize latency between frames. */ + u8 *phase_buffer = ctx->phase[frame % 2]; + dma_addr_t phase_handle = virt_to_phys(phase_buffer); + bool sync_next = false; + bool sync_prev = false; + + /* Move the queued damage areas to the local list. */ + spin_lock(&ctx->queue_lock); + list_splice_tail_init(&ctx->queue, &areas); + spin_unlock(&ctx->queue_lock); + + list_for_each_entry_safe(area, next_area, &areas, list) { + s32 frame_delta; + u32 phase; + + /* + * Determine when this area can start its refresh. + * If the area is redundant, drop it immediately. + */ + if (area->frame_begin == EBC_FRAME_PENDING && + !rockchip_ebc_schedule_area(&areas, area, frame, + ebc->lut.num_phases)) { + list_del(&area->list); + kfree(area); + continue; + } + + frame_delta = frame - area->frame_begin; + if (frame_delta < 0) + continue; + + /* Copy ctx->final to ctx->next on the first frame. */ + if (frame_delta == 0) { + rockchip_ebc_blit_pixels(ctx, ctx->next, + ctx->final, + &area->clip); + sync_next = true; + } + + /* + * Take advantage of the fact that the last phase in a + * waveform is always zero (neutral polarity). Instead + * of writing the actual phase number, write 0xff (the + * last possible phase number), which is guaranteed to + * be neutral for every waveform. + */ + phase = frame_delta >= last_phase ? 0xff : frame_delta; + rockchip_ebc_blit_phase(ctx, phase_buffer, phase, + &area->clip); + + /* + * Copy ctx->next to ctx->prev after the last phase. + * Technically, this races with the hardware computing + * the last phase, but the last phase is all zeroes + * anyway, regardless of prev/next (see above). + * + * Keeping the area in the list for one extra frame + * also ensures both phase buffers get set to 0xff. + */ + if (frame_delta > last_phase) { + rockchip_ebc_blit_pixels(ctx, ctx->prev, + ctx->next, + &area->clip); + sync_prev = true; + + list_del(&area->list); + kfree(area); + } + } + + if (sync_next) + dma_sync_single_for_device(dev, next_handle, + gray4_size, DMA_TO_DEVICE); + if (sync_prev) + dma_sync_single_for_device(dev, prev_handle, + gray4_size, DMA_TO_DEVICE); + dma_sync_single_for_device(dev, phase_handle, + ctx->phase_size, DMA_TO_DEVICE); + + if (frame) { + if (!wait_for_completion_timeout(&ebc->display_end, + EBC_FRAME_TIMEOUT)) + drm_err(drm, "Frame %d timed out!\n", frame); + } - drm_dbg(drm, "partial refresh\n"); + if (list_empty(&areas)) + break; + + regmap_write(ebc->regmap, EBC_WIN_MST2, + phase_handle); + regmap_write(ebc->regmap, EBC_CONFIG_DONE, + EBC_CONFIG_DONE_REG_CONFIG_DONE); + regmap_write(ebc->regmap, EBC_DSP_START, + ebc->dsp_start | + EBC_DSP_START_DSP_FRM_START); + } } static void rockchip_ebc_refresh(struct rockchip_ebc *ebc, @@ -438,7 +658,8 @@ static int rockchip_ebc_refresh_thread(void *data) rockchip_ebc_refresh(ebc, ctx, false, default_waveform); set_current_state(TASK_IDLE); - schedule(); + if (list_empty(&ctx->queue)) + schedule(); __set_current_state(TASK_RUNNING); } @@ -686,6 +907,7 @@ static const struct drm_crtc_funcs rockchip_ebc_crtc_funcs = { struct ebc_plane_state { struct drm_shadow_plane_state base; + struct list_head areas; }; static inline struct ebc_plane_state * @@ -702,8 +924,13 @@ static inline struct rockchip_ebc *plane_to_ebc(struct drm_plane *plane) static int rockchip_ebc_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) { + struct drm_atomic_helper_damage_iter iter; + struct ebc_plane_state *ebc_plane_state; + struct drm_plane_state *old_plane_state; struct drm_plane_state *plane_state; struct drm_crtc_state *crtc_state; + struct rockchip_ebc_area *area; + struct drm_rect clip; int ret; plane_state = drm_atomic_get_new_plane_state(state, plane); @@ -718,19 +945,126 @@ static int rockchip_ebc_plane_atomic_check(struct drm_plane *plane, if (ret) return ret; + ebc_plane_state = to_ebc_plane_state(plane_state); + old_plane_state = drm_atomic_get_old_plane_state(state, plane); + drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); + drm_atomic_for_each_plane_damage(&iter, &clip) { + area = kmalloc(sizeof(*area), GFP_KERNEL); + if (!area) + return -ENOMEM; + + area->frame_begin = EBC_FRAME_PENDING; + area->clip = clip; + + list_add_tail(&area->list, &ebc_plane_state->areas); + } + return 0; } +static bool rockchip_ebc_blit_fb(const struct rockchip_ebc_ctx *ctx, + const struct drm_rect *dst_clip, + const void *vaddr, + const struct drm_framebuffer *fb, + const struct drm_rect *src_clip) +{ + unsigned int dst_pitch = ctx->gray4_pitch; + unsigned int src_pitch = fb->pitches[0]; + unsigned int x, y; + const void *src; + u8 changed = 0; + void *dst; + + dst = ctx->final + dst_clip->y1 * dst_pitch + dst_clip->x1 / 2; + src = vaddr + src_clip->y1 * src_pitch + src_clip->x1 * fb->format->cpp[0]; + + for (y = src_clip->y1; y < src_clip->y2; y++) { + const u32 *sbuf = src; + u8 *dbuf = dst; + + for (x = src_clip->x1; x < src_clip->x2; x += 2) { + u32 rgb0 = *sbuf++; + u32 rgb1 = *sbuf++; + u8 gray; + + /* Truncate the RGB values to 5 bits each. */ + rgb0 &= 0x00f8f8f8U; rgb1 &= 0x00f8f8f8U; + /* Put the sum 2R+5G+B in bits 24-31. */ + rgb0 *= 0x0020a040U; rgb1 *= 0x0020a040U; + /* Unbias the value for rounding to 4 bits. */ + rgb0 += 0x07000000U; rgb1 += 0x07000000U; + + gray = rgb0 >> 28 | rgb1 >> 28 << 4; + changed |= gray ^ *dbuf; + *dbuf++ = gray; + } + + dst += dst_pitch; + src += src_pitch; + } + + return !!changed; +} + static void rockchip_ebc_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state) { struct rockchip_ebc *ebc = plane_to_ebc(plane); + struct rockchip_ebc_area *area, *next_area; + struct ebc_plane_state *ebc_plane_state; struct drm_plane_state *plane_state; + struct drm_crtc_state *crtc_state; + struct rockchip_ebc_ctx *ctx; + int translate_x, translate_y; + struct drm_rect src; + const void *vaddr; plane_state = drm_atomic_get_new_plane_state(state, plane); if (!plane_state->crtc) return; + crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc); + ctx = to_ebc_crtc_state(crtc_state)->ctx; + + drm_rect_fp_to_int(&src, &plane_state->src); + translate_x = plane_state->dst.x1 - src.x1; + translate_y = plane_state->dst.y1 - src.y1; + + ebc_plane_state = to_ebc_plane_state(plane_state); + vaddr = ebc_plane_state->base.data[0].vaddr; + + list_for_each_entry_safe(area, next_area, &ebc_plane_state->areas, list) { + struct drm_rect *dst_clip = &area->clip; + struct drm_rect src_clip = area->clip; + int adjust; + + /* Convert from plane coordinates to CRTC coordinates. */ + drm_rect_translate(dst_clip, translate_x, translate_y); + + /* Adjust the clips to always process full bytes (2 pixels). */ + adjust = dst_clip->x1 & 1; + dst_clip->x1 -= adjust; + src_clip.x1 -= adjust; + + adjust = dst_clip->x2 & 1; + dst_clip->x2 += adjust; + src_clip.x2 += adjust; + + if (!rockchip_ebc_blit_fb(ctx, dst_clip, vaddr, + plane_state->fb, &src_clip)) { + /* Drop the area if the FB didn't actually change. */ + list_del(&area->list); + kfree(area); + } + } + + if (list_empty(&ebc_plane_state->areas)) + return; + + spin_lock(&ctx->queue_lock); + list_splice_tail_init(&ebc_plane_state->areas, &ctx->queue); + spin_unlock(&ctx->queue_lock); + wake_up_process(ebc->refresh_thread); } @@ -756,6 +1090,8 @@ static void rockchip_ebc_plane_reset(struct drm_plane *plane) return; __drm_gem_reset_shadow_plane(plane, &ebc_plane_state->base); + + INIT_LIST_HEAD(&ebc_plane_state->areas); } static struct drm_plane_state * @@ -772,6 +1108,8 @@ rockchip_ebc_plane_duplicate_state(struct drm_plane *plane) __drm_gem_duplicate_shadow_plane_state(plane, &ebc_plane_state->base); + INIT_LIST_HEAD(&ebc_plane_state->areas); + return &ebc_plane_state->base.base; } @@ -779,6 +1117,10 @@ static void rockchip_ebc_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *plane_state) { struct ebc_plane_state *ebc_plane_state = to_ebc_plane_state(plane_state); + struct rockchip_ebc_area *area, *next_area; + + list_for_each_entry_safe(area, next_area, &ebc_plane_state->areas, list) + kfree(area); __drm_gem_destroy_shadow_plane_state(&ebc_plane_state->base); From patchwork Wed Apr 13 22:19:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Holland X-Patchwork-Id: 12812742 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 25406C433EF for ; Wed, 13 Apr 2022 22:19:50 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 4BA3510F14F; Wed, 13 Apr 2022 22:19:49 +0000 (UTC) Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by gabe.freedesktop.org (Postfix) with ESMTPS id 8E2C210F146 for ; Wed, 13 Apr 2022 22:19:44 +0000 (UTC) Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.nyi.internal (Postfix) with ESMTP id DA9EB5C0340; Wed, 13 Apr 2022 18:19:43 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute5.internal (MEProxy); Wed, 13 Apr 2022 18:19:43 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sholland.org; h= cc:cc:content-transfer-encoding:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm2; t=1649888383; x=1649974783; bh=Qt Ox4T0HCpftqJcX0VmKkuT5uvDIfTobCkM4Jig4EYE=; b=XDrAt+uvDf0VTBvnBx xV6fY/r43+56hVhxGIinMCoZBALz9K+MTpsGGOGYZcgk6X8fxFKUdcKfo7hvoAw3 rlmpRXK+IAxkbSMnxfTd5+xXfl+VKP+V2S4O6kLq/ucyEQM3VfupIPIbBFd9hLcV ZPMPME1EXUQFiCr7H4thhG4/vKr/pnP9lQ5WurO3wV5w3bhhxKYZj0yAxN2DZzwT 734mWh478oLDkTKIL4oh18DtNtf7b+LmWjZeUnJg5wzMJZCOJGrpn6KbsQ/Z545+ xSsE2wb6d1r/o65h9a8LVKYox9AM16nKNg8n6vcf8teN9UjOhVNU2t+c/tlrhQxo /N0A== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1649888383; x=1649974783; bh=QtOx4T0HCpftqJcX0VmKkuT5uvDIfTobCkM 4Jig4EYE=; b=bZiOfd0iJLPlzQ2/ZVIL+ux8BJZtFvN7R7gXr9xO4tjFQReZG6S PgjGn2fxUzoxC4EUae30tFI2E3IIlAJjwYk204JoEi8fOaHmUYXaVarSrzf4o1Lk WuV6x7ne4j1UEmh/ke9qXMgHI1xMjhChma1ajoNjlDIXfx0oNu3ylhRnU/frmSXf +YyXpunm+zqpYIyFdAE7Ou1dKKfBWdWuJIxq81ihfgbEh3fvkehvdFA5X/LmuswJ wBIlg5Tjgs5+1kezxWtkNFRGBxwuo7fRQUeT2lDBmlJqXVWvjYkfgkNz/C0tbg6b YH1bkCZVzhPu3XJtnw2OAMA3UMV8iBJi0Jg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudelvddgtdelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefurghmuhgv lhcujfholhhlrghnugcuoehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhgqeenucggtf frrghtthgvrhhnpeduhfejfedvhffgfeehtefghfeiiefgfeehgfdvvdevfeegjeehjedv gfejheeuieenucevlhhushhtvghrufhiiigvpeehnecurfgrrhgrmhepmhgrihhlfhhroh hmpehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhg X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 13 Apr 2022 18:19:42 -0400 (EDT) From: Samuel Holland To: =?utf-8?q?Heiko_St=C3=BCbner?= , Sandy Huang , dri-devel@lists.freedesktop.org Subject: [RFC PATCH 11/16] drm/rockchip: ebc: Enable diff mode for partial refreshes Date: Wed, 13 Apr 2022 17:19:11 -0500 Message-Id: <20220413221916.50995-12-samuel@sholland.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220413221916.50995-1-samuel@sholland.org> References: <20220413221916.50995-1-samuel@sholland.org> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Airlie , =?utf-8?q?Ond=C5=99ej_Jirman?= , Thierry Reding , Michael Riesch , Sam Ravnborg , Samuel Holland , Nicolas Frattaroli , linux-rockchip@lists.infradead.org, Andreas Kemnade , Geert Uytterhoeven , Liang Chen , devicetree@vger.kernel.org, Thomas Zimmermann , Alistair Francis , Rob Herring , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peter Geis , Krzysztof Kozlowski Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Some waveforms, such as GC16, cause the display to flash even when the previous and next pixel values are the same. This can be helpful, because it produces more consistent brightness, but usually it is more distracting. Add an option, enabled by default, for the hardware to ignore the LUT and always send zeroes for pixels with unchanged values. Signed-off-by: Samuel Holland --- drivers/gpu/drm/rockchip/rockchip_ebc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_ebc.c b/drivers/gpu/drm/rockchip/rockchip_ebc.c index c3e4b65bdee6..dcd8c8e8208e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_ebc.c +++ b/drivers/gpu/drm/rockchip/rockchip_ebc.c @@ -158,6 +158,10 @@ static int default_waveform = DRM_EPD_WF_GC16; module_param(default_waveform, int, 0644); MODULE_PARM_DESC(default_waveform, "waveform to use for display updates"); +static bool diff_mode = true; +module_param(diff_mode, bool, 0644); +MODULE_PARM_DESC(diff_mode, "only compute waveforms for changed pixels"); + static bool skip_reset; module_param(skip_reset, bool, 0444); MODULE_PARM_DESC(skip_reset, "skip the initial display reset"); @@ -582,11 +586,14 @@ static void rockchip_ebc_refresh(struct rockchip_ebc *ebc, dsp_ctrl |= EBC_DSP_CTRL_DSP_LUT_MODE; } else { epd_ctrl |= EBC_EPD_CTRL_DSP_THREE_WIN_MODE; + if (diff_mode) + dsp_ctrl |= EBC_DSP_CTRL_DSP_DIFF_MODE; } regmap_update_bits(ebc->regmap, EBC_EPD_CTRL, EBC_EPD_CTRL_DSP_THREE_WIN_MODE, epd_ctrl); regmap_update_bits(ebc->regmap, EBC_DSP_CTRL, + EBC_DSP_CTRL_DSP_DIFF_MODE | EBC_DSP_CTRL_DSP_LUT_MODE, dsp_ctrl); From patchwork Wed Apr 13 22:19:12 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Holland X-Patchwork-Id: 12812750 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 7F386C433EF for ; Wed, 13 Apr 2022 22:20:05 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 87BEF10F15D; Wed, 13 Apr 2022 22:20:04 +0000 (UTC) Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by gabe.freedesktop.org (Postfix) with ESMTPS id 865F110F146 for ; Wed, 13 Apr 2022 22:19:46 +0000 (UTC) Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.nyi.internal (Postfix) with ESMTP id D15815C033E; Wed, 13 Apr 2022 18:19:45 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute5.internal (MEProxy); Wed, 13 Apr 2022 18:19:45 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sholland.org; h= cc:cc:content-transfer-encoding:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm2; t=1649888385; x=1649974785; bh=yM jDNZk22ts1QSeZuHA3iHwk+1FDAWv58BJ1pfqsy94=; b=whdq+uqQW2un1gyfjq QH/YN4888u9WajBX6vFAnjzIXIm/0H3dnT7DmqEnv87XNVxuQAICx/F0JRuxFrvd jBoSJYdsPUeZ3VtIuzLd7+W5IC2xlLLWIDR30BHtuL6zjv5ydSTpOzE7Czl3L/QH V90CyPj8z5UYaSPfAHCySnGFxjtfxBrHaXUv74TwKHQmynfgrlCWE4JZHynJbUeH gifbwQA52NroLRoKZqU+rCtB6va60KonAfmTE3ohwg36qb3Xsjjt90XwmMRFpdIJ 88yXZ8u57UFZnxNQhEwLraXeT4/bjSA3xsXeV3gyVMvB7ttGj7bse4a9xYVKWaRR hy5g== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1649888385; x=1649974785; bh=yMjDNZk22ts1QSeZuHA3iHwk+1FDAWv58BJ 1pfqsy94=; b=o/8Pde0ihVf9vakWSJ1n68tyevicS+zcAaZm7XMY10IOCxXE/3k po4pyR51AAUrVHwYmXCbHsyrMxJOQfmkwukTuGlIo6QbPXPrceg0K3/VD5R5H1oW A9fkmmqGST3jlFXnqfEtq9CWDhz0FHG/0KtkRZsokjhNbKCxKxlN029jZyTJcPO4 L1XuIOZkPtNTI9GGBy2OtRtu6NaOhDu051UnsDAmJzfP6O2BIARGPw9REoFYlT2Q Rg9GZ3+KiK0YlR5BhYR96LwzxvRzMNvyF3KBEviqET3TYoEbDqL5ZUTi4Zjymd7g IpXOgxYuYM1gt4Zw43gmmnfJkpaRF+sfC8A== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudelvddgtdelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefurghmuhgv lhcujfholhhlrghnugcuoehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhgqeenucggtf frrghtthgvrhhnpeduhfejfedvhffgfeehtefghfeiiefgfeehgfdvvdevfeegjeehjedv gfejheeuieenucevlhhushhtvghrufhiiigvpeehnecurfgrrhgrmhepmhgrihhlfhhroh hmpehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhg X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 13 Apr 2022 18:19:44 -0400 (EDT) From: Samuel Holland To: =?utf-8?q?Heiko_St=C3=BCbner?= , Sandy Huang , dri-devel@lists.freedesktop.org Subject: [RFC PATCH 12/16] drm/rockchip: ebc: Add support for direct mode Date: Wed, 13 Apr 2022 17:19:12 -0500 Message-Id: <20220413221916.50995-13-samuel@sholland.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220413221916.50995-1-samuel@sholland.org> References: <20220413221916.50995-1-samuel@sholland.org> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Airlie , =?utf-8?q?Ond=C5=99ej_Jirman?= , Thierry Reding , Michael Riesch , Sam Ravnborg , Samuel Holland , Nicolas Frattaroli , linux-rockchip@lists.infradead.org, Andreas Kemnade , Geert Uytterhoeven , Liang Chen , devicetree@vger.kernel.org, Thomas Zimmermann , Alistair Francis , Rob Herring , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peter Geis , Krzysztof Kozlowski Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Currently, 3-window mode causes some artifacting. Until the cause is determined, provide an option to use direct mode instead. Direct mode does the waveform lookups in software, so it has much higher CPU usage. This limits the frame rate below the panel's ideal 85 Hz, so it leads to slightly lower brightness accuracy. On the other hand, it doesn't leave random lines all over the screen. Signed-off-by: Samuel Holland --- drivers/gpu/drm/rockchip/rockchip_ebc.c | 97 ++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_ebc.c b/drivers/gpu/drm/rockchip/rockchip_ebc.c index dcd8c8e8208e..93d689ff0933 100644 --- a/drivers/gpu/drm/rockchip/rockchip_ebc.c +++ b/drivers/gpu/drm/rockchip/rockchip_ebc.c @@ -162,6 +162,10 @@ static bool diff_mode = true; module_param(diff_mode, bool, 0644); MODULE_PARM_DESC(diff_mode, "only compute waveforms for changed pixels"); +static bool direct_mode = true; +module_param(direct_mode, bool, 0444); +MODULE_PARM_DESC(direct_mode, "compute waveforms in software (software LUT)"); + static bool skip_reset; module_param(skip_reset, bool, 0444); MODULE_PARM_DESC(skip_reset, "skip the initial display reset"); @@ -370,6 +374,59 @@ static bool rockchip_ebc_schedule_area(struct list_head *areas, return true; } +static void rockchip_ebc_blit_direct(const struct rockchip_ebc_ctx *ctx, + u8 *dst, u8 phase, + const struct drm_epd_lut *lut, + const struct drm_rect *clip) +{ + const u32 *phase_lut = (const u32 *)lut->buf + 16 * phase; + unsigned int dst_pitch = ctx->phase_pitch / 4; + unsigned int src_pitch = ctx->gray4_pitch; + unsigned int x, y; + u8 *dst_line; + u32 src_line; + + dst_line = dst + clip->y1 * dst_pitch + clip->x1 / 4; + src_line = clip->y1 * src_pitch + clip->x1 / 2; + + for (y = clip->y1; y < clip->y2; y++) { + u32 src_offset = src_line; + u8 *dbuf = dst_line; + + for (x = clip->x1; x < clip->x2; x += 4) { + u8 prev0 = ctx->prev[src_offset]; + u8 next0 = ctx->next[src_offset++]; + u8 prev1 = ctx->prev[src_offset]; + u8 next1 = ctx->next[src_offset++]; + + /* + * The LUT is 256 phases * 16 next * 16 previous levels. + * Each value is two bits, so the last dimension neatly + * fits in a 32-bit word. + */ + u8 data = ((phase_lut[next0 & 0xf] >> ((prev0 & 0xf) << 1)) & 0x3) << 0 | + ((phase_lut[next0 >> 4] >> ((prev0 >> 4) << 1)) & 0x3) << 2 | + ((phase_lut[next1 & 0xf] >> ((prev1 & 0xf) << 1)) & 0x3) << 4 | + ((phase_lut[next1 >> 4] >> ((prev1 >> 4) << 1)) & 0x3) << 6; + + /* Diff mode ignores pixels that did not change brightness. */ + if (diff_mode) { + u8 mask = ((next0 ^ prev0) & 0x0f ? 0x03 : 0) | + ((next0 ^ prev0) & 0xf0 ? 0x0c : 0) | + ((next1 ^ prev1) & 0x0f ? 0x30 : 0) | + ((next1 ^ prev1) & 0xf0 ? 0xc0 : 0); + + data &= mask; + } + + *dbuf++ = data; + } + + dst_line += dst_pitch; + src_line += src_pitch; + } +} + static void rockchip_ebc_blit_phase(const struct rockchip_ebc_ctx *ctx, u8 *dst, u8 phase, const struct drm_rect *clip) @@ -472,8 +529,13 @@ static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc, * be neutral for every waveform. */ phase = frame_delta >= last_phase ? 0xff : frame_delta; - rockchip_ebc_blit_phase(ctx, phase_buffer, phase, - &area->clip); + if (direct_mode) + rockchip_ebc_blit_direct(ctx, phase_buffer, + phase, &ebc->lut, + &area->clip); + else + rockchip_ebc_blit_phase(ctx, phase_buffer, + phase, &area->clip); /* * Copy ctx->next to ctx->prev after the last phase. @@ -513,7 +575,8 @@ static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc, if (list_empty(&areas)) break; - regmap_write(ebc->regmap, EBC_WIN_MST2, + regmap_write(ebc->regmap, + direct_mode ? EBC_WIN_MST0 : EBC_WIN_MST2, phase_handle); regmap_write(ebc->regmap, EBC_CONFIG_DONE, EBC_CONFIG_DONE_REG_CONFIG_DONE); @@ -581,10 +644,12 @@ static void rockchip_ebc_refresh(struct rockchip_ebc *ebc, /* * The hardware has a separate bit for each mode, with some priority * scheme between them. For clarity, only set one bit at a time. + * + * NOTE: In direct mode, no mode bits are set. */ if (global_refresh) { dsp_ctrl |= EBC_DSP_CTRL_DSP_LUT_MODE; - } else { + } else if (!direct_mode) { epd_ctrl |= EBC_EPD_CTRL_DSP_THREE_WIN_MODE; if (diff_mode) dsp_ctrl |= EBC_DSP_CTRL_DSP_DIFF_MODE; @@ -647,8 +712,12 @@ static int rockchip_ebc_refresh_thread(void *data) */ memset(ctx->prev, 0xff, ctx->gray4_size); memset(ctx->next, 0xff, ctx->gray4_size); - memset(ctx->phase[0], 0xff, ctx->phase_size); - memset(ctx->phase[1], 0xff, ctx->phase_size); + /* + * NOTE: In direct mode, the phase buffers are repurposed for + * source driver polarity data, where the no-op value is 0. + */ + memset(ctx->phase[0], direct_mode ? 0 : 0xff, ctx->phase_size); + memset(ctx->phase[1], direct_mode ? 0 : 0xff, ctx->phase_size); /* * LUTs use both the old and the new pixel values as inputs. @@ -1048,12 +1117,22 @@ static void rockchip_ebc_plane_atomic_update(struct drm_plane *plane, /* Convert from plane coordinates to CRTC coordinates. */ drm_rect_translate(dst_clip, translate_x, translate_y); - /* Adjust the clips to always process full bytes (2 pixels). */ - adjust = dst_clip->x1 & 1; + /* + * Adjust the clips to always process full bytes (2 pixels). + * + * NOTE: in direct mode, the minimum block size is 4 pixels. + */ + if (direct_mode) + adjust = dst_clip->x1 & 3; + else + adjust = dst_clip->x1 & 1; dst_clip->x1 -= adjust; src_clip.x1 -= adjust; - adjust = dst_clip->x2 & 1; + if (direct_mode) + adjust = ((dst_clip->x2 + 3) ^ 3) & 3; + else + adjust = dst_clip->x2 & 1; dst_clip->x2 += adjust; src_clip.x2 += adjust; From patchwork Wed Apr 13 22:19:13 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Holland X-Patchwork-Id: 12812744 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C637DC4332F for ; Wed, 13 Apr 2022 22:19:53 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 4CE3910F152; Wed, 13 Apr 2022 22:19:51 +0000 (UTC) Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by gabe.freedesktop.org (Postfix) with ESMTPS id 7C40610F14C for ; Wed, 13 Apr 2022 22:19:48 +0000 (UTC) Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.nyi.internal (Postfix) with ESMTP id CB4D95C02B7; Wed, 13 Apr 2022 18:19:47 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute5.internal (MEProxy); Wed, 13 Apr 2022 18:19:47 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sholland.org; h= cc:cc:content-transfer-encoding:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm2; t=1649888387; x=1649974787; bh=fM itBsbOl69eJtZqeNqN7y5Gep0bncSngDUeMZp8zB4=; b=qJkffVFYB9u7OIdDzI T+1qUMCsmcnyDpSK9V3nkFZ5QOoQsHC/fGuXl63TdKyWdr72KmxelbV6YPH7WaQ7 Baf3DTKZeommUEDIxwu+J+/OwRmkTX+phQZWLXNE4EyZ/80yATPkevMKvx6PQQku DvbyMupWMAu9HlWSjjud30mpLgrW1oaWCLhiDEuirEqfEAgEbRvOd2i1IWyhqqmo flEf8CWNhsligN4vGyse639Z6hV+Avv09HlueYb/KVCsbk7jLUeIaQ/MRmy+AFqH Q2lNi5ZeQNi5RgdxbYaaq+YAowpHa5WnFT3Ek6/aP2swQ7dSpi0Myn0Ctc3uTi6i TQNw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1649888387; x=1649974787; bh=fMitBsbOl69eJtZqeNqN7y5Gep0bncSngDU eMZp8zB4=; b=iFab+bH6MXUBpnDsciPRLYKcTitrp1MRRAMJsBccGx0Yj72+C54 qt0C6cHdYHQgI536AX+ZfWtAyYD1261wPAL10dugJO1L+R9kDXDwJVRzYgYhS3Wg igMT9SrlenjEXrpj5bTVasZpwFp+wTYHSKMLPgcjAoorkJILWjszYaFWU3DQZQ39 kzqHcMf2F16lcAa/dIedVMMsg16vJ4kPkYy96vHFp+Wl3hOZO5/cA1pXmsNA5mBv zsHy4zQi4qGoDlhvchcnQ36PgsEErts66IqUmxTVpmtRw77/GCSsf9TTdbO3aOhm zWRxjedZPyxwL68m8khLTjbcXEqqG0X0ezA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudelvddgtdelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefurghmuhgv lhcujfholhhlrghnugcuoehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhgqeenucggtf frrghtthgvrhhnpeduhfejfedvhffgfeehtefghfeiiefgfeehgfdvvdevfeegjeehjedv gfejheeuieenucevlhhushhtvghrufhiiigvpeejnecurfgrrhgrmhepmhgrihhlfhhroh hmpehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhg X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 13 Apr 2022 18:19:46 -0400 (EDT) From: Samuel Holland To: =?utf-8?q?Heiko_St=C3=BCbner?= , Sandy Huang , dri-devel@lists.freedesktop.org Subject: [RFC PATCH 13/16] drm/rockchip: ebc: Add a panel reflection option Date: Wed, 13 Apr 2022 17:19:13 -0500 Message-Id: <20220413221916.50995-14-samuel@sholland.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220413221916.50995-1-samuel@sholland.org> References: <20220413221916.50995-1-samuel@sholland.org> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Airlie , =?utf-8?q?Ond=C5=99ej_Jirman?= , Thierry Reding , Michael Riesch , Sam Ravnborg , Samuel Holland , Nicolas Frattaroli , linux-rockchip@lists.infradead.org, Andreas Kemnade , Geert Uytterhoeven , Liang Chen , devicetree@vger.kernel.org, Thomas Zimmermann , Alistair Francis , Rob Herring , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peter Geis , Krzysztof Kozlowski Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Some panels, like the one in the PineNote, are reflected. Since the driver already has to copy pixels, the driver can handle this with little additional overhead. Currently, there is no devicetree binding for this situation, so control the behavior via a module parameter. Signed-off-by: Samuel Holland --- drivers/gpu/drm/rockchip/rockchip_ebc.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_ebc.c b/drivers/gpu/drm/rockchip/rockchip_ebc.c index 93d689ff0933..9d0b2cdc5fdc 100644 --- a/drivers/gpu/drm/rockchip/rockchip_ebc.c +++ b/drivers/gpu/drm/rockchip/rockchip_ebc.c @@ -166,6 +166,10 @@ static bool direct_mode = true; module_param(direct_mode, bool, 0444); MODULE_PARM_DESC(direct_mode, "compute waveforms in software (software LUT)"); +static bool panel_reflection = true; +module_param(panel_reflection, bool, 0644); +MODULE_PARM_DESC(panel_reflection, "reflect the image horizontally"); + static bool skip_reset; module_param(skip_reset, bool, 0444); MODULE_PARM_DESC(skip_reset, "skip the initial display reset"); @@ -1046,23 +1050,29 @@ static bool rockchip_ebc_blit_fb(const struct rockchip_ebc_ctx *ctx, { unsigned int dst_pitch = ctx->gray4_pitch; unsigned int src_pitch = fb->pitches[0]; - unsigned int x, y; + unsigned int start_x, x, y; const void *src; u8 changed = 0; + int delta_x; void *dst; + delta_x = panel_reflection ? -1 : 1; + start_x = panel_reflection ? src_clip->x2 - 1 : src_clip->x1; + dst = ctx->final + dst_clip->y1 * dst_pitch + dst_clip->x1 / 2; - src = vaddr + src_clip->y1 * src_pitch + src_clip->x1 * fb->format->cpp[0]; + src = vaddr + src_clip->y1 * src_pitch + start_x * fb->format->cpp[0]; for (y = src_clip->y1; y < src_clip->y2; y++) { const u32 *sbuf = src; u8 *dbuf = dst; for (x = src_clip->x1; x < src_clip->x2; x += 2) { - u32 rgb0 = *sbuf++; - u32 rgb1 = *sbuf++; + u32 rgb0, rgb1; u8 gray; + rgb0 = *sbuf; sbuf += delta_x; + rgb1 = *sbuf; sbuf += delta_x; + /* Truncate the RGB values to 5 bits each. */ rgb0 &= 0x00f8f8f8U; rgb1 &= 0x00f8f8f8U; /* Put the sum 2R+5G+B in bits 24-31. */ @@ -1136,6 +1146,13 @@ static void rockchip_ebc_plane_atomic_update(struct drm_plane *plane, dst_clip->x2 += adjust; src_clip.x2 += adjust; + if (panel_reflection) { + int x1 = dst_clip->x1, x2 = dst_clip->x2; + + dst_clip->x1 = plane_state->dst.x2 - x2; + dst_clip->x2 = plane_state->dst.x2 - x1; + } + if (!rockchip_ebc_blit_fb(ctx, dst_clip, vaddr, plane_state->fb, &src_clip)) { /* Drop the area if the FB didn't actually change. */ From patchwork Wed Apr 13 22:19:14 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Holland X-Patchwork-Id: 12812747 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 20CA6C4332F for ; Wed, 13 Apr 2022 22:19:58 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id BDD4910F156; Wed, 13 Apr 2022 22:19:51 +0000 (UTC) Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by gabe.freedesktop.org (Postfix) with ESMTPS id 73DAE10F152 for ; Wed, 13 Apr 2022 22:19:50 +0000 (UTC) Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id C2EC85C0347; Wed, 13 Apr 2022 18:19:49 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Wed, 13 Apr 2022 18:19:49 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sholland.org; h= cc:cc:content-transfer-encoding:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm2; t=1649888389; x=1649974789; bh=Ix LBprYD2crzgvrunvWymMhkE+BNBrBvN21E3wbwSFs=; b=F0pVSeeJEeN1Z2J7WT 2sMD/Ww3ziFwKcYXwvLoicHMtLPYxUv98wFKu8AoOtsK00YNmglvA8b++NZ/DxLg OtcCt2AZjZfa/qVRgVDqwPyCOFuKEeKof/AiOp8kgUnZof16PdUbH+X/t5gmHLuv s6p7OrBqffK+IT8QVY32iD+oyVNWFnkma9/q9mLy4sZq/IuukJmv7IhPS09/j/Mq cJbaT3w2lH9pQPmThQhf4ir3Ka5IL0rK+uc7DQkx7n/8OajV8Y4TAOzEFPjheBdo G0Tum5uKE+RSsr3yr/OAFoKtlSMeiGpTqvndwMHSWzGURbvbT2OKxGRzhQottMaF 2IBg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1649888389; x=1649974789; bh=IxLBprYD2crzgvrunvWymMhkE+BNBrBvN21 E3wbwSFs=; b=WHBYwoeJdEcfsRY7exrnwpuzazuw+st4toSxu0pPTvq2UaKL/+a hyzHJM1H4mohKKXkkyM0NOygsRl1XqqIGjwSX7Jj5s7F8R58wWbVSQye0psNMAnd +U7TZYi053Tk13RPWLCP/EqiahCyQteZk+dB3FMgOhzQ3nfTI1DHcjEUndB7tbza reNqUjwq8EmnHJpDPGZYg04pAnFYH8oBlvJACrrlB3eoDI8RjURVYckVxKwQPe1H ziPmtc1FZTC5exk5RP9I7iiW2VzYsW4Q40QH4pm7wii4LsJdUuXTsPJY5PiYVNAZ vtj8D14l++mzYOgkQ6DYfgEK22Qc3O3sphQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudelvddguddtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefurghmuhgv lhcujfholhhlrghnugcuoehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhgqeenucggtf frrghtthgvrhhnpefhvddvjeevleduteevveeiieetudejheetgeevgefhveehtdegieet jeevgeduveenucffohhmrghinhepphhinhgvieegrdhorhhgnecuvehluhhsthgvrhfuih iivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepshgrmhhuvghlsehshhholhhlrghn ugdrohhrgh X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 13 Apr 2022 18:19:48 -0400 (EDT) From: Samuel Holland To: =?utf-8?q?Heiko_St=C3=BCbner?= , Sandy Huang , dri-devel@lists.freedesktop.org Subject: [RFC PATCH 14/16] drm/panel-simple: Add eInk ED103TC2 Date: Wed, 13 Apr 2022 17:19:14 -0500 Message-Id: <20220413221916.50995-15-samuel@sholland.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220413221916.50995-1-samuel@sholland.org> References: <20220413221916.50995-1-samuel@sholland.org> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Airlie , =?utf-8?q?Ond=C5=99ej_Jirman?= , Thierry Reding , Michael Riesch , Sam Ravnborg , Samuel Holland , Nicolas Frattaroli , linux-rockchip@lists.infradead.org, Andreas Kemnade , Geert Uytterhoeven , Liang Chen , devicetree@vger.kernel.org, Thomas Zimmermann , Alistair Francis , Rob Herring , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peter Geis , Krzysztof Kozlowski Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" ED103TC2 is a 10.3" 1872x1404 eInk panel which supports up to 16 levels of grayscale and an 85 Hz frame rate. The timings and polarities here were taken from the manufacturer's datasheet. Since this panel is an electrophoretic display (EPD), the color depth is independent from the bus width. Instead, it is largely determined by the number of frames in the selected waveform. Each pixel uses two parallel data lines to specify one of only three states each frame: positive, negative, or no voltage. This specific panel has a 16-bit data bus, allowing it to update 8 pixels during each source driver (horizontal) clock cycle. As a result, the horizontal timings given in the datasheet were all multiplied by 8 to convert the units from clock cycles to pixels. Since the 16-bit data bus is double the width of the usual 8-bit bus used by eInk panels, the source driver clock will be half the usual frequency. This is signified by the DRM_MODE_FLAG_CLKDIV2 flag. The hskew parameter provides the spacing between the horizontal sync puls and the gate driver (vertical) clock pulse. This spacing is symmetrical on both sides, so it can be used to compute the gate driver clock pulse width. Datasheet: https://files.pine64.org/doc/quartz64/Eink%20P-511-828-V1_ED103TC2%20Formal%20Spec%20V1.0_20190514.pdf Signed-off-by: Samuel Holland --- drivers/gpu/drm/panel/panel-simple.c | 31 ++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index a34f4198a534..c6b104ba01ee 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1686,6 +1686,34 @@ static const struct panel_desc edt_etmv570g2dhu = { .connector_type = DRM_MODE_CONNECTOR_DPI, }; +static const struct drm_display_mode eink_ed103tc2_mode = { + .clock = 266693, + .hdisplay = 1872, + .hsync_start = 1872 + 184, + .hsync_end = 1872 + 184 + 88, + .htotal = 1872 + 184 + 88 + 64, + .hskew = 136, + .vdisplay = 1404, + .vsync_start = 1404 + 12, + .vsync_end = 1404 + 12 + 1, + .vtotal = 1404 + 12 + 1 + 4, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_HSKEW | DRM_MODE_FLAG_CLKDIV2, +}; + +static const struct panel_desc eink_ed103tc2 = { + .modes = &eink_ed103tc2_mode, + .num_modes = 1, + .bpc = 4, + .size = { + .width = 210, + .height = 157, + }, + .bus_format = MEDIA_BUS_FMT_FIXED, + .bus_flags = DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE, + .connector_type = DRM_MODE_CONNECTOR_DPI, +}; + static const struct display_timing eink_vb3300_kca_timing = { .pixelclock = { 40000000, 40000000, 40000000 }, .hactive = { 334, 334, 334 }, @@ -3807,6 +3835,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "edt,etmv570g2dhu", .data = &edt_etmv570g2dhu, + }, { + .compatible = "eink,ed103tc2", + .data = &eink_ed103tc2, }, { .compatible = "eink,vb3300-kca", .data = &eink_vb3300_kca, From patchwork Wed Apr 13 22:19:15 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Holland X-Patchwork-Id: 12812749 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A0035C433FE for ; Wed, 13 Apr 2022 22:20:02 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 6F74110F15B; Wed, 13 Apr 2022 22:20:00 +0000 (UTC) Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by gabe.freedesktop.org (Postfix) with ESMTPS id 6854610F15B for ; Wed, 13 Apr 2022 22:19:52 +0000 (UTC) Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.nyi.internal (Postfix) with ESMTP id B5DB05C029F; Wed, 13 Apr 2022 18:19:51 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute4.internal (MEProxy); Wed, 13 Apr 2022 18:19:51 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sholland.org; h= cc:cc:content-transfer-encoding:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm2; t=1649888391; x=1649974791; bh=r6 8Xnm3H33EQgdbz7LYraAskJdNQ1ivO7aFZEAoIKAI=; b=i1JMYe+VYvdvr43zkv rDuNGZ58Ro3xDHMyKyBN4OnEAlxiHGLPtCA4+O4bdMEUCj14lZE8046cnZCJ9jnD 8DLeXDbxxpqVN2xqdlD4cKBi3N/KFWK+l2jmNrrj3TD2wIAfJcE+PH1IyjO7KMkA 5h+nsE12K6BGbwmLolsUNvj7e1/0ZVxxEcd2LrhvLve6b2Hd2ZGPkb10J8DTfg1N n/4Il/14MsUqiF4LmQ15q2tSfeI+3eEab/HWqd5/OY5Bttbjkf7zkhJtr37YIF+d 1/S+sHJdKWT9rxKu/K2a0xb/s1bpv5XsegcU6zMXBylPARz6LyaWebpxLNBunYxI 0qYQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1649888391; x=1649974791; bh=r68Xnm3H33EQgdbz7LYraAskJdNQ1ivO7aF ZEAoIKAI=; b=oJmZjkvbs64pHexVyL74MFyo9GHxVwHCiDfNn4xRbkQq4HDfreq QStpQ8heF6cB14ziPQPfc/GPgN0wbD6qAgc8KvyZjnTrDvsTtUFzBqRiKW81EBu1 7K2TUQ8fm84JxB/xtYY2MvqGO3ln2axczz8UPpfY9/kNAb7Zw3hl9HyYGFK1U+lD 2RXkZTz9/V3qRhIRgvqtU/VPh6ZWwm34BSY5LkJn7y9cw5IwT08i7kHCgzmZj8oD QecYDvudLylKTpyEDTqNAIpHTwMelF+BocUpWdFy1MT+BPSQsEJrx1ew9ksbQS0Y akqFdJqTkcpdv7usqoKqzH4oLDWqxd0mNTg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudelvddgtdelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefurghmuhgv lhcujfholhhlrghnugcuoehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhgqeenucggtf frrghtthgvrhhnpeduhfejfedvhffgfeehtefghfeiiefgfeehgfdvvdevfeegjeehjedv gfejheeuieenucevlhhushhtvghrufhiiigvpedunecurfgrrhgrmhepmhgrihhlfhhroh hmpehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhg X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 13 Apr 2022 18:19:50 -0400 (EDT) From: Samuel Holland To: =?utf-8?q?Heiko_St=C3=BCbner?= , Sandy Huang , dri-devel@lists.freedesktop.org Subject: [RFC PATCH 15/16] arm64: dts: rockchip: rk356x: Add EBC node Date: Wed, 13 Apr 2022 17:19:15 -0500 Message-Id: <20220413221916.50995-16-samuel@sholland.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220413221916.50995-1-samuel@sholland.org> References: <20220413221916.50995-1-samuel@sholland.org> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Airlie , =?utf-8?q?Ond=C5=99ej_Jirman?= , Thierry Reding , Michael Riesch , Sam Ravnborg , Samuel Holland , Nicolas Frattaroli , linux-rockchip@lists.infradead.org, Andreas Kemnade , Geert Uytterhoeven , Liang Chen , devicetree@vger.kernel.org, Thomas Zimmermann , Alistair Francis , Rob Herring , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peter Geis , Krzysztof Kozlowski Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" The RK356x SoCs contain an EBC. Add its node. Signed-off-by: Samuel Holland --- arch/arm64/boot/dts/rockchip/rk356x.dtsi | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk356x.dtsi b/arch/arm64/boot/dts/rockchip/rk356x.dtsi index 7cdef800cb3c..58c26f240af0 100644 --- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi @@ -508,6 +508,20 @@ gpu: gpu@fde60000 { status = "disabled"; }; + ebc: ebc@fdec0000 { + compatible = "rockchip,rk3568-ebc"; + reg = <0x0 0xfdec0000 0x0 0x5000>; + interrupts = ; + clocks = <&cru HCLK_EBC>, <&cru DCLK_EBC>; + clock-names = "hclk", "dclk"; + pinctrl-0 = <&ebc_pins>; + pinctrl-names = "default"; + power-domains = <&power RK3568_PD_RGA>; + resets = <&cru SRST_H_EBC>, <&cru SRST_D_EBC>; + reset-names = "hclk", "dclk"; + status = "disabled"; + }; + sdmmc2: mmc@fe000000 { compatible = "rockchip,rk3568-dw-mshc", "rockchip,rk3288-dw-mshc"; reg = <0x0 0xfe000000 0x0 0x4000>; From patchwork Wed Apr 13 22:19:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Holland X-Patchwork-Id: 12812748 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 0FAC9C433F5 for ; Wed, 13 Apr 2022 22:20:01 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id F315110F155; Wed, 13 Apr 2022 22:19:59 +0000 (UTC) Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by gabe.freedesktop.org (Postfix) with ESMTPS id 5403710F155 for ; Wed, 13 Apr 2022 22:19:54 +0000 (UTC) Received: from compute2.internal (compute2.nyi.internal [10.202.2.46]) by mailout.nyi.internal (Postfix) with ESMTP id A2E4E5C034D; Wed, 13 Apr 2022 18:19:53 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute2.internal (MEProxy); Wed, 13 Apr 2022 18:19:53 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sholland.org; h= cc:cc:content-transfer-encoding:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to; s=fm2; t=1649888393; x= 1649974793; bh=hsDsSOvCiPnQ5iI1qwr559UylC5AhqoZAQgmwuaC8k8=; b=k Xb3zpUzSFboY38A9QsINY8zApMK7WgMQOw4Ng9USwQlBfyE0MVR1tylfrDy1I+qT g6Ae3V2zcIx2tvVyWavFpOefn02gLujLxskrpAgB2ouD6bVYY/TyCEtU75OJgzuQ CtDJ1zFxURn+0MoLRdIN9C5oEb8rS2PPEtEpqdLe9pzkjMDfbS3gbsHqCpwyVtr3 wkSz6DEc0SZGuSDZdhgr84lkYnQBSwUn0BiU2neopyrN2eKfYhL7P8/EGsNz5vgo g3LS5Q5MwFtxZK393zFQkVhuycwBfDKjq6aUHmXoKC26Z9uZCOxMyUUcQG0H4Pir 6UwhlIZrILTqi9yBgtJzQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm1; t=1649888393; x=1649974793; bh=hsDsSOvCiPnQ5 iI1qwr559UylC5AhqoZAQgmwuaC8k8=; b=n79GBWEz27CFo3CUyVTIM2mlJvVB4 GWqkXbvRylHmhP1oBQmf9fho/teYBHdDOG4ciwUJa76OD4mn4/2Vhv88prKdzsW0 zJZZJ90LMSOxjMeMr3hYVNwNmiyuzpPExJw5afj7suKgWw1VCOJyy/makbfugb+K At/hXMNATMZE+gAq/ptOXpa5IUQeFYzeaphTCFZw6othu5L1LkG/H4rnOPr816Lq +BWxhlisnGN2dshkh4kdJYtxilmZRcY4DX37I3Jn2eIzIVZ1xcauxjM8hy8VMMca mSptsN/8SF34KnI+sG6ZJsOzf3i1xJmQ9kB6W3R0ecCzGd4JlhpKzLmhg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudelvddguddtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfgggtgfesthekredtredtjeenucfhrhhomhepufgrmhhu vghlucfjohhllhgrnhguuceoshgrmhhuvghlsehshhholhhlrghnugdrohhrgheqnecugg ftrfgrthhtvghrnhepfedvffetgeduiedtfffgleelvdfhheekkeduffetuddvgeeffedu fefhgeehueejnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrh homhepshgrmhhuvghlsehshhholhhlrghnugdrohhrgh X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 13 Apr 2022 18:19:52 -0400 (EDT) From: Samuel Holland To: =?utf-8?q?Heiko_St=C3=BCbner?= , Sandy Huang , dri-devel@lists.freedesktop.org Subject: [RFC PATCH 16/16] [DO NOT MERGE] arm64: dts: rockchip: pinenote: Enable EBC display pipeline Date: Wed, 13 Apr 2022 17:19:16 -0500 Message-Id: <20220413221916.50995-17-samuel@sholland.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220413221916.50995-1-samuel@sholland.org> References: <20220413221916.50995-1-samuel@sholland.org> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Airlie , =?utf-8?q?Ond=C5=99ej_Jirman?= , Thierry Reding , Michael Riesch , Sam Ravnborg , Samuel Holland , Nicolas Frattaroli , linux-rockchip@lists.infradead.org, Andreas Kemnade , Geert Uytterhoeven , Liang Chen , devicetree@vger.kernel.org, Thomas Zimmermann , Alistair Francis , Rob Herring , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peter Geis , Krzysztof Kozlowski Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" The PineNote contains an eInk ED103TC2 panel connected to the EBC, powered by a TI TPS651851 PMIC. Signed-off-by: Samuel Holland --- .../boot/dts/rockchip/rk3566-pinenote.dtsi | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi index fea748adfa90..4a53931c3f92 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi @@ -72,6 +72,16 @@ led-0 { }; }; + panel { + compatible = "eink,ed103tc2"; + + port { + panel_in_ebc: endpoint { + remote-endpoint = <&ebc_out_panel>; + }; + }; + }; + sdio_pwrseq: sdio-pwrseq { compatible = "mmc-pwrseq-simple"; clocks = <&rk817 1>; @@ -213,6 +223,20 @@ &cpu3 { cpu-supply = <&vdd_cpu>; }; +&ebc { + io-channels = <&ebc_pmic 0>; + panel-supply = <&v3p3>; + vcom-supply = <&vcom>; + vdrive-supply = <&vdrive>; + status = "okay"; + + port { + ebc_out_panel: endpoint { + remote-endpoint = <&panel_in_ebc>; + }; + }; +}; + &i2c0 { status = "okay"; @@ -466,6 +490,47 @@ led@1 { default-brightness = <0>; }; }; + + /* TODO: write binding */ + ebc_pmic: pmic@68 { + compatible = "ti,tps65185"; + reg = <0x68>; + interrupt-parent = <&gpio3>; + interrupts = ; + #io-channel-cells = <1>; + pinctrl-0 = <&ebc_pmic_pins>; + pinctrl-names = "default"; + powerup-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>; + pwr_good-gpios = <&gpio3 RK_PA7 GPIO_ACTIVE_HIGH>; + vcom_ctrl-gpios = <&gpio4 RK_PB2 GPIO_ACTIVE_HIGH>; + vin-supply = <&vcc_bat>; + vin3p3-supply = <&vcc_3v3>; + wakeup-gpios = <&gpio3 RK_PA5 GPIO_ACTIVE_HIGH>; + ti,up-sequence = <1>, <0>, <2>, <3>; + ti,up-delay-ms = <3>, <3>, <3>, <3>; + ti,down-sequence = <2>, <3>, <1>, <0>; + ti,down-delay-ms = <3>, <6>, <6>, <6>; + + regulators { + v3p3: v3p3 { + regulator-name = "v3p3"; + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + vcom: vcom { + regulator-name = "vcom"; + /* voltage range is board-specific */ + }; + + vdrive: vdrive { + regulator-name = "vdrive"; + regulator-min-microvolt = <15000000>; + regulator-max-microvolt = <15000000>; + }; + }; + }; }; &i2s1_8ch { @@ -508,6 +573,21 @@ bt_wake_h: bt-wake-h { }; }; + ebc-pmic { + ebc_pmic_pins: ebc-pmic-pins { + rockchip,pins = /* wakeup */ + <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>, + /* int */ + <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>, + /* pwr_good */ + <3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>, + /* pwrup */ + <3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>, + /* vcom_ctrl */ + <4 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + led { led_pin: led-pin { rockchip,pins = <3 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;