diff options
author | Biju Das <biju.das.jz@bp.renesas.com> | 2023-05-02 12:09:08 +0200 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2023-05-29 15:41:03 +0200 |
commit | 11696c5e89245a1d360f75be3dfc4960b25a265a (patch) | |
tree | 3b88479798b74644ee8d55d02e891df0c782683a /drivers/gpu/drm/rcar-du | |
parent | drm: rcar-du: remove R-Car H3 ES1.* workarounds (diff) | |
download | linux-11696c5e89245a1d360f75be3dfc4960b25a265a.tar.xz linux-11696c5e89245a1d360f75be3dfc4960b25a265a.zip |
drm: Place Renesas drivers in a separate dir
Create vendor specific renesas directory and move renesas drivers
to that directory.
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Acked-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Diffstat (limited to 'drivers/gpu/drm/rcar-du')
30 files changed, 0 insertions, 10322 deletions
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig deleted file mode 100644 index 53c356aed5d5..000000000000 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ /dev/null @@ -1,82 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config DRM_RCAR_DU - tristate "DRM Support for R-Car Display Unit" - depends on DRM && OF - depends on ARM || ARM64 - depends on ARCH_RENESAS || COMPILE_TEST - select DRM_KMS_HELPER - select DRM_GEM_DMA_HELPER - select VIDEOMODE_HELPERS - help - Choose this option if you have an R-Car chipset. - If M is selected the module will be called rcar-du-drm. - -config DRM_RCAR_USE_CMM - bool "R-Car DU Color Management Module (CMM) Support" - depends on DRM_RCAR_DU - default DRM_RCAR_DU - help - Enable support for R-Car Color Management Module (CMM). - -config DRM_RCAR_CMM - def_tristate DRM_RCAR_DU - depends on DRM_RCAR_USE_CMM - -config DRM_RCAR_DW_HDMI - tristate "R-Car Gen3 and RZ/G2 DU HDMI Encoder Support" - depends on DRM && OF - depends on DRM_RCAR_DU || COMPILE_TEST - select DRM_DW_HDMI - help - Enable support for R-Car Gen3 or RZ/G2 internal HDMI encoder. - -config DRM_RCAR_USE_LVDS - bool "R-Car DU LVDS Encoder Support" - depends on DRM_BRIDGE && OF - depends on DRM_RCAR_DU || COMPILE_TEST - default DRM_RCAR_DU - help - Enable support for the R-Car Display Unit embedded LVDS encoders. - -config DRM_RCAR_LVDS - def_tristate DRM_RCAR_DU - depends on DRM_RCAR_USE_LVDS - depends on PM - select DRM_KMS_HELPER - select DRM_PANEL - select RESET_CONTROLLER - -config DRM_RCAR_USE_MIPI_DSI - bool "R-Car DU MIPI DSI Encoder Support" - depends on DRM_BRIDGE && OF - depends on DRM_RCAR_DU || COMPILE_TEST - default DRM_RCAR_DU - help - Enable support for the R-Car Display Unit embedded MIPI DSI encoders. - -config DRM_RCAR_MIPI_DSI - def_tristate DRM_RCAR_DU - depends on DRM_RCAR_USE_MIPI_DSI - select DRM_MIPI_DSI - select RESET_CONTROLLER - -config DRM_RZG2L_MIPI_DSI - tristate "RZ/G2L MIPI DSI Encoder Support" - depends on DRM && DRM_BRIDGE && OF - depends on ARCH_RENESAS || COMPILE_TEST - select DRM_MIPI_DSI - help - Enable support for the RZ/G2L Display Unit embedded MIPI DSI encoders. - -config DRM_RCAR_VSP - bool "R-Car DU VSP Compositor Support" if ARM - default y if ARM64 - depends on DRM_RCAR_DU - depends on VIDEO_RENESAS_VSP1=y || (VIDEO_RENESAS_VSP1 && DRM_RCAR_DU=m) - help - Enable support to expose the R-Car VSP Compositor as KMS planes. - -config DRM_RCAR_WRITEBACK - bool - default y if ARM64 - depends on DRM_RCAR_DU diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile deleted file mode 100644 index b8f2c82651d9..000000000000 --- a/drivers/gpu/drm/rcar-du/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -rcar-du-drm-y := rcar_du_crtc.o \ - rcar_du_drv.o \ - rcar_du_encoder.o \ - rcar_du_group.o \ - rcar_du_kms.o \ - rcar_du_plane.o \ - -rcar-du-drm-$(CONFIG_DRM_RCAR_VSP) += rcar_du_vsp.o -rcar-du-drm-$(CONFIG_DRM_RCAR_WRITEBACK) += rcar_du_writeback.o - -obj-$(CONFIG_DRM_RCAR_CMM) += rcar_cmm.o -obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o -obj-$(CONFIG_DRM_RCAR_DW_HDMI) += rcar_dw_hdmi.o -obj-$(CONFIG_DRM_RCAR_LVDS) += rcar_lvds.o -obj-$(CONFIG_DRM_RCAR_MIPI_DSI) += rcar_mipi_dsi.o - -obj-$(CONFIG_DRM_RZG2L_MIPI_DSI) += rzg2l_mipi_dsi.o diff --git a/drivers/gpu/drm/rcar-du/rcar_cmm.c b/drivers/gpu/drm/rcar-du/rcar_cmm.c deleted file mode 100644 index e2a67dda4658..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_cmm.c +++ /dev/null @@ -1,217 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * R-Car Display Unit Color Management Module - * - * Copyright (C) 2019 Jacopo Mondi <jacopo+renesas@jmondi.org> - */ - -#include <linux/io.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> - -#include <drm/drm_color_mgmt.h> - -#include "rcar_cmm.h" - -#define CM2_LUT_CTRL 0x0000 -#define CM2_LUT_CTRL_LUT_EN BIT(0) -#define CM2_LUT_TBL_BASE 0x0600 -#define CM2_LUT_TBL(__i) (CM2_LUT_TBL_BASE + (__i) * 4) - -struct rcar_cmm { - void __iomem *base; - - /* - * @lut: 1D-LUT state - * @lut.enabled: 1D-LUT enabled flag - */ - struct { - bool enabled; - } lut; -}; - -static inline int rcar_cmm_read(struct rcar_cmm *rcmm, u32 reg) -{ - return ioread32(rcmm->base + reg); -} - -static inline void rcar_cmm_write(struct rcar_cmm *rcmm, u32 reg, u32 data) -{ - iowrite32(data, rcmm->base + reg); -} - -/* - * rcar_cmm_lut_write() - Scale the DRM LUT table entries to hardware precision - * and write to the CMM registers - * @rcmm: Pointer to the CMM device - * @drm_lut: Pointer to the DRM LUT table - */ -static void rcar_cmm_lut_write(struct rcar_cmm *rcmm, - const struct drm_color_lut *drm_lut) -{ - unsigned int i; - - for (i = 0; i < CM2_LUT_SIZE; ++i) { - u32 entry = drm_color_lut_extract(drm_lut[i].red, 8) << 16 - | drm_color_lut_extract(drm_lut[i].green, 8) << 8 - | drm_color_lut_extract(drm_lut[i].blue, 8); - - rcar_cmm_write(rcmm, CM2_LUT_TBL(i), entry); - } -} - -/* - * rcar_cmm_setup() - Configure the CMM unit - * @pdev: The platform device associated with the CMM instance - * @config: The CMM unit configuration - * - * Configure the CMM unit with the given configuration. Currently enabling, - * disabling and programming of the 1-D LUT unit is supported. - * - * As rcar_cmm_setup() accesses the CMM registers the unit should be powered - * and its functional clock enabled. To guarantee this, before any call to - * this function is made, the CMM unit has to be enabled by calling - * rcar_cmm_enable() first. - * - * TODO: Add support for LUT double buffer operations to avoid updating the - * LUT table entries while a frame is being displayed. - */ -int rcar_cmm_setup(struct platform_device *pdev, - const struct rcar_cmm_config *config) -{ - struct rcar_cmm *rcmm = platform_get_drvdata(pdev); - - /* Disable LUT if no table is provided. */ - if (!config->lut.table) { - if (rcmm->lut.enabled) { - rcar_cmm_write(rcmm, CM2_LUT_CTRL, 0); - rcmm->lut.enabled = false; - } - - return 0; - } - - /* Enable LUT and program the new gamma table values. */ - if (!rcmm->lut.enabled) { - rcar_cmm_write(rcmm, CM2_LUT_CTRL, CM2_LUT_CTRL_LUT_EN); - rcmm->lut.enabled = true; - } - - rcar_cmm_lut_write(rcmm, config->lut.table); - - return 0; -} -EXPORT_SYMBOL_GPL(rcar_cmm_setup); - -/* - * rcar_cmm_enable() - Enable the CMM unit - * @pdev: The platform device associated with the CMM instance - * - * When the output of the corresponding DU channel is routed to the CMM unit, - * the unit shall be enabled before the DU channel is started, and remain - * enabled until the channel is stopped. The CMM unit shall be disabled with - * rcar_cmm_disable(). - * - * Calls to rcar_cmm_enable() and rcar_cmm_disable() are not reference-counted. - * It is an error to attempt to enable an already enabled CMM unit, or to - * attempt to disable a disabled unit. - */ -int rcar_cmm_enable(struct platform_device *pdev) -{ - int ret; - - ret = pm_runtime_resume_and_get(&pdev->dev); - if (ret < 0) - return ret; - - return 0; -} -EXPORT_SYMBOL_GPL(rcar_cmm_enable); - -/* - * rcar_cmm_disable() - Disable the CMM unit - * @pdev: The platform device associated with the CMM instance - * - * See rcar_cmm_enable() for usage information. - * - * Disabling the CMM unit disable all the internal processing blocks. The CMM - * state shall thus be restored with rcar_cmm_setup() when re-enabling the CMM - * unit after the next rcar_cmm_enable() call. - */ -void rcar_cmm_disable(struct platform_device *pdev) -{ - struct rcar_cmm *rcmm = platform_get_drvdata(pdev); - - rcar_cmm_write(rcmm, CM2_LUT_CTRL, 0); - rcmm->lut.enabled = false; - - pm_runtime_put(&pdev->dev); -} -EXPORT_SYMBOL_GPL(rcar_cmm_disable); - -/* - * rcar_cmm_init() - Initialize the CMM unit - * @pdev: The platform device associated with the CMM instance - * - * Return: 0 on success, -EPROBE_DEFER if the CMM is not available yet, - * -ENODEV if the DRM_RCAR_CMM config option is disabled - */ -int rcar_cmm_init(struct platform_device *pdev) -{ - struct rcar_cmm *rcmm = platform_get_drvdata(pdev); - - if (!rcmm) - return -EPROBE_DEFER; - - return 0; -} -EXPORT_SYMBOL_GPL(rcar_cmm_init); - -static int rcar_cmm_probe(struct platform_device *pdev) -{ - struct rcar_cmm *rcmm; - - rcmm = devm_kzalloc(&pdev->dev, sizeof(*rcmm), GFP_KERNEL); - if (!rcmm) - return -ENOMEM; - platform_set_drvdata(pdev, rcmm); - - rcmm->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(rcmm->base)) - return PTR_ERR(rcmm->base); - - pm_runtime_enable(&pdev->dev); - - return 0; -} - -static int rcar_cmm_remove(struct platform_device *pdev) -{ - pm_runtime_disable(&pdev->dev); - - return 0; -} - -static const struct of_device_id rcar_cmm_of_table[] = { - { .compatible = "renesas,rcar-gen3-cmm", }, - { .compatible = "renesas,rcar-gen2-cmm", }, - { }, -}; -MODULE_DEVICE_TABLE(of, rcar_cmm_of_table); - -static struct platform_driver rcar_cmm_platform_driver = { - .probe = rcar_cmm_probe, - .remove = rcar_cmm_remove, - .driver = { - .name = "rcar-cmm", - .of_match_table = rcar_cmm_of_table, - }, -}; - -module_platform_driver(rcar_cmm_platform_driver); - -MODULE_AUTHOR("Jacopo Mondi <jacopo+renesas@jmondi.org>"); -MODULE_DESCRIPTION("Renesas R-Car CMM Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/rcar-du/rcar_cmm.h b/drivers/gpu/drm/rcar-du/rcar_cmm.h deleted file mode 100644 index 628072acc98b..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_cmm.h +++ /dev/null @@ -1,58 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * R-Car Display Unit Color Management Module - * - * Copyright (C) 2019 Jacopo Mondi <jacopo+renesas@jmondi.org> - */ - -#ifndef __RCAR_CMM_H__ -#define __RCAR_CMM_H__ - -#define CM2_LUT_SIZE 256 - -struct drm_color_lut; -struct platform_device; - -/** - * struct rcar_cmm_config - CMM configuration - * - * @lut: 1D-LUT configuration - * @lut.table: 1D-LUT table entries. Disable LUT operations when NULL - */ -struct rcar_cmm_config { - struct { - struct drm_color_lut *table; - } lut; -}; - -#if IS_ENABLED(CONFIG_DRM_RCAR_CMM) -int rcar_cmm_init(struct platform_device *pdev); - -int rcar_cmm_enable(struct platform_device *pdev); -void rcar_cmm_disable(struct platform_device *pdev); - -int rcar_cmm_setup(struct platform_device *pdev, - const struct rcar_cmm_config *config); -#else -static inline int rcar_cmm_init(struct platform_device *pdev) -{ - return -ENODEV; -} - -static inline int rcar_cmm_enable(struct platform_device *pdev) -{ - return 0; -} - -static inline void rcar_cmm_disable(struct platform_device *pdev) -{ -} - -static inline int rcar_cmm_setup(struct platform_device *pdev, - const struct rcar_cmm_config *config) -{ - return 0; -} -#endif /* IS_ENABLED(CONFIG_DRM_RCAR_CMM) */ - -#endif /* __RCAR_CMM_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c deleted file mode 100644 index 7e175dbfd892..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ /dev/null @@ -1,1338 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * R-Car Display Unit CRTCs - * - * Copyright (C) 2013-2015 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#include <linux/clk.h> -#include <linux/mutex.h> -#include <linux/platform_device.h> - -#include <drm/drm_atomic.h> -#include <drm/drm_atomic_helper.h> -#include <drm/drm_bridge.h> -#include <drm/drm_crtc.h> -#include <drm/drm_device.h> -#include <drm/drm_gem_dma_helper.h> -#include <drm/drm_vblank.h> - -#include "rcar_cmm.h" -#include "rcar_du_crtc.h" -#include "rcar_du_drv.h" -#include "rcar_du_encoder.h" -#include "rcar_du_kms.h" -#include "rcar_du_plane.h" -#include "rcar_du_regs.h" -#include "rcar_du_vsp.h" -#include "rcar_lvds.h" -#include "rcar_mipi_dsi.h" - -static u32 rcar_du_crtc_read(struct rcar_du_crtc *rcrtc, u32 reg) -{ - struct rcar_du_device *rcdu = rcrtc->dev; - - return rcar_du_read(rcdu, rcrtc->mmio_offset + reg); -} - -static void rcar_du_crtc_write(struct rcar_du_crtc *rcrtc, u32 reg, u32 data) -{ - struct rcar_du_device *rcdu = rcrtc->dev; - - rcar_du_write(rcdu, rcrtc->mmio_offset + reg, data); -} - -static void rcar_du_crtc_clr(struct rcar_du_crtc *rcrtc, u32 reg, u32 clr) -{ - struct rcar_du_device *rcdu = rcrtc->dev; - - rcar_du_write(rcdu, rcrtc->mmio_offset + reg, - rcar_du_read(rcdu, rcrtc->mmio_offset + reg) & ~clr); -} - -static void rcar_du_crtc_set(struct rcar_du_crtc *rcrtc, u32 reg, u32 set) -{ - struct rcar_du_device *rcdu = rcrtc->dev; - - rcar_du_write(rcdu, rcrtc->mmio_offset + reg, - rcar_du_read(rcdu, rcrtc->mmio_offset + reg) | set); -} - -void rcar_du_crtc_dsysr_clr_set(struct rcar_du_crtc *rcrtc, u32 clr, u32 set) -{ - struct rcar_du_device *rcdu = rcrtc->dev; - - rcrtc->dsysr = (rcrtc->dsysr & ~clr) | set; - rcar_du_write(rcdu, rcrtc->mmio_offset + DSYSR, rcrtc->dsysr); -} - -/* ----------------------------------------------------------------------------- - * Hardware Setup - */ - -struct dpll_info { - unsigned int output; - unsigned int fdpll; - unsigned int n; - unsigned int m; -}; - -static void rcar_du_dpll_divider(struct rcar_du_crtc *rcrtc, - struct dpll_info *dpll, - unsigned long input, - unsigned long target) -{ - unsigned long best_diff = (unsigned long)-1; - unsigned long diff; - unsigned int fdpll; - unsigned int m; - unsigned int n; - - /* - * fin fvco fout fclkout - * in --> [1/M] --> |PD| -> [LPF] -> [VCO] -> [1/P] -+-> [1/FDPLL] -> out - * +-> | | | - * | | - * +---------------- [1/N] <------------+ - * - * fclkout = fvco / P / FDPLL -- (1) - * - * fin/M = fvco/P/N - * - * fvco = fin * P * N / M -- (2) - * - * (1) + (2) indicates - * - * fclkout = fin * N / M / FDPLL - * - * NOTES - * N : (n + 1) - * M : (m + 1) - * FDPLL : (fdpll + 1) - * P : 2 - * 2kHz < fvco < 4096MHz - * - * To minimize the jitter, - * N : as large as possible - * M : as small as possible - */ - for (m = 0; m < 4; m++) { - for (n = 119; n > 38; n--) { - /* - * This code only runs on 64-bit architectures, the - * unsigned long type can thus be used for 64-bit - * computation. It will still compile without any - * warning on 32-bit architectures. - * - * To optimize calculations, use fout instead of fvco - * to verify the VCO frequency constraint. - */ - unsigned long fout = input * (n + 1) / (m + 1); - - if (fout < 1000 || fout > 2048 * 1000 * 1000U) - continue; - - for (fdpll = 1; fdpll < 32; fdpll++) { - unsigned long output; - - output = fout / (fdpll + 1); - if (output >= 400 * 1000 * 1000) - continue; - - diff = abs((long)output - (long)target); - if (best_diff > diff) { - best_diff = diff; - dpll->n = n; - dpll->m = m; - dpll->fdpll = fdpll; - dpll->output = output; - } - - if (diff == 0) - goto done; - } - } - } - -done: - dev_dbg(rcrtc->dev->dev, - "output:%u, fdpll:%u, n:%u, m:%u, diff:%lu\n", - dpll->output, dpll->fdpll, dpll->n, dpll->m, best_diff); -} - -struct du_clk_params { - struct clk *clk; - unsigned long rate; - unsigned long diff; - u32 escr; -}; - -static void rcar_du_escr_divider(struct clk *clk, unsigned long target, - u32 escr, struct du_clk_params *params) -{ - unsigned long rate; - unsigned long diff; - u32 div; - - /* - * If the target rate has already been achieved perfectly we can't do - * better. - */ - if (params->diff == 0) - return; - - /* - * Compute the input clock rate and internal divisor values to obtain - * the clock rate closest to the target frequency. - */ - rate = clk_round_rate(clk, target); - div = clamp(DIV_ROUND_CLOSEST(rate, target), 1UL, 64UL) - 1; - diff = abs(rate / (div + 1) - target); - - /* - * Store the parameters if the resulting frequency is better than any - * previously calculated value. - */ - if (diff < params->diff) { - params->clk = clk; - params->rate = rate; - params->diff = diff; - params->escr = escr | div; - } -} - -static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) -{ - const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode; - struct rcar_du_device *rcdu = rcrtc->dev; - unsigned long mode_clock = mode->clock * 1000; - unsigned int hdse_offset; - u32 dsmr; - u32 escr; - - if (rcdu->info->dpll_mask & (1 << rcrtc->index)) { - unsigned long target = mode_clock; - struct dpll_info dpll = { 0 }; - unsigned long extclk; - u32 dpllcr; - u32 div = 0; - - /* - * DU channels that have a display PLL can't use the internal - * system clock, and have no internal clock divider. - */ - extclk = clk_get_rate(rcrtc->extclock); - rcar_du_dpll_divider(rcrtc, &dpll, extclk, target); - - dpllcr = DPLLCR_CODE | DPLLCR_CLKE - | DPLLCR_FDPLL(dpll.fdpll) - | DPLLCR_N(dpll.n) | DPLLCR_M(dpll.m) - | DPLLCR_STBY; - - if (rcrtc->index == 1) - dpllcr |= DPLLCR_PLCS1 - | DPLLCR_INCS_DOTCLKIN1; - else - dpllcr |= DPLLCR_PLCS0 - | DPLLCR_INCS_DOTCLKIN0; - - rcar_du_group_write(rcrtc->group, DPLLCR, dpllcr); - - escr = ESCR_DCLKSEL_DCLKIN | div; - } else if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index) || - rcdu->info->dsi_clk_mask & BIT(rcrtc->index)) { - /* - * Use the external LVDS or DSI PLL output as the dot clock when - * outputting to the LVDS or DSI encoder on an SoC that supports - * this clock routing option. We use the clock directly in that - * case, without any additional divider. - */ - escr = ESCR_DCLKSEL_DCLKIN; - } else { - struct du_clk_params params = { .diff = (unsigned long)-1 }; - - rcar_du_escr_divider(rcrtc->clock, mode_clock, - ESCR_DCLKSEL_CLKS, ¶ms); - if (rcrtc->extclock) - rcar_du_escr_divider(rcrtc->extclock, mode_clock, - ESCR_DCLKSEL_DCLKIN, ¶ms); - - dev_dbg(rcrtc->dev->dev, "mode clock %lu %s rate %lu\n", - mode_clock, params.clk == rcrtc->clock ? "cpg" : "ext", - params.rate); - - clk_set_rate(params.clk, params.rate); - escr = params.escr; - } - - /* - * The ESCR register only exists in DU channels that can output to an - * LVDS or DPAT, and the OTAR register in DU channels that can output - * to a DPAD. - */ - if ((rcdu->info->routes[RCAR_DU_OUTPUT_DPAD0].possible_crtcs | - rcdu->info->routes[RCAR_DU_OUTPUT_DPAD1].possible_crtcs | - rcdu->info->routes[RCAR_DU_OUTPUT_LVDS0].possible_crtcs | - rcdu->info->routes[RCAR_DU_OUTPUT_LVDS1].possible_crtcs) & - BIT(rcrtc->index)) { - dev_dbg(rcrtc->dev->dev, "%s: ESCR 0x%08x\n", __func__, escr); - - rcar_du_crtc_write(rcrtc, rcrtc->index % 2 ? ESCR13 : ESCR02, escr); - } - - if ((rcdu->info->routes[RCAR_DU_OUTPUT_DPAD0].possible_crtcs | - rcdu->info->routes[RCAR_DU_OUTPUT_DPAD1].possible_crtcs) & - BIT(rcrtc->index)) - rcar_du_crtc_write(rcrtc, rcrtc->index % 2 ? OTAR13 : OTAR02, 0); - - /* Signal polarities */ - dsmr = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DSMR_VSL : 0) - | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? DSMR_HSL : 0) - | ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? DSMR_ODEV : 0) - | DSMR_DIPM_DISP | DSMR_CSPM; - rcar_du_crtc_write(rcrtc, DSMR, dsmr); - - /* - * When the CMM is enabled, an additional offset of 25 pixels must be - * subtracted from the HDS (horizontal display start) and HDE - * (horizontal display end) registers. - */ - hdse_offset = 19; - if (rcrtc->group->cmms_mask & BIT(rcrtc->index % 2)) - hdse_offset += 25; - - /* Display timings */ - rcar_du_crtc_write(rcrtc, HDSR, mode->htotal - mode->hsync_start - - hdse_offset); - rcar_du_crtc_write(rcrtc, HDER, mode->htotal - mode->hsync_start + - mode->hdisplay - hdse_offset); - rcar_du_crtc_write(rcrtc, HSWR, mode->hsync_end - - mode->hsync_start - 1); - rcar_du_crtc_write(rcrtc, HCR, mode->htotal - 1); - - rcar_du_crtc_write(rcrtc, VDSR, mode->crtc_vtotal - - mode->crtc_vsync_end - 2); - rcar_du_crtc_write(rcrtc, VDER, mode->crtc_vtotal - - mode->crtc_vsync_end + - mode->crtc_vdisplay - 2); - rcar_du_crtc_write(rcrtc, VSPR, mode->crtc_vtotal - - mode->crtc_vsync_end + - mode->crtc_vsync_start - 1); - rcar_du_crtc_write(rcrtc, VCR, mode->crtc_vtotal - 1); - - rcar_du_crtc_write(rcrtc, DESR, mode->htotal - mode->hsync_start - 1); - rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay); -} - -static unsigned int plane_zpos(struct rcar_du_plane *plane) -{ - return plane->plane.state->normalized_zpos; -} - -static const struct rcar_du_format_info * -plane_format(struct rcar_du_plane *plane) -{ - return to_rcar_plane_state(plane->plane.state)->format; -} - -static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc) -{ - struct rcar_du_plane *planes[RCAR_DU_NUM_HW_PLANES]; - struct rcar_du_device *rcdu = rcrtc->dev; - unsigned int num_planes = 0; - unsigned int dptsr_planes; - unsigned int hwplanes = 0; - unsigned int prio = 0; - unsigned int i; - u32 dspr = 0; - - for (i = 0; i < rcrtc->group->num_planes; ++i) { - struct rcar_du_plane *plane = &rcrtc->group->planes[i]; - unsigned int j; - - if (plane->plane.state->crtc != &rcrtc->crtc || - !plane->plane.state->visible) - continue; - - /* Insert the plane in the sorted planes array. */ - for (j = num_planes++; j > 0; --j) { - if (plane_zpos(planes[j-1]) <= plane_zpos(plane)) - break; - planes[j] = planes[j-1]; - } - - planes[j] = plane; - prio += plane_format(plane)->planes * 4; - } - - for (i = 0; i < num_planes; ++i) { - struct rcar_du_plane *plane = planes[i]; - struct drm_plane_state *state = plane->plane.state; - unsigned int index = to_rcar_plane_state(state)->hwindex; - - prio -= 4; - dspr |= (index + 1) << prio; - hwplanes |= 1 << index; - - if (plane_format(plane)->planes == 2) { - index = (index + 1) % 8; - - prio -= 4; - dspr |= (index + 1) << prio; - hwplanes |= 1 << index; - } - } - - /* If VSP+DU integration is enabled the plane assignment is fixed. */ - if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) { - if (rcdu->info->gen < 3) { - dspr = (rcrtc->index % 2) + 1; - hwplanes = 1 << (rcrtc->index % 2); - } else { - dspr = (rcrtc->index % 2) ? 3 : 1; - hwplanes = 1 << ((rcrtc->index % 2) ? 2 : 0); - } - } - - /* - * Update the planes to display timing and dot clock generator - * associations. - * - * Updating the DPTSR register requires restarting the CRTC group, - * resulting in visible flicker. To mitigate the issue only update the - * association if needed by enabled planes. Planes being disabled will - * keep their current association. - */ - mutex_lock(&rcrtc->group->lock); - - dptsr_planes = rcrtc->index % 2 ? rcrtc->group->dptsr_planes | hwplanes - : rcrtc->group->dptsr_planes & ~hwplanes; - - if (dptsr_planes != rcrtc->group->dptsr_planes) { - rcar_du_group_write(rcrtc->group, DPTSR, - (dptsr_planes << 16) | dptsr_planes); - rcrtc->group->dptsr_planes = dptsr_planes; - - if (rcrtc->group->used_crtcs) - rcar_du_group_restart(rcrtc->group); - } - - /* Restart the group if plane sources have changed. */ - if (rcrtc->group->need_restart) - rcar_du_group_restart(rcrtc->group); - - mutex_unlock(&rcrtc->group->lock); - - rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, - dspr); -} - -/* ----------------------------------------------------------------------------- - * Page Flip - */ - -void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc) -{ - struct drm_pending_vblank_event *event; - struct drm_device *dev = rcrtc->crtc.dev; - unsigned long flags; - - spin_lock_irqsave(&dev->event_lock, flags); - event = rcrtc->event; - rcrtc->event = NULL; - spin_unlock_irqrestore(&dev->event_lock, flags); - - if (event == NULL) - return; - - spin_lock_irqsave(&dev->event_lock, flags); - drm_crtc_send_vblank_event(&rcrtc->crtc, event); - wake_up(&rcrtc->flip_wait); - spin_unlock_irqrestore(&dev->event_lock, flags); - - drm_crtc_vblank_put(&rcrtc->crtc); -} - -static bool rcar_du_crtc_page_flip_pending(struct rcar_du_crtc *rcrtc) -{ - struct drm_device *dev = rcrtc->crtc.dev; - unsigned long flags; - bool pending; - - spin_lock_irqsave(&dev->event_lock, flags); - pending = rcrtc->event != NULL; - spin_unlock_irqrestore(&dev->event_lock, flags); - - return pending; -} - -static void rcar_du_crtc_wait_page_flip(struct rcar_du_crtc *rcrtc) -{ - struct rcar_du_device *rcdu = rcrtc->dev; - - if (wait_event_timeout(rcrtc->flip_wait, - !rcar_du_crtc_page_flip_pending(rcrtc), - msecs_to_jiffies(50))) - return; - - dev_warn(rcdu->dev, "page flip timeout\n"); - - rcar_du_crtc_finish_page_flip(rcrtc); -} - -/* ----------------------------------------------------------------------------- - * Color Management Module (CMM) - */ - -static int rcar_du_cmm_check(struct drm_crtc *crtc, - struct drm_crtc_state *state) -{ - struct drm_property_blob *drm_lut = state->gamma_lut; - struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); - struct device *dev = rcrtc->dev->dev; - - if (!drm_lut) - return 0; - - /* We only accept fully populated LUT tables. */ - if (drm_color_lut_size(drm_lut) != CM2_LUT_SIZE) { - dev_err(dev, "invalid gamma lut size: %zu bytes\n", - drm_lut->length); - return -EINVAL; - } - - return 0; -} - -static void rcar_du_cmm_setup(struct drm_crtc *crtc) -{ - struct drm_property_blob *drm_lut = crtc->state->gamma_lut; - struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); - struct rcar_cmm_config cmm_config = {}; - - if (!rcrtc->cmm) - return; - - if (drm_lut) - cmm_config.lut.table = (struct drm_color_lut *)drm_lut->data; - - rcar_cmm_setup(rcrtc->cmm, &cmm_config); -} - -/* ----------------------------------------------------------------------------- - * Start/Stop and Suspend/Resume - */ - -static void rcar_du_crtc_setup(struct rcar_du_crtc *rcrtc) -{ - /* Set display off and background to black */ - rcar_du_crtc_write(rcrtc, DOOR, DOOR_RGB(0, 0, 0)); - rcar_du_crtc_write(rcrtc, BPOR, BPOR_RGB(0, 0, 0)); - - /* Configure display timings and output routing */ - rcar_du_crtc_set_display_timing(rcrtc); - rcar_du_group_set_routing(rcrtc->group); - - /* Start with all planes disabled. */ - rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0); - - /* Enable the VSP compositor. */ - if (rcar_du_has(rcrtc->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) - rcar_du_vsp_enable(rcrtc); - - /* Turn vertical blanking interrupt reporting on. */ - drm_crtc_vblank_on(&rcrtc->crtc); -} - -static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc) -{ - int ret; - - /* - * Guard against double-get, as the function is called from both the - * .atomic_enable() and .atomic_begin() handlers. - */ - if (rcrtc->initialized) - return 0; - - ret = clk_prepare_enable(rcrtc->clock); - if (ret < 0) - return ret; - - ret = clk_prepare_enable(rcrtc->extclock); - if (ret < 0) - goto error_clock; - - ret = rcar_du_group_get(rcrtc->group); - if (ret < 0) - goto error_group; - - rcar_du_crtc_setup(rcrtc); - rcrtc->initialized = true; - - return 0; - -error_group: - clk_disable_unprepare(rcrtc->extclock); -error_clock: - clk_disable_unprepare(rcrtc->clock); - return ret; -} - -static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc) -{ - rcar_du_group_put(rcrtc->group); - - clk_disable_unprepare(rcrtc->extclock); - clk_disable_unprepare(rcrtc->clock); - - rcrtc->initialized = false; -} - -static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) -{ - bool interlaced; - - /* - * Select master sync mode. This enables display operation in master - * sync mode (with the HSYNC and VSYNC signals configured as outputs and - * actively driven). - */ - interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE; - rcar_du_crtc_dsysr_clr_set(rcrtc, DSYSR_TVM_MASK | DSYSR_SCM_MASK, - (interlaced ? DSYSR_SCM_INT_VIDEO : 0) | - DSYSR_TVM_MASTER); - - rcar_du_group_start_stop(rcrtc->group, true); -} - -static void rcar_du_crtc_disable_planes(struct rcar_du_crtc *rcrtc) -{ - struct rcar_du_device *rcdu = rcrtc->dev; - struct drm_crtc *crtc = &rcrtc->crtc; - u32 status; - - /* Make sure vblank interrupts are enabled. */ - drm_crtc_vblank_get(crtc); - - /* - * Disable planes and calculate how many vertical blanking interrupts we - * have to wait for. If a vertical blanking interrupt has been triggered - * but not processed yet, we don't know whether it occurred before or - * after the planes got disabled. We thus have to wait for two vblank - * interrupts in that case. - */ - spin_lock_irq(&rcrtc->vblank_lock); - rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0); - status = rcar_du_crtc_read(rcrtc, DSSR); - rcrtc->vblank_count = status & DSSR_VBK ? 2 : 1; - spin_unlock_irq(&rcrtc->vblank_lock); - - if (!wait_event_timeout(rcrtc->vblank_wait, rcrtc->vblank_count == 0, - msecs_to_jiffies(100))) - dev_warn(rcdu->dev, "vertical blanking timeout\n"); - - drm_crtc_vblank_put(crtc); -} - -static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) -{ - struct drm_crtc *crtc = &rcrtc->crtc; - - /* - * Disable all planes and wait for the change to take effect. This is - * required as the plane enable registers are updated on vblank, and no - * vblank will occur once the CRTC is stopped. Disabling planes when - * starting the CRTC thus wouldn't be enough as it would start scanning - * out immediately from old frame buffers until the next vblank. - * - * This increases the CRTC stop delay, especially when multiple CRTCs - * are stopped in one operation as we now wait for one vblank per CRTC. - * Whether this can be improved needs to be researched. - */ - rcar_du_crtc_disable_planes(rcrtc); - - /* - * Disable vertical blanking interrupt reporting. We first need to wait - * for page flip completion before stopping the CRTC as userspace - * expects page flips to eventually complete. - */ - rcar_du_crtc_wait_page_flip(rcrtc); - drm_crtc_vblank_off(crtc); - - /* Disable the VSP compositor. */ - if (rcar_du_has(rcrtc->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) - rcar_du_vsp_disable(rcrtc); - - if (rcrtc->cmm) - rcar_cmm_disable(rcrtc->cmm); - - /* - * Select switch sync mode. This stops display operation and configures - * the HSYNC and VSYNC signals as inputs. - * - * TODO: Find another way to stop the display for DUs that don't support - * TVM sync. - */ - if (rcar_du_has(rcrtc->dev, RCAR_DU_FEATURE_TVM_SYNC)) - rcar_du_crtc_dsysr_clr_set(rcrtc, DSYSR_TVM_MASK, - DSYSR_TVM_SWITCH); - - rcar_du_group_start_stop(rcrtc->group, false); -} - -/* ----------------------------------------------------------------------------- - * CRTC Functions - */ - -static int rcar_du_crtc_atomic_check(struct drm_crtc *crtc, - struct drm_atomic_state *state) -{ - struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, - crtc); - struct rcar_du_crtc_state *rstate = to_rcar_crtc_state(crtc_state); - struct drm_encoder *encoder; - int ret; - - ret = rcar_du_cmm_check(crtc, crtc_state); - if (ret) - return ret; - - /* Store the routes from the CRTC output to the DU outputs. */ - rstate->outputs = 0; - - drm_for_each_encoder_mask(encoder, crtc->dev, - crtc_state->encoder_mask) { - struct rcar_du_encoder *renc; - - /* Skip the writeback encoder. */ - if (encoder->encoder_type == DRM_MODE_ENCODER_VIRTUAL) - continue; - - renc = to_rcar_encoder(encoder); - rstate->outputs |= BIT(renc->output); - } - - return 0; -} - -static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc, - struct drm_atomic_state *state) -{ - struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); - struct rcar_du_crtc_state *rstate = to_rcar_crtc_state(crtc->state); - struct rcar_du_device *rcdu = rcrtc->dev; - - if (rcrtc->cmm) - rcar_cmm_enable(rcrtc->cmm); - rcar_du_crtc_get(rcrtc); - - /* - * On D3/E3 the dot clock is provided by the LVDS encoder attached to - * the DU channel. We need to enable its clock output explicitly before - * starting the CRTC, as the bridge hasn't been enabled by the atomic - * helpers yet. - */ - if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index)) { - bool dot_clk_only = rstate->outputs == BIT(RCAR_DU_OUTPUT_DPAD0); - struct drm_bridge *bridge = rcdu->lvds[rcrtc->index]; - const struct drm_display_mode *mode = - &crtc->state->adjusted_mode; - - rcar_lvds_pclk_enable(bridge, mode->clock * 1000, dot_clk_only); - } - - /* - * Similarly to LVDS, on V3U the dot clock is provided by the DSI - * encoder, and we need to enable the DSI clocks before enabling the CRTC. - */ - if ((rcdu->info->dsi_clk_mask & BIT(rcrtc->index)) && - (rstate->outputs & - (BIT(RCAR_DU_OUTPUT_DSI0) | BIT(RCAR_DU_OUTPUT_DSI1)))) { - struct drm_bridge *bridge = rcdu->dsi[rcrtc->index]; - - rcar_mipi_dsi_pclk_enable(bridge, state); - } - - rcar_du_crtc_start(rcrtc); - - /* - * TODO: The chip manual indicates that CMM tables should be written - * after the DU channel has been activated. Investigate the impact - * of this restriction on the first displayed frame. - */ - rcar_du_cmm_setup(crtc); -} - -static void rcar_du_crtc_atomic_disable(struct drm_crtc *crtc, - struct drm_atomic_state *state) -{ - struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state, - crtc); - struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); - struct rcar_du_crtc_state *rstate = to_rcar_crtc_state(old_state); - struct rcar_du_device *rcdu = rcrtc->dev; - - rcar_du_crtc_stop(rcrtc); - rcar_du_crtc_put(rcrtc); - - if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index)) { - bool dot_clk_only = rstate->outputs == BIT(RCAR_DU_OUTPUT_DPAD0); - struct drm_bridge *bridge = rcdu->lvds[rcrtc->index]; - - /* - * Disable the LVDS clock output, see - * rcar_du_crtc_atomic_enable(). When the LVDS output is used, - * this also disables the LVDS encoder. - */ - rcar_lvds_pclk_disable(bridge, dot_clk_only); - } - - if ((rcdu->info->dsi_clk_mask & BIT(rcrtc->index)) && - (rstate->outputs & - (BIT(RCAR_DU_OUTPUT_DSI0) | BIT(RCAR_DU_OUTPUT_DSI1)))) { - struct drm_bridge *bridge = rcdu->dsi[rcrtc->index]; - - /* - * Disable the DSI clock output, see - * rcar_du_crtc_atomic_enable(). - */ - rcar_mipi_dsi_pclk_disable(bridge); - } - - spin_lock_irq(&crtc->dev->event_lock); - if (crtc->state->event) { - drm_crtc_send_vblank_event(crtc, crtc->state->event); - crtc->state->event = NULL; - } - spin_unlock_irq(&crtc->dev->event_lock); -} - -static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc, - struct drm_atomic_state *state) -{ - struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); - - WARN_ON(!crtc->state->enable); - - /* - * If a mode set is in progress we can be called with the CRTC disabled. - * We thus need to first get and setup the CRTC in order to configure - * planes. We must *not* put the CRTC in .atomic_flush(), as it must be - * kept awake until the .atomic_enable() call that will follow. The get - * operation in .atomic_enable() will in that case be a no-op, and the - * CRTC will be put later in .atomic_disable(). - * - * If a mode set is not in progress the CRTC is enabled, and the - * following get call will be a no-op. There is thus no need to balance - * it in .atomic_flush() either. - */ - rcar_du_crtc_get(rcrtc); - - /* If the active state changed, we let .atomic_enable handle CMM. */ - if (crtc->state->color_mgmt_changed && !crtc->state->active_changed) - rcar_du_cmm_setup(crtc); - - if (rcar_du_has(rcrtc->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) - rcar_du_vsp_atomic_begin(rcrtc); -} - -static void rcar_du_crtc_atomic_flush(struct drm_crtc *crtc, - struct drm_atomic_state *state) -{ - struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); - struct drm_device *dev = rcrtc->crtc.dev; - unsigned long flags; - - rcar_du_crtc_update_planes(rcrtc); - - if (crtc->state->event) { - WARN_ON(drm_crtc_vblank_get(crtc) != 0); - - spin_lock_irqsave(&dev->event_lock, flags); - rcrtc->event = crtc->state->event; - crtc->state->event = NULL; - spin_unlock_irqrestore(&dev->event_lock, flags); - } - - if (rcar_du_has(rcrtc->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) - rcar_du_vsp_atomic_flush(rcrtc); -} - -static enum drm_mode_status -rcar_du_crtc_mode_valid(struct drm_crtc *crtc, - const struct drm_display_mode *mode) -{ - struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); - struct rcar_du_device *rcdu = rcrtc->dev; - bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE; - unsigned int min_sync_porch; - unsigned int vbp; - - if (interlaced && !rcar_du_has(rcdu, RCAR_DU_FEATURE_INTERLACED)) - return MODE_NO_INTERLACE; - - /* - * The hardware requires a minimum combined horizontal sync and back - * porch of 20 pixels (when CMM isn't used) or 45 pixels (when CMM is - * used), and a minimum vertical back porch of 3 lines. - */ - min_sync_porch = 20; - if (rcrtc->group->cmms_mask & BIT(rcrtc->index % 2)) - min_sync_porch += 25; - - if (mode->htotal - mode->hsync_start < min_sync_porch) - return MODE_HBLANK_NARROW; - - vbp = (mode->vtotal - mode->vsync_end) / (interlaced ? 2 : 1); - if (vbp < 3) - return MODE_VBLANK_NARROW; - - return MODE_OK; -} - -static const struct drm_crtc_helper_funcs crtc_helper_funcs = { - .atomic_check = rcar_du_crtc_atomic_check, - .atomic_begin = rcar_du_crtc_atomic_begin, - .atomic_flush = rcar_du_crtc_atomic_flush, - .atomic_enable = rcar_du_crtc_atomic_enable, - .atomic_disable = rcar_du_crtc_atomic_disable, - .mode_valid = rcar_du_crtc_mode_valid, -}; - -static void rcar_du_crtc_crc_init(struct rcar_du_crtc *rcrtc) -{ - struct rcar_du_device *rcdu = rcrtc->dev; - const char **sources; - unsigned int count; - int i = -1; - - /* CRC available only on Gen3 HW. */ - if (rcdu->info->gen < 3) - return; - - /* Reserve 1 for "auto" source. */ - count = rcrtc->vsp->num_planes + 1; - - sources = kmalloc_array(count, sizeof(*sources), GFP_KERNEL); - if (!sources) - return; - - sources[0] = kstrdup("auto", GFP_KERNEL); - if (!sources[0]) - goto error; - - for (i = 0; i < rcrtc->vsp->num_planes; ++i) { - struct drm_plane *plane = &rcrtc->vsp->planes[i].plane; - char name[16]; - - sprintf(name, "plane%u", plane->base.id); - sources[i + 1] = kstrdup(name, GFP_KERNEL); - if (!sources[i + 1]) - goto error; - } - - rcrtc->sources = sources; - rcrtc->sources_count = count; - return; - -error: - while (i >= 0) { - kfree(sources[i]); - i--; - } - kfree(sources); -} - -static void rcar_du_crtc_crc_cleanup(struct rcar_du_crtc *rcrtc) -{ - unsigned int i; - - if (!rcrtc->sources) - return; - - for (i = 0; i < rcrtc->sources_count; i++) - kfree(rcrtc->sources[i]); - kfree(rcrtc->sources); - - rcrtc->sources = NULL; - rcrtc->sources_count = 0; -} - -static struct drm_crtc_state * -rcar_du_crtc_atomic_duplicate_state(struct drm_crtc *crtc) -{ - struct rcar_du_crtc_state *state; - struct rcar_du_crtc_state *copy; - - if (WARN_ON(!crtc->state)) - return NULL; - - state = to_rcar_crtc_state(crtc->state); - copy = kmemdup(state, sizeof(*state), GFP_KERNEL); - if (copy == NULL) - return NULL; - - __drm_atomic_helper_crtc_duplicate_state(crtc, ©->state); - - return ©->state; -} - -static void rcar_du_crtc_atomic_destroy_state(struct drm_crtc *crtc, - struct drm_crtc_state *state) -{ - __drm_atomic_helper_crtc_destroy_state(state); - kfree(to_rcar_crtc_state(state)); -} - -static void rcar_du_crtc_cleanup(struct drm_crtc *crtc) -{ - struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); - - rcar_du_crtc_crc_cleanup(rcrtc); - - return drm_crtc_cleanup(crtc); -} - -static void rcar_du_crtc_reset(struct drm_crtc *crtc) -{ - struct rcar_du_crtc_state *state; - - if (crtc->state) { - rcar_du_crtc_atomic_destroy_state(crtc, crtc->state); - crtc->state = NULL; - } - - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (state == NULL) - return; - - state->crc.source = VSP1_DU_CRC_NONE; - state->crc.index = 0; - - __drm_atomic_helper_crtc_reset(crtc, &state->state); -} - -static int rcar_du_crtc_enable_vblank(struct drm_crtc *crtc) -{ - struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); - - rcar_du_crtc_write(rcrtc, DSRCR, DSRCR_VBCL); - rcar_du_crtc_set(rcrtc, DIER, DIER_VBE); - rcrtc->vblank_enable = true; - - return 0; -} - -static void rcar_du_crtc_disable_vblank(struct drm_crtc *crtc) -{ - struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); - - rcar_du_crtc_clr(rcrtc, DIER, DIER_VBE); - rcrtc->vblank_enable = false; -} - -static int rcar_du_crtc_parse_crc_source(struct rcar_du_crtc *rcrtc, - const char *source_name, - enum vsp1_du_crc_source *source) -{ - unsigned int index; - int ret; - - /* - * Parse the source name. Supported values are "plane%u" to compute the - * CRC on an input plane (%u is the plane ID), and "auto" to compute the - * CRC on the composer (VSP) output. - */ - - if (!source_name) { - *source = VSP1_DU_CRC_NONE; - return 0; - } else if (!strcmp(source_name, "auto")) { - *source = VSP1_DU_CRC_OUTPUT; - return 0; - } else if (strstarts(source_name, "plane")) { - unsigned int i; - - *source = VSP1_DU_CRC_PLANE; - - ret = kstrtouint(source_name + strlen("plane"), 10, &index); - if (ret < 0) - return ret; - - for (i = 0; i < rcrtc->vsp->num_planes; ++i) { - if (index == rcrtc->vsp->planes[i].plane.base.id) - return i; - } - } - - return -EINVAL; -} - -static int rcar_du_crtc_verify_crc_source(struct drm_crtc *crtc, - const char *source_name, - size_t *values_cnt) -{ - struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); - enum vsp1_du_crc_source source; - - if (rcar_du_crtc_parse_crc_source(rcrtc, source_name, &source) < 0) { - DRM_DEBUG_DRIVER("unknown source %s\n", source_name); - return -EINVAL; - } - - *values_cnt = 1; - return 0; -} - -static const char *const * -rcar_du_crtc_get_crc_sources(struct drm_crtc *crtc, size_t *count) -{ - struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); - - *count = rcrtc->sources_count; - return rcrtc->sources; -} - -static int rcar_du_crtc_set_crc_source(struct drm_crtc *crtc, - const char *source_name) -{ - struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); - struct drm_modeset_acquire_ctx ctx; - struct drm_crtc_state *crtc_state; - struct drm_atomic_state *state; - enum vsp1_du_crc_source source; - unsigned int index; - int ret; - - ret = rcar_du_crtc_parse_crc_source(rcrtc, source_name, &source); - if (ret < 0) - return ret; - - index = ret; - - /* Perform an atomic commit to set the CRC source. */ - drm_modeset_acquire_init(&ctx, 0); - - state = drm_atomic_state_alloc(crtc->dev); - if (!state) { - ret = -ENOMEM; - goto unlock; - } - - state->acquire_ctx = &ctx; - -retry: - crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (!IS_ERR(crtc_state)) { - struct rcar_du_crtc_state *rcrtc_state; - - rcrtc_state = to_rcar_crtc_state(crtc_state); - rcrtc_state->crc.source = source; - rcrtc_state->crc.index = index; - - ret = drm_atomic_commit(state); - } else { - ret = PTR_ERR(crtc_state); - } - - if (ret == -EDEADLK) { - drm_atomic_state_clear(state); - drm_modeset_backoff(&ctx); - goto retry; - } - - drm_atomic_state_put(state); - -unlock: - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); - - return ret; -} - -static const struct drm_crtc_funcs crtc_funcs_gen2 = { - .reset = rcar_du_crtc_reset, - .destroy = drm_crtc_cleanup, - .set_config = drm_atomic_helper_set_config, - .page_flip = drm_atomic_helper_page_flip, - .atomic_duplicate_state = rcar_du_crtc_atomic_duplicate_state, - .atomic_destroy_state = rcar_du_crtc_atomic_destroy_state, - .enable_vblank = rcar_du_crtc_enable_vblank, - .disable_vblank = rcar_du_crtc_disable_vblank, -}; - -static const struct drm_crtc_funcs crtc_funcs_gen3 = { - .reset = rcar_du_crtc_reset, - .destroy = rcar_du_crtc_cleanup, - .set_config = drm_atomic_helper_set_config, - .page_flip = drm_atomic_helper_page_flip, - .atomic_duplicate_state = rcar_du_crtc_atomic_duplicate_state, - .atomic_destroy_state = rcar_du_crtc_atomic_destroy_state, - .enable_vblank = rcar_du_crtc_enable_vblank, - .disable_vblank = rcar_du_crtc_disable_vblank, - .set_crc_source = rcar_du_crtc_set_crc_source, - .verify_crc_source = rcar_du_crtc_verify_crc_source, - .get_crc_sources = rcar_du_crtc_get_crc_sources, -}; - -/* ----------------------------------------------------------------------------- - * Interrupt Handling - */ - -static irqreturn_t rcar_du_crtc_irq(int irq, void *arg) -{ - struct rcar_du_crtc *rcrtc = arg; - struct rcar_du_device *rcdu = rcrtc->dev; - irqreturn_t ret = IRQ_NONE; - u32 status; - - spin_lock(&rcrtc->vblank_lock); - - status = rcar_du_crtc_read(rcrtc, DSSR); - rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK); - - if (status & DSSR_VBK) { - /* - * Wake up the vblank wait if the counter reaches 0. This must - * be protected by the vblank_lock to avoid races in - * rcar_du_crtc_disable_planes(). - */ - if (rcrtc->vblank_count) { - if (--rcrtc->vblank_count == 0) - wake_up(&rcrtc->vblank_wait); - } - } - - spin_unlock(&rcrtc->vblank_lock); - - if (status & DSSR_VBK) { - if (rcdu->info->gen < 3) { - drm_crtc_handle_vblank(&rcrtc->crtc); - rcar_du_crtc_finish_page_flip(rcrtc); - } - - ret = IRQ_HANDLED; - } - - return ret; -} - -/* ----------------------------------------------------------------------------- - * Initialization - */ - -int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex, - unsigned int hwindex) -{ - static const unsigned int mmio_offsets[] = { - DU0_REG_OFFSET, DU1_REG_OFFSET, DU2_REG_OFFSET, DU3_REG_OFFSET - }; - - struct rcar_du_device *rcdu = rgrp->dev; - struct platform_device *pdev = to_platform_device(rcdu->dev); - struct rcar_du_crtc *rcrtc = &rcdu->crtcs[swindex]; - struct drm_crtc *crtc = &rcrtc->crtc; - struct drm_plane *primary; - unsigned int irqflags; - struct clk *clk; - char clk_name[9]; - char *name; - int irq; - int ret; - - /* Get the CRTC clock and the optional external clock. */ - if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CRTC_CLOCK)) { - sprintf(clk_name, "du.%u", hwindex); - name = clk_name; - } else { - name = NULL; - } - - rcrtc->clock = devm_clk_get(rcdu->dev, name); - if (IS_ERR(rcrtc->clock)) { - dev_err(rcdu->dev, "no clock for DU channel %u\n", hwindex); - return PTR_ERR(rcrtc->clock); - } - - sprintf(clk_name, "dclkin.%u", hwindex); - clk = devm_clk_get(rcdu->dev, clk_name); - if (!IS_ERR(clk)) { - rcrtc->extclock = clk; - } else if (PTR_ERR(clk) == -EPROBE_DEFER) { - return -EPROBE_DEFER; - } else if (rcdu->info->dpll_mask & BIT(hwindex)) { - /* - * DU channels that have a display PLL can't use the internal - * system clock and thus require an external clock. - */ - ret = PTR_ERR(clk); - dev_err(rcdu->dev, "can't get dclkin.%u: %d\n", hwindex, ret); - return ret; - } - - init_waitqueue_head(&rcrtc->flip_wait); - init_waitqueue_head(&rcrtc->vblank_wait); - spin_lock_init(&rcrtc->vblank_lock); - - rcrtc->dev = rcdu; - rcrtc->group = rgrp; - rcrtc->mmio_offset = mmio_offsets[hwindex]; - rcrtc->index = hwindex; - rcrtc->dsysr = rcrtc->index % 2 ? 0 : DSYSR_DRES; - - if (rcar_du_has(rcdu, RCAR_DU_FEATURE_TVM_SYNC)) - rcrtc->dsysr |= DSYSR_TVM_TVSYNC; - - if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) - primary = &rcrtc->vsp->planes[rcrtc->vsp_pipe].plane; - else - primary = &rgrp->planes[swindex % 2].plane; - - ret = drm_crtc_init_with_planes(&rcdu->ddev, crtc, primary, NULL, - rcdu->info->gen <= 2 ? - &crtc_funcs_gen2 : &crtc_funcs_gen3, - NULL); - if (ret < 0) - return ret; - - /* CMM might be disabled for this CRTC. */ - if (rcdu->cmms[swindex]) { - rcrtc->cmm = rcdu->cmms[swindex]; - rgrp->cmms_mask |= BIT(hwindex % 2); - - drm_mode_crtc_set_gamma_size(crtc, CM2_LUT_SIZE); - drm_crtc_enable_color_mgmt(crtc, 0, false, CM2_LUT_SIZE); - } - - drm_crtc_helper_add(crtc, &crtc_helper_funcs); - - /* Register the interrupt handler. */ - if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CRTC_IRQ)) { - /* The IRQ's are associated with the CRTC (sw)index. */ - irq = platform_get_irq(pdev, swindex); - irqflags = 0; - } else { - irq = platform_get_irq(pdev, 0); - irqflags = IRQF_SHARED; - } - - if (irq < 0) { - dev_err(rcdu->dev, "no IRQ for CRTC %u\n", swindex); - return irq; - } - - ret = devm_request_irq(rcdu->dev, irq, rcar_du_crtc_irq, irqflags, - dev_name(rcdu->dev), rcrtc); - if (ret < 0) { - dev_err(rcdu->dev, - "failed to register IRQ for CRTC %u\n", swindex); - return ret; - } - - rcar_du_crtc_crc_init(rcrtc); - - return 0; -} diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h deleted file mode 100644 index d0f38a8b3561..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ /dev/null @@ -1,103 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * R-Car Display Unit CRTCs - * - * Copyright (C) 2013-2015 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#ifndef __RCAR_DU_CRTC_H__ -#define __RCAR_DU_CRTC_H__ - -#include <linux/mutex.h> -#include <linux/spinlock.h> -#include <linux/wait.h> - -#include <drm/drm_crtc.h> -#include <drm/drm_writeback.h> - -#include <media/vsp1.h> - -struct rcar_du_group; -struct rcar_du_vsp; - -/** - * struct rcar_du_crtc - the CRTC, representing a DU superposition processor - * @crtc: base DRM CRTC - * @dev: the DU device - * @clock: the CRTC functional clock - * @extclock: external pixel dot clock (optional) - * @mmio_offset: offset of the CRTC registers in the DU MMIO block - * @index: CRTC hardware index - * @initialized: whether the CRTC has been initialized and clocks enabled - * @dsysr: cached value of the DSYSR register - * @vblank_enable: whether vblank events are enabled on this CRTC - * @event: event to post when the pending page flip completes - * @flip_wait: wait queue used to signal page flip completion - * @vblank_lock: protects vblank_wait and vblank_count - * @vblank_wait: wait queue used to signal vertical blanking - * @vblank_count: number of vertical blanking interrupts to wait for - * @group: CRTC group this CRTC belongs to - * @cmm: CMM associated with this CRTC - * @vsp: VSP feeding video to this CRTC - * @vsp_pipe: index of the VSP pipeline feeding video to this CRTC - * @writeback: the writeback connector - */ -struct rcar_du_crtc { - struct drm_crtc crtc; - - struct rcar_du_device *dev; - struct clk *clock; - struct clk *extclock; - unsigned int mmio_offset; - unsigned int index; - bool initialized; - - u32 dsysr; - - bool vblank_enable; - struct drm_pending_vblank_event *event; - wait_queue_head_t flip_wait; - - spinlock_t vblank_lock; - wait_queue_head_t vblank_wait; - unsigned int vblank_count; - - struct rcar_du_group *group; - struct platform_device *cmm; - struct rcar_du_vsp *vsp; - unsigned int vsp_pipe; - - const char *const *sources; - unsigned int sources_count; - - struct drm_writeback_connector writeback; -}; - -#define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc) -#define wb_to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, writeback) - -/** - * struct rcar_du_crtc_state - Driver-specific CRTC state - * @state: base DRM CRTC state - * @crc: CRC computation configuration - * @outputs: bitmask of the outputs (enum rcar_du_output) driven by this CRTC - */ -struct rcar_du_crtc_state { - struct drm_crtc_state state; - - struct vsp1_du_crc_config crc; - unsigned int outputs; -}; - -#define to_rcar_crtc_state(s) container_of(s, struct rcar_du_crtc_state, state) - -int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex, - unsigned int hwindex); - -void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc); - -void rcar_du_crtc_dsysr_clr_set(struct rcar_du_crtc *rcrtc, u32 clr, u32 set); - -#endif /* __RCAR_DU_CRTC_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c deleted file mode 100644 index 1ffde19cb87f..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ /dev/null @@ -1,744 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * R-Car Display Unit DRM driver - * - * Copyright (C) 2013-2015 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#include <linux/clk.h> -#include <linux/dma-mapping.h> -#include <linux/io.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/of_device.h> -#include <linux/platform_device.h> -#include <linux/pm.h> -#include <linux/slab.h> -#include <linux/wait.h> - -#include <drm/drm_atomic_helper.h> -#include <drm/drm_drv.h> -#include <drm/drm_fbdev_generic.h> -#include <drm/drm_gem_dma_helper.h> -#include <drm/drm_managed.h> -#include <drm/drm_probe_helper.h> - -#include "rcar_du_drv.h" -#include "rcar_du_kms.h" - -/* ----------------------------------------------------------------------------- - * Device Information - */ - -static const struct rcar_du_device_info rzg1_du_r8a7743_info = { - .gen = 2, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_CRTC_CLOCK - | RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, - .channels_mask = BIT(1) | BIT(0), - .routes = { - /* - * R8A774[34] has one RGB output and one LVDS output - */ - [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(1) | BIT(0), - .port = 0, - }, - [RCAR_DU_OUTPUT_LVDS0] = { - .possible_crtcs = BIT(0), - .port = 1, - }, - }, - .num_lvds = 1, - .num_rpf = 4, -}; - -static const struct rcar_du_device_info rzg1_du_r8a7745_info = { - .gen = 2, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_CRTC_CLOCK - | RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, - .channels_mask = BIT(1) | BIT(0), - .routes = { - /* - * R8A7745 has two RGB outputs - */ - [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(0), - .port = 0, - }, - [RCAR_DU_OUTPUT_DPAD1] = { - .possible_crtcs = BIT(1), - .port = 1, - }, - }, - .num_rpf = 4, -}; - -static const struct rcar_du_device_info rzg1_du_r8a77470_info = { - .gen = 2, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_CRTC_CLOCK - | RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, - .channels_mask = BIT(1) | BIT(0), - .routes = { - /* - * R8A77470 has two RGB outputs, one LVDS output, and - * one (currently unsupported) analog video output - */ - [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(0), - .port = 0, - }, - [RCAR_DU_OUTPUT_DPAD1] = { - .possible_crtcs = BIT(1), - .port = 1, - }, - [RCAR_DU_OUTPUT_LVDS0] = { - .possible_crtcs = BIT(0) | BIT(1), - .port = 2, - }, - }, - .num_rpf = 4, -}; - -static const struct rcar_du_device_info rcar_du_r8a774a1_info = { - .gen = 3, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_CRTC_CLOCK - | RCAR_DU_FEATURE_VSP1_SOURCE - | RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, - .channels_mask = BIT(2) | BIT(1) | BIT(0), - .routes = { - /* - * R8A774A1 has one RGB output, one LVDS output and one HDMI - * output. - */ - [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(2), - .port = 0, - }, - [RCAR_DU_OUTPUT_HDMI0] = { - .possible_crtcs = BIT(1), - .port = 1, - }, - [RCAR_DU_OUTPUT_LVDS0] = { - .possible_crtcs = BIT(0), - .port = 2, - }, - }, - .num_lvds = 1, - .num_rpf = 5, - .dpll_mask = BIT(1), -}; - -static const struct rcar_du_device_info rcar_du_r8a774b1_info = { - .gen = 3, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_CRTC_CLOCK - | RCAR_DU_FEATURE_VSP1_SOURCE - | RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, - .channels_mask = BIT(3) | BIT(1) | BIT(0), - .routes = { - /* - * R8A774B1 has one RGB output, one LVDS output and one HDMI - * output. - */ - [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(2), - .port = 0, - }, - [RCAR_DU_OUTPUT_HDMI0] = { - .possible_crtcs = BIT(1), - .port = 1, - }, - [RCAR_DU_OUTPUT_LVDS0] = { - .possible_crtcs = BIT(0), - .port = 2, - }, - }, - .num_lvds = 1, - .num_rpf = 5, - .dpll_mask = BIT(1), -}; - -static const struct rcar_du_device_info rcar_du_r8a774c0_info = { - .gen = 3, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_CRTC_CLOCK - | RCAR_DU_FEATURE_VSP1_SOURCE, - .channels_mask = BIT(1) | BIT(0), - .routes = { - /* - * R8A774C0 has one RGB output and two LVDS outputs - */ - [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(0) | BIT(1), - .port = 0, - }, - [RCAR_DU_OUTPUT_LVDS0] = { - .possible_crtcs = BIT(0), - .port = 1, - }, - [RCAR_DU_OUTPUT_LVDS1] = { - .possible_crtcs = BIT(1), - .port = 2, - }, - }, - .num_lvds = 2, - .num_rpf = 4, - .lvds_clk_mask = BIT(1) | BIT(0), -}; - -static const struct rcar_du_device_info rcar_du_r8a774e1_info = { - .gen = 3, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_CRTC_CLOCK - | RCAR_DU_FEATURE_VSP1_SOURCE - | RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, - .channels_mask = BIT(3) | BIT(1) | BIT(0), - .routes = { - /* - * R8A774E1 has one RGB output, one LVDS output and one HDMI - * output. - */ - [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(2), - .port = 0, - }, - [RCAR_DU_OUTPUT_HDMI0] = { - .possible_crtcs = BIT(1), - .port = 1, - }, - [RCAR_DU_OUTPUT_LVDS0] = { - .possible_crtcs = BIT(0), - .port = 2, - }, - }, - .num_lvds = 1, - .num_rpf = 5, - .dpll_mask = BIT(1), -}; - -static const struct rcar_du_device_info rcar_du_r8a7779_info = { - .gen = 1, - .features = RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, - .channels_mask = BIT(1) | BIT(0), - .routes = { - /* - * R8A7779 has two RGB outputs and one (currently unsupported) - * TCON output. - */ - [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(0), - .port = 0, - }, - [RCAR_DU_OUTPUT_DPAD1] = { - .possible_crtcs = BIT(1) | BIT(0), - .port = 1, - }, - }, -}; - -static const struct rcar_du_device_info rcar_du_r8a7790_info = { - .gen = 2, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_CRTC_CLOCK - | RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, - .quirks = RCAR_DU_QUIRK_ALIGN_128B, - .channels_mask = BIT(2) | BIT(1) | BIT(0), - .routes = { - /* - * R8A7742 and R8A7790 each have one RGB output and two LVDS - * outputs. Additionally R8A7790 supports one TCON output - * (currently unsupported by the driver). - */ - [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(2) | BIT(1) | BIT(0), - .port = 0, - }, - [RCAR_DU_OUTPUT_LVDS0] = { - .possible_crtcs = BIT(0), - .port = 1, - }, - [RCAR_DU_OUTPUT_LVDS1] = { - .possible_crtcs = BIT(2) | BIT(1), - .port = 2, - }, - }, - .num_lvds = 2, - .num_rpf = 4, -}; - -/* M2-W (r8a7791) and M2-N (r8a7793) are identical */ -static const struct rcar_du_device_info rcar_du_r8a7791_info = { - .gen = 2, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_CRTC_CLOCK - | RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, - .channels_mask = BIT(1) | BIT(0), - .routes = { - /* - * R8A779[13] has one RGB output, one LVDS output and one - * (currently unsupported) TCON output. - */ - [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(1) | BIT(0), - .port = 0, - }, - [RCAR_DU_OUTPUT_LVDS0] = { - .possible_crtcs = BIT(0), - .port = 1, - }, - }, - .num_lvds = 1, - .num_rpf = 4, -}; - -static const struct rcar_du_device_info rcar_du_r8a7792_info = { - .gen = 2, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_CRTC_CLOCK - | RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, - .channels_mask = BIT(1) | BIT(0), - .routes = { - /* R8A7792 has two RGB outputs. */ - [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(0), - .port = 0, - }, - [RCAR_DU_OUTPUT_DPAD1] = { - .possible_crtcs = BIT(1), - .port = 1, - }, - }, - .num_rpf = 4, -}; - -static const struct rcar_du_device_info rcar_du_r8a7794_info = { - .gen = 2, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_CRTC_CLOCK - | RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, - .channels_mask = BIT(1) | BIT(0), - .routes = { - /* - * R8A7794 has two RGB outputs and one (currently unsupported) - * TCON output. - */ - [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(0), - .port = 0, - }, - [RCAR_DU_OUTPUT_DPAD1] = { - .possible_crtcs = BIT(1), - .port = 1, - }, - }, - .num_rpf = 4, -}; - -static const struct rcar_du_device_info rcar_du_r8a7795_info = { - .gen = 3, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_CRTC_CLOCK - | RCAR_DU_FEATURE_VSP1_SOURCE - | RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, - .channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0), - .routes = { - /* - * R8A7795 has one RGB output, two HDMI outputs and one - * LVDS output. - */ - [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(3), - .port = 0, - }, - [RCAR_DU_OUTPUT_HDMI0] = { - .possible_crtcs = BIT(1), - .port = 1, - }, - [RCAR_DU_OUTPUT_HDMI1] = { - .possible_crtcs = BIT(2), - .port = 2, - }, - [RCAR_DU_OUTPUT_LVDS0] = { - .possible_crtcs = BIT(0), - .port = 3, - }, - }, - .num_lvds = 1, - .num_rpf = 5, - .dpll_mask = BIT(2) | BIT(1), -}; - -static const struct rcar_du_device_info rcar_du_r8a7796_info = { - .gen = 3, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_CRTC_CLOCK - | RCAR_DU_FEATURE_VSP1_SOURCE - | RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, - .channels_mask = BIT(2) | BIT(1) | BIT(0), - .routes = { - /* - * R8A7796 has one RGB output, one LVDS output and one HDMI - * output. - */ - [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(2), - .port = 0, - }, - [RCAR_DU_OUTPUT_HDMI0] = { - .possible_crtcs = BIT(1), - .port = 1, - }, - [RCAR_DU_OUTPUT_LVDS0] = { - .possible_crtcs = BIT(0), - .port = 2, - }, - }, - .num_lvds = 1, - .num_rpf = 5, - .dpll_mask = BIT(1), -}; - -static const struct rcar_du_device_info rcar_du_r8a77965_info = { - .gen = 3, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_CRTC_CLOCK - | RCAR_DU_FEATURE_VSP1_SOURCE - | RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, - .channels_mask = BIT(3) | BIT(1) | BIT(0), - .routes = { - /* - * R8A77965 has one RGB output, one LVDS output and one HDMI - * output. - */ - [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(2), - .port = 0, - }, - [RCAR_DU_OUTPUT_HDMI0] = { - .possible_crtcs = BIT(1), - .port = 1, - }, - [RCAR_DU_OUTPUT_LVDS0] = { - .possible_crtcs = BIT(0), - .port = 2, - }, - }, - .num_lvds = 1, - .num_rpf = 5, - .dpll_mask = BIT(1), -}; - -static const struct rcar_du_device_info rcar_du_r8a77970_info = { - .gen = 3, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_CRTC_CLOCK - | RCAR_DU_FEATURE_VSP1_SOURCE - | RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, - .channels_mask = BIT(0), - .routes = { - /* - * R8A77970 and R8A77980 have one RGB output and one LVDS - * output. - */ - [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(0), - .port = 0, - }, - [RCAR_DU_OUTPUT_LVDS0] = { - .possible_crtcs = BIT(0), - .port = 1, - }, - }, - .num_lvds = 1, - .num_rpf = 5, -}; - -static const struct rcar_du_device_info rcar_du_r8a7799x_info = { - .gen = 3, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_CRTC_CLOCK - | RCAR_DU_FEATURE_VSP1_SOURCE, - .channels_mask = BIT(1) | BIT(0), - .routes = { - /* - * R8A77990 and R8A77995 have one RGB output and two LVDS - * outputs. - */ - [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(0) | BIT(1), - .port = 0, - }, - [RCAR_DU_OUTPUT_LVDS0] = { - .possible_crtcs = BIT(0), - .port = 1, - }, - [RCAR_DU_OUTPUT_LVDS1] = { - .possible_crtcs = BIT(1), - .port = 2, - }, - }, - .num_lvds = 2, - .num_rpf = 5, - .lvds_clk_mask = BIT(1) | BIT(0), -}; - -static const struct rcar_du_device_info rcar_du_r8a779a0_info = { - .gen = 4, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_VSP1_SOURCE - | RCAR_DU_FEATURE_NO_BLENDING, - .channels_mask = BIT(1) | BIT(0), - .routes = { - /* R8A779A0 has two MIPI DSI outputs. */ - [RCAR_DU_OUTPUT_DSI0] = { - .possible_crtcs = BIT(0), - .port = 0, - }, - [RCAR_DU_OUTPUT_DSI1] = { - .possible_crtcs = BIT(1), - .port = 1, - }, - }, - .num_rpf = 5, - .dsi_clk_mask = BIT(1) | BIT(0), -}; - -static const struct rcar_du_device_info rcar_du_r8a779g0_info = { - .gen = 4, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_VSP1_SOURCE - | RCAR_DU_FEATURE_NO_BLENDING, - .channels_mask = BIT(1) | BIT(0), - .routes = { - /* R8A779G0 has two MIPI DSI outputs. */ - [RCAR_DU_OUTPUT_DSI0] = { - .possible_crtcs = BIT(0), - .port = 0, - }, - [RCAR_DU_OUTPUT_DSI1] = { - .possible_crtcs = BIT(1), - .port = 1, - }, - }, - .num_rpf = 5, - .dsi_clk_mask = BIT(1) | BIT(0), -}; - -static const struct of_device_id rcar_du_of_table[] = { - { .compatible = "renesas,du-r8a7742", .data = &rcar_du_r8a7790_info }, - { .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info }, - { .compatible = "renesas,du-r8a7744", .data = &rzg1_du_r8a7743_info }, - { .compatible = "renesas,du-r8a7745", .data = &rzg1_du_r8a7745_info }, - { .compatible = "renesas,du-r8a77470", .data = &rzg1_du_r8a77470_info }, - { .compatible = "renesas,du-r8a774a1", .data = &rcar_du_r8a774a1_info }, - { .compatible = "renesas,du-r8a774b1", .data = &rcar_du_r8a774b1_info }, - { .compatible = "renesas,du-r8a774c0", .data = &rcar_du_r8a774c0_info }, - { .compatible = "renesas,du-r8a774e1", .data = &rcar_du_r8a774e1_info }, - { .compatible = "renesas,du-r8a7779", .data = &rcar_du_r8a7779_info }, - { .compatible = "renesas,du-r8a7790", .data = &rcar_du_r8a7790_info }, - { .compatible = "renesas,du-r8a7791", .data = &rcar_du_r8a7791_info }, - { .compatible = "renesas,du-r8a7792", .data = &rcar_du_r8a7792_info }, - { .compatible = "renesas,du-r8a7793", .data = &rcar_du_r8a7791_info }, - { .compatible = "renesas,du-r8a7794", .data = &rcar_du_r8a7794_info }, - { .compatible = "renesas,du-r8a7795", .data = &rcar_du_r8a7795_info }, - { .compatible = "renesas,du-r8a7796", .data = &rcar_du_r8a7796_info }, - { .compatible = "renesas,du-r8a77961", .data = &rcar_du_r8a7796_info }, - { .compatible = "renesas,du-r8a77965", .data = &rcar_du_r8a77965_info }, - { .compatible = "renesas,du-r8a77970", .data = &rcar_du_r8a77970_info }, - { .compatible = "renesas,du-r8a77980", .data = &rcar_du_r8a77970_info }, - { .compatible = "renesas,du-r8a77990", .data = &rcar_du_r8a7799x_info }, - { .compatible = "renesas,du-r8a77995", .data = &rcar_du_r8a7799x_info }, - { .compatible = "renesas,du-r8a779a0", .data = &rcar_du_r8a779a0_info }, - { .compatible = "renesas,du-r8a779g0", .data = &rcar_du_r8a779g0_info }, - { } -}; - -MODULE_DEVICE_TABLE(of, rcar_du_of_table); - -const char *rcar_du_output_name(enum rcar_du_output output) -{ - static const char * const names[] = { - [RCAR_DU_OUTPUT_DPAD0] = "DPAD0", - [RCAR_DU_OUTPUT_DPAD1] = "DPAD1", - [RCAR_DU_OUTPUT_DSI0] = "DSI0", - [RCAR_DU_OUTPUT_DSI1] = "DSI1", - [RCAR_DU_OUTPUT_HDMI0] = "HDMI0", - [RCAR_DU_OUTPUT_HDMI1] = "HDMI1", - [RCAR_DU_OUTPUT_LVDS0] = "LVDS0", - [RCAR_DU_OUTPUT_LVDS1] = "LVDS1", - [RCAR_DU_OUTPUT_TCON] = "TCON", - }; - - if (output >= ARRAY_SIZE(names) || !names[output]) - return "UNKNOWN"; - - return names[output]; -} - -/* ----------------------------------------------------------------------------- - * DRM operations - */ - -DEFINE_DRM_GEM_DMA_FOPS(rcar_du_fops); - -static const struct drm_driver rcar_du_driver = { - .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, - .dumb_create = rcar_du_dumb_create, - .prime_handle_to_fd = drm_gem_prime_handle_to_fd, - .prime_fd_to_handle = drm_gem_prime_fd_to_handle, - .gem_prime_import_sg_table = rcar_du_gem_prime_import_sg_table, - .gem_prime_mmap = drm_gem_prime_mmap, - .fops = &rcar_du_fops, - .name = "rcar-du", - .desc = "Renesas R-Car Display Unit", - .date = "20130110", - .major = 1, - .minor = 0, -}; - -/* ----------------------------------------------------------------------------- - * Power management - */ - -static int rcar_du_pm_suspend(struct device *dev) -{ - struct rcar_du_device *rcdu = dev_get_drvdata(dev); - - return drm_mode_config_helper_suspend(&rcdu->ddev); -} - -static int rcar_du_pm_resume(struct device *dev) -{ - struct rcar_du_device *rcdu = dev_get_drvdata(dev); - - return drm_mode_config_helper_resume(&rcdu->ddev); -} - -static DEFINE_SIMPLE_DEV_PM_OPS(rcar_du_pm_ops, - rcar_du_pm_suspend, rcar_du_pm_resume); - -/* ----------------------------------------------------------------------------- - * Platform driver - */ - -static int rcar_du_remove(struct platform_device *pdev) -{ - struct rcar_du_device *rcdu = platform_get_drvdata(pdev); - struct drm_device *ddev = &rcdu->ddev; - - drm_dev_unregister(ddev); - drm_atomic_helper_shutdown(ddev); - - drm_kms_helper_poll_fini(ddev); - - return 0; -} - -static void rcar_du_shutdown(struct platform_device *pdev) -{ - struct rcar_du_device *rcdu = platform_get_drvdata(pdev); - - drm_atomic_helper_shutdown(&rcdu->ddev); -} - -static int rcar_du_probe(struct platform_device *pdev) -{ - struct rcar_du_device *rcdu; - unsigned int mask; - int ret; - - if (drm_firmware_drivers_only()) - return -ENODEV; - - /* Allocate and initialize the R-Car device structure. */ - rcdu = devm_drm_dev_alloc(&pdev->dev, &rcar_du_driver, - struct rcar_du_device, ddev); - if (IS_ERR(rcdu)) - return PTR_ERR(rcdu); - - rcdu->dev = &pdev->dev; - - rcdu->info = of_device_get_match_data(rcdu->dev); - - platform_set_drvdata(pdev, rcdu); - - /* I/O resources */ - rcdu->mmio = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(rcdu->mmio)) - return PTR_ERR(rcdu->mmio); - - /* - * Set the DMA coherent mask to reflect the DU 32-bit DMA address space - * limitations. When sourcing frames from a VSP the DU doesn't perform - * any memory access so set the mask to 40 bits to accept all buffers. - */ - mask = rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE) ? 40 : 32; - ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(mask)); - if (ret) - return ret; - - /* DRM/KMS objects */ - ret = rcar_du_modeset_init(rcdu); - if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "failed to initialize DRM/KMS (%d)\n", ret); - goto error; - } - - /* - * Register the DRM device with the core and the connectors with - * sysfs. - */ - ret = drm_dev_register(&rcdu->ddev, 0); - if (ret) - goto error; - - DRM_INFO("Device %s probed\n", dev_name(&pdev->dev)); - - drm_fbdev_generic_setup(&rcdu->ddev, 32); - - return 0; - -error: - drm_kms_helper_poll_fini(&rcdu->ddev); - return ret; -} - -static struct platform_driver rcar_du_platform_driver = { - .probe = rcar_du_probe, - .remove = rcar_du_remove, - .shutdown = rcar_du_shutdown, - .driver = { - .name = "rcar-du", - .pm = pm_sleep_ptr(&rcar_du_pm_ops), - .of_match_table = rcar_du_of_table, - }, -}; - -module_platform_driver(rcar_du_platform_driver); - -MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); -MODULE_DESCRIPTION("Renesas R-Car Display Unit DRM Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h deleted file mode 100644 index 5cfa2bb7ad93..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ /dev/null @@ -1,152 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * R-Car Display Unit DRM driver - * - * Copyright (C) 2013-2015 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#ifndef __RCAR_DU_DRV_H__ -#define __RCAR_DU_DRV_H__ - -#include <linux/kernel.h> -#include <linux/wait.h> - -#include <drm/drm_device.h> - -#include "rcar_cmm.h" -#include "rcar_du_crtc.h" -#include "rcar_du_group.h" -#include "rcar_du_vsp.h" - -struct clk; -struct device; -struct drm_bridge; -struct drm_property; -struct rcar_du_device; - -#define RCAR_DU_FEATURE_CRTC_IRQ BIT(0) /* Per-CRTC IRQ */ -#define RCAR_DU_FEATURE_CRTC_CLOCK BIT(1) /* Per-CRTC clock */ -#define RCAR_DU_FEATURE_VSP1_SOURCE BIT(2) /* Has inputs from VSP1 */ -#define RCAR_DU_FEATURE_INTERLACED BIT(3) /* HW supports interlaced */ -#define RCAR_DU_FEATURE_TVM_SYNC BIT(4) /* Has TV switch/sync modes */ -#define RCAR_DU_FEATURE_NO_BLENDING BIT(5) /* PnMR.SPIM does not have ALP nor EOR bits */ - -#define RCAR_DU_QUIRK_ALIGN_128B BIT(0) /* Align pitches to 128 bytes */ - -enum rcar_du_output { - RCAR_DU_OUTPUT_DPAD0, - RCAR_DU_OUTPUT_DPAD1, - RCAR_DU_OUTPUT_DSI0, - RCAR_DU_OUTPUT_DSI1, - RCAR_DU_OUTPUT_HDMI0, - RCAR_DU_OUTPUT_HDMI1, - RCAR_DU_OUTPUT_LVDS0, - RCAR_DU_OUTPUT_LVDS1, - RCAR_DU_OUTPUT_TCON, - RCAR_DU_OUTPUT_MAX, -}; - -/* - * struct rcar_du_output_routing - Output routing specification - * @possible_crtcs: bitmask of possible CRTCs for the output - * @port: device tree port number corresponding to this output route - * - * The DU has 5 possible outputs (DPAD0/1, LVDS0/1, TCON). Output routing data - * specify the valid SoC outputs, which CRTCs can drive the output, and the type - * of in-SoC encoder for the output. - */ -struct rcar_du_output_routing { - unsigned int possible_crtcs; - unsigned int port; -}; - -/* - * struct rcar_du_device_info - DU model-specific information - * @gen: device generation (2 or 3) - * @features: device features (RCAR_DU_FEATURE_*) - * @quirks: device quirks (RCAR_DU_QUIRK_*) - * @channels_mask: bit mask of available DU channels - * @routes: array of CRTC to output routes, indexed by output (RCAR_DU_OUTPUT_*) - * @num_lvds: number of internal LVDS encoders - * @num_rpf: number of RPFs in VSP - * @dpll_mask: bit mask of DU channels equipped with a DPLL - * @dsi_clk_mask: bitmask of channels that can use the DSI clock as dot clock - * @lvds_clk_mask: bitmask of channels that can use the LVDS clock as dot clock - */ -struct rcar_du_device_info { - unsigned int gen; - unsigned int features; - unsigned int quirks; - unsigned int channels_mask; - struct rcar_du_output_routing routes[RCAR_DU_OUTPUT_MAX]; - unsigned int num_lvds; - unsigned int num_rpf; - unsigned int dpll_mask; - unsigned int dsi_clk_mask; - unsigned int lvds_clk_mask; -}; - -#define RCAR_DU_MAX_CRTCS 4 -#define RCAR_DU_MAX_GROUPS DIV_ROUND_UP(RCAR_DU_MAX_CRTCS, 2) -#define RCAR_DU_MAX_VSPS 4 -#define RCAR_DU_MAX_LVDS 2 -#define RCAR_DU_MAX_DSI 2 - -struct rcar_du_device { - struct device *dev; - const struct rcar_du_device_info *info; - - void __iomem *mmio; - - struct drm_device ddev; - - struct rcar_du_crtc crtcs[RCAR_DU_MAX_CRTCS]; - unsigned int num_crtcs; - - struct rcar_du_group groups[RCAR_DU_MAX_GROUPS]; - struct platform_device *cmms[RCAR_DU_MAX_CRTCS]; - struct rcar_du_vsp vsps[RCAR_DU_MAX_VSPS]; - struct drm_bridge *lvds[RCAR_DU_MAX_LVDS]; - struct drm_bridge *dsi[RCAR_DU_MAX_DSI]; - - struct { - struct drm_property *colorkey; - } props; - - unsigned int dpad0_source; - unsigned int dpad1_source; - unsigned int vspd1_sink; -}; - -static inline struct rcar_du_device *to_rcar_du_device(struct drm_device *dev) -{ - return container_of(dev, struct rcar_du_device, ddev); -} - -static inline bool rcar_du_has(struct rcar_du_device *rcdu, - unsigned int feature) -{ - return rcdu->info->features & feature; -} - -static inline bool rcar_du_needs(struct rcar_du_device *rcdu, - unsigned int quirk) -{ - return rcdu->info->quirks & quirk; -} - -static inline u32 rcar_du_read(struct rcar_du_device *rcdu, u32 reg) -{ - return ioread32(rcdu->mmio + reg); -} - -static inline void rcar_du_write(struct rcar_du_device *rcdu, u32 reg, u32 data) -{ - iowrite32(data, rcdu->mmio + reg); -} - -const char *rcar_du_output_name(enum rcar_du_output output); - -#endif /* __RCAR_DU_DRV_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c deleted file mode 100644 index 7ecec7b04a8d..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c +++ /dev/null @@ -1,137 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * R-Car Display Unit Encoder - * - * Copyright (C) 2013-2014 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#include <linux/export.h> -#include <linux/of.h> - -#include <drm/drm_bridge.h> -#include <drm/drm_bridge_connector.h> -#include <drm/drm_panel.h> - -#include "rcar_du_drv.h" -#include "rcar_du_encoder.h" -#include "rcar_lvds.h" - -/* ----------------------------------------------------------------------------- - * Encoder - */ - -static unsigned int rcar_du_encoder_count_ports(struct device_node *node) -{ - struct device_node *ports; - struct device_node *port; - unsigned int num_ports = 0; - - ports = of_get_child_by_name(node, "ports"); - if (!ports) - ports = of_node_get(node); - - for_each_child_of_node(ports, port) { - if (of_node_name_eq(port, "port")) - num_ports++; - } - - of_node_put(ports); - - return num_ports; -} - -static const struct drm_encoder_funcs rcar_du_encoder_funcs = { -}; - -int rcar_du_encoder_init(struct rcar_du_device *rcdu, - enum rcar_du_output output, - struct device_node *enc_node) -{ - struct rcar_du_encoder *renc; - struct drm_connector *connector; - struct drm_bridge *bridge; - int ret; - - /* - * Locate the DRM bridge from the DT node. For the DPAD outputs, if the - * DT node has a single port, assume that it describes a panel and - * create a panel bridge. - */ - if ((output == RCAR_DU_OUTPUT_DPAD0 || - output == RCAR_DU_OUTPUT_DPAD1) && - rcar_du_encoder_count_ports(enc_node) == 1) { - struct drm_panel *panel = of_drm_find_panel(enc_node); - - if (IS_ERR(panel)) - return PTR_ERR(panel); - - bridge = devm_drm_panel_bridge_add_typed(rcdu->dev, panel, - DRM_MODE_CONNECTOR_DPI); - if (IS_ERR(bridge)) - return PTR_ERR(bridge); - } else { - bridge = of_drm_find_bridge(enc_node); - if (!bridge) - return -EPROBE_DEFER; - - if (output == RCAR_DU_OUTPUT_LVDS0 || - output == RCAR_DU_OUTPUT_LVDS1) - rcdu->lvds[output - RCAR_DU_OUTPUT_LVDS0] = bridge; - - if (output == RCAR_DU_OUTPUT_DSI0 || - output == RCAR_DU_OUTPUT_DSI1) - rcdu->dsi[output - RCAR_DU_OUTPUT_DSI0] = bridge; - } - - /* - * Create and initialize the encoder. On Gen3, skip the LVDS1 output if - * the LVDS1 encoder is used as a companion for LVDS0 in dual-link - * mode, or any LVDS output if it isn't connected. The latter may happen - * on D3 or E3 as the LVDS encoders are needed to provide the pixel - * clock to the DU, even when the LVDS outputs are not used. - */ - if (rcdu->info->gen >= 3) { - if (output == RCAR_DU_OUTPUT_LVDS1 && - rcar_lvds_dual_link(bridge)) - return -ENOLINK; - - if ((output == RCAR_DU_OUTPUT_LVDS0 || - output == RCAR_DU_OUTPUT_LVDS1) && - !rcar_lvds_is_connected(bridge)) - return -ENOLINK; - } - - dev_dbg(rcdu->dev, "initializing encoder %pOF for output %s\n", - enc_node, rcar_du_output_name(output)); - - renc = drmm_encoder_alloc(&rcdu->ddev, struct rcar_du_encoder, base, - &rcar_du_encoder_funcs, DRM_MODE_ENCODER_NONE, - NULL); - if (IS_ERR(renc)) - return PTR_ERR(renc); - - renc->output = output; - - /* Attach the bridge to the encoder. */ - ret = drm_bridge_attach(&renc->base, bridge, NULL, - DRM_BRIDGE_ATTACH_NO_CONNECTOR); - if (ret) { - dev_err(rcdu->dev, - "failed to attach bridge %pOF for output %s (%d)\n", - bridge->of_node, rcar_du_output_name(output), ret); - return ret; - } - - /* Create the connector for the chain of bridges. */ - connector = drm_bridge_connector_init(&rcdu->ddev, &renc->base); - if (IS_ERR(connector)) { - dev_err(rcdu->dev, - "failed to created connector for output %s (%ld)\n", - rcar_du_output_name(output), PTR_ERR(connector)); - return PTR_ERR(connector); - } - - return drm_connector_attach_encoder(connector, &renc->base); -} diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h deleted file mode 100644 index e5ec8fbb3979..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * R-Car Display Unit Encoder - * - * Copyright (C) 2013-2014 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#ifndef __RCAR_DU_ENCODER_H__ -#define __RCAR_DU_ENCODER_H__ - -#include <drm/drm_encoder.h> - -struct rcar_du_device; - -struct rcar_du_encoder { - struct drm_encoder base; - enum rcar_du_output output; -}; - -#define to_rcar_encoder(e) \ - container_of(e, struct rcar_du_encoder, base) - -int rcar_du_encoder_init(struct rcar_du_device *rcdu, - enum rcar_du_output output, - struct device_node *enc_node); - -#endif /* __RCAR_DU_ENCODER_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c deleted file mode 100644 index 2ccd2581f544..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c +++ /dev/null @@ -1,377 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * R-Car Display Unit Channels Pair - * - * Copyright (C) 2013-2015 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -/* - * The R8A7779 DU is split in per-CRTC resources (scan-out engine, blending - * unit, timings generator, ...) and device-global resources (start/stop - * control, planes, ...) shared between the two CRTCs. - * - * The R8A7790 introduced a third CRTC with its own set of global resources. - * This would be modeled as two separate DU device instances if it wasn't for - * a handful or resources that are shared between the three CRTCs (mostly - * related to input and output routing). For this reason the R8A7790 DU must be - * modeled as a single device with three CRTCs, two sets of "semi-global" - * resources, and a few device-global resources. - * - * The rcar_du_group object is a driver specific object, without any real - * counterpart in the DU documentation, that models those semi-global resources. - */ - -#include <linux/clk.h> -#include <linux/io.h> - -#include "rcar_du_drv.h" -#include "rcar_du_group.h" -#include "rcar_du_regs.h" - -u32 rcar_du_group_read(struct rcar_du_group *rgrp, u32 reg) -{ - return rcar_du_read(rgrp->dev, rgrp->mmio_offset + reg); -} - -void rcar_du_group_write(struct rcar_du_group *rgrp, u32 reg, u32 data) -{ - rcar_du_write(rgrp->dev, rgrp->mmio_offset + reg, data); -} - -static void rcar_du_group_setup_pins(struct rcar_du_group *rgrp) -{ - u32 defr6 = DEFR6_CODE; - - if (rgrp->channels_mask & BIT(0)) - defr6 |= DEFR6_ODPM02_DISP; - - if (rgrp->channels_mask & BIT(1)) - defr6 |= DEFR6_ODPM12_DISP; - - rcar_du_group_write(rgrp, DEFR6, defr6); -} - -static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp) -{ - struct rcar_du_device *rcdu = rgrp->dev; - u32 defr8 = DEFR8_CODE; - - if (rcdu->info->gen < 3) { - defr8 |= DEFR8_DEFE8; - - /* - * On Gen2 the DEFR8 register for the first group also controls - * RGB output routing to DPAD0 and VSPD1 routing to DU0/1/2 for - * DU instances that support it. - */ - if (rgrp->index == 0) { - defr8 |= DEFR8_DRGBS_DU(rcdu->dpad0_source); - if (rgrp->dev->vspd1_sink == 2) - defr8 |= DEFR8_VSCS; - } - } else { - /* - * On Gen3 VSPD routing can't be configured, and DPAD routing - * is set in the group corresponding to the DPAD output (no Gen3 - * SoC has multiple DPAD sources belonging to separate groups). - */ - if (rgrp->index == rcdu->dpad0_source / 2) - defr8 |= DEFR8_DRGBS_DU(rcdu->dpad0_source); - } - - rcar_du_group_write(rgrp, DEFR8, defr8); -} - -static void rcar_du_group_setup_didsr(struct rcar_du_group *rgrp) -{ - struct rcar_du_device *rcdu = rgrp->dev; - struct rcar_du_crtc *rcrtc; - unsigned int num_crtcs = 0; - unsigned int i; - u32 didsr; - - /* - * Configure input dot clock routing with a hardcoded configuration. If - * the DU channel can use the LVDS encoder output clock as the dot - * clock, do so. Otherwise route DU_DOTCLKINn signal to DUn. - * - * Each channel can then select between the dot clock configured here - * and the clock provided by the CPG through the ESCR register. - */ - if (rcdu->info->gen < 3 && rgrp->index == 0) { - /* - * On Gen2 a single register in the first group controls dot - * clock selection for all channels. - */ - rcrtc = rcdu->crtcs; - num_crtcs = rcdu->num_crtcs; - } else if (rcdu->info->gen >= 3 && rgrp->num_crtcs > 1) { - /* - * On Gen3 dot clocks are setup through per-group registers, - * only available when the group has two channels. - */ - rcrtc = &rcdu->crtcs[rgrp->index * 2]; - num_crtcs = rgrp->num_crtcs; - } - - if (!num_crtcs) - return; - - didsr = DIDSR_CODE; - for (i = 0; i < num_crtcs; ++i, ++rcrtc) { - if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index)) - didsr |= DIDSR_LDCS_LVDS0(i) - | DIDSR_PDCS_CLK(i, 0); - else if (rcdu->info->dsi_clk_mask & BIT(rcrtc->index)) - didsr |= DIDSR_LDCS_DSI(i); - else - didsr |= DIDSR_LDCS_DCLKIN(i) - | DIDSR_PDCS_CLK(i, 0); - } - - rcar_du_group_write(rgrp, DIDSR, didsr); -} - -static void rcar_du_group_setup(struct rcar_du_group *rgrp) -{ - struct rcar_du_device *rcdu = rgrp->dev; - u32 defr7 = DEFR7_CODE; - u32 dorcr; - - /* Enable extended features */ - rcar_du_group_write(rgrp, DEFR, DEFR_CODE | DEFR_DEFE); - if (rcdu->info->gen < 3) { - rcar_du_group_write(rgrp, DEFR2, DEFR2_CODE | DEFR2_DEFE2G); - rcar_du_group_write(rgrp, DEFR3, DEFR3_CODE | DEFR3_DEFE3); - rcar_du_group_write(rgrp, DEFR4, DEFR4_CODE); - } - rcar_du_group_write(rgrp, DEFR5, DEFR5_CODE | DEFR5_DEFE5); - - if (rcdu->info->gen < 4) - rcar_du_group_setup_pins(rgrp); - - if (rcdu->info->gen < 4) { - /* - * TODO: Handle routing of the DU output to CMM dynamically, as - * we should bypass CMM completely when no color management - * feature is used. - */ - defr7 |= (rgrp->cmms_mask & BIT(1) ? DEFR7_CMME1 : 0) | - (rgrp->cmms_mask & BIT(0) ? DEFR7_CMME0 : 0); - rcar_du_group_write(rgrp, DEFR7, defr7); - } - - if (rcdu->info->gen >= 2) { - if (rcdu->info->gen < 4) - rcar_du_group_setup_defr8(rgrp); - rcar_du_group_setup_didsr(rgrp); - } - - if (rcdu->info->gen >= 3) - rcar_du_group_write(rgrp, DEFR10, DEFR10_CODE | DEFR10_DEFE10); - - /* - * Use DS1PR and DS2PR to configure planes priorities and connects the - * superposition 0 to DU0 pins. DU1 pins will be configured dynamically. - * - * Groups that have a single channel have a hardcoded configuration. On - * Gen3 and newer, the documentation requires PG1T, DK1S and PG1D_DS1 to - * always be set in this case. - */ - dorcr = DORCR_PG0D_DS0 | DORCR_DPRS; - if (rcdu->info->gen >= 3 && rgrp->num_crtcs == 1) - dorcr |= DORCR_PG1T | DORCR_DK1S | DORCR_PG1D_DS1; - rcar_du_group_write(rgrp, DORCR, dorcr); - - /* Apply planes to CRTCs association. */ - mutex_lock(&rgrp->lock); - rcar_du_group_write(rgrp, DPTSR, (rgrp->dptsr_planes << 16) | - rgrp->dptsr_planes); - mutex_unlock(&rgrp->lock); -} - -/* - * rcar_du_group_get - Acquire a reference to the DU channels group - * - * Acquiring the first reference setups core registers. A reference must be held - * before accessing any hardware registers. - * - * This function must be called with the DRM mode_config lock held. - * - * Return 0 in case of success or a negative error code otherwise. - */ -int rcar_du_group_get(struct rcar_du_group *rgrp) -{ - if (rgrp->use_count) - goto done; - - rcar_du_group_setup(rgrp); - -done: - rgrp->use_count++; - return 0; -} - -/* - * rcar_du_group_put - Release a reference to the DU - * - * This function must be called with the DRM mode_config lock held. - */ -void rcar_du_group_put(struct rcar_du_group *rgrp) -{ - --rgrp->use_count; -} - -static void __rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start) -{ - struct rcar_du_device *rcdu = rgrp->dev; - - /* - * Group start/stop is controlled by the DRES and DEN bits of DSYSR0 - * for the first group and DSYSR2 for the second group. On most DU - * instances, this maps to the first CRTC of the group, and we can just - * use rcar_du_crtc_dsysr_clr_set() to access the correct DSYSR. On - * M3-N, however, DU2 doesn't exist, but DSYSR2 does. We thus need to - * access the register directly using group read/write. - */ - if (rcdu->info->channels_mask & BIT(rgrp->index * 2)) { - struct rcar_du_crtc *rcrtc = &rgrp->dev->crtcs[rgrp->index * 2]; - - rcar_du_crtc_dsysr_clr_set(rcrtc, DSYSR_DRES | DSYSR_DEN, - start ? DSYSR_DEN : DSYSR_DRES); - } else { - rcar_du_group_write(rgrp, DSYSR, - start ? DSYSR_DEN : DSYSR_DRES); - } -} - -void rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start) -{ - /* - * Many of the configuration bits are only updated when the display - * reset (DRES) bit in DSYSR is set to 1, disabling *both* CRTCs. Some - * of those bits could be pre-configured, but others (especially the - * bits related to plane assignment to display timing controllers) need - * to be modified at runtime. - * - * Restart the display controller if a start is requested. Sorry for the - * flicker. It should be possible to move most of the "DRES-update" bits - * setup to driver initialization time and minimize the number of cases - * when the display controller will have to be restarted. - */ - if (start) { - if (rgrp->used_crtcs++ != 0) - __rcar_du_group_start_stop(rgrp, false); - __rcar_du_group_start_stop(rgrp, true); - } else { - if (--rgrp->used_crtcs == 0) - __rcar_du_group_start_stop(rgrp, false); - } -} - -void rcar_du_group_restart(struct rcar_du_group *rgrp) -{ - rgrp->need_restart = false; - - __rcar_du_group_start_stop(rgrp, false); - __rcar_du_group_start_stop(rgrp, true); -} - -int rcar_du_set_dpad0_vsp1_routing(struct rcar_du_device *rcdu) -{ - struct rcar_du_group *rgrp; - struct rcar_du_crtc *crtc; - unsigned int index; - int ret; - - if (rcdu->info->gen < 2) - return 0; - - /* - * RGB output routing to DPAD0 and VSP1D routing to DU0/1/2 are - * configured in the DEFR8 register of the first group on Gen2 and the - * last group on Gen3. As this function can be called with the DU - * channels of the corresponding CRTCs disabled, we need to enable the - * group clock before accessing the register. - */ - index = rcdu->info->gen < 3 ? 0 : DIV_ROUND_UP(rcdu->num_crtcs, 2) - 1; - rgrp = &rcdu->groups[index]; - crtc = &rcdu->crtcs[index * 2]; - - ret = clk_prepare_enable(crtc->clock); - if (ret < 0) - return ret; - - rcar_du_group_setup_defr8(rgrp); - - clk_disable_unprepare(crtc->clock); - - return 0; -} - -static void rcar_du_group_set_dpad_levels(struct rcar_du_group *rgrp) -{ - static const u32 doflr_values[2] = { - DOFLR_HSYCFL0 | DOFLR_VSYCFL0 | DOFLR_ODDFL0 | - DOFLR_DISPFL0 | DOFLR_CDEFL0 | DOFLR_RGBFL0, - DOFLR_HSYCFL1 | DOFLR_VSYCFL1 | DOFLR_ODDFL1 | - DOFLR_DISPFL1 | DOFLR_CDEFL1 | DOFLR_RGBFL1, - }; - static const u32 dpad_mask = BIT(RCAR_DU_OUTPUT_DPAD1) - | BIT(RCAR_DU_OUTPUT_DPAD0); - struct rcar_du_device *rcdu = rgrp->dev; - u32 doflr = DOFLR_CODE; - unsigned int i; - - if (rcdu->info->gen < 2) - return; - - /* - * The DPAD outputs can't be controlled directly. However, the parallel - * output of the DU channels routed to DPAD can be set to fixed levels - * through the DOFLR group register. Use this to turn the DPAD on or off - * by driving fixed low-level signals at the output of any DU channel - * not routed to a DPAD output. This doesn't affect the DU output - * signals going to other outputs, such as the internal LVDS and HDMI - * encoders. - */ - - for (i = 0; i < rgrp->num_crtcs; ++i) { - struct rcar_du_crtc_state *rstate; - struct rcar_du_crtc *rcrtc; - - rcrtc = &rcdu->crtcs[rgrp->index * 2 + i]; - rstate = to_rcar_crtc_state(rcrtc->crtc.state); - - if (!(rstate->outputs & dpad_mask)) - doflr |= doflr_values[i]; - } - - rcar_du_group_write(rgrp, DOFLR, doflr); -} - -int rcar_du_group_set_routing(struct rcar_du_group *rgrp) -{ - struct rcar_du_device *rcdu = rgrp->dev; - u32 dorcr = rcar_du_group_read(rgrp, DORCR); - - dorcr &= ~(DORCR_PG1T | DORCR_DK1S | DORCR_PG1D_MASK); - - /* - * Set the DPAD1 pins sources. Select CRTC 0 if explicitly requested and - * CRTC 1 in all other cases to avoid cloning CRTC 0 to DPAD0 and DPAD1 - * by default. - */ - if (rcdu->dpad1_source == rgrp->index * 2) - dorcr |= DORCR_PG1D_DS0; - else - dorcr |= DORCR_PG1T | DORCR_DK1S | DORCR_PG1D_DS1; - - rcar_du_group_write(rgrp, DORCR, dorcr); - - rcar_du_group_set_dpad_levels(rgrp); - - return rcar_du_set_dpad0_vsp1_routing(rgrp->dev); -} diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.h b/drivers/gpu/drm/rcar-du/rcar_du_group.h deleted file mode 100644 index 55649ad86a10..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.h +++ /dev/null @@ -1,65 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * R-Car Display Unit Planes and CRTCs Group - * - * Copyright (C) 2013-2014 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#ifndef __RCAR_DU_GROUP_H__ -#define __RCAR_DU_GROUP_H__ - -#include <linux/mutex.h> - -#include "rcar_du_plane.h" - -struct rcar_du_device; - -/* - * struct rcar_du_group - CRTCs and planes group - * @dev: the DU device - * @mmio_offset: registers offset in the device memory map - * @index: group index - * @channels_mask: bitmask of populated DU channels in this group - * @cmms_mask: bitmask of available CMMs in this group - * @num_crtcs: number of CRTCs in this group (1 or 2) - * @use_count: number of users of the group (rcar_du_group_(get|put)) - * @used_crtcs: number of CRTCs currently in use - * @lock: protects the dptsr_planes field and the DPTSR register - * @dptsr_planes: bitmask of planes driven by dot-clock and timing generator 1 - * @num_planes: number of planes in the group - * @planes: planes handled by the group - * @need_restart: the group needs to be restarted due to a configuration change - */ -struct rcar_du_group { - struct rcar_du_device *dev; - unsigned int mmio_offset; - unsigned int index; - - unsigned int channels_mask; - unsigned int cmms_mask; - unsigned int num_crtcs; - unsigned int use_count; - unsigned int used_crtcs; - - struct mutex lock; - unsigned int dptsr_planes; - - unsigned int num_planes; - struct rcar_du_plane planes[RCAR_DU_NUM_KMS_PLANES]; - bool need_restart; -}; - -u32 rcar_du_group_read(struct rcar_du_group *rgrp, u32 reg); -void rcar_du_group_write(struct rcar_du_group *rgrp, u32 reg, u32 data); - -int rcar_du_group_get(struct rcar_du_group *rgrp); -void rcar_du_group_put(struct rcar_du_group *rgrp); -void rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start); -void rcar_du_group_restart(struct rcar_du_group *rgrp); -int rcar_du_group_set_routing(struct rcar_du_group *rgrp); - -int rcar_du_set_dpad0_vsp1_routing(struct rcar_du_device *rcdu); - -#endif /* __RCAR_DU_GROUP_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c deleted file mode 100644 index adfb36b0e815..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ /dev/null @@ -1,1006 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * R-Car Display Unit Mode Setting - * - * Copyright (C) 2013-2015 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#include <drm/drm_atomic.h> -#include <drm/drm_atomic_helper.h> -#include <drm/drm_crtc.h> -#include <drm/drm_device.h> -#include <drm/drm_framebuffer.h> -#include <drm/drm_gem_dma_helper.h> -#include <drm/drm_gem_framebuffer_helper.h> -#include <drm/drm_managed.h> -#include <drm/drm_probe_helper.h> -#include <drm/drm_vblank.h> - -#include <linux/device.h> -#include <linux/dma-buf.h> -#include <linux/of_graph.h> -#include <linux/of_platform.h> -#include <linux/wait.h> - -#include "rcar_du_crtc.h" -#include "rcar_du_drv.h" -#include "rcar_du_encoder.h" -#include "rcar_du_kms.h" -#include "rcar_du_regs.h" -#include "rcar_du_vsp.h" -#include "rcar_du_writeback.h" - -/* ----------------------------------------------------------------------------- - * Format helpers - */ - -static const struct rcar_du_format_info rcar_du_format_infos[] = { - { - .fourcc = DRM_FORMAT_RGB565, - .v4l2 = V4L2_PIX_FMT_RGB565, - .bpp = 16, - .planes = 1, - .hsub = 1, - .pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP, - .edf = PnDDCR4_EDF_NONE, - }, { - .fourcc = DRM_FORMAT_ARGB1555, - .v4l2 = V4L2_PIX_FMT_ARGB555, - .bpp = 16, - .planes = 1, - .hsub = 1, - .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB, - .edf = PnDDCR4_EDF_NONE, - }, { - .fourcc = DRM_FORMAT_XRGB1555, - .v4l2 = V4L2_PIX_FMT_XRGB555, - .bpp = 16, - .planes = 1, - .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB, - .edf = PnDDCR4_EDF_NONE, - }, { - .fourcc = DRM_FORMAT_XRGB8888, - .v4l2 = V4L2_PIX_FMT_XBGR32, - .bpp = 32, - .planes = 1, - .hsub = 1, - .pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP, - .edf = PnDDCR4_EDF_RGB888, - }, { - .fourcc = DRM_FORMAT_ARGB8888, - .v4l2 = V4L2_PIX_FMT_ABGR32, - .bpp = 32, - .planes = 1, - .hsub = 1, - .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_16BPP, - .edf = PnDDCR4_EDF_ARGB8888, - }, { - .fourcc = DRM_FORMAT_UYVY, - .v4l2 = V4L2_PIX_FMT_UYVY, - .bpp = 16, - .planes = 1, - .hsub = 2, - .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, - .edf = PnDDCR4_EDF_NONE, - }, { - .fourcc = DRM_FORMAT_YUYV, - .v4l2 = V4L2_PIX_FMT_YUYV, - .bpp = 16, - .planes = 1, - .hsub = 2, - .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, - .edf = PnDDCR4_EDF_NONE, - }, { - .fourcc = DRM_FORMAT_NV12, - .v4l2 = V4L2_PIX_FMT_NV12M, - .bpp = 12, - .planes = 2, - .hsub = 2, - .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, - .edf = PnDDCR4_EDF_NONE, - }, { - .fourcc = DRM_FORMAT_NV21, - .v4l2 = V4L2_PIX_FMT_NV21M, - .bpp = 12, - .planes = 2, - .hsub = 2, - .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, - .edf = PnDDCR4_EDF_NONE, - }, { - .fourcc = DRM_FORMAT_NV16, - .v4l2 = V4L2_PIX_FMT_NV16M, - .bpp = 16, - .planes = 2, - .hsub = 2, - .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, - .edf = PnDDCR4_EDF_NONE, - }, - /* - * The following formats are not supported on Gen2 and thus have no - * associated .pnmr or .edf settings. - */ - { - .fourcc = DRM_FORMAT_RGB332, - .v4l2 = V4L2_PIX_FMT_RGB332, - .bpp = 8, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_ARGB4444, - .v4l2 = V4L2_PIX_FMT_ARGB444, - .bpp = 16, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_XRGB4444, - .v4l2 = V4L2_PIX_FMT_XRGB444, - .bpp = 16, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_RGBA4444, - .v4l2 = V4L2_PIX_FMT_RGBA444, - .bpp = 16, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_RGBX4444, - .v4l2 = V4L2_PIX_FMT_RGBX444, - .bpp = 16, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_ABGR4444, - .v4l2 = V4L2_PIX_FMT_ABGR444, - .bpp = 16, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_XBGR4444, - .v4l2 = V4L2_PIX_FMT_XBGR444, - .bpp = 16, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_BGRA4444, - .v4l2 = V4L2_PIX_FMT_BGRA444, - .bpp = 16, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_BGRX4444, - .v4l2 = V4L2_PIX_FMT_BGRX444, - .bpp = 16, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_RGBA5551, - .v4l2 = V4L2_PIX_FMT_RGBA555, - .bpp = 16, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_RGBX5551, - .v4l2 = V4L2_PIX_FMT_RGBX555, - .bpp = 16, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_ABGR1555, - .v4l2 = V4L2_PIX_FMT_ABGR555, - .bpp = 16, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_XBGR1555, - .v4l2 = V4L2_PIX_FMT_XBGR555, - .bpp = 16, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_BGRA5551, - .v4l2 = V4L2_PIX_FMT_BGRA555, - .bpp = 16, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_BGRX5551, - .v4l2 = V4L2_PIX_FMT_BGRX555, - .bpp = 16, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_BGR888, - .v4l2 = V4L2_PIX_FMT_RGB24, - .bpp = 24, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_RGB888, - .v4l2 = V4L2_PIX_FMT_BGR24, - .bpp = 24, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_RGBA8888, - .v4l2 = V4L2_PIX_FMT_BGRA32, - .bpp = 32, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_RGBX8888, - .v4l2 = V4L2_PIX_FMT_BGRX32, - .bpp = 32, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_ABGR8888, - .v4l2 = V4L2_PIX_FMT_RGBA32, - .bpp = 32, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_XBGR8888, - .v4l2 = V4L2_PIX_FMT_RGBX32, - .bpp = 32, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_BGRA8888, - .v4l2 = V4L2_PIX_FMT_ARGB32, - .bpp = 32, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_BGRX8888, - .v4l2 = V4L2_PIX_FMT_XRGB32, - .bpp = 32, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_RGBX1010102, - .v4l2 = V4L2_PIX_FMT_RGBX1010102, - .bpp = 32, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_RGBA1010102, - .v4l2 = V4L2_PIX_FMT_RGBA1010102, - .bpp = 32, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_ARGB2101010, - .v4l2 = V4L2_PIX_FMT_ARGB2101010, - .bpp = 32, - .planes = 1, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_YVYU, - .v4l2 = V4L2_PIX_FMT_YVYU, - .bpp = 16, - .planes = 1, - .hsub = 2, - }, { - .fourcc = DRM_FORMAT_NV61, - .v4l2 = V4L2_PIX_FMT_NV61M, - .bpp = 16, - .planes = 2, - .hsub = 2, - }, { - .fourcc = DRM_FORMAT_YUV420, - .v4l2 = V4L2_PIX_FMT_YUV420M, - .bpp = 12, - .planes = 3, - .hsub = 2, - }, { - .fourcc = DRM_FORMAT_YVU420, - .v4l2 = V4L2_PIX_FMT_YVU420M, - .bpp = 12, - .planes = 3, - .hsub = 2, - }, { - .fourcc = DRM_FORMAT_YUV422, - .v4l2 = V4L2_PIX_FMT_YUV422M, - .bpp = 16, - .planes = 3, - .hsub = 2, - }, { - .fourcc = DRM_FORMAT_YVU422, - .v4l2 = V4L2_PIX_FMT_YVU422M, - .bpp = 16, - .planes = 3, - .hsub = 2, - }, { - .fourcc = DRM_FORMAT_YUV444, - .v4l2 = V4L2_PIX_FMT_YUV444M, - .bpp = 24, - .planes = 3, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_YVU444, - .v4l2 = V4L2_PIX_FMT_YVU444M, - .bpp = 24, - .planes = 3, - .hsub = 1, - }, { - .fourcc = DRM_FORMAT_Y210, - .v4l2 = V4L2_PIX_FMT_Y210, - .bpp = 32, - .planes = 1, - .hsub = 2, - }, { - .fourcc = DRM_FORMAT_Y212, - .v4l2 = V4L2_PIX_FMT_Y212, - .bpp = 32, - .planes = 1, - .hsub = 2, - }, -}; - -const struct rcar_du_format_info *rcar_du_format_info(u32 fourcc) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(rcar_du_format_infos); ++i) { - if (rcar_du_format_infos[i].fourcc == fourcc) - return &rcar_du_format_infos[i]; - } - - return NULL; -} - -/* ----------------------------------------------------------------------------- - * Frame buffer - */ - -static const struct drm_gem_object_funcs rcar_du_gem_funcs = { - .free = drm_gem_dma_object_free, - .print_info = drm_gem_dma_object_print_info, - .get_sg_table = drm_gem_dma_object_get_sg_table, - .vmap = drm_gem_dma_object_vmap, - .mmap = drm_gem_dma_object_mmap, - .vm_ops = &drm_gem_dma_vm_ops, -}; - -struct drm_gem_object *rcar_du_gem_prime_import_sg_table(struct drm_device *dev, - struct dma_buf_attachment *attach, - struct sg_table *sgt) -{ - struct rcar_du_device *rcdu = to_rcar_du_device(dev); - struct drm_gem_dma_object *dma_obj; - struct drm_gem_object *gem_obj; - int ret; - - if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) - return drm_gem_dma_prime_import_sg_table(dev, attach, sgt); - - /* Create a DMA GEM buffer. */ - dma_obj = kzalloc(sizeof(*dma_obj), GFP_KERNEL); - if (!dma_obj) - return ERR_PTR(-ENOMEM); - - gem_obj = &dma_obj->base; - gem_obj->funcs = &rcar_du_gem_funcs; - - drm_gem_private_object_init(dev, gem_obj, attach->dmabuf->size); - dma_obj->map_noncoherent = false; - - ret = drm_gem_create_mmap_offset(gem_obj); - if (ret) { - drm_gem_object_release(gem_obj); - kfree(dma_obj); - return ERR_PTR(ret); - } - - dma_obj->dma_addr = 0; - dma_obj->sgt = sgt; - - return gem_obj; -} - -int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev, - struct drm_mode_create_dumb *args) -{ - struct rcar_du_device *rcdu = to_rcar_du_device(dev); - unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); - unsigned int align; - - /* - * The R8A7779 DU requires a 16 pixels pitch alignment as documented, - * but the R8A7790 DU seems to require a 128 bytes pitch alignment. - */ - if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B)) - align = 128; - else - align = 16 * args->bpp / 8; - - args->pitch = roundup(min_pitch, align); - - return drm_gem_dma_dumb_create_internal(file, dev, args); -} - -static struct drm_framebuffer * -rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv, - const struct drm_mode_fb_cmd2 *mode_cmd) -{ - struct rcar_du_device *rcdu = to_rcar_du_device(dev); - const struct rcar_du_format_info *format; - unsigned int chroma_pitch; - unsigned int max_pitch; - unsigned int align; - unsigned int i; - - format = rcar_du_format_info(mode_cmd->pixel_format); - if (format == NULL) { - dev_dbg(dev->dev, "unsupported pixel format %p4cc\n", - &mode_cmd->pixel_format); - return ERR_PTR(-EINVAL); - } - - if (rcdu->info->gen < 3) { - /* - * On Gen2 the DU limits the pitch to 4095 pixels and requires - * buffers to be aligned to a 16 pixels boundary (or 128 bytes - * on some platforms). - */ - unsigned int bpp = format->planes == 1 ? format->bpp / 8 : 1; - - max_pitch = 4095 * bpp; - - if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B)) - align = 128; - else - align = 16 * bpp; - } else { - /* - * On Gen3 the memory interface is handled by the VSP that - * limits the pitch to 65535 bytes and has no alignment - * constraint. - */ - max_pitch = 65535; - align = 1; - } - - if (mode_cmd->pitches[0] & (align - 1) || - mode_cmd->pitches[0] > max_pitch) { - dev_dbg(dev->dev, "invalid pitch value %u\n", - mode_cmd->pitches[0]); - return ERR_PTR(-EINVAL); - } - - /* - * Calculate the chroma plane(s) pitch using the horizontal subsampling - * factor. For semi-planar formats, the U and V planes are combined, the - * pitch must thus be doubled. - */ - chroma_pitch = mode_cmd->pitches[0] / format->hsub; - if (format->planes == 2) - chroma_pitch *= 2; - - for (i = 1; i < format->planes; ++i) { - if (mode_cmd->pitches[i] != chroma_pitch) { - dev_dbg(dev->dev, - "luma and chroma pitches are not compatible\n"); - return ERR_PTR(-EINVAL); - } - } - - return drm_gem_fb_create(dev, file_priv, mode_cmd); -} - -/* ----------------------------------------------------------------------------- - * Atomic Check and Update - */ - -static int rcar_du_atomic_check(struct drm_device *dev, - struct drm_atomic_state *state) -{ - struct rcar_du_device *rcdu = to_rcar_du_device(dev); - int ret; - - ret = drm_atomic_helper_check(dev, state); - if (ret) - return ret; - - if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) - return 0; - - return rcar_du_atomic_check_planes(dev, state); -} - -static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state) -{ - struct drm_device *dev = old_state->dev; - struct rcar_du_device *rcdu = to_rcar_du_device(dev); - struct drm_crtc_state *crtc_state; - struct drm_crtc *crtc; - unsigned int i; - - /* - * Store RGB routing to DPAD0 and DPAD1, the hardware will be configured - * when starting the CRTCs. - */ - rcdu->dpad1_source = -1; - - for_each_new_crtc_in_state(old_state, crtc, crtc_state, i) { - struct rcar_du_crtc_state *rcrtc_state = - to_rcar_crtc_state(crtc_state); - struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); - - if (rcrtc_state->outputs & BIT(RCAR_DU_OUTPUT_DPAD0)) - rcdu->dpad0_source = rcrtc->index; - - if (rcrtc_state->outputs & BIT(RCAR_DU_OUTPUT_DPAD1)) - rcdu->dpad1_source = rcrtc->index; - } - - /* Apply the atomic update. */ - drm_atomic_helper_commit_modeset_disables(dev, old_state); - drm_atomic_helper_commit_planes(dev, old_state, - DRM_PLANE_COMMIT_ACTIVE_ONLY); - drm_atomic_helper_commit_modeset_enables(dev, old_state); - - drm_atomic_helper_commit_hw_done(old_state); - drm_atomic_helper_wait_for_flip_done(dev, old_state); - - drm_atomic_helper_cleanup_planes(dev, old_state); -} - -/* ----------------------------------------------------------------------------- - * Initialization - */ - -static const struct drm_mode_config_helper_funcs rcar_du_mode_config_helper = { - .atomic_commit_tail = rcar_du_atomic_commit_tail, -}; - -static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = { - .fb_create = rcar_du_fb_create, - .atomic_check = rcar_du_atomic_check, - .atomic_commit = drm_atomic_helper_commit, -}; - -static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu, - enum rcar_du_output output, - struct of_endpoint *ep) -{ - struct device_node *entity; - int ret; - - /* Locate the connected entity and initialize the encoder. */ - entity = of_graph_get_remote_port_parent(ep->local_node); - if (!entity) { - dev_dbg(rcdu->dev, "unconnected endpoint %pOF, skipping\n", - ep->local_node); - return -ENODEV; - } - - if (!of_device_is_available(entity)) { - dev_dbg(rcdu->dev, - "connected entity %pOF is disabled, skipping\n", - entity); - of_node_put(entity); - return -ENODEV; - } - - ret = rcar_du_encoder_init(rcdu, output, entity); - if (ret && ret != -EPROBE_DEFER && ret != -ENOLINK) - dev_warn(rcdu->dev, - "failed to initialize encoder %pOF on output %s (%d), skipping\n", - entity, rcar_du_output_name(output), ret); - - of_node_put(entity); - - return ret; -} - -static int rcar_du_encoders_init(struct rcar_du_device *rcdu) -{ - struct device_node *np = rcdu->dev->of_node; - struct device_node *ep_node; - unsigned int num_encoders = 0; - - /* - * Iterate over the endpoints and create one encoder for each output - * pipeline. - */ - for_each_endpoint_of_node(np, ep_node) { - enum rcar_du_output output; - struct of_endpoint ep; - unsigned int i; - int ret; - - ret = of_graph_parse_endpoint(ep_node, &ep); - if (ret < 0) { - of_node_put(ep_node); - return ret; - } - - /* Find the output route corresponding to the port number. */ - for (i = 0; i < RCAR_DU_OUTPUT_MAX; ++i) { - if (rcdu->info->routes[i].possible_crtcs && - rcdu->info->routes[i].port == ep.port) { - output = i; - break; - } - } - - if (i == RCAR_DU_OUTPUT_MAX) { - dev_warn(rcdu->dev, - "port %u references unexisting output, skipping\n", - ep.port); - continue; - } - - /* Process the output pipeline. */ - ret = rcar_du_encoders_init_one(rcdu, output, &ep); - if (ret < 0) { - if (ret == -EPROBE_DEFER) { - of_node_put(ep_node); - return ret; - } - - continue; - } - - num_encoders++; - } - - return num_encoders; -} - -static int rcar_du_properties_init(struct rcar_du_device *rcdu) -{ - /* - * The color key is expressed as an RGB888 triplet stored in a 32-bit - * integer in XRGB8888 format. Bit 24 is used as a flag to disable (0) - * or enable source color keying (1). - */ - rcdu->props.colorkey = - drm_property_create_range(&rcdu->ddev, 0, "colorkey", - 0, 0x01ffffff); - if (rcdu->props.colorkey == NULL) - return -ENOMEM; - - return 0; -} - -static int rcar_du_vsps_init(struct rcar_du_device *rcdu) -{ - const struct device_node *np = rcdu->dev->of_node; - const char *vsps_prop_name = "renesas,vsps"; - struct of_phandle_args args; - struct { - struct device_node *np; - unsigned int crtcs_mask; - } vsps[RCAR_DU_MAX_VSPS] = { { NULL, }, }; - unsigned int vsps_count = 0; - unsigned int cells; - unsigned int i; - int ret; - - /* - * First parse the DT vsps property to populate the list of VSPs. Each - * entry contains a pointer to the VSP DT node and a bitmask of the - * connected DU CRTCs. - */ - ret = of_property_count_u32_elems(np, vsps_prop_name); - if (ret < 0) { - /* Backward compatibility with old DTBs. */ - vsps_prop_name = "vsps"; - ret = of_property_count_u32_elems(np, vsps_prop_name); - } - cells = ret / rcdu->num_crtcs - 1; - if (cells > 1) - return -EINVAL; - - for (i = 0; i < rcdu->num_crtcs; ++i) { - unsigned int j; - - ret = of_parse_phandle_with_fixed_args(np, vsps_prop_name, - cells, i, &args); - if (ret < 0) - goto error; - - /* - * Add the VSP to the list or update the corresponding existing - * entry if the VSP has already been added. - */ - for (j = 0; j < vsps_count; ++j) { - if (vsps[j].np == args.np) - break; - } - - if (j < vsps_count) - of_node_put(args.np); - else - vsps[vsps_count++].np = args.np; - - vsps[j].crtcs_mask |= BIT(i); - - /* - * Store the VSP pointer and pipe index in the CRTC. If the - * second cell of the 'renesas,vsps' specifier isn't present, - * default to 0 to remain compatible with older DT bindings. - */ - rcdu->crtcs[i].vsp = &rcdu->vsps[j]; - rcdu->crtcs[i].vsp_pipe = cells >= 1 ? args.args[0] : 0; - } - - /* - * Then initialize all the VSPs from the node pointers and CRTCs bitmask - * computed previously. - */ - for (i = 0; i < vsps_count; ++i) { - struct rcar_du_vsp *vsp = &rcdu->vsps[i]; - - vsp->index = i; - vsp->dev = rcdu; - - ret = rcar_du_vsp_init(vsp, vsps[i].np, vsps[i].crtcs_mask); - if (ret < 0) - goto error; - } - - return 0; - -error: - for (i = 0; i < ARRAY_SIZE(vsps); ++i) - of_node_put(vsps[i].np); - - return ret; -} - -static int rcar_du_cmm_init(struct rcar_du_device *rcdu) -{ - const struct device_node *np = rcdu->dev->of_node; - unsigned int i; - int cells; - - cells = of_property_count_u32_elems(np, "renesas,cmms"); - if (cells == -EINVAL) - return 0; - - if (cells > rcdu->num_crtcs) { - dev_err(rcdu->dev, - "Invalid number of entries in 'renesas,cmms'\n"); - return -EINVAL; - } - - for (i = 0; i < cells; ++i) { - struct platform_device *pdev; - struct device_link *link; - struct device_node *cmm; - int ret; - - cmm = of_parse_phandle(np, "renesas,cmms", i); - if (!cmm) { - dev_err(rcdu->dev, - "Failed to parse 'renesas,cmms' property\n"); - return -EINVAL; - } - - if (!of_device_is_available(cmm)) { - /* It's fine to have a phandle to a non-enabled CMM. */ - of_node_put(cmm); - continue; - } - - pdev = of_find_device_by_node(cmm); - if (!pdev) { - dev_err(rcdu->dev, "No device found for CMM%u\n", i); - of_node_put(cmm); - return -EINVAL; - } - - of_node_put(cmm); - - /* - * -ENODEV is used to report that the CMM config option is - * disabled: return 0 and let the DU continue probing. - */ - ret = rcar_cmm_init(pdev); - if (ret) { - platform_device_put(pdev); - return ret == -ENODEV ? 0 : ret; - } - - rcdu->cmms[i] = pdev; - - /* - * Enforce suspend/resume ordering by making the CMM a provider - * of the DU: CMM is suspended after and resumed before the DU. - */ - link = device_link_add(rcdu->dev, &pdev->dev, DL_FLAG_STATELESS); - if (!link) { - dev_err(rcdu->dev, - "Failed to create device link to CMM%u\n", i); - return -EINVAL; - } - } - - return 0; -} - -static void rcar_du_modeset_cleanup(struct drm_device *dev, void *res) -{ - struct rcar_du_device *rcdu = to_rcar_du_device(dev); - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(rcdu->cmms); ++i) - platform_device_put(rcdu->cmms[i]); -} - -int rcar_du_modeset_init(struct rcar_du_device *rcdu) -{ - static const unsigned int mmio_offsets[] = { - DU0_REG_OFFSET, DU2_REG_OFFSET - }; - - struct drm_device *dev = &rcdu->ddev; - struct drm_encoder *encoder; - unsigned int dpad0_sources; - unsigned int num_encoders; - unsigned int num_groups; - unsigned int swindex; - unsigned int hwindex; - unsigned int i; - int ret; - - ret = drmm_mode_config_init(dev); - if (ret) - return ret; - - ret = drmm_add_action(&rcdu->ddev, rcar_du_modeset_cleanup, NULL); - if (ret) - return ret; - - dev->mode_config.min_width = 0; - dev->mode_config.min_height = 0; - dev->mode_config.normalize_zpos = true; - dev->mode_config.funcs = &rcar_du_mode_config_funcs; - dev->mode_config.helper_private = &rcar_du_mode_config_helper; - - if (rcdu->info->gen < 3) { - dev->mode_config.max_width = 4095; - dev->mode_config.max_height = 2047; - } else { - /* - * The Gen3 DU uses the VSP1 for memory access, and is limited - * to frame sizes of 8190x8190. - */ - dev->mode_config.max_width = 8190; - dev->mode_config.max_height = 8190; - } - - rcdu->num_crtcs = hweight8(rcdu->info->channels_mask); - - ret = rcar_du_properties_init(rcdu); - if (ret < 0) - return ret; - - /* - * Initialize vertical blanking interrupts handling. Start with vblank - * disabled for all CRTCs. - */ - ret = drm_vblank_init(dev, rcdu->num_crtcs); - if (ret < 0) - return ret; - - /* Initialize the groups. */ - num_groups = DIV_ROUND_UP(rcdu->num_crtcs, 2); - - for (i = 0; i < num_groups; ++i) { - struct rcar_du_group *rgrp = &rcdu->groups[i]; - - mutex_init(&rgrp->lock); - - rgrp->dev = rcdu; - rgrp->mmio_offset = mmio_offsets[i]; - rgrp->index = i; - /* Extract the channel mask for this group only. */ - rgrp->channels_mask = (rcdu->info->channels_mask >> (2 * i)) - & GENMASK(1, 0); - rgrp->num_crtcs = hweight8(rgrp->channels_mask); - - /* - * If we have more than one CRTCs in this group pre-associate - * the low-order planes with CRTC 0 and the high-order planes - * with CRTC 1 to minimize flicker occurring when the - * association is changed. - */ - rgrp->dptsr_planes = rgrp->num_crtcs > 1 - ? (rcdu->info->gen >= 3 ? 0x04 : 0xf0) - : 0; - - if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) { - ret = rcar_du_planes_init(rgrp); - if (ret < 0) - return ret; - } - } - - /* Initialize the compositors. */ - if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) { - ret = rcar_du_vsps_init(rcdu); - if (ret < 0) - return ret; - } - - /* Initialize the Color Management Modules. */ - ret = rcar_du_cmm_init(rcdu); - if (ret) - return ret; - - /* Create the CRTCs. */ - for (swindex = 0, hwindex = 0; swindex < rcdu->num_crtcs; ++hwindex) { - struct rcar_du_group *rgrp; - - /* Skip unpopulated DU channels. */ - if (!(rcdu->info->channels_mask & BIT(hwindex))) - continue; - - rgrp = &rcdu->groups[hwindex / 2]; - - ret = rcar_du_crtc_create(rgrp, swindex++, hwindex); - if (ret < 0) - return ret; - } - - /* Initialize the encoders. */ - ret = rcar_du_encoders_init(rcdu); - if (ret < 0) - return ret; - - if (ret == 0) { - dev_err(rcdu->dev, "error: no encoder could be initialized\n"); - return -EINVAL; - } - - num_encoders = ret; - - /* - * Set the possible CRTCs and possible clones. There's always at least - * one way for all encoders to clone each other, set all bits in the - * possible clones field. - */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - struct rcar_du_encoder *renc = to_rcar_encoder(encoder); - const struct rcar_du_output_routing *route = - &rcdu->info->routes[renc->output]; - - encoder->possible_crtcs = route->possible_crtcs; - encoder->possible_clones = (1 << num_encoders) - 1; - } - - /* Create the writeback connectors. */ - if (rcdu->info->gen >= 3) { - for (i = 0; i < rcdu->num_crtcs; ++i) { - struct rcar_du_crtc *rcrtc = &rcdu->crtcs[i]; - - ret = rcar_du_writeback_init(rcdu, rcrtc); - if (ret < 0) - return ret; - } - } - - /* - * Initialize the default DPAD0 source to the index of the first DU - * channel that can be connected to DPAD0. The exact value doesn't - * matter as it should be overwritten by mode setting for the RGB - * output, but it is nonetheless required to ensure a valid initial - * hardware configuration on Gen3 where DU0 can't always be connected to - * DPAD0. - */ - dpad0_sources = rcdu->info->routes[RCAR_DU_OUTPUT_DPAD0].possible_crtcs; - rcdu->dpad0_source = ffs(dpad0_sources) - 1; - - drm_mode_config_reset(dev); - - drm_kms_helper_poll_init(dev); - - return 0; -} diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.h b/drivers/gpu/drm/rcar-du/rcar_du_kms.h deleted file mode 100644 index f31afeeee05a..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * R-Car Display Unit Mode Setting - * - * Copyright (C) 2013-2014 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#ifndef __RCAR_DU_KMS_H__ -#define __RCAR_DU_KMS_H__ - -#include <linux/types.h> - -struct dma_buf_attachment; -struct drm_file; -struct drm_device; -struct drm_gem_object; -struct drm_mode_create_dumb; -struct rcar_du_device; -struct sg_table; - -struct rcar_du_format_info { - u32 fourcc; - u32 v4l2; - unsigned int bpp; - unsigned int planes; - unsigned int hsub; - unsigned int pnmr; - unsigned int edf; -}; - -const struct rcar_du_format_info *rcar_du_format_info(u32 fourcc); - -int rcar_du_modeset_init(struct rcar_du_device *rcdu); - -int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev, - struct drm_mode_create_dumb *args); - -struct drm_gem_object *rcar_du_gem_prime_import_sg_table(struct drm_device *dev, - struct dma_buf_attachment *attach, - struct sg_table *sgt); - -#endif /* __RCAR_DU_KMS_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c deleted file mode 100644 index d759e0192181..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ /dev/null @@ -1,831 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * R-Car Display Unit Planes - * - * Copyright (C) 2013-2015 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#include <drm/drm_atomic.h> -#include <drm/drm_atomic_helper.h> -#include <drm/drm_blend.h> -#include <drm/drm_crtc.h> -#include <drm/drm_device.h> -#include <drm/drm_fb_dma_helper.h> -#include <drm/drm_fourcc.h> -#include <drm/drm_framebuffer.h> -#include <drm/drm_gem_dma_helper.h> - -#include "rcar_du_drv.h" -#include "rcar_du_group.h" -#include "rcar_du_kms.h" -#include "rcar_du_plane.h" -#include "rcar_du_regs.h" - -/* ----------------------------------------------------------------------------- - * Atomic hardware plane allocator - * - * The hardware plane allocator is solely based on the atomic plane states - * without keeping any external state to avoid races between .atomic_check() - * and .atomic_commit(). - * - * The core idea is to avoid using a free planes bitmask that would need to be - * shared between check and commit handlers with a collective knowledge based on - * the allocated hardware plane(s) for each KMS plane. The allocator then loops - * over all plane states to compute the free planes bitmask, allocates hardware - * planes based on that bitmask, and stores the result back in the plane states. - * - * For this to work we need to access the current state of planes not touched by - * the atomic update. To ensure that it won't be modified, we need to lock all - * planes using drm_atomic_get_plane_state(). This effectively serializes atomic - * updates from .atomic_check() up to completion (when swapping the states if - * the check step has succeeded) or rollback (when freeing the states if the - * check step has failed). - * - * Allocation is performed in the .atomic_check() handler and applied - * automatically when the core swaps the old and new states. - */ - -static bool rcar_du_plane_needs_realloc( - const struct rcar_du_plane_state *old_state, - const struct rcar_du_plane_state *new_state) -{ - /* - * Lowering the number of planes doesn't strictly require reallocation - * as the extra hardware plane will be freed when committing, but doing - * so could lead to more fragmentation. - */ - if (!old_state->format || - old_state->format->planes != new_state->format->planes) - return true; - - /* Reallocate hardware planes if the source has changed. */ - if (old_state->source != new_state->source) - return true; - - return false; -} - -static unsigned int rcar_du_plane_hwmask(struct rcar_du_plane_state *state) -{ - unsigned int mask; - - if (state->hwindex == -1) - return 0; - - mask = 1 << state->hwindex; - if (state->format->planes == 2) - mask |= 1 << ((state->hwindex + 1) % 8); - - return mask; -} - -/* - * The R8A7790 DU can source frames directly from the VSP1 devices VSPD0 and - * VSPD1. VSPD0 feeds DU0/1 plane 0, and VSPD1 feeds either DU2 plane 0 or - * DU0/1 plane 1. - * - * Allocate the correct fixed plane when sourcing frames from VSPD0 or VSPD1, - * and allocate planes in reverse index order otherwise to ensure maximum - * availability of planes 0 and 1. - * - * The caller is responsible for ensuring that the requested source is - * compatible with the DU revision. - */ -static int rcar_du_plane_hwalloc(struct rcar_du_plane *plane, - struct rcar_du_plane_state *state, - unsigned int free) -{ - unsigned int num_planes = state->format->planes; - int fixed = -1; - int i; - - if (state->source == RCAR_DU_PLANE_VSPD0) { - /* VSPD0 feeds plane 0 on DU0/1. */ - if (plane->group->index != 0) - return -EINVAL; - - fixed = 0; - } else if (state->source == RCAR_DU_PLANE_VSPD1) { - /* VSPD1 feeds plane 1 on DU0/1 or plane 0 on DU2. */ - fixed = plane->group->index == 0 ? 1 : 0; - } - - if (fixed >= 0) - return free & (1 << fixed) ? fixed : -EBUSY; - - for (i = RCAR_DU_NUM_HW_PLANES - 1; i >= 0; --i) { - if (!(free & (1 << i))) - continue; - - if (num_planes == 1 || free & (1 << ((i + 1) % 8))) - break; - } - - return i < 0 ? -EBUSY : i; -} - -int rcar_du_atomic_check_planes(struct drm_device *dev, - struct drm_atomic_state *state) -{ - struct rcar_du_device *rcdu = to_rcar_du_device(dev); - unsigned int group_freed_planes[RCAR_DU_MAX_GROUPS] = { 0, }; - unsigned int group_free_planes[RCAR_DU_MAX_GROUPS] = { 0, }; - bool needs_realloc = false; - unsigned int groups = 0; - unsigned int i; - struct drm_plane *drm_plane; - struct drm_plane_state *old_drm_plane_state; - struct drm_plane_state *new_drm_plane_state; - - /* Check if hardware planes need to be reallocated. */ - for_each_oldnew_plane_in_state(state, drm_plane, old_drm_plane_state, - new_drm_plane_state, i) { - struct rcar_du_plane_state *old_plane_state; - struct rcar_du_plane_state *new_plane_state; - struct rcar_du_plane *plane; - unsigned int index; - - plane = to_rcar_plane(drm_plane); - old_plane_state = to_rcar_plane_state(old_drm_plane_state); - new_plane_state = to_rcar_plane_state(new_drm_plane_state); - - dev_dbg(rcdu->dev, "%s: checking plane (%u,%tu)\n", __func__, - plane->group->index, plane - plane->group->planes); - - /* - * If the plane is being disabled we don't need to go through - * the full reallocation procedure. Just mark the hardware - * plane(s) as freed. - */ - if (!new_plane_state->format) { - dev_dbg(rcdu->dev, "%s: plane is being disabled\n", - __func__); - index = plane - plane->group->planes; - group_freed_planes[plane->group->index] |= 1 << index; - new_plane_state->hwindex = -1; - continue; - } - - /* - * If the plane needs to be reallocated mark it as such, and - * mark the hardware plane(s) as free. - */ - if (rcar_du_plane_needs_realloc(old_plane_state, new_plane_state)) { - dev_dbg(rcdu->dev, "%s: plane needs reallocation\n", - __func__); - groups |= 1 << plane->group->index; - needs_realloc = true; - - index = plane - plane->group->planes; - group_freed_planes[plane->group->index] |= 1 << index; - new_plane_state->hwindex = -1; - } - } - - if (!needs_realloc) - return 0; - - /* - * Grab all plane states for the groups that need reallocation to ensure - * locking and avoid racy updates. This serializes the update operation, - * but there's not much we can do about it as that's the hardware - * design. - * - * Compute the used planes mask for each group at the same time to avoid - * looping over the planes separately later. - */ - while (groups) { - unsigned int index = ffs(groups) - 1; - struct rcar_du_group *group = &rcdu->groups[index]; - unsigned int used_planes = 0; - - dev_dbg(rcdu->dev, "%s: finding free planes for group %u\n", - __func__, index); - - for (i = 0; i < group->num_planes; ++i) { - struct rcar_du_plane *plane = &group->planes[i]; - struct rcar_du_plane_state *new_plane_state; - struct drm_plane_state *s; - - s = drm_atomic_get_plane_state(state, &plane->plane); - if (IS_ERR(s)) - return PTR_ERR(s); - - /* - * If the plane has been freed in the above loop its - * hardware planes must not be added to the used planes - * bitmask. However, the current state doesn't reflect - * the free state yet, as we've modified the new state - * above. Use the local freed planes list to check for - * that condition instead. - */ - if (group_freed_planes[index] & (1 << i)) { - dev_dbg(rcdu->dev, - "%s: plane (%u,%tu) has been freed, skipping\n", - __func__, plane->group->index, - plane - plane->group->planes); - continue; - } - - new_plane_state = to_rcar_plane_state(s); - used_planes |= rcar_du_plane_hwmask(new_plane_state); - - dev_dbg(rcdu->dev, - "%s: plane (%u,%tu) uses %u hwplanes (index %d)\n", - __func__, plane->group->index, - plane - plane->group->planes, - new_plane_state->format ? - new_plane_state->format->planes : 0, - new_plane_state->hwindex); - } - - group_free_planes[index] = 0xff & ~used_planes; - groups &= ~(1 << index); - - dev_dbg(rcdu->dev, "%s: group %u free planes mask 0x%02x\n", - __func__, index, group_free_planes[index]); - } - - /* Reallocate hardware planes for each plane that needs it. */ - for_each_oldnew_plane_in_state(state, drm_plane, old_drm_plane_state, - new_drm_plane_state, i) { - struct rcar_du_plane_state *old_plane_state; - struct rcar_du_plane_state *new_plane_state; - struct rcar_du_plane *plane; - unsigned int crtc_planes; - unsigned int free; - int idx; - - plane = to_rcar_plane(drm_plane); - old_plane_state = to_rcar_plane_state(old_drm_plane_state); - new_plane_state = to_rcar_plane_state(new_drm_plane_state); - - dev_dbg(rcdu->dev, "%s: allocating plane (%u,%tu)\n", __func__, - plane->group->index, plane - plane->group->planes); - - /* - * Skip planes that are being disabled or don't need to be - * reallocated. - */ - if (!new_plane_state->format || - !rcar_du_plane_needs_realloc(old_plane_state, new_plane_state)) - continue; - - /* - * Try to allocate the plane from the free planes currently - * associated with the target CRTC to avoid restarting the CRTC - * group and thus minimize flicker. If it fails fall back to - * allocating from all free planes. - */ - crtc_planes = to_rcar_crtc(new_plane_state->state.crtc)->index % 2 - ? plane->group->dptsr_planes - : ~plane->group->dptsr_planes; - free = group_free_planes[plane->group->index]; - - idx = rcar_du_plane_hwalloc(plane, new_plane_state, - free & crtc_planes); - if (idx < 0) - idx = rcar_du_plane_hwalloc(plane, new_plane_state, - free); - if (idx < 0) { - dev_dbg(rcdu->dev, "%s: no available hardware plane\n", - __func__); - return idx; - } - - dev_dbg(rcdu->dev, "%s: allocated %u hwplanes (index %u)\n", - __func__, new_plane_state->format->planes, idx); - - new_plane_state->hwindex = idx; - - group_free_planes[plane->group->index] &= - ~rcar_du_plane_hwmask(new_plane_state); - - dev_dbg(rcdu->dev, "%s: group %u free planes mask 0x%02x\n", - __func__, plane->group->index, - group_free_planes[plane->group->index]); - } - - return 0; -} - -/* ----------------------------------------------------------------------------- - * Plane Setup - */ - -#define RCAR_DU_COLORKEY_NONE (0 << 24) -#define RCAR_DU_COLORKEY_SOURCE (1 << 24) -#define RCAR_DU_COLORKEY_MASK (1 << 24) - -static void rcar_du_plane_write(struct rcar_du_group *rgrp, - unsigned int index, u32 reg, u32 data) -{ - rcar_du_write(rgrp->dev, rgrp->mmio_offset + index * PLANE_OFF + reg, - data); -} - -static void rcar_du_plane_setup_scanout(struct rcar_du_group *rgrp, - const struct rcar_du_plane_state *state) -{ - unsigned int src_x = state->state.src.x1 >> 16; - unsigned int src_y = state->state.src.y1 >> 16; - unsigned int index = state->hwindex; - unsigned int pitch; - bool interlaced; - u32 dma[2]; - - interlaced = state->state.crtc->state->adjusted_mode.flags - & DRM_MODE_FLAG_INTERLACE; - - if (state->source == RCAR_DU_PLANE_MEMORY) { - struct drm_framebuffer *fb = state->state.fb; - struct drm_gem_dma_object *gem; - unsigned int i; - - if (state->format->planes == 2) - pitch = fb->pitches[0]; - else - pitch = fb->pitches[0] * 8 / state->format->bpp; - - for (i = 0; i < state->format->planes; ++i) { - gem = drm_fb_dma_get_gem_obj(fb, i); - dma[i] = gem->dma_addr + fb->offsets[i]; - } - } else { - pitch = drm_rect_width(&state->state.src) >> 16; - dma[0] = 0; - dma[1] = 0; - } - - /* - * Memory pitch (expressed in pixels). Must be doubled for interlaced - * operation with 32bpp formats. - */ - rcar_du_plane_write(rgrp, index, PnMWR, - (interlaced && state->format->bpp == 32) ? - pitch * 2 : pitch); - - /* - * The Y position is expressed in raster line units and must be doubled - * for 32bpp formats, according to the R8A7790 datasheet. No mention of - * doubling the Y position is found in the R8A7779 datasheet, but the - * rule seems to apply there as well. - * - * Despite not being documented, doubling seem not to be needed when - * operating in interlaced mode. - * - * Similarly, for the second plane, NV12 and NV21 formats seem to - * require a halved Y position value, in both progressive and interlaced - * modes. - */ - rcar_du_plane_write(rgrp, index, PnSPXR, src_x); - rcar_du_plane_write(rgrp, index, PnSPYR, src_y * - (!interlaced && state->format->bpp == 32 ? 2 : 1)); - - rcar_du_plane_write(rgrp, index, PnDSA0R, dma[0]); - - if (state->format->planes == 2) { - index = (index + 1) % 8; - - rcar_du_plane_write(rgrp, index, PnMWR, pitch); - - rcar_du_plane_write(rgrp, index, PnSPXR, src_x); - rcar_du_plane_write(rgrp, index, PnSPYR, src_y * - (state->format->bpp == 16 ? 2 : 1) / 2); - - rcar_du_plane_write(rgrp, index, PnDSA0R, dma[1]); - } -} - -static void rcar_du_plane_setup_mode(struct rcar_du_group *rgrp, - unsigned int index, - const struct rcar_du_plane_state *state) -{ - u32 colorkey; - u32 pnmr; - - /* - * The PnALPHAR register controls alpha-blending in 16bpp formats - * (ARGB1555 and XRGB1555). - * - * For ARGB, set the alpha value to 0, and enable alpha-blending when - * the A bit is 0. This maps A=0 to alpha=0 and A=1 to alpha=255. - * - * For XRGB, set the alpha value to the plane-wide alpha value and - * enable alpha-blending regardless of the X bit value. - */ - if (state->format->fourcc != DRM_FORMAT_XRGB1555) - rcar_du_plane_write(rgrp, index, PnALPHAR, PnALPHAR_ABIT_0); - else - rcar_du_plane_write(rgrp, index, PnALPHAR, - PnALPHAR_ABIT_X | state->state.alpha >> 8); - - pnmr = PnMR_BM_MD | state->format->pnmr; - - /* - * Disable color keying when requested. YUV formats have the - * PnMR_SPIM_TP_OFF bit set in their pnmr field, disabling color keying - * automatically. - */ - if ((state->colorkey & RCAR_DU_COLORKEY_MASK) == RCAR_DU_COLORKEY_NONE) - pnmr |= PnMR_SPIM_TP_OFF; - - /* For packed YUV formats we need to select the U/V order. */ - if (state->format->fourcc == DRM_FORMAT_YUYV) - pnmr |= PnMR_YCDF_YUYV; - - rcar_du_plane_write(rgrp, index, PnMR, pnmr); - - switch (state->format->fourcc) { - case DRM_FORMAT_RGB565: - colorkey = ((state->colorkey & 0xf80000) >> 8) - | ((state->colorkey & 0x00fc00) >> 5) - | ((state->colorkey & 0x0000f8) >> 3); - rcar_du_plane_write(rgrp, index, PnTC2R, colorkey); - break; - - case DRM_FORMAT_ARGB1555: - case DRM_FORMAT_XRGB1555: - colorkey = ((state->colorkey & 0xf80000) >> 9) - | ((state->colorkey & 0x00f800) >> 6) - | ((state->colorkey & 0x0000f8) >> 3); - rcar_du_plane_write(rgrp, index, PnTC2R, colorkey); - break; - - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_ARGB8888: - rcar_du_plane_write(rgrp, index, PnTC3R, - PnTC3R_CODE | (state->colorkey & 0xffffff)); - break; - } -} - -static void rcar_du_plane_setup_format_gen2(struct rcar_du_group *rgrp, - unsigned int index, - const struct rcar_du_plane_state *state) -{ - u32 ddcr2 = PnDDCR2_CODE; - u32 ddcr4; - - /* - * Data format - * - * The data format is selected by the DDDF field in PnMR and the EDF - * field in DDCR4. - */ - - rcar_du_plane_setup_mode(rgrp, index, state); - - if (state->format->planes == 2) { - if (state->hwindex != index) { - if (state->format->fourcc == DRM_FORMAT_NV12 || - state->format->fourcc == DRM_FORMAT_NV21) - ddcr2 |= PnDDCR2_Y420; - - if (state->format->fourcc == DRM_FORMAT_NV21) - ddcr2 |= PnDDCR2_NV21; - - ddcr2 |= PnDDCR2_DIVU; - } else { - ddcr2 |= PnDDCR2_DIVY; - } - } - - rcar_du_plane_write(rgrp, index, PnDDCR2, ddcr2); - - ddcr4 = state->format->edf | PnDDCR4_CODE; - if (state->source != RCAR_DU_PLANE_MEMORY) - ddcr4 |= PnDDCR4_VSPS; - - rcar_du_plane_write(rgrp, index, PnDDCR4, ddcr4); -} - -static void rcar_du_plane_setup_format_gen3(struct rcar_du_group *rgrp, - unsigned int index, - const struct rcar_du_plane_state *state) -{ - struct rcar_du_device *rcdu = rgrp->dev; - u32 pnmr = state->format->pnmr | PnMR_SPIM_TP_OFF; - - if (rcdu->info->features & RCAR_DU_FEATURE_NO_BLENDING) { - /* No blending. ALP and EOR are not supported. */ - pnmr &= ~(PnMR_SPIM_ALP | PnMR_SPIM_EOR); - } - - rcar_du_plane_write(rgrp, index, PnMR, pnmr); - - rcar_du_plane_write(rgrp, index, PnDDCR4, - state->format->edf | PnDDCR4_CODE); - - /* - * On Gen3, some DU channels have two planes, each being wired to a - * separate VSPD instance. The DU can then blend two planes. While - * this feature isn't used by the driver, issues related to alpha - * blending (such as incorrect colors or planes being invisible) may - * still occur if the PnALPHAR register has a stale value. Set the - * register to 0 to avoid this. - */ - - rcar_du_plane_write(rgrp, index, PnALPHAR, 0); -} - -static void rcar_du_plane_setup_format(struct rcar_du_group *rgrp, - unsigned int index, - const struct rcar_du_plane_state *state) -{ - struct rcar_du_device *rcdu = rgrp->dev; - const struct drm_rect *dst = &state->state.dst; - - if (rcdu->info->gen < 3) - rcar_du_plane_setup_format_gen2(rgrp, index, state); - else - rcar_du_plane_setup_format_gen3(rgrp, index, state); - - /* Destination position and size */ - rcar_du_plane_write(rgrp, index, PnDSXR, drm_rect_width(dst)); - rcar_du_plane_write(rgrp, index, PnDSYR, drm_rect_height(dst)); - rcar_du_plane_write(rgrp, index, PnDPXR, dst->x1); - rcar_du_plane_write(rgrp, index, PnDPYR, dst->y1); - - if (rcdu->info->gen < 3) { - /* Wrap-around and blinking, disabled */ - rcar_du_plane_write(rgrp, index, PnWASPR, 0); - rcar_du_plane_write(rgrp, index, PnWAMWR, 4095); - rcar_du_plane_write(rgrp, index, PnBTR, 0); - rcar_du_plane_write(rgrp, index, PnMLR, 0); - } -} - -void __rcar_du_plane_setup(struct rcar_du_group *rgrp, - const struct rcar_du_plane_state *state) -{ - struct rcar_du_device *rcdu = rgrp->dev; - - rcar_du_plane_setup_format(rgrp, state->hwindex, state); - if (state->format->planes == 2) - rcar_du_plane_setup_format(rgrp, (state->hwindex + 1) % 8, - state); - - if (rcdu->info->gen >= 3) - return; - - rcar_du_plane_setup_scanout(rgrp, state); - - if (state->source == RCAR_DU_PLANE_VSPD1) { - unsigned int vspd1_sink = rgrp->index ? 2 : 0; - - if (rcdu->vspd1_sink != vspd1_sink) { - rcdu->vspd1_sink = vspd1_sink; - rcar_du_set_dpad0_vsp1_routing(rcdu); - - /* - * Changes to the VSP1 sink take effect on DRES and thus - * need a restart of the group. - */ - rgrp->need_restart = true; - } - } -} - -int __rcar_du_plane_atomic_check(struct drm_plane *plane, - struct drm_plane_state *state, - const struct rcar_du_format_info **format) -{ - struct drm_device *dev = plane->dev; - struct drm_crtc_state *crtc_state; - int ret; - - if (!state->crtc) { - /* - * The visible field is not reset by the DRM core but only - * updated by drm_plane_helper_check_state(), set it manually. - */ - state->visible = false; - *format = NULL; - return 0; - } - - crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - - ret = drm_atomic_helper_check_plane_state(state, crtc_state, - DRM_PLANE_NO_SCALING, - DRM_PLANE_NO_SCALING, - true, true); - if (ret < 0) - return ret; - - if (!state->visible) { - *format = NULL; - return 0; - } - - *format = rcar_du_format_info(state->fb->format->format); - if (*format == NULL) { - dev_dbg(dev->dev, "%s: unsupported format %p4cc\n", __func__, - &state->fb->format->format); - return -EINVAL; - } - - return 0; -} - -static int rcar_du_plane_atomic_check(struct drm_plane *plane, - struct drm_atomic_state *state) -{ - struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, - plane); - struct rcar_du_plane_state *rstate = to_rcar_plane_state(new_plane_state); - - return __rcar_du_plane_atomic_check(plane, new_plane_state, - &rstate->format); -} - -static void rcar_du_plane_atomic_update(struct drm_plane *plane, - struct drm_atomic_state *state) -{ - struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); - struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); - struct rcar_du_plane *rplane = to_rcar_plane(plane); - struct rcar_du_plane_state *old_rstate; - struct rcar_du_plane_state *new_rstate; - - if (!new_state->visible) - return; - - rcar_du_plane_setup(rplane); - - /* - * Check whether the source has changed from memory to live source or - * from live source to memory. The source has been configured by the - * VSPS bit in the PnDDCR4 register. Although the datasheet states that - * the bit is updated during vertical blanking, it seems that updates - * only occur when the DU group is held in reset through the DSYSR.DRES - * bit. We thus need to restart the group if the source changes. - */ - old_rstate = to_rcar_plane_state(old_state); - new_rstate = to_rcar_plane_state(new_state); - - if ((old_rstate->source == RCAR_DU_PLANE_MEMORY) != - (new_rstate->source == RCAR_DU_PLANE_MEMORY)) - rplane->group->need_restart = true; -} - -static const struct drm_plane_helper_funcs rcar_du_plane_helper_funcs = { - .atomic_check = rcar_du_plane_atomic_check, - .atomic_update = rcar_du_plane_atomic_update, -}; - -static struct drm_plane_state * -rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane) -{ - struct rcar_du_plane_state *state; - struct rcar_du_plane_state *copy; - - if (WARN_ON(!plane->state)) - return NULL; - - state = to_rcar_plane_state(plane->state); - copy = kmemdup(state, sizeof(*state), GFP_KERNEL); - if (copy == NULL) - return NULL; - - __drm_atomic_helper_plane_duplicate_state(plane, ©->state); - - return ©->state; -} - -static void rcar_du_plane_atomic_destroy_state(struct drm_plane *plane, - struct drm_plane_state *state) -{ - __drm_atomic_helper_plane_destroy_state(state); - kfree(to_rcar_plane_state(state)); -} - -static void rcar_du_plane_reset(struct drm_plane *plane) -{ - struct rcar_du_plane_state *state; - - if (plane->state) { - rcar_du_plane_atomic_destroy_state(plane, plane->state); - plane->state = NULL; - } - - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (state == NULL) - return; - - __drm_atomic_helper_plane_reset(plane, &state->state); - - state->hwindex = -1; - state->source = RCAR_DU_PLANE_MEMORY; - state->colorkey = RCAR_DU_COLORKEY_NONE; -} - -static int rcar_du_plane_atomic_set_property(struct drm_plane *plane, - struct drm_plane_state *state, - struct drm_property *property, - uint64_t val) -{ - struct rcar_du_plane_state *rstate = to_rcar_plane_state(state); - struct rcar_du_device *rcdu = to_rcar_plane(plane)->group->dev; - - if (property == rcdu->props.colorkey) - rstate->colorkey = val; - else - return -EINVAL; - - return 0; -} - -static int rcar_du_plane_atomic_get_property(struct drm_plane *plane, - const struct drm_plane_state *state, struct drm_property *property, - uint64_t *val) -{ - const struct rcar_du_plane_state *rstate = - container_of(state, const struct rcar_du_plane_state, state); - struct rcar_du_device *rcdu = to_rcar_plane(plane)->group->dev; - - if (property == rcdu->props.colorkey) - *val = rstate->colorkey; - else - return -EINVAL; - - return 0; -} - -static const struct drm_plane_funcs rcar_du_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .reset = rcar_du_plane_reset, - .destroy = drm_plane_cleanup, - .atomic_duplicate_state = rcar_du_plane_atomic_duplicate_state, - .atomic_destroy_state = rcar_du_plane_atomic_destroy_state, - .atomic_set_property = rcar_du_plane_atomic_set_property, - .atomic_get_property = rcar_du_plane_atomic_get_property, -}; - -static const uint32_t formats[] = { - DRM_FORMAT_RGB565, - DRM_FORMAT_ARGB1555, - DRM_FORMAT_XRGB1555, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_UYVY, - DRM_FORMAT_YUYV, - DRM_FORMAT_NV12, - DRM_FORMAT_NV21, - DRM_FORMAT_NV16, -}; - -int rcar_du_planes_init(struct rcar_du_group *rgrp) -{ - struct rcar_du_device *rcdu = rgrp->dev; - unsigned int crtcs; - unsigned int i; - int ret; - - /* - * Create one primary plane per CRTC in this group and seven overlay - * planes. - */ - rgrp->num_planes = rgrp->num_crtcs + 7; - - crtcs = ((1 << rcdu->num_crtcs) - 1) & (3 << (2 * rgrp->index)); - - for (i = 0; i < rgrp->num_planes; ++i) { - enum drm_plane_type type = i < rgrp->num_crtcs - ? DRM_PLANE_TYPE_PRIMARY - : DRM_PLANE_TYPE_OVERLAY; - struct rcar_du_plane *plane = &rgrp->planes[i]; - - plane->group = rgrp; - - ret = drm_universal_plane_init(&rcdu->ddev, &plane->plane, - crtcs, &rcar_du_plane_funcs, - formats, ARRAY_SIZE(formats), - NULL, type, NULL); - if (ret < 0) - return ret; - - drm_plane_helper_add(&plane->plane, - &rcar_du_plane_helper_funcs); - - drm_plane_create_alpha_property(&plane->plane); - - if (type == DRM_PLANE_TYPE_PRIMARY) { - drm_plane_create_zpos_immutable_property(&plane->plane, - 0); - } else { - drm_object_attach_property(&plane->plane.base, - rcdu->props.colorkey, - RCAR_DU_COLORKEY_NONE); - drm_plane_create_zpos_property(&plane->plane, 1, 1, 7); - } - } - - return 0; -} diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.h b/drivers/gpu/drm/rcar-du/rcar_du_plane.h deleted file mode 100644 index f9893d7d6dfc..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.h +++ /dev/null @@ -1,86 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * R-Car Display Unit Planes - * - * Copyright (C) 2013-2014 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#ifndef __RCAR_DU_PLANE_H__ -#define __RCAR_DU_PLANE_H__ - -#include <drm/drm_plane.h> - -struct rcar_du_format_info; -struct rcar_du_group; - -/* - * The RCAR DU has 8 hardware planes, shared between primary and overlay planes. - * As using overlay planes requires at least one of the CRTCs being enabled, no - * more than 7 overlay planes can be available. We thus create 1 primary plane - * per CRTC and 7 overlay planes, for a total of up to 9 KMS planes. - */ -#define RCAR_DU_NUM_KMS_PLANES 9 -#define RCAR_DU_NUM_HW_PLANES 8 - -enum rcar_du_plane_source { - RCAR_DU_PLANE_MEMORY, - RCAR_DU_PLANE_VSPD0, - RCAR_DU_PLANE_VSPD1, -}; - -struct rcar_du_plane { - struct drm_plane plane; - struct rcar_du_group *group; -}; - -static inline struct rcar_du_plane *to_rcar_plane(struct drm_plane *plane) -{ - return container_of(plane, struct rcar_du_plane, plane); -} - -/** - * struct rcar_du_plane_state - Driver-specific plane state - * @state: base DRM plane state - * @format: information about the pixel format used by the plane - * @hwindex: 0-based hardware plane index, -1 means unused - * @colorkey: value of the plane colorkey property - */ -struct rcar_du_plane_state { - struct drm_plane_state state; - - const struct rcar_du_format_info *format; - int hwindex; - enum rcar_du_plane_source source; - - unsigned int colorkey; -}; - -static inline struct rcar_du_plane_state * -to_rcar_plane_state(struct drm_plane_state *state) -{ - return container_of(state, struct rcar_du_plane_state, state); -} - -int rcar_du_atomic_check_planes(struct drm_device *dev, - struct drm_atomic_state *state); - -int __rcar_du_plane_atomic_check(struct drm_plane *plane, - struct drm_plane_state *state, - const struct rcar_du_format_info **format); - -int rcar_du_planes_init(struct rcar_du_group *rgrp); - -void __rcar_du_plane_setup(struct rcar_du_group *rgrp, - const struct rcar_du_plane_state *state); - -static inline void rcar_du_plane_setup(struct rcar_du_plane *plane) -{ - struct rcar_du_plane_state *state = - to_rcar_plane_state(plane->plane.state); - - return __rcar_du_plane_setup(plane->group, state); -} - -#endif /* __RCAR_DU_PLANE_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h deleted file mode 100644 index 391de6661d8b..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h +++ /dev/null @@ -1,553 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * R-Car Display Unit Registers Definitions - * - * Copyright (C) 2013-2015 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#ifndef __RCAR_DU_REGS_H__ -#define __RCAR_DU_REGS_H__ - -#define DU0_REG_OFFSET 0x00000 -#define DU1_REG_OFFSET 0x30000 -#define DU2_REG_OFFSET 0x40000 -#define DU3_REG_OFFSET 0x70000 - -/* ----------------------------------------------------------------------------- - * Display Control Registers - */ - -#define DSYSR 0x00000 /* display 1 */ -#define DSYSR_ILTS (1 << 29) -#define DSYSR_DSEC (1 << 20) -#define DSYSR_IUPD (1 << 16) -#define DSYSR_DRES (1 << 9) -#define DSYSR_DEN (1 << 8) -#define DSYSR_TVM_MASTER (0 << 6) -#define DSYSR_TVM_SWITCH (1 << 6) -#define DSYSR_TVM_TVSYNC (2 << 6) -#define DSYSR_TVM_MASK (3 << 6) -#define DSYSR_SCM_INT_NONE (0 << 4) -#define DSYSR_SCM_INT_SYNC (2 << 4) -#define DSYSR_SCM_INT_VIDEO (3 << 4) -#define DSYSR_SCM_MASK (3 << 4) - -#define DSMR 0x00004 -#define DSMR_VSPM (1 << 28) -#define DSMR_ODPM (1 << 27) -#define DSMR_DIPM_DISP (0 << 25) -#define DSMR_DIPM_CSYNC (1 << 25) -#define DSMR_DIPM_DE (3 << 25) -#define DSMR_DIPM_MASK (3 << 25) -#define DSMR_CSPM (1 << 24) -#define DSMR_DIL (1 << 19) -#define DSMR_VSL (1 << 18) -#define DSMR_HSL (1 << 17) -#define DSMR_DDIS (1 << 16) -#define DSMR_CDEL (1 << 15) -#define DSMR_CDEM_CDE (0 << 13) -#define DSMR_CDEM_LOW (2 << 13) -#define DSMR_CDEM_HIGH (3 << 13) -#define DSMR_CDEM_MASK (3 << 13) -#define DSMR_CDED (1 << 12) -#define DSMR_ODEV (1 << 8) -#define DSMR_CSY_VH_OR (0 << 6) -#define DSMR_CSY_333 (2 << 6) -#define DSMR_CSY_222 (3 << 6) -#define DSMR_CSY_MASK (3 << 6) - -#define DSSR 0x00008 -#define DSSR_VC1FB_DSA0 (0 << 30) -#define DSSR_VC1FB_DSA1 (1 << 30) -#define DSSR_VC1FB_DSA2 (2 << 30) -#define DSSR_VC1FB_INIT (3 << 30) -#define DSSR_VC1FB_MASK (3 << 30) -#define DSSR_VC0FB_DSA0 (0 << 28) -#define DSSR_VC0FB_DSA1 (1 << 28) -#define DSSR_VC0FB_DSA2 (2 << 28) -#define DSSR_VC0FB_INIT (3 << 28) -#define DSSR_VC0FB_MASK (3 << 28) -#define DSSR_DFB(n) (1 << ((n)+15)) -#define DSSR_TVR (1 << 15) -#define DSSR_FRM (1 << 14) -#define DSSR_VBK (1 << 11) -#define DSSR_RINT (1 << 9) -#define DSSR_HBK (1 << 8) -#define DSSR_ADC(n) (1 << ((n)-1)) - -#define DSRCR 0x0000c -#define DSRCR_TVCL (1 << 15) -#define DSRCR_FRCL (1 << 14) -#define DSRCR_VBCL (1 << 11) -#define DSRCR_RICL (1 << 9) -#define DSRCR_HBCL (1 << 8) -#define DSRCR_ADCL(n) (1 << ((n)-1)) -#define DSRCR_MASK 0x0000cbff - -#define DIER 0x00010 -#define DIER_TVE (1 << 15) -#define DIER_FRE (1 << 14) -#define DIER_VBE (1 << 11) -#define DIER_RIE (1 << 9) -#define DIER_HBE (1 << 8) -#define DIER_ADCE(n) (1 << ((n)-1)) - -#define CPCR 0x00014 -#define CPCR_CP4CE (1 << 19) -#define CPCR_CP3CE (1 << 18) -#define CPCR_CP2CE (1 << 17) -#define CPCR_CP1CE (1 << 16) - -#define DPPR 0x00018 -#define DPPR_DPE(n) (1 << ((n)*4-1)) -#define DPPR_DPS(n, p) (((p)-1) << DPPR_DPS_SHIFT(n)) -#define DPPR_DPS_SHIFT(n) (((n)-1)*4) -#define DPPR_BPP16 (DPPR_DPE(8) | DPPR_DPS(8, 1)) /* plane1 */ -#define DPPR_BPP32_P1 (DPPR_DPE(7) | DPPR_DPS(7, 1)) -#define DPPR_BPP32_P2 (DPPR_DPE(8) | DPPR_DPS(8, 2)) -#define DPPR_BPP32 (DPPR_BPP32_P1 | DPPR_BPP32_P2) /* plane1 & 2 */ - -#define DEFR 0x00020 -#define DEFR_CODE (0x7773 << 16) -#define DEFR_EXSL (1 << 12) -#define DEFR_EXVL (1 << 11) -#define DEFR_EXUP (1 << 5) -#define DEFR_VCUP (1 << 4) -#define DEFR_DEFE (1 << 0) - -#define DAPCR 0x00024 -#define DAPCR_CODE (0x7773 << 16) -#define DAPCR_AP2E (1 << 4) -#define DAPCR_AP1E (1 << 0) - -#define DCPCR 0x00028 -#define DCPCR_CODE (0x7773 << 16) -#define DCPCR_CA2B (1 << 13) -#define DCPCR_CD2F (1 << 12) -#define DCPCR_DC2E (1 << 8) -#define DCPCR_CAB (1 << 5) -#define DCPCR_CDF (1 << 4) -#define DCPCR_DCE (1 << 0) - -#define DEFR2 0x00034 -#define DEFR2_CODE (0x7775 << 16) -#define DEFR2_DEFE2G (1 << 0) - -#define DEFR3 0x00038 -#define DEFR3_CODE (0x7776 << 16) -#define DEFR3_EVDA (1 << 14) -#define DEFR3_EVDM_1 (1 << 12) -#define DEFR3_EVDM_2 (2 << 12) -#define DEFR3_EVDM_3 (3 << 12) -#define DEFR3_VMSM2_EMA (1 << 6) -#define DEFR3_VMSM1_ENA (1 << 4) -#define DEFR3_DEFE3 (1 << 0) - -#define DEFR4 0x0003c -#define DEFR4_CODE (0x7777 << 16) -#define DEFR4_LRUO (1 << 5) -#define DEFR4_SPCE (1 << 4) - -#define DVCSR 0x000d0 -#define DVCSR_VCnFB2_DSA0(n) (0 << ((n)*2+16)) -#define DVCSR_VCnFB2_DSA1(n) (1 << ((n)*2+16)) -#define DVCSR_VCnFB2_DSA2(n) (2 << ((n)*2+16)) -#define DVCSR_VCnFB2_INIT(n) (3 << ((n)*2+16)) -#define DVCSR_VCnFB2_MASK(n) (3 << ((n)*2+16)) -#define DVCSR_VCnFB_DSA0(n) (0 << ((n)*2)) -#define DVCSR_VCnFB_DSA1(n) (1 << ((n)*2)) -#define DVCSR_VCnFB_DSA2(n) (2 << ((n)*2)) -#define DVCSR_VCnFB_INIT(n) (3 << ((n)*2)) -#define DVCSR_VCnFB_MASK(n) (3 << ((n)*2)) - -#define DEFR5 0x000e0 -#define DEFR5_CODE (0x66 << 24) -#define DEFR5_YCRGB2_DIS (0 << 14) -#define DEFR5_YCRGB2_PRI1 (1 << 14) -#define DEFR5_YCRGB2_PRI2 (2 << 14) -#define DEFR5_YCRGB2_PRI3 (3 << 14) -#define DEFR5_YCRGB2_MASK (3 << 14) -#define DEFR5_YCRGB1_DIS (0 << 12) -#define DEFR5_YCRGB1_PRI1 (1 << 12) -#define DEFR5_YCRGB1_PRI2 (2 << 12) -#define DEFR5_YCRGB1_PRI3 (3 << 12) -#define DEFR5_YCRGB1_MASK (3 << 12) -#define DEFR5_DEFE5 (1 << 0) - -#define DDLTR 0x000e4 -#define DDLTR_CODE (0x7766 << 16) -#define DDLTR_DLAR2 (1 << 6) -#define DDLTR_DLAY2 (1 << 5) -#define DDLTR_DLAY1 (1 << 1) - -#define DEFR6 0x000e8 -#define DEFR6_CODE (0x7778 << 16) -#define DEFR6_ODPM12_DSMR (0 << 10) -#define DEFR6_ODPM12_DISP (2 << 10) -#define DEFR6_ODPM12_CDE (3 << 10) -#define DEFR6_ODPM12_MASK (3 << 10) -#define DEFR6_ODPM02_DSMR (0 << 8) -#define DEFR6_ODPM02_DISP (2 << 8) -#define DEFR6_ODPM02_CDE (3 << 8) -#define DEFR6_ODPM02_MASK (3 << 8) -#define DEFR6_TCNE1 (1 << 6) -#define DEFR6_TCNE0 (1 << 4) -#define DEFR6_MLOS1 (1 << 2) -#define DEFR6_DEFAULT (DEFR6_CODE | DEFR6_TCNE1) - -#define DEFR7 0x000ec -#define DEFR7_CODE (0x7779 << 16) -#define DEFR7_CMME1 BIT(6) -#define DEFR7_CMME0 BIT(4) - -/* ----------------------------------------------------------------------------- - * R8A7790-only Control Registers - */ - -#define DD1SSR 0x20008 -#define DD1SSR_TVR (1 << 15) -#define DD1SSR_FRM (1 << 14) -#define DD1SSR_BUF (1 << 12) -#define DD1SSR_VBK (1 << 11) -#define DD1SSR_RINT (1 << 9) -#define DD1SSR_HBK (1 << 8) -#define DD1SSR_ADC(n) (1 << ((n)-1)) - -#define DD1SRCR 0x2000c -#define DD1SRCR_TVR (1 << 15) -#define DD1SRCR_FRM (1 << 14) -#define DD1SRCR_BUF (1 << 12) -#define DD1SRCR_VBK (1 << 11) -#define DD1SRCR_RINT (1 << 9) -#define DD1SRCR_HBK (1 << 8) -#define DD1SRCR_ADC(n) (1 << ((n)-1)) - -#define DD1IER 0x20010 -#define DD1IER_TVR (1 << 15) -#define DD1IER_FRM (1 << 14) -#define DD1IER_BUF (1 << 12) -#define DD1IER_VBK (1 << 11) -#define DD1IER_RINT (1 << 9) -#define DD1IER_HBK (1 << 8) -#define DD1IER_ADC(n) (1 << ((n)-1)) - -#define DEFR8 0x20020 -#define DEFR8_CODE (0x7790 << 16) -#define DEFR8_VSCS (1 << 6) -#define DEFR8_DRGBS_DU(n) ((n) << 4) -#define DEFR8_DRGBS_MASK (3 << 4) -#define DEFR8_DEFE8 (1 << 0) - -#define DOFLR 0x20024 -#define DOFLR_CODE (0x7790 << 16) -#define DOFLR_HSYCFL1 (1 << 13) -#define DOFLR_VSYCFL1 (1 << 12) -#define DOFLR_ODDFL1 (1 << 11) -#define DOFLR_DISPFL1 (1 << 10) -#define DOFLR_CDEFL1 (1 << 9) -#define DOFLR_RGBFL1 (1 << 8) -#define DOFLR_HSYCFL0 (1 << 5) -#define DOFLR_VSYCFL0 (1 << 4) -#define DOFLR_ODDFL0 (1 << 3) -#define DOFLR_DISPFL0 (1 << 2) -#define DOFLR_CDEFL0 (1 << 1) -#define DOFLR_RGBFL0 (1 << 0) - -#define DIDSR 0x20028 -#define DIDSR_CODE (0x7790 << 16) -#define DIDSR_LDCS_DCLKIN(n) (0 << (8 + (n) * 2)) -#define DIDSR_LDCS_DSI(n) (2 << (8 + (n) * 2)) /* V3U only */ -#define DIDSR_LDCS_LVDS0(n) (2 << (8 + (n) * 2)) -#define DIDSR_LDCS_LVDS1(n) (3 << (8 + (n) * 2)) -#define DIDSR_LDCS_MASK(n) (3 << (8 + (n) * 2)) -#define DIDSR_PDCS_CLK(n, clk) (clk << ((n) * 2)) -#define DIDSR_PDCS_MASK(n) (3 << ((n) * 2)) - -#define DEFR10 0x20038 -#define DEFR10_CODE (0x7795 << 16) -#define DEFR10_VSPF1_RGB (0 << 14) -#define DEFR10_VSPF1_YC (1 << 14) -#define DEFR10_DOCF1_RGB (0 << 12) -#define DEFR10_DOCF1_YC (1 << 12) -#define DEFR10_YCDF0_YCBCR444 (0 << 11) -#define DEFR10_YCDF0_YCBCR422 (1 << 11) -#define DEFR10_VSPF0_RGB (0 << 10) -#define DEFR10_VSPF0_YC (1 << 10) -#define DEFR10_DOCF0_RGB (0 << 8) -#define DEFR10_DOCF0_YC (1 << 8) -#define DEFR10_TSEL_H3_TCON1 (0 << 1) /* DEFR102 register only (DU2/DU3) */ -#define DEFR10_DEFE10 (1 << 0) - -#define DPLLCR 0x20044 -#define DPLLCR_CODE (0x95 << 24) -#define DPLLCR_PLCS1 (1 << 23) -#define DPLLCR_PLCS0 (1 << 21) -#define DPLLCR_CLKE (1 << 18) -#define DPLLCR_FDPLL(n) ((n) << 12) -#define DPLLCR_N(n) ((n) << 5) -#define DPLLCR_M(n) ((n) << 3) -#define DPLLCR_STBY (1 << 2) -#define DPLLCR_INCS_DOTCLKIN0 (0 << 0) -#define DPLLCR_INCS_DOTCLKIN1 (1 << 1) - -#define DPLLC2R 0x20048 -#define DPLLC2R_CODE (0x95 << 24) -#define DPLLC2R_SELC (1 << 12) -#define DPLLC2R_M(n) ((n) << 8) -#define DPLLC2R_FDPLL(n) ((n) << 0) - -/* ----------------------------------------------------------------------------- - * Display Timing Generation Registers - */ - -#define HDSR 0x00040 -#define HDER 0x00044 -#define VDSR 0x00048 -#define VDER 0x0004c -#define HCR 0x00050 -#define HSWR 0x00054 -#define VCR 0x00058 -#define VSPR 0x0005c -#define EQWR 0x00060 -#define SPWR 0x00064 -#define CLAMPSR 0x00070 -#define CLAMPWR 0x00074 -#define DESR 0x00078 -#define DEWR 0x0007c - -/* ----------------------------------------------------------------------------- - * Display Attribute Registers - */ - -#define CP1TR 0x00080 -#define CP2TR 0x00084 -#define CP3TR 0x00088 -#define CP4TR 0x0008c - -#define DOOR 0x00090 -#define DOOR_RGB(r, g, b) (((r) << 18) | ((g) << 10) | ((b) << 2)) -#define CDER 0x00094 -#define CDER_RGB(r, g, b) (((r) << 18) | ((g) << 10) | ((b) << 2)) -#define BPOR 0x00098 -#define BPOR_RGB(r, g, b) (((r) << 18) | ((g) << 10) | ((b) << 2)) - -#define RINTOFSR 0x0009c - -#define DSHPR 0x000c8 -#define DSHPR_CODE (0x7776 << 16) -#define DSHPR_PRIH (0xa << 4) -#define DSHPR_PRIL_BPP16 (0x8 << 0) -#define DSHPR_PRIL_BPP32 (0x9 << 0) - -/* ----------------------------------------------------------------------------- - * Display Plane Registers - */ - -#define PLANE_OFF 0x00100 - -#define PnMR 0x00100 /* plane 1 */ -#define PnMR_VISL_VIN0 (0 << 26) /* use Video Input 0 */ -#define PnMR_VISL_VIN1 (1 << 26) /* use Video Input 1 */ -#define PnMR_VISL_VIN2 (2 << 26) /* use Video Input 2 */ -#define PnMR_VISL_VIN3 (3 << 26) /* use Video Input 3 */ -#define PnMR_YCDF_YUYV (1 << 20) /* YUYV format */ -#define PnMR_TC_R (0 << 17) /* Tranparent color is PnTC1R */ -#define PnMR_TC_CP (1 << 17) /* Tranparent color is color palette */ -#define PnMR_WAE (1 << 16) /* Wrap around Enable */ -#define PnMR_SPIM_TP (0 << 12) /* Transparent Color */ -#define PnMR_SPIM_ALP (1 << 12) /* Alpha Blending */ -#define PnMR_SPIM_EOR (2 << 12) /* EOR */ -#define PnMR_SPIM_TP_OFF (1 << 14) /* No Transparent Color */ -#define PnMR_CPSL_CP1 (0 << 8) /* Color Palette selected 1 */ -#define PnMR_CPSL_CP2 (1 << 8) /* Color Palette selected 2 */ -#define PnMR_CPSL_CP3 (2 << 8) /* Color Palette selected 3 */ -#define PnMR_CPSL_CP4 (3 << 8) /* Color Palette selected 4 */ -#define PnMR_DC (1 << 7) /* Display Area Change */ -#define PnMR_BM_MD (0 << 4) /* Manual Display Change Mode */ -#define PnMR_BM_AR (1 << 4) /* Auto Rendering Mode */ -#define PnMR_BM_AD (2 << 4) /* Auto Display Change Mode */ -#define PnMR_BM_VC (3 << 4) /* Video Capture Mode */ -#define PnMR_DDDF_8BPP (0 << 0) /* 8bit */ -#define PnMR_DDDF_16BPP (1 << 0) /* 16bit or 32bit */ -#define PnMR_DDDF_ARGB (2 << 0) /* ARGB */ -#define PnMR_DDDF_YC (3 << 0) /* YC */ -#define PnMR_DDDF_MASK (3 << 0) - -#define PnMWR 0x00104 - -#define PnALPHAR 0x00108 -#define PnALPHAR_ABIT_1 (0 << 12) -#define PnALPHAR_ABIT_0 (1 << 12) -#define PnALPHAR_ABIT_X (2 << 12) - -#define PnDSXR 0x00110 -#define PnDSYR 0x00114 -#define PnDPXR 0x00118 -#define PnDPYR 0x0011c - -#define PnDSA0R 0x00120 -#define PnDSA1R 0x00124 -#define PnDSA2R 0x00128 -#define PnDSA_MASK 0xfffffff0 - -#define PnSPXR 0x00130 -#define PnSPYR 0x00134 -#define PnWASPR 0x00138 -#define PnWAMWR 0x0013c - -#define PnBTR 0x00140 - -#define PnTC1R 0x00144 -#define PnTC2R 0x00148 -#define PnTC3R 0x0014c -#define PnTC3R_CODE (0x66 << 24) - -#define PnMLR 0x00150 - -#define PnSWAPR 0x00180 -#define PnSWAPR_DIGN (1 << 4) -#define PnSWAPR_SPQW (1 << 3) -#define PnSWAPR_SPLW (1 << 2) -#define PnSWAPR_SPWD (1 << 1) -#define PnSWAPR_SPBY (1 << 0) - -#define PnDDCR 0x00184 -#define PnDDCR_CODE (0x7775 << 16) -#define PnDDCR_LRGB1 (1 << 11) -#define PnDDCR_LRGB0 (1 << 10) - -#define PnDDCR2 0x00188 -#define PnDDCR2_CODE (0x7776 << 16) -#define PnDDCR2_NV21 (1 << 5) -#define PnDDCR2_Y420 (1 << 4) -#define PnDDCR2_DIVU (1 << 1) -#define PnDDCR2_DIVY (1 << 0) - -#define PnDDCR4 0x00190 -#define PnDDCR4_CODE (0x7766 << 16) -#define PnDDCR4_VSPS (1 << 13) -#define PnDDCR4_SDFS_RGB (0 << 4) -#define PnDDCR4_SDFS_YC (5 << 4) -#define PnDDCR4_SDFS_MASK (7 << 4) -#define PnDDCR4_EDF_NONE (0 << 0) -#define PnDDCR4_EDF_ARGB8888 (1 << 0) -#define PnDDCR4_EDF_RGB888 (2 << 0) -#define PnDDCR4_EDF_RGB666 (3 << 0) -#define PnDDCR4_EDF_MASK (7 << 0) - -#define APnMR 0x0a100 -#define APnMR_WAE (1 << 16) /* Wrap around Enable */ -#define APnMR_DC (1 << 7) /* Display Area Change */ -#define APnMR_BM_MD (0 << 4) /* Manual Display Change Mode */ -#define APnMR_BM_AD (2 << 4) /* Auto Display Change Mode */ - -#define APnMWR 0x0a104 - -#define APnDSXR 0x0a110 -#define APnDSYR 0x0a114 -#define APnDPXR 0x0a118 -#define APnDPYR 0x0a11c - -#define APnDSA0R 0x0a120 -#define APnDSA1R 0x0a124 -#define APnDSA2R 0x0a128 - -#define APnSPXR 0x0a130 -#define APnSPYR 0x0a134 -#define APnWASPR 0x0a138 -#define APnWAMWR 0x0a13c - -#define APnBTR 0x0a140 - -#define APnMLR 0x0a150 -#define APnSWAPR 0x0a180 - -/* ----------------------------------------------------------------------------- - * Display Capture Registers - */ - -#define DCMR 0x0c100 -#define DCMWR 0x0c104 -#define DCSAR 0x0c120 -#define DCMLR 0x0c150 - -/* ----------------------------------------------------------------------------- - * Color Palette Registers - */ - -#define CP1_000R 0x01000 -#define CP1_255R 0x013fc -#define CP2_000R 0x02000 -#define CP2_255R 0x023fc -#define CP3_000R 0x03000 -#define CP3_255R 0x033fc -#define CP4_000R 0x04000 -#define CP4_255R 0x043fc - -/* ----------------------------------------------------------------------------- - * External Synchronization Control Registers - */ - -#define ESCR02 0x10000 -#define ESCR13 0x01000 -#define ESCR_DCLKOINV (1 << 25) -#define ESCR_DCLKSEL_DCLKIN (0 << 20) -#define ESCR_DCLKSEL_CLKS (1 << 20) -#define ESCR_DCLKSEL_MASK (1 << 20) -#define ESCR_DCLKDIS (1 << 16) -#define ESCR_SYNCSEL_OFF (0 << 8) -#define ESCR_SYNCSEL_EXVSYNC (2 << 8) -#define ESCR_SYNCSEL_EXHSYNC (3 << 8) -#define ESCR_FRQSEL_MASK (0x3f << 0) - -#define OTAR02 0x10004 -#define OTAR13 0x01004 - -/* ----------------------------------------------------------------------------- - * Dual Display Output Control Registers - */ - -#define DORCR 0x11000 -#define DORCR_PG1T (1 << 30) -#define DORCR_DK1S (1 << 28) -#define DORCR_PG1D_DS0 (0 << 24) -#define DORCR_PG1D_DS1 (1 << 24) -#define DORCR_PG1D_FIX0 (2 << 24) -#define DORCR_PG1D_DOOR (3 << 24) -#define DORCR_PG1D_MASK (3 << 24) -#define DORCR_DR0D (1 << 21) -#define DORCR_PG0D_DS0 (0 << 16) -#define DORCR_PG0D_DS1 (1 << 16) -#define DORCR_PG0D_FIX0 (2 << 16) -#define DORCR_PG0D_DOOR (3 << 16) -#define DORCR_PG0D_MASK (3 << 16) -#define DORCR_RGPV (1 << 4) -#define DORCR_DPRS (1 << 0) - -#define DPTSR 0x11004 -#define DPTSR_PnDK(n) (1 << ((n) + 16)) -#define DPTSR_PnTS(n) (1 << (n)) - -#define DAPTSR 0x11008 -#define DAPTSR_APnDK(n) (1 << ((n) + 16)) -#define DAPTSR_APnTS(n) (1 << (n)) - -#define DS1PR 0x11020 -#define DS2PR 0x11024 - -/* ----------------------------------------------------------------------------- - * YC-RGB Conversion Coefficient Registers - */ - -#define YNCR 0x11080 -#define YNOR 0x11084 -#define CRNOR 0x11088 -#define CBNOR 0x1108c -#define RCRCR 0x11090 -#define GCRCR 0x11094 -#define GCBCR 0x11098 -#define BCBCR 0x1109c - -#endif /* __RCAR_DU_REGS_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c deleted file mode 100644 index 45c05d0ffc70..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c +++ /dev/null @@ -1,513 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * R-Car Display Unit VSP-Based Compositor - * - * Copyright (C) 2015 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#include <drm/drm_atomic.h> -#include <drm/drm_atomic_helper.h> -#include <drm/drm_blend.h> -#include <drm/drm_crtc.h> -#include <drm/drm_fb_dma_helper.h> -#include <drm/drm_fourcc.h> -#include <drm/drm_framebuffer.h> -#include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_dma_helper.h> -#include <drm/drm_managed.h> -#include <drm/drm_vblank.h> - -#include <linux/bitops.h> -#include <linux/dma-mapping.h> -#include <linux/of_platform.h> -#include <linux/scatterlist.h> -#include <linux/slab.h> -#include <linux/videodev2.h> - -#include <media/vsp1.h> - -#include "rcar_du_drv.h" -#include "rcar_du_kms.h" -#include "rcar_du_vsp.h" -#include "rcar_du_writeback.h" - -static void rcar_du_vsp_complete(void *private, unsigned int status, u32 crc) -{ - struct rcar_du_crtc *crtc = private; - - if (crtc->vblank_enable) - drm_crtc_handle_vblank(&crtc->crtc); - - if (status & VSP1_DU_STATUS_COMPLETE) - rcar_du_crtc_finish_page_flip(crtc); - if (status & VSP1_DU_STATUS_WRITEBACK) - rcar_du_writeback_complete(crtc); - - drm_crtc_add_crc_entry(&crtc->crtc, false, 0, &crc); -} - -void rcar_du_vsp_enable(struct rcar_du_crtc *crtc) -{ - const struct drm_display_mode *mode = &crtc->crtc.state->adjusted_mode; - struct rcar_du_device *rcdu = crtc->dev; - struct vsp1_du_lif_config cfg = { - .width = mode->hdisplay, - .height = mode->vdisplay, - .interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE, - .callback = rcar_du_vsp_complete, - .callback_data = crtc, - }; - struct rcar_du_plane_state state = { - .state = { - .alpha = DRM_BLEND_ALPHA_OPAQUE, - .crtc = &crtc->crtc, - .dst.x1 = 0, - .dst.y1 = 0, - .dst.x2 = mode->hdisplay, - .dst.y2 = mode->vdisplay, - .src.x1 = 0, - .src.y1 = 0, - .src.x2 = mode->hdisplay << 16, - .src.y2 = mode->vdisplay << 16, - .zpos = 0, - }, - .format = rcar_du_format_info(DRM_FORMAT_XRGB8888), - .source = RCAR_DU_PLANE_VSPD1, - .colorkey = 0, - }; - - if (rcdu->info->gen >= 3) - state.hwindex = (crtc->index % 2) ? 2 : 0; - else - state.hwindex = crtc->index % 2; - - __rcar_du_plane_setup(crtc->group, &state); - - vsp1_du_setup_lif(crtc->vsp->vsp, crtc->vsp_pipe, &cfg); -} - -void rcar_du_vsp_disable(struct rcar_du_crtc *crtc) -{ - vsp1_du_setup_lif(crtc->vsp->vsp, crtc->vsp_pipe, NULL); -} - -void rcar_du_vsp_atomic_begin(struct rcar_du_crtc *crtc) -{ - vsp1_du_atomic_begin(crtc->vsp->vsp, crtc->vsp_pipe); -} - -void rcar_du_vsp_atomic_flush(struct rcar_du_crtc *crtc) -{ - struct vsp1_du_atomic_pipe_config cfg = { { 0, } }; - struct rcar_du_crtc_state *state; - - state = to_rcar_crtc_state(crtc->crtc.state); - cfg.crc = state->crc; - - rcar_du_writeback_setup(crtc, &cfg.writeback); - - vsp1_du_atomic_flush(crtc->vsp->vsp, crtc->vsp_pipe, &cfg); -} - -static const u32 rcar_du_vsp_formats[] = { - DRM_FORMAT_RGB332, - DRM_FORMAT_ARGB4444, - DRM_FORMAT_XRGB4444, - DRM_FORMAT_ARGB1555, - DRM_FORMAT_XRGB1555, - DRM_FORMAT_RGB565, - DRM_FORMAT_BGR888, - DRM_FORMAT_RGB888, - DRM_FORMAT_BGRA8888, - DRM_FORMAT_BGRX8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_UYVY, - DRM_FORMAT_YUYV, - DRM_FORMAT_YVYU, - DRM_FORMAT_NV12, - DRM_FORMAT_NV21, - DRM_FORMAT_NV16, - DRM_FORMAT_NV61, - DRM_FORMAT_YUV420, - DRM_FORMAT_YVU420, - DRM_FORMAT_YUV422, - DRM_FORMAT_YVU422, - DRM_FORMAT_YUV444, - DRM_FORMAT_YVU444, -}; - -/* - * Gen4 supports the same formats as above, and additionally 2-10-10-10 RGB - * formats and Y210 & Y212 formats. - */ -static const u32 rcar_du_vsp_formats_gen4[] = { - DRM_FORMAT_RGB332, - DRM_FORMAT_ARGB4444, - DRM_FORMAT_XRGB4444, - DRM_FORMAT_ARGB1555, - DRM_FORMAT_XRGB1555, - DRM_FORMAT_RGB565, - DRM_FORMAT_BGR888, - DRM_FORMAT_RGB888, - DRM_FORMAT_BGRA8888, - DRM_FORMAT_BGRX8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_RGBX1010102, - DRM_FORMAT_RGBA1010102, - DRM_FORMAT_ARGB2101010, - DRM_FORMAT_UYVY, - DRM_FORMAT_YUYV, - DRM_FORMAT_YVYU, - DRM_FORMAT_NV12, - DRM_FORMAT_NV21, - DRM_FORMAT_NV16, - DRM_FORMAT_NV61, - DRM_FORMAT_YUV420, - DRM_FORMAT_YVU420, - DRM_FORMAT_YUV422, - DRM_FORMAT_YVU422, - DRM_FORMAT_YUV444, - DRM_FORMAT_YVU444, - DRM_FORMAT_Y210, - DRM_FORMAT_Y212, -}; - -static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane) -{ - struct rcar_du_vsp_plane_state *state = - to_rcar_vsp_plane_state(plane->plane.state); - struct rcar_du_crtc *crtc = to_rcar_crtc(state->state.crtc); - struct drm_framebuffer *fb = plane->plane.state->fb; - const struct rcar_du_format_info *format; - struct vsp1_du_atomic_config cfg = { - .pixelformat = 0, - .pitch = fb->pitches[0], - .alpha = state->state.alpha >> 8, - .zpos = state->state.zpos, - }; - u32 fourcc = state->format->fourcc; - unsigned int i; - - cfg.src.left = state->state.src.x1 >> 16; - cfg.src.top = state->state.src.y1 >> 16; - cfg.src.width = drm_rect_width(&state->state.src) >> 16; - cfg.src.height = drm_rect_height(&state->state.src) >> 16; - - cfg.dst.left = state->state.dst.x1; - cfg.dst.top = state->state.dst.y1; - cfg.dst.width = drm_rect_width(&state->state.dst); - cfg.dst.height = drm_rect_height(&state->state.dst); - - for (i = 0; i < state->format->planes; ++i) - cfg.mem[i] = sg_dma_address(state->sg_tables[i].sgl) - + fb->offsets[i]; - - if (state->state.pixel_blend_mode == DRM_MODE_BLEND_PIXEL_NONE) { - switch (fourcc) { - case DRM_FORMAT_ARGB1555: - fourcc = DRM_FORMAT_XRGB1555; - break; - - case DRM_FORMAT_ARGB4444: - fourcc = DRM_FORMAT_XRGB4444; - break; - - case DRM_FORMAT_ARGB8888: - fourcc = DRM_FORMAT_XRGB8888; - break; - } - } - - format = rcar_du_format_info(fourcc); - cfg.pixelformat = format->v4l2; - - cfg.premult = state->state.pixel_blend_mode == DRM_MODE_BLEND_PREMULTI; - - vsp1_du_atomic_update(plane->vsp->vsp, crtc->vsp_pipe, - plane->index, &cfg); -} - -int rcar_du_vsp_map_fb(struct rcar_du_vsp *vsp, struct drm_framebuffer *fb, - struct sg_table sg_tables[3]) -{ - struct rcar_du_device *rcdu = vsp->dev; - unsigned int i, j; - int ret; - - for (i = 0; i < fb->format->num_planes; ++i) { - struct drm_gem_dma_object *gem = drm_fb_dma_get_gem_obj(fb, i); - struct sg_table *sgt = &sg_tables[i]; - - if (gem->sgt) { - struct scatterlist *src; - struct scatterlist *dst; - - /* - * If the GEM buffer has a scatter gather table, it has - * been imported from a dma-buf and has no physical - * address as it might not be physically contiguous. - * Copy the original scatter gather table to map it to - * the VSP. - */ - ret = sg_alloc_table(sgt, gem->sgt->orig_nents, - GFP_KERNEL); - if (ret) - goto fail; - - src = gem->sgt->sgl; - dst = sgt->sgl; - for (j = 0; j < gem->sgt->orig_nents; ++j) { - sg_set_page(dst, sg_page(src), src->length, - src->offset); - src = sg_next(src); - dst = sg_next(dst); - } - } else { - ret = dma_get_sgtable(rcdu->dev, sgt, gem->vaddr, - gem->dma_addr, gem->base.size); - if (ret) - goto fail; - } - - ret = vsp1_du_map_sg(vsp->vsp, sgt); - if (ret) { - sg_free_table(sgt); - goto fail; - } - } - - return 0; - -fail: - while (i--) { - struct sg_table *sgt = &sg_tables[i]; - - vsp1_du_unmap_sg(vsp->vsp, sgt); - sg_free_table(sgt); - } - - return ret; -} - -static int rcar_du_vsp_plane_prepare_fb(struct drm_plane *plane, - struct drm_plane_state *state) -{ - struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state); - struct rcar_du_vsp *vsp = to_rcar_vsp_plane(plane)->vsp; - int ret; - - /* - * There's no need to prepare (and unprepare) the framebuffer when the - * plane is not visible, as it will not be displayed. - */ - if (!state->visible) - return 0; - - ret = rcar_du_vsp_map_fb(vsp, state->fb, rstate->sg_tables); - if (ret < 0) - return ret; - - return drm_gem_plane_helper_prepare_fb(plane, state); -} - -void rcar_du_vsp_unmap_fb(struct rcar_du_vsp *vsp, struct drm_framebuffer *fb, - struct sg_table sg_tables[3]) -{ - unsigned int i; - - for (i = 0; i < fb->format->num_planes; ++i) { - struct sg_table *sgt = &sg_tables[i]; - - vsp1_du_unmap_sg(vsp->vsp, sgt); - sg_free_table(sgt); - } -} - -static void rcar_du_vsp_plane_cleanup_fb(struct drm_plane *plane, - struct drm_plane_state *state) -{ - struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state); - struct rcar_du_vsp *vsp = to_rcar_vsp_plane(plane)->vsp; - - if (!state->visible) - return; - - rcar_du_vsp_unmap_fb(vsp, state->fb, rstate->sg_tables); -} - -static int rcar_du_vsp_plane_atomic_check(struct drm_plane *plane, - struct drm_atomic_state *state) -{ - struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, - plane); - struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(new_plane_state); - - return __rcar_du_plane_atomic_check(plane, new_plane_state, - &rstate->format); -} - -static void rcar_du_vsp_plane_atomic_update(struct drm_plane *plane, - struct drm_atomic_state *state) -{ - struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); - struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); - struct rcar_du_vsp_plane *rplane = to_rcar_vsp_plane(plane); - struct rcar_du_crtc *crtc = to_rcar_crtc(old_state->crtc); - - if (new_state->visible) - rcar_du_vsp_plane_setup(rplane); - else if (old_state->crtc) - vsp1_du_atomic_update(rplane->vsp->vsp, crtc->vsp_pipe, - rplane->index, NULL); -} - -static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs = { - .prepare_fb = rcar_du_vsp_plane_prepare_fb, - .cleanup_fb = rcar_du_vsp_plane_cleanup_fb, - .atomic_check = rcar_du_vsp_plane_atomic_check, - .atomic_update = rcar_du_vsp_plane_atomic_update, -}; - -static struct drm_plane_state * -rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane *plane) -{ - struct rcar_du_vsp_plane_state *copy; - - if (WARN_ON(!plane->state)) - return NULL; - - copy = kzalloc(sizeof(*copy), GFP_KERNEL); - if (copy == NULL) - return NULL; - - __drm_atomic_helper_plane_duplicate_state(plane, ©->state); - - return ©->state; -} - -static void rcar_du_vsp_plane_atomic_destroy_state(struct drm_plane *plane, - struct drm_plane_state *state) -{ - __drm_atomic_helper_plane_destroy_state(state); - kfree(to_rcar_vsp_plane_state(state)); -} - -static void rcar_du_vsp_plane_reset(struct drm_plane *plane) -{ - struct rcar_du_vsp_plane_state *state; - - if (plane->state) { - rcar_du_vsp_plane_atomic_destroy_state(plane, plane->state); - plane->state = NULL; - } - - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (state == NULL) - return; - - __drm_atomic_helper_plane_reset(plane, &state->state); -} - -static const struct drm_plane_funcs rcar_du_vsp_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .reset = rcar_du_vsp_plane_reset, - .destroy = drm_plane_cleanup, - .atomic_duplicate_state = rcar_du_vsp_plane_atomic_duplicate_state, - .atomic_destroy_state = rcar_du_vsp_plane_atomic_destroy_state, -}; - -static void rcar_du_vsp_cleanup(struct drm_device *dev, void *res) -{ - struct rcar_du_vsp *vsp = res; - unsigned int i; - - for (i = 0; i < vsp->num_planes; ++i) { - struct rcar_du_vsp_plane *plane = &vsp->planes[i]; - - drm_plane_cleanup(&plane->plane); - } - - kfree(vsp->planes); - - put_device(vsp->vsp); -} - -int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np, - unsigned int crtcs) -{ - struct rcar_du_device *rcdu = vsp->dev; - struct platform_device *pdev; - unsigned int num_crtcs = hweight32(crtcs); - unsigned int num_planes; - unsigned int i; - int ret; - - /* Find the VSP device and initialize it. */ - pdev = of_find_device_by_node(np); - if (!pdev) - return -ENXIO; - - vsp->vsp = &pdev->dev; - - ret = drmm_add_action_or_reset(&rcdu->ddev, rcar_du_vsp_cleanup, vsp); - if (ret < 0) - return ret; - - ret = vsp1_du_init(vsp->vsp); - if (ret < 0) - return ret; - - num_planes = rcdu->info->num_rpf; - - vsp->planes = kcalloc(num_planes, sizeof(*vsp->planes), GFP_KERNEL); - if (!vsp->planes) - return -ENOMEM; - - for (i = 0; i < num_planes; ++i) { - enum drm_plane_type type = i < num_crtcs - ? DRM_PLANE_TYPE_PRIMARY - : DRM_PLANE_TYPE_OVERLAY; - struct rcar_du_vsp_plane *plane = &vsp->planes[i]; - unsigned int num_formats; - const u32 *formats; - - if (rcdu->info->gen < 4) { - num_formats = ARRAY_SIZE(rcar_du_vsp_formats); - formats = rcar_du_vsp_formats; - } else { - num_formats = ARRAY_SIZE(rcar_du_vsp_formats_gen4); - formats = rcar_du_vsp_formats_gen4; - } - - plane->vsp = vsp; - plane->index = i; - - ret = drm_universal_plane_init(&rcdu->ddev, &plane->plane, - crtcs, &rcar_du_vsp_plane_funcs, - formats, num_formats, - NULL, type, NULL); - if (ret < 0) - return ret; - - drm_plane_helper_add(&plane->plane, - &rcar_du_vsp_plane_helper_funcs); - - drm_plane_create_alpha_property(&plane->plane); - drm_plane_create_zpos_property(&plane->plane, i, 0, - num_planes - 1); - - drm_plane_create_blend_mode_property(&plane->plane, - BIT(DRM_MODE_BLEND_PIXEL_NONE) | - BIT(DRM_MODE_BLEND_PREMULTI) | - BIT(DRM_MODE_BLEND_COVERAGE)); - - vsp->num_planes++; - } - - return 0; -} diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h deleted file mode 100644 index 67630f0b6599..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h +++ /dev/null @@ -1,93 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * R-Car Display Unit VSP-Based Compositor - * - * Copyright (C) 2015 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#ifndef __RCAR_DU_VSP_H__ -#define __RCAR_DU_VSP_H__ - -#include <drm/drm_plane.h> - -struct drm_framebuffer; -struct rcar_du_format_info; -struct rcar_du_vsp; -struct sg_table; - -struct rcar_du_vsp_plane { - struct drm_plane plane; - struct rcar_du_vsp *vsp; - unsigned int index; -}; - -struct rcar_du_vsp { - unsigned int index; - struct device *vsp; - struct rcar_du_device *dev; - struct rcar_du_vsp_plane *planes; - unsigned int num_planes; -}; - -static inline struct rcar_du_vsp_plane *to_rcar_vsp_plane(struct drm_plane *p) -{ - return container_of(p, struct rcar_du_vsp_plane, plane); -} - -/** - * struct rcar_du_vsp_plane_state - Driver-specific plane state - * @state: base DRM plane state - * @format: information about the pixel format used by the plane - * @sg_tables: scatter-gather tables for the frame buffer memory - */ -struct rcar_du_vsp_plane_state { - struct drm_plane_state state; - - const struct rcar_du_format_info *format; - struct sg_table sg_tables[3]; -}; - -static inline struct rcar_du_vsp_plane_state * -to_rcar_vsp_plane_state(struct drm_plane_state *state) -{ - return container_of(state, struct rcar_du_vsp_plane_state, state); -} - -#ifdef CONFIG_DRM_RCAR_VSP -int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np, - unsigned int crtcs); -void rcar_du_vsp_enable(struct rcar_du_crtc *crtc); -void rcar_du_vsp_disable(struct rcar_du_crtc *crtc); -void rcar_du_vsp_atomic_begin(struct rcar_du_crtc *crtc); -void rcar_du_vsp_atomic_flush(struct rcar_du_crtc *crtc); -int rcar_du_vsp_map_fb(struct rcar_du_vsp *vsp, struct drm_framebuffer *fb, - struct sg_table sg_tables[3]); -void rcar_du_vsp_unmap_fb(struct rcar_du_vsp *vsp, struct drm_framebuffer *fb, - struct sg_table sg_tables[3]); -#else -static inline int rcar_du_vsp_init(struct rcar_du_vsp *vsp, - struct device_node *np, - unsigned int crtcs) -{ - return -ENXIO; -} -static inline void rcar_du_vsp_enable(struct rcar_du_crtc *crtc) { }; -static inline void rcar_du_vsp_disable(struct rcar_du_crtc *crtc) { }; -static inline void rcar_du_vsp_atomic_begin(struct rcar_du_crtc *crtc) { }; -static inline void rcar_du_vsp_atomic_flush(struct rcar_du_crtc *crtc) { }; -static inline int rcar_du_vsp_map_fb(struct rcar_du_vsp *vsp, - struct drm_framebuffer *fb, - struct sg_table sg_tables[3]) -{ - return -ENXIO; -} -static inline void rcar_du_vsp_unmap_fb(struct rcar_du_vsp *vsp, - struct drm_framebuffer *fb, - struct sg_table sg_tables[3]) -{ -} -#endif - -#endif /* __RCAR_DU_VSP_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_writeback.c b/drivers/gpu/drm/rcar-du/rcar_du_writeback.c deleted file mode 100644 index 8cd37d7b8ae2..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_du_writeback.c +++ /dev/null @@ -1,246 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * R-Car Display Unit Writeback Support - * - * Copyright (C) 2019 Laurent Pinchart <laurent.pinchart@ideasonboard.com> - */ - -#include <drm/drm_atomic_helper.h> -#include <drm/drm_device.h> -#include <drm/drm_edid.h> -#include <drm/drm_fourcc.h> -#include <drm/drm_framebuffer.h> -#include <drm/drm_probe_helper.h> -#include <drm/drm_writeback.h> - -#include "rcar_du_crtc.h" -#include "rcar_du_drv.h" -#include "rcar_du_kms.h" -#include "rcar_du_writeback.h" - -/** - * struct rcar_du_wb_conn_state - Driver-specific writeback connector state - * @state: base DRM connector state - * @format: format of the writeback framebuffer - */ -struct rcar_du_wb_conn_state { - struct drm_connector_state state; - const struct rcar_du_format_info *format; -}; - -#define to_rcar_wb_conn_state(s) \ - container_of(s, struct rcar_du_wb_conn_state, state) - -/** - * struct rcar_du_wb_job - Driver-private data for writeback jobs - * @sg_tables: scatter-gather tables for the framebuffer memory - */ -struct rcar_du_wb_job { - struct sg_table sg_tables[3]; -}; - -static int rcar_du_wb_conn_get_modes(struct drm_connector *connector) -{ - struct drm_device *dev = connector->dev; - - return drm_add_modes_noedid(connector, dev->mode_config.max_width, - dev->mode_config.max_height); -} - -static int rcar_du_wb_prepare_job(struct drm_writeback_connector *connector, - struct drm_writeback_job *job) -{ - struct rcar_du_crtc *rcrtc = wb_to_rcar_crtc(connector); - struct rcar_du_wb_job *rjob; - int ret; - - if (!job->fb) - return 0; - - rjob = kzalloc(sizeof(*rjob), GFP_KERNEL); - if (!rjob) - return -ENOMEM; - - /* Map the framebuffer to the VSP. */ - ret = rcar_du_vsp_map_fb(rcrtc->vsp, job->fb, rjob->sg_tables); - if (ret < 0) { - kfree(rjob); - return ret; - } - - job->priv = rjob; - return 0; -} - -static void rcar_du_wb_cleanup_job(struct drm_writeback_connector *connector, - struct drm_writeback_job *job) -{ - struct rcar_du_crtc *rcrtc = wb_to_rcar_crtc(connector); - struct rcar_du_wb_job *rjob = job->priv; - - if (!job->fb) - return; - - rcar_du_vsp_unmap_fb(rcrtc->vsp, job->fb, rjob->sg_tables); - kfree(rjob); -} - -static const struct drm_connector_helper_funcs rcar_du_wb_conn_helper_funcs = { - .get_modes = rcar_du_wb_conn_get_modes, - .prepare_writeback_job = rcar_du_wb_prepare_job, - .cleanup_writeback_job = rcar_du_wb_cleanup_job, -}; - -static struct drm_connector_state * -rcar_du_wb_conn_duplicate_state(struct drm_connector *connector) -{ - struct rcar_du_wb_conn_state *copy; - - if (WARN_ON(!connector->state)) - return NULL; - - copy = kzalloc(sizeof(*copy), GFP_KERNEL); - if (!copy) - return NULL; - - __drm_atomic_helper_connector_duplicate_state(connector, ©->state); - - return ©->state; -} - -static void rcar_du_wb_conn_destroy_state(struct drm_connector *connector, - struct drm_connector_state *state) -{ - __drm_atomic_helper_connector_destroy_state(state); - kfree(to_rcar_wb_conn_state(state)); -} - -static void rcar_du_wb_conn_reset(struct drm_connector *connector) -{ - struct rcar_du_wb_conn_state *state; - - if (connector->state) { - rcar_du_wb_conn_destroy_state(connector, connector->state); - connector->state = NULL; - } - - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (state == NULL) - return; - - __drm_atomic_helper_connector_reset(connector, &state->state); -} - -static const struct drm_connector_funcs rcar_du_wb_conn_funcs = { - .reset = rcar_du_wb_conn_reset, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = drm_connector_cleanup, - .atomic_duplicate_state = rcar_du_wb_conn_duplicate_state, - .atomic_destroy_state = rcar_du_wb_conn_destroy_state, -}; - -static int rcar_du_wb_enc_atomic_check(struct drm_encoder *encoder, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - struct rcar_du_wb_conn_state *wb_state = - to_rcar_wb_conn_state(conn_state); - const struct drm_display_mode *mode = &crtc_state->mode; - struct drm_device *dev = encoder->dev; - struct drm_framebuffer *fb; - - if (!conn_state->writeback_job) - return 0; - - fb = conn_state->writeback_job->fb; - - /* - * Verify that the framebuffer format is supported and that its size - * matches the current mode. - */ - if (fb->width != mode->hdisplay || fb->height != mode->vdisplay) { - dev_dbg(dev->dev, "%s: invalid framebuffer size %ux%u\n", - __func__, fb->width, fb->height); - return -EINVAL; - } - - wb_state->format = rcar_du_format_info(fb->format->format); - if (wb_state->format == NULL) { - dev_dbg(dev->dev, "%s: unsupported format %p4cc\n", __func__, - &fb->format->format); - return -EINVAL; - } - - return 0; -} - -static const struct drm_encoder_helper_funcs rcar_du_wb_enc_helper_funcs = { - .atomic_check = rcar_du_wb_enc_atomic_check, -}; - -/* - * Only RGB formats are currently supported as the VSP outputs RGB to the DU - * and can't convert to YUV separately for writeback. - */ -static const u32 writeback_formats[] = { - DRM_FORMAT_RGB332, - DRM_FORMAT_ARGB4444, - DRM_FORMAT_XRGB4444, - DRM_FORMAT_ARGB1555, - DRM_FORMAT_XRGB1555, - DRM_FORMAT_RGB565, - DRM_FORMAT_BGR888, - DRM_FORMAT_RGB888, - DRM_FORMAT_BGRA8888, - DRM_FORMAT_BGRX8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_XRGB8888, -}; - -int rcar_du_writeback_init(struct rcar_du_device *rcdu, - struct rcar_du_crtc *rcrtc) -{ - struct drm_writeback_connector *wb_conn = &rcrtc->writeback; - - drm_connector_helper_add(&wb_conn->base, - &rcar_du_wb_conn_helper_funcs); - - return drm_writeback_connector_init(&rcdu->ddev, wb_conn, - &rcar_du_wb_conn_funcs, - &rcar_du_wb_enc_helper_funcs, - writeback_formats, - ARRAY_SIZE(writeback_formats), - 1 << drm_crtc_index(&rcrtc->crtc)); -} - -void rcar_du_writeback_setup(struct rcar_du_crtc *rcrtc, - struct vsp1_du_writeback_config *cfg) -{ - struct rcar_du_wb_conn_state *wb_state; - struct drm_connector_state *state; - struct rcar_du_wb_job *rjob; - struct drm_framebuffer *fb; - unsigned int i; - - state = rcrtc->writeback.base.state; - if (!state || !state->writeback_job) - return; - - fb = state->writeback_job->fb; - rjob = state->writeback_job->priv; - wb_state = to_rcar_wb_conn_state(state); - - cfg->pixelformat = wb_state->format->v4l2; - cfg->pitch = fb->pitches[0]; - - for (i = 0; i < wb_state->format->planes; ++i) - cfg->mem[i] = sg_dma_address(rjob->sg_tables[i].sgl) - + fb->offsets[i]; - - drm_writeback_queue_job(&rcrtc->writeback, state); -} - -void rcar_du_writeback_complete(struct rcar_du_crtc *rcrtc) -{ - drm_writeback_signal_completion(&rcrtc->writeback, 0); -} diff --git a/drivers/gpu/drm/rcar-du/rcar_du_writeback.h b/drivers/gpu/drm/rcar-du/rcar_du_writeback.h deleted file mode 100644 index a71c9c08cafa..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_du_writeback.h +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * R-Car Display Unit Writeback Support - * - * Copyright (C) 2019 Laurent Pinchart <laurent.pinchart@ideasonboard.com> - */ - -#ifndef __RCAR_DU_WRITEBACK_H__ -#define __RCAR_DU_WRITEBACK_H__ - -#include <drm/drm_plane.h> - -struct rcar_du_crtc; -struct rcar_du_device; -struct vsp1_du_atomic_pipe_config; - -#ifdef CONFIG_DRM_RCAR_WRITEBACK -int rcar_du_writeback_init(struct rcar_du_device *rcdu, - struct rcar_du_crtc *rcrtc); -void rcar_du_writeback_setup(struct rcar_du_crtc *rcrtc, - struct vsp1_du_writeback_config *cfg); -void rcar_du_writeback_complete(struct rcar_du_crtc *rcrtc); -#else -static inline int rcar_du_writeback_init(struct rcar_du_device *rcdu, - struct rcar_du_crtc *rcrtc) -{ - return -ENXIO; -} -static inline void -rcar_du_writeback_setup(struct rcar_du_crtc *rcrtc, - struct vsp1_du_writeback_config *cfg) -{ -} -static inline void rcar_du_writeback_complete(struct rcar_du_crtc *rcrtc) -{ -} -#endif - -#endif /* __RCAR_DU_WRITEBACK_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c deleted file mode 100644 index 18ed14911b98..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +++ /dev/null @@ -1,124 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * R-Car Gen3 HDMI PHY - * - * Copyright (C) 2016 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#include <linux/mod_devicetable.h> -#include <linux/module.h> -#include <linux/platform_device.h> - -#include <drm/bridge/dw_hdmi.h> -#include <drm/drm_modes.h> - -#define RCAR_HDMI_PHY_OPMODE_PLLCFG 0x06 /* Mode of operation and PLL dividers */ -#define RCAR_HDMI_PHY_PLLCURRGMPCTRL 0x10 /* PLL current and Gmp (conductance) */ -#define RCAR_HDMI_PHY_PLLDIVCTRL 0x11 /* PLL dividers */ - -struct rcar_hdmi_phy_params { - unsigned long mpixelclock; - u16 opmode_div; /* Mode of operation and PLL dividers */ - u16 curr_gmp; /* PLL current and Gmp (conductance) */ - u16 div; /* PLL dividers */ -}; - -static const struct rcar_hdmi_phy_params rcar_hdmi_phy_params[] = { - { 35500000, 0x0003, 0x0344, 0x0328 }, - { 44900000, 0x0003, 0x0285, 0x0128 }, - { 71000000, 0x0002, 0x1184, 0x0314 }, - { 90000000, 0x0002, 0x1144, 0x0114 }, - { 140250000, 0x0001, 0x20c4, 0x030a }, - { 182750000, 0x0001, 0x2084, 0x010a }, - { 281250000, 0x0000, 0x0084, 0x0305 }, - { 297000000, 0x0000, 0x0084, 0x0105 }, - { ~0UL, 0x0000, 0x0000, 0x0000 }, -}; - -static enum drm_mode_status -rcar_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, - const struct drm_display_info *info, - const struct drm_display_mode *mode) -{ - /* - * The maximum supported clock frequency is 297 MHz, as shown in the PHY - * parameters table. - */ - if (mode->clock > 297000) - return MODE_CLOCK_HIGH; - - return MODE_OK; -} - -static int rcar_hdmi_phy_configure(struct dw_hdmi *hdmi, void *data, - unsigned long mpixelclock) -{ - const struct rcar_hdmi_phy_params *params = rcar_hdmi_phy_params; - - for (; params->mpixelclock != ~0UL; ++params) { - if (mpixelclock <= params->mpixelclock) - break; - } - - if (params->mpixelclock == ~0UL) - return -EINVAL; - - dw_hdmi_phy_i2c_write(hdmi, params->opmode_div, - RCAR_HDMI_PHY_OPMODE_PLLCFG); - dw_hdmi_phy_i2c_write(hdmi, params->curr_gmp, - RCAR_HDMI_PHY_PLLCURRGMPCTRL); - dw_hdmi_phy_i2c_write(hdmi, params->div, RCAR_HDMI_PHY_PLLDIVCTRL); - - return 0; -} - -static const struct dw_hdmi_plat_data rcar_dw_hdmi_plat_data = { - .output_port = 1, - .mode_valid = rcar_hdmi_mode_valid, - .configure_phy = rcar_hdmi_phy_configure, -}; - -static int rcar_dw_hdmi_probe(struct platform_device *pdev) -{ - struct dw_hdmi *hdmi; - - hdmi = dw_hdmi_probe(pdev, &rcar_dw_hdmi_plat_data); - if (IS_ERR(hdmi)) - return PTR_ERR(hdmi); - - platform_set_drvdata(pdev, hdmi); - - return 0; -} - -static int rcar_dw_hdmi_remove(struct platform_device *pdev) -{ - struct dw_hdmi *hdmi = platform_get_drvdata(pdev); - - dw_hdmi_remove(hdmi); - - return 0; -} - -static const struct of_device_id rcar_dw_hdmi_of_table[] = { - { .compatible = "renesas,rcar-gen3-hdmi" }, - { /* Sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, rcar_dw_hdmi_of_table); - -static struct platform_driver rcar_dw_hdmi_platform_driver = { - .probe = rcar_dw_hdmi_probe, - .remove = rcar_dw_hdmi_remove, - .driver = { - .name = "rcar-dw-hdmi", - .of_match_table = rcar_dw_hdmi_of_table, - }, -}; - -module_platform_driver(rcar_dw_hdmi_platform_driver); - -MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); -MODULE_DESCRIPTION("Renesas R-Car Gen3 HDMI Encoder Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c deleted file mode 100644 index ca215b588fd7..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ /dev/null @@ -1,1035 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * R-Car LVDS Encoder - * - * Copyright (C) 2013-2018 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/media-bus-format.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_graph.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> -#include <linux/reset.h> -#include <linux/slab.h> -#include <linux/sys_soc.h> - -#include <drm/drm_atomic.h> -#include <drm/drm_atomic_helper.h> -#include <drm/drm_bridge.h> -#include <drm/drm_of.h> -#include <drm/drm_panel.h> -#include <drm/drm_print.h> -#include <drm/drm_probe_helper.h> - -#include "rcar_lvds.h" -#include "rcar_lvds_regs.h" - -struct rcar_lvds; - -/* Keep in sync with the LVDCR0.LVMD hardware register values. */ -enum rcar_lvds_mode { - RCAR_LVDS_MODE_JEIDA = 0, - RCAR_LVDS_MODE_MIRROR = 1, - RCAR_LVDS_MODE_VESA = 4, -}; - -enum rcar_lvds_link_type { - RCAR_LVDS_SINGLE_LINK = 0, - RCAR_LVDS_DUAL_LINK_EVEN_ODD_PIXELS = 1, - RCAR_LVDS_DUAL_LINK_ODD_EVEN_PIXELS = 2, -}; - -#define RCAR_LVDS_QUIRK_LANES BIT(0) /* LVDS lanes 1 and 3 inverted */ -#define RCAR_LVDS_QUIRK_GEN3_LVEN BIT(1) /* LVEN bit needs to be set on R8A77970/R8A7799x */ -#define RCAR_LVDS_QUIRK_PWD BIT(2) /* PWD bit available (all of Gen3 but E3) */ -#define RCAR_LVDS_QUIRK_EXT_PLL BIT(3) /* Has extended PLL */ -#define RCAR_LVDS_QUIRK_DUAL_LINK BIT(4) /* Supports dual-link operation */ - -struct rcar_lvds_device_info { - unsigned int gen; - unsigned int quirks; - void (*pll_setup)(struct rcar_lvds *lvds, unsigned int freq); -}; - -struct rcar_lvds { - struct device *dev; - const struct rcar_lvds_device_info *info; - struct reset_control *rstc; - - struct drm_bridge bridge; - - struct drm_bridge *next_bridge; - struct drm_panel *panel; - - void __iomem *mmio; - struct { - struct clk *mod; /* CPG module clock */ - struct clk *extal; /* External clock */ - struct clk *dotclkin[2]; /* External DU clocks */ - } clocks; - - struct drm_bridge *companion; - enum rcar_lvds_link_type link_type; -}; - -#define bridge_to_rcar_lvds(b) \ - container_of(b, struct rcar_lvds, bridge) - -static u32 rcar_lvds_read(struct rcar_lvds *lvds, u32 reg) -{ - return ioread32(lvds->mmio + reg); -} - -static void rcar_lvds_write(struct rcar_lvds *lvds, u32 reg, u32 data) -{ - iowrite32(data, lvds->mmio + reg); -} - -/* ----------------------------------------------------------------------------- - * PLL Setup - */ - -static void rcar_lvds_pll_setup_gen2(struct rcar_lvds *lvds, unsigned int freq) -{ - u32 val; - - if (freq < 39000000) - val = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_38M; - else if (freq < 61000000) - val = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_60M; - else if (freq < 121000000) - val = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_121M; - else - val = LVDPLLCR_PLLDLYCNT_150M; - - rcar_lvds_write(lvds, LVDPLLCR, val); -} - -static void rcar_lvds_pll_setup_gen3(struct rcar_lvds *lvds, unsigned int freq) -{ - u32 val; - - if (freq < 42000000) - val = LVDPLLCR_PLLDIVCNT_42M; - else if (freq < 85000000) - val = LVDPLLCR_PLLDIVCNT_85M; - else if (freq < 128000000) - val = LVDPLLCR_PLLDIVCNT_128M; - else - val = LVDPLLCR_PLLDIVCNT_148M; - - rcar_lvds_write(lvds, LVDPLLCR, val); -} - -struct pll_info { - unsigned long diff; - unsigned int pll_m; - unsigned int pll_n; - unsigned int pll_e; - unsigned int div; - u32 clksel; -}; - -static void rcar_lvds_d3_e3_pll_calc(struct rcar_lvds *lvds, struct clk *clk, - unsigned long target, struct pll_info *pll, - u32 clksel, bool dot_clock_only) -{ - unsigned int div7 = dot_clock_only ? 1 : 7; - unsigned long output; - unsigned long fin; - unsigned int m_min; - unsigned int m_max; - unsigned int m; - int error; - - if (!clk) - return; - - /* - * The LVDS PLL is made of a pre-divider and a multiplier (strangely - * enough called M and N respectively), followed by a post-divider E. - * - * ,-----. ,-----. ,-----. ,-----. - * Fin --> | 1/M | -Fpdf-> | PFD | --> | VCO | -Fvco-> | 1/E | --> Fout - * `-----' ,-> | | `-----' | `-----' - * | `-----' | - * | ,-----. | - * `-------- | 1/N | <-------' - * `-----' - * - * The clock output by the PLL is then further divided by a programmable - * divider DIV to achieve the desired target frequency. Finally, an - * optional fixed /7 divider is used to convert the bit clock to a pixel - * clock (as LVDS transmits 7 bits per lane per clock sample). - * - * ,-------. ,-----. |\ - * Fout --> | 1/DIV | --> | 1/7 | --> | | - * `-------' | `-----' | | --> dot clock - * `------------> | | - * |/ - * - * The /7 divider is optional, it is enabled when the LVDS PLL is used - * to drive the LVDS encoder, and disabled when used to generate a dot - * clock for the DU RGB output, without using the LVDS encoder. - * - * The PLL allowed input frequency range is 12 MHz to 192 MHz. - */ - - fin = clk_get_rate(clk); - if (fin < 12000000 || fin > 192000000) - return; - - /* - * The comparison frequency range is 12 MHz to 24 MHz, which limits the - * allowed values for the pre-divider M (normal range 1-8). - * - * Fpfd = Fin / M - */ - m_min = max_t(unsigned int, 1, DIV_ROUND_UP(fin, 24000000)); - m_max = min_t(unsigned int, 8, fin / 12000000); - - for (m = m_min; m <= m_max; ++m) { - unsigned long fpfd; - unsigned int n_min; - unsigned int n_max; - unsigned int n; - - /* - * The VCO operating range is 900 Mhz to 1800 MHz, which limits - * the allowed values for the multiplier N (normal range - * 60-120). - * - * Fvco = Fin * N / M - */ - fpfd = fin / m; - n_min = max_t(unsigned int, 60, DIV_ROUND_UP(900000000, fpfd)); - n_max = min_t(unsigned int, 120, 1800000000 / fpfd); - - for (n = n_min; n < n_max; ++n) { - unsigned long fvco; - unsigned int e_min; - unsigned int e; - - /* - * The output frequency is limited to 1039.5 MHz, - * limiting again the allowed values for the - * post-divider E (normal value 1, 2 or 4). - * - * Fout = Fvco / E - */ - fvco = fpfd * n; - e_min = fvco > 1039500000 ? 1 : 0; - - for (e = e_min; e < 3; ++e) { - unsigned long fout; - unsigned long diff; - unsigned int div; - - /* - * Finally we have a programable divider after - * the PLL, followed by a an optional fixed /7 - * divider. - */ - fout = fvco / (1 << e) / div7; - div = max(1UL, DIV_ROUND_CLOSEST(fout, target)); - diff = abs(fout / div - target); - - if (diff < pll->diff) { - pll->diff = diff; - pll->pll_m = m; - pll->pll_n = n; - pll->pll_e = e; - pll->div = div; - pll->clksel = clksel; - - if (diff == 0) - goto done; - } - } - } - } - -done: - output = fin * pll->pll_n / pll->pll_m / (1 << pll->pll_e) - / div7 / pll->div; - error = (long)(output - target) * 10000 / (long)target; - - dev_dbg(lvds->dev, - "%pC %lu Hz -> Fout %lu Hz (target %lu Hz, error %d.%02u%%), PLL M/N/E/DIV %u/%u/%u/%u\n", - clk, fin, output, target, error / 100, - error < 0 ? -error % 100 : error % 100, - pll->pll_m, pll->pll_n, pll->pll_e, pll->div); -} - -static void rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds, - unsigned int freq, bool dot_clock_only) -{ - struct pll_info pll = { .diff = (unsigned long)-1 }; - u32 lvdpllcr; - - rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.dotclkin[0], freq, &pll, - LVDPLLCR_CKSEL_DU_DOTCLKIN(0), dot_clock_only); - rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.dotclkin[1], freq, &pll, - LVDPLLCR_CKSEL_DU_DOTCLKIN(1), dot_clock_only); - rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.extal, freq, &pll, - LVDPLLCR_CKSEL_EXTAL, dot_clock_only); - - lvdpllcr = LVDPLLCR_PLLON | pll.clksel | LVDPLLCR_CLKOUT - | LVDPLLCR_PLLN(pll.pll_n - 1) | LVDPLLCR_PLLM(pll.pll_m - 1); - - if (pll.pll_e > 0) - lvdpllcr |= LVDPLLCR_STP_CLKOUTE | LVDPLLCR_OUTCLKSEL - | LVDPLLCR_PLLE(pll.pll_e - 1); - - if (dot_clock_only) - lvdpllcr |= LVDPLLCR_OCKSEL; - - rcar_lvds_write(lvds, LVDPLLCR, lvdpllcr); - - if (pll.div > 1) - /* - * The DIVRESET bit is a misnomer, setting it to 1 deasserts the - * divisor reset. - */ - rcar_lvds_write(lvds, LVDDIV, LVDDIV_DIVSEL | - LVDDIV_DIVRESET | LVDDIV_DIV(pll.div - 1)); - else - rcar_lvds_write(lvds, LVDDIV, 0); -} - -/* ----------------------------------------------------------------------------- - * Enable/disable - */ - -static enum rcar_lvds_mode rcar_lvds_get_lvds_mode(struct rcar_lvds *lvds, - const struct drm_connector *connector) -{ - const struct drm_display_info *info; - enum rcar_lvds_mode mode; - - /* - * There is no API yet to retrieve LVDS mode from a bridge, only panels - * are supported. - */ - if (!lvds->panel) - return RCAR_LVDS_MODE_JEIDA; - - info = &connector->display_info; - if (!info->num_bus_formats || !info->bus_formats) { - dev_warn(lvds->dev, - "no LVDS bus format reported, using JEIDA\n"); - return RCAR_LVDS_MODE_JEIDA; - } - - switch (info->bus_formats[0]) { - case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: - case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: - mode = RCAR_LVDS_MODE_JEIDA; - break; - case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: - mode = RCAR_LVDS_MODE_VESA; - break; - default: - dev_warn(lvds->dev, - "unsupported LVDS bus format 0x%04x, using JEIDA\n", - info->bus_formats[0]); - return RCAR_LVDS_MODE_JEIDA; - } - - if (info->bus_flags & DRM_BUS_FLAG_DATA_LSB_TO_MSB) - mode |= RCAR_LVDS_MODE_MIRROR; - - return mode; -} - -static void rcar_lvds_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state, - struct drm_crtc *crtc, - struct drm_connector *connector) -{ - struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); - u32 lvdhcr; - u32 lvdcr0; - int ret; - - ret = pm_runtime_resume_and_get(lvds->dev); - if (ret) - return; - - /* Enable the companion LVDS encoder in dual-link mode. */ - if (lvds->link_type != RCAR_LVDS_SINGLE_LINK && lvds->companion) - rcar_lvds_enable(lvds->companion, state, crtc, connector); - - /* - * Hardcode the channels and control signals routing for now. - * - * HSYNC -> CTRL0 - * VSYNC -> CTRL1 - * DISP -> CTRL2 - * 0 -> CTRL3 - */ - rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO | - LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC | - LVDCTRCR_CTR0SEL_HSYNC); - - if (lvds->info->quirks & RCAR_LVDS_QUIRK_LANES) - lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3) - | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1); - else - lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 1) - | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 3); - - rcar_lvds_write(lvds, LVDCHCR, lvdhcr); - - if (lvds->info->quirks & RCAR_LVDS_QUIRK_DUAL_LINK) { - u32 lvdstripe = 0; - - if (lvds->link_type != RCAR_LVDS_SINGLE_LINK) { - /* - * By default we generate even pixels from the primary - * encoder and odd pixels from the companion encoder. - * Swap pixels around if the sink requires odd pixels - * from the primary encoder and even pixels from the - * companion encoder. - */ - bool swap_pixels = lvds->link_type == - RCAR_LVDS_DUAL_LINK_ODD_EVEN_PIXELS; - - /* - * Configure vertical stripe since we are dealing with - * an LVDS dual-link connection. - * - * ST_SWAP is reserved for the companion encoder, only - * set it in the primary encoder. - */ - lvdstripe = LVDSTRIPE_ST_ON - | (lvds->companion && swap_pixels ? - LVDSTRIPE_ST_SWAP : 0); - } - rcar_lvds_write(lvds, LVDSTRIPE, lvdstripe); - } - - /* - * PLL clock configuration on all instances but the companion in - * dual-link mode. - * - * The extended PLL has been turned on by an explicit call to - * rcar_lvds_pclk_enable() from the DU driver. - */ - if ((lvds->link_type == RCAR_LVDS_SINGLE_LINK || lvds->companion) && - !(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) { - const struct drm_crtc_state *crtc_state = - drm_atomic_get_new_crtc_state(state, crtc); - const struct drm_display_mode *mode = - &crtc_state->adjusted_mode; - - lvds->info->pll_setup(lvds, mode->clock * 1000); - } - - /* Set the LVDS mode and select the input. */ - lvdcr0 = rcar_lvds_get_lvds_mode(lvds, connector) << LVDCR0_LVMD_SHIFT; - - if (lvds->bridge.encoder) { - if (drm_crtc_index(crtc) == 2) - lvdcr0 |= LVDCR0_DUSEL; - } - - rcar_lvds_write(lvds, LVDCR0, lvdcr0); - - /* Turn all the channels on. */ - rcar_lvds_write(lvds, LVDCR1, - LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) | - LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) | LVDCR1_CLKSTBY); - - if (lvds->info->gen < 3) { - /* Enable LVDS operation and turn the bias circuitry on. */ - lvdcr0 |= LVDCR0_BEN | LVDCR0_LVEN; - rcar_lvds_write(lvds, LVDCR0, lvdcr0); - } - - if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) { - /* - * Turn the PLL on (simple PLL only, extended PLL is fully - * controlled through LVDPLLCR). - */ - lvdcr0 |= LVDCR0_PLLON; - rcar_lvds_write(lvds, LVDCR0, lvdcr0); - } - - if (lvds->info->quirks & RCAR_LVDS_QUIRK_PWD) { - /* Set LVDS normal mode. */ - lvdcr0 |= LVDCR0_PWD; - rcar_lvds_write(lvds, LVDCR0, lvdcr0); - } - - if (lvds->info->quirks & RCAR_LVDS_QUIRK_GEN3_LVEN) { - /* - * Turn on the LVDS PHY. On D3, the LVEN and LVRES bit must be - * set at the same time, so don't write the register yet. - */ - lvdcr0 |= LVDCR0_LVEN; - if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_PWD)) - rcar_lvds_write(lvds, LVDCR0, lvdcr0); - } - - if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) { - /* Wait for the PLL startup delay (simple PLL only). */ - usleep_range(100, 150); - } - - /* Turn the output on. */ - lvdcr0 |= LVDCR0_LVRES; - rcar_lvds_write(lvds, LVDCR0, lvdcr0); -} - -static void rcar_lvds_disable(struct drm_bridge *bridge) -{ - struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); - u32 lvdcr0; - - /* - * Clear the LVDCR0 bits in the order specified by the hardware - * documentation, ending with a write of 0 to the full register to - * clear all remaining bits. - */ - lvdcr0 = rcar_lvds_read(lvds, LVDCR0); - - lvdcr0 &= ~LVDCR0_LVRES; - rcar_lvds_write(lvds, LVDCR0, lvdcr0); - - if (lvds->info->quirks & RCAR_LVDS_QUIRK_GEN3_LVEN) { - lvdcr0 &= ~LVDCR0_LVEN; - rcar_lvds_write(lvds, LVDCR0, lvdcr0); - } - - if (lvds->info->quirks & RCAR_LVDS_QUIRK_PWD) { - lvdcr0 &= ~LVDCR0_PWD; - rcar_lvds_write(lvds, LVDCR0, lvdcr0); - } - - if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) { - lvdcr0 &= ~LVDCR0_PLLON; - rcar_lvds_write(lvds, LVDCR0, lvdcr0); - } - - rcar_lvds_write(lvds, LVDCR0, 0); - rcar_lvds_write(lvds, LVDCR1, 0); - - /* The extended PLL is turned off in rcar_lvds_pclk_disable(). */ - if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) - rcar_lvds_write(lvds, LVDPLLCR, 0); - - /* Disable the companion LVDS encoder in dual-link mode. */ - if (lvds->link_type != RCAR_LVDS_SINGLE_LINK && lvds->companion) - rcar_lvds_disable(lvds->companion); - - pm_runtime_put_sync(lvds->dev); -} - -/* ----------------------------------------------------------------------------- - * Clock - D3/E3 only - */ - -int rcar_lvds_pclk_enable(struct drm_bridge *bridge, unsigned long freq, - bool dot_clk_only) -{ - struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); - int ret; - - if (WARN_ON(!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL))) - return -ENODEV; - - dev_dbg(lvds->dev, "enabling LVDS PLL, freq=%luHz\n", freq); - - ret = pm_runtime_resume_and_get(lvds->dev); - if (ret) - return ret; - - rcar_lvds_pll_setup_d3_e3(lvds, freq, dot_clk_only); - - return 0; -} -EXPORT_SYMBOL_GPL(rcar_lvds_pclk_enable); - -void rcar_lvds_pclk_disable(struct drm_bridge *bridge, bool dot_clk_only) -{ - struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); - - if (WARN_ON(!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL))) - return; - - dev_dbg(lvds->dev, "disabling LVDS PLL\n"); - - if (!dot_clk_only) - rcar_lvds_disable(bridge); - - rcar_lvds_write(lvds, LVDPLLCR, 0); - - pm_runtime_put_sync(lvds->dev); -} -EXPORT_SYMBOL_GPL(rcar_lvds_pclk_disable); - -/* ----------------------------------------------------------------------------- - * Bridge - */ - -static void rcar_lvds_atomic_enable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) -{ - struct drm_atomic_state *state = old_bridge_state->base.state; - struct drm_connector *connector; - struct drm_crtc *crtc; - - connector = drm_atomic_get_new_connector_for_encoder(state, - bridge->encoder); - crtc = drm_atomic_get_new_connector_state(state, connector)->crtc; - - rcar_lvds_enable(bridge, state, crtc, connector); -} - -static void rcar_lvds_atomic_disable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) -{ - struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); - - /* - * For D3 and E3, disabling the LVDS encoder before the DU would stall - * the DU, causing a vblank wait timeout when stopping the DU. This has - * been traced to clearing the LVEN bit, but the exact reason is - * unknown. Keep the encoder enabled, it will be disabled by an explicit - * call to rcar_lvds_pclk_disable() from the DU driver. - * - * We could clear the LVRES bit already to disable the LVDS output, but - * that's likely pointless. - */ - if (lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL) - return; - - rcar_lvds_disable(bridge); -} - -static bool rcar_lvds_mode_fixup(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); - int min_freq; - - /* - * The internal LVDS encoder has a restricted clock frequency operating - * range, from 5MHz to 148.5MHz on D3 and E3, and from 31MHz to - * 148.5MHz on all other platforms. Clamp the clock accordingly. - */ - min_freq = lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL ? 5000 : 31000; - adjusted_mode->clock = clamp(adjusted_mode->clock, min_freq, 148500); - - return true; -} - -static int rcar_lvds_attach(struct drm_bridge *bridge, - enum drm_bridge_attach_flags flags) -{ - struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); - - if (!lvds->next_bridge) - return 0; - - return drm_bridge_attach(bridge->encoder, lvds->next_bridge, bridge, - flags); -} - -static const struct drm_bridge_funcs rcar_lvds_bridge_ops = { - .attach = rcar_lvds_attach, - .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, - .atomic_reset = drm_atomic_helper_bridge_reset, - .atomic_enable = rcar_lvds_atomic_enable, - .atomic_disable = rcar_lvds_atomic_disable, - .mode_fixup = rcar_lvds_mode_fixup, -}; - -bool rcar_lvds_dual_link(struct drm_bridge *bridge) -{ - struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); - - return lvds->link_type != RCAR_LVDS_SINGLE_LINK; -} -EXPORT_SYMBOL_GPL(rcar_lvds_dual_link); - -bool rcar_lvds_is_connected(struct drm_bridge *bridge) -{ - struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); - - return lvds->next_bridge != NULL; -} -EXPORT_SYMBOL_GPL(rcar_lvds_is_connected); - -/* ----------------------------------------------------------------------------- - * Probe & Remove - */ - -static int rcar_lvds_parse_dt_companion(struct rcar_lvds *lvds) -{ - const struct of_device_id *match; - struct device_node *companion; - struct device_node *port0, *port1; - struct rcar_lvds *companion_lvds; - struct device *dev = lvds->dev; - int dual_link; - int ret = 0; - - /* Locate the companion LVDS encoder for dual-link operation, if any. */ - companion = of_parse_phandle(dev->of_node, "renesas,companion", 0); - if (!companion) - return 0; - - /* - * Sanity check: the companion encoder must have the same compatible - * string. - */ - match = of_match_device(dev->driver->of_match_table, dev); - if (!of_device_is_compatible(companion, match->compatible)) { - dev_err(dev, "Companion LVDS encoder is invalid\n"); - ret = -ENXIO; - goto done; - } - - /* - * We need to work out if the sink is expecting us to function in - * dual-link mode. We do this by looking at the DT port nodes we are - * connected to, if they are marked as expecting even pixels and - * odd pixels than we need to enable vertical stripe output. - */ - port0 = of_graph_get_port_by_id(dev->of_node, 1); - port1 = of_graph_get_port_by_id(companion, 1); - dual_link = drm_of_lvds_get_dual_link_pixel_order(port0, port1); - of_node_put(port0); - of_node_put(port1); - - switch (dual_link) { - case DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS: - lvds->link_type = RCAR_LVDS_DUAL_LINK_ODD_EVEN_PIXELS; - break; - case DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS: - lvds->link_type = RCAR_LVDS_DUAL_LINK_EVEN_ODD_PIXELS; - break; - default: - /* - * Early dual-link bridge specific implementations populate the - * timings field of drm_bridge. If the flag is set, we assume - * that we are expected to generate even pixels from the primary - * encoder, and odd pixels from the companion encoder. - */ - if (lvds->next_bridge->timings && - lvds->next_bridge->timings->dual_link) - lvds->link_type = RCAR_LVDS_DUAL_LINK_EVEN_ODD_PIXELS; - else - lvds->link_type = RCAR_LVDS_SINGLE_LINK; - } - - if (lvds->link_type == RCAR_LVDS_SINGLE_LINK) { - dev_dbg(dev, "Single-link configuration detected\n"); - goto done; - } - - lvds->companion = of_drm_find_bridge(companion); - if (!lvds->companion) { - ret = -EPROBE_DEFER; - goto done; - } - - dev_dbg(dev, - "Dual-link configuration detected (companion encoder %pOF)\n", - companion); - - if (lvds->link_type == RCAR_LVDS_DUAL_LINK_ODD_EVEN_PIXELS) - dev_dbg(dev, "Data swapping required\n"); - - /* - * FIXME: We should not be messing with the companion encoder private - * data from the primary encoder, we should rather let the companion - * encoder work things out on its own. However, the companion encoder - * doesn't hold a reference to the primary encoder, and - * drm_of_lvds_get_dual_link_pixel_order needs to be given references - * to the output ports of both encoders, therefore leave it like this - * for the time being. - */ - companion_lvds = bridge_to_rcar_lvds(lvds->companion); - companion_lvds->link_type = lvds->link_type; - -done: - of_node_put(companion); - - return ret; -} - -static int rcar_lvds_parse_dt(struct rcar_lvds *lvds) -{ - int ret; - - ret = drm_of_find_panel_or_bridge(lvds->dev->of_node, 1, 0, - &lvds->panel, &lvds->next_bridge); - if (ret) - goto done; - - if (lvds->panel) { - lvds->next_bridge = devm_drm_panel_bridge_add(lvds->dev, - lvds->panel); - if (IS_ERR_OR_NULL(lvds->next_bridge)) { - ret = -EINVAL; - goto done; - } - } - - if (lvds->info->quirks & RCAR_LVDS_QUIRK_DUAL_LINK) - ret = rcar_lvds_parse_dt_companion(lvds); - -done: - /* - * On D3/E3 the LVDS encoder provides a clock to the DU, which can be - * used for the DPAD output even when the LVDS output is not connected. - * Don't fail probe in that case as the DU will need the bridge to - * control the clock. - */ - if (lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL) - return ret == -ENODEV ? 0 : ret; - - return ret; -} - -static struct clk *rcar_lvds_get_clock(struct rcar_lvds *lvds, const char *name, - bool optional) -{ - struct clk *clk; - - clk = devm_clk_get(lvds->dev, name); - if (!IS_ERR(clk)) - return clk; - - if (PTR_ERR(clk) == -ENOENT && optional) - return NULL; - - dev_err_probe(lvds->dev, PTR_ERR(clk), "failed to get %s clock\n", - name ? name : "module"); - - return clk; -} - -static int rcar_lvds_get_clocks(struct rcar_lvds *lvds) -{ - lvds->clocks.mod = rcar_lvds_get_clock(lvds, NULL, false); - if (IS_ERR(lvds->clocks.mod)) - return PTR_ERR(lvds->clocks.mod); - - /* - * LVDS encoders without an extended PLL have no external clock inputs. - */ - if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) - return 0; - - lvds->clocks.extal = rcar_lvds_get_clock(lvds, "extal", true); - if (IS_ERR(lvds->clocks.extal)) - return PTR_ERR(lvds->clocks.extal); - - lvds->clocks.dotclkin[0] = rcar_lvds_get_clock(lvds, "dclkin.0", true); - if (IS_ERR(lvds->clocks.dotclkin[0])) - return PTR_ERR(lvds->clocks.dotclkin[0]); - - lvds->clocks.dotclkin[1] = rcar_lvds_get_clock(lvds, "dclkin.1", true); - if (IS_ERR(lvds->clocks.dotclkin[1])) - return PTR_ERR(lvds->clocks.dotclkin[1]); - - /* At least one input to the PLL must be available. */ - if (!lvds->clocks.extal && !lvds->clocks.dotclkin[0] && - !lvds->clocks.dotclkin[1]) { - dev_err(lvds->dev, - "no input clock (extal, dclkin.0 or dclkin.1)\n"); - return -EINVAL; - } - - return 0; -} - -static const struct rcar_lvds_device_info rcar_lvds_r8a7790es1_info = { - .gen = 2, - .quirks = RCAR_LVDS_QUIRK_LANES, - .pll_setup = rcar_lvds_pll_setup_gen2, -}; - -static const struct soc_device_attribute lvds_quirk_matches[] = { - { - .soc_id = "r8a7790", .revision = "ES1.*", - .data = &rcar_lvds_r8a7790es1_info, - }, - { /* sentinel */ } -}; - -static int rcar_lvds_probe(struct platform_device *pdev) -{ - const struct soc_device_attribute *attr; - struct rcar_lvds *lvds; - int ret; - - lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL); - if (lvds == NULL) - return -ENOMEM; - - platform_set_drvdata(pdev, lvds); - - lvds->dev = &pdev->dev; - lvds->info = of_device_get_match_data(&pdev->dev); - - attr = soc_device_match(lvds_quirk_matches); - if (attr) - lvds->info = attr->data; - - ret = rcar_lvds_parse_dt(lvds); - if (ret < 0) - return ret; - - lvds->bridge.funcs = &rcar_lvds_bridge_ops; - lvds->bridge.of_node = pdev->dev.of_node; - - lvds->mmio = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(lvds->mmio)) - return PTR_ERR(lvds->mmio); - - ret = rcar_lvds_get_clocks(lvds); - if (ret < 0) - return ret; - - lvds->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); - if (IS_ERR(lvds->rstc)) - return dev_err_probe(&pdev->dev, PTR_ERR(lvds->rstc), - "failed to get cpg reset\n"); - - pm_runtime_enable(&pdev->dev); - - drm_bridge_add(&lvds->bridge); - - return 0; -} - -static int rcar_lvds_remove(struct platform_device *pdev) -{ - struct rcar_lvds *lvds = platform_get_drvdata(pdev); - - drm_bridge_remove(&lvds->bridge); - - pm_runtime_disable(&pdev->dev); - - return 0; -} - -static const struct rcar_lvds_device_info rcar_lvds_gen2_info = { - .gen = 2, - .pll_setup = rcar_lvds_pll_setup_gen2, -}; - -static const struct rcar_lvds_device_info rcar_lvds_gen3_info = { - .gen = 3, - .quirks = RCAR_LVDS_QUIRK_PWD, - .pll_setup = rcar_lvds_pll_setup_gen3, -}; - -static const struct rcar_lvds_device_info rcar_lvds_r8a77970_info = { - .gen = 3, - .quirks = RCAR_LVDS_QUIRK_PWD | RCAR_LVDS_QUIRK_GEN3_LVEN, - .pll_setup = rcar_lvds_pll_setup_gen2, -}; - -static const struct rcar_lvds_device_info rcar_lvds_r8a77990_info = { - .gen = 3, - .quirks = RCAR_LVDS_QUIRK_GEN3_LVEN | RCAR_LVDS_QUIRK_EXT_PLL - | RCAR_LVDS_QUIRK_DUAL_LINK, -}; - -static const struct rcar_lvds_device_info rcar_lvds_r8a77995_info = { - .gen = 3, - .quirks = RCAR_LVDS_QUIRK_GEN3_LVEN | RCAR_LVDS_QUIRK_PWD - | RCAR_LVDS_QUIRK_EXT_PLL | RCAR_LVDS_QUIRK_DUAL_LINK, -}; - -static const struct of_device_id rcar_lvds_of_table[] = { - { .compatible = "renesas,r8a7742-lvds", .data = &rcar_lvds_gen2_info }, - { .compatible = "renesas,r8a7743-lvds", .data = &rcar_lvds_gen2_info }, - { .compatible = "renesas,r8a7744-lvds", .data = &rcar_lvds_gen2_info }, - { .compatible = "renesas,r8a774a1-lvds", .data = &rcar_lvds_gen3_info }, - { .compatible = "renesas,r8a774b1-lvds", .data = &rcar_lvds_gen3_info }, - { .compatible = "renesas,r8a774c0-lvds", .data = &rcar_lvds_r8a77990_info }, - { .compatible = "renesas,r8a774e1-lvds", .data = &rcar_lvds_gen3_info }, - { .compatible = "renesas,r8a7790-lvds", .data = &rcar_lvds_gen2_info }, - { .compatible = "renesas,r8a7791-lvds", .data = &rcar_lvds_gen2_info }, - { .compatible = "renesas,r8a7793-lvds", .data = &rcar_lvds_gen2_info }, - { .compatible = "renesas,r8a7795-lvds", .data = &rcar_lvds_gen3_info }, - { .compatible = "renesas,r8a7796-lvds", .data = &rcar_lvds_gen3_info }, - { .compatible = "renesas,r8a77961-lvds", .data = &rcar_lvds_gen3_info }, - { .compatible = "renesas,r8a77965-lvds", .data = &rcar_lvds_gen3_info }, - { .compatible = "renesas,r8a77970-lvds", .data = &rcar_lvds_r8a77970_info }, - { .compatible = "renesas,r8a77980-lvds", .data = &rcar_lvds_gen3_info }, - { .compatible = "renesas,r8a77990-lvds", .data = &rcar_lvds_r8a77990_info }, - { .compatible = "renesas,r8a77995-lvds", .data = &rcar_lvds_r8a77995_info }, - { } -}; - -MODULE_DEVICE_TABLE(of, rcar_lvds_of_table); - -static int rcar_lvds_runtime_suspend(struct device *dev) -{ - struct rcar_lvds *lvds = dev_get_drvdata(dev); - - clk_disable_unprepare(lvds->clocks.mod); - - reset_control_assert(lvds->rstc); - - return 0; -} - -static int rcar_lvds_runtime_resume(struct device *dev) -{ - struct rcar_lvds *lvds = dev_get_drvdata(dev); - int ret; - - ret = reset_control_deassert(lvds->rstc); - if (ret) - return ret; - - ret = clk_prepare_enable(lvds->clocks.mod); - if (ret < 0) - goto err_reset_assert; - - return 0; - -err_reset_assert: - reset_control_assert(lvds->rstc); - - return ret; -} - -static const struct dev_pm_ops rcar_lvds_pm_ops = { - SET_RUNTIME_PM_OPS(rcar_lvds_runtime_suspend, rcar_lvds_runtime_resume, NULL) -}; - -static struct platform_driver rcar_lvds_platform_driver = { - .probe = rcar_lvds_probe, - .remove = rcar_lvds_remove, - .driver = { - .name = "rcar-lvds", - .pm = &rcar_lvds_pm_ops, - .of_match_table = rcar_lvds_of_table, - }, -}; - -module_platform_driver(rcar_lvds_platform_driver); - -MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); -MODULE_DESCRIPTION("Renesas R-Car LVDS Encoder Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.h b/drivers/gpu/drm/rcar-du/rcar_lvds.h deleted file mode 100644 index 887c63500000..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.h +++ /dev/null @@ -1,41 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * R-Car LVDS Encoder - * - * Copyright (C) 2013-2018 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#ifndef __RCAR_LVDS_H__ -#define __RCAR_LVDS_H__ - -struct drm_bridge; - -#if IS_ENABLED(CONFIG_DRM_RCAR_LVDS) -int rcar_lvds_pclk_enable(struct drm_bridge *bridge, unsigned long freq, - bool dot_clk_only); -void rcar_lvds_pclk_disable(struct drm_bridge *bridge, bool dot_clk_only); -bool rcar_lvds_dual_link(struct drm_bridge *bridge); -bool rcar_lvds_is_connected(struct drm_bridge *bridge); -#else -static inline int rcar_lvds_pclk_enable(struct drm_bridge *bridge, - unsigned long freq, bool dot_clk_only) -{ - return -ENOSYS; -} -static inline void rcar_lvds_pclk_disable(struct drm_bridge *bridge, - bool dot_clock_only) -{ -} -static inline bool rcar_lvds_dual_link(struct drm_bridge *bridge) -{ - return false; -} -static inline bool rcar_lvds_is_connected(struct drm_bridge *bridge) -{ - return false; -} -#endif /* CONFIG_DRM_RCAR_LVDS */ - -#endif /* __RCAR_LVDS_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h deleted file mode 100644 index ab0406a27d33..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h +++ /dev/null @@ -1,111 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * R-Car LVDS Interface Registers Definitions - * - * Copyright (C) 2013-2015 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#ifndef __RCAR_LVDS_REGS_H__ -#define __RCAR_LVDS_REGS_H__ - -#define LVDCR0 0x0000 -#define LVDCR0_DUSEL (1 << 15) -#define LVDCR0_DMD (1 << 12) /* Gen2 only */ -#define LVDCR0_LVMD_MASK (0xf << 8) -#define LVDCR0_LVMD_SHIFT 8 -#define LVDCR0_PLLON (1 << 4) -#define LVDCR0_PWD (1 << 2) /* Gen3 only */ -#define LVDCR0_BEN (1 << 2) /* Gen2 only */ -#define LVDCR0_LVEN (1 << 1) -#define LVDCR0_LVRES (1 << 0) - -#define LVDCR1 0x0004 -#define LVDCR1_CKSEL (1 << 15) /* Gen2 only */ -#define LVDCR1_CHSTBY(n) (3 << (2 + (n) * 2)) -#define LVDCR1_CLKSTBY (3 << 0) - -#define LVDPLLCR 0x0008 -/* Gen2 & V3M */ -#define LVDPLLCR_CEEN (1 << 14) -#define LVDPLLCR_FBEN (1 << 13) -#define LVDPLLCR_COSEL (1 << 12) -#define LVDPLLCR_PLLDLYCNT_150M (0x1bf << 0) -#define LVDPLLCR_PLLDLYCNT_121M (0x22c << 0) -#define LVDPLLCR_PLLDLYCNT_60M (0x77b << 0) -#define LVDPLLCR_PLLDLYCNT_38M (0x69a << 0) -#define LVDPLLCR_PLLDLYCNT_MASK (0x7ff << 0) -/* Gen3 but V3M,D3 and E3 */ -#define LVDPLLCR_PLLDIVCNT_42M (0x014cb << 0) -#define LVDPLLCR_PLLDIVCNT_85M (0x00a45 << 0) -#define LVDPLLCR_PLLDIVCNT_128M (0x006c3 << 0) -#define LVDPLLCR_PLLDIVCNT_148M (0x046c1 << 0) -#define LVDPLLCR_PLLDIVCNT_MASK (0x7ffff << 0) -/* D3 and E3 */ -#define LVDPLLCR_PLLON (1 << 22) -#define LVDPLLCR_PLLSEL_PLL0 (0 << 20) -#define LVDPLLCR_PLLSEL_LVX (1 << 20) -#define LVDPLLCR_PLLSEL_PLL1 (2 << 20) -#define LVDPLLCR_CKSEL_LVX (1 << 17) -#define LVDPLLCR_CKSEL_EXTAL (3 << 17) -#define LVDPLLCR_CKSEL_DU_DOTCLKIN(n) ((5 + (n) * 2) << 17) -#define LVDPLLCR_OCKSEL (1 << 16) -#define LVDPLLCR_STP_CLKOUTE (1 << 14) -#define LVDPLLCR_OUTCLKSEL (1 << 12) -#define LVDPLLCR_CLKOUT (1 << 11) -#define LVDPLLCR_PLLE(n) ((n) << 10) -#define LVDPLLCR_PLLN(n) ((n) << 3) -#define LVDPLLCR_PLLM(n) ((n) << 0) - -#define LVDCTRCR 0x000c -#define LVDCTRCR_CTR3SEL_ZERO (0 << 12) -#define LVDCTRCR_CTR3SEL_ODD (1 << 12) -#define LVDCTRCR_CTR3SEL_CDE (2 << 12) -#define LVDCTRCR_CTR3SEL_MASK (7 << 12) -#define LVDCTRCR_CTR2SEL_DISP (0 << 8) -#define LVDCTRCR_CTR2SEL_ODD (1 << 8) -#define LVDCTRCR_CTR2SEL_CDE (2 << 8) -#define LVDCTRCR_CTR2SEL_HSYNC (3 << 8) -#define LVDCTRCR_CTR2SEL_VSYNC (4 << 8) -#define LVDCTRCR_CTR2SEL_MASK (7 << 8) -#define LVDCTRCR_CTR1SEL_VSYNC (0 << 4) -#define LVDCTRCR_CTR1SEL_DISP (1 << 4) -#define LVDCTRCR_CTR1SEL_ODD (2 << 4) -#define LVDCTRCR_CTR1SEL_CDE (3 << 4) -#define LVDCTRCR_CTR1SEL_HSYNC (4 << 4) -#define LVDCTRCR_CTR1SEL_MASK (7 << 4) -#define LVDCTRCR_CTR0SEL_HSYNC (0 << 0) -#define LVDCTRCR_CTR0SEL_VSYNC (1 << 0) -#define LVDCTRCR_CTR0SEL_DISP (2 << 0) -#define LVDCTRCR_CTR0SEL_ODD (3 << 0) -#define LVDCTRCR_CTR0SEL_CDE (4 << 0) -#define LVDCTRCR_CTR0SEL_MASK (7 << 0) - -#define LVDCHCR 0x0010 -#define LVDCHCR_CHSEL_CH(n, c) ((((c) - (n)) & 3) << ((n) * 4)) -#define LVDCHCR_CHSEL_MASK(n) (3 << ((n) * 4)) - -/* All registers below are specific to D3 and E3 */ -#define LVDSTRIPE 0x0014 -#define LVDSTRIPE_ST_TRGSEL_DISP (0 << 2) -#define LVDSTRIPE_ST_TRGSEL_HSYNC_R (1 << 2) -#define LVDSTRIPE_ST_TRGSEL_HSYNC_F (2 << 2) -#define LVDSTRIPE_ST_SWAP (1 << 1) -#define LVDSTRIPE_ST_ON (1 << 0) - -#define LVDSCR 0x0018 -#define LVDSCR_DEPTH(n) (((n) - 1) << 29) -#define LVDSCR_BANDSET (1 << 28) -#define LVDSCR_TWGCNT(n) ((((n) - 256) / 16) << 24) -#define LVDSCR_SDIV(n) ((n) << 22) -#define LVDSCR_MODE (1 << 21) -#define LVDSCR_RSTN (1 << 20) - -#define LVDDIV 0x001c -#define LVDDIV_DIVSEL (1 << 8) -#define LVDDIV_DIVRESET (1 << 7) -#define LVDDIV_DIVSTP (1 << 6) -#define LVDDIV_DIV(n) ((n) << 0) - -#endif /* __RCAR_LVDS_REGS_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c deleted file mode 100644 index e10e4d4b89a2..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c +++ /dev/null @@ -1,1106 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * R-Car MIPI DSI Encoder - * - * Copyright (C) 2020 Renesas Electronics Corporation - */ - -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/iopoll.h> -#include <linux/math64.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_graph.h> -#include <linux/platform_device.h> -#include <linux/reset.h> -#include <linux/slab.h> - -#include <drm/drm_atomic.h> -#include <drm/drm_atomic_helper.h> -#include <drm/drm_bridge.h> -#include <drm/drm_mipi_dsi.h> -#include <drm/drm_of.h> -#include <drm/drm_panel.h> -#include <drm/drm_probe_helper.h> - -#include "rcar_mipi_dsi.h" -#include "rcar_mipi_dsi_regs.h" - -#define MHZ(v) ((u32)((v) * 1000000U)) - -enum rcar_mipi_dsi_hw_model { - RCAR_DSI_V3U, - RCAR_DSI_V4H, -}; - -struct rcar_mipi_dsi_device_info { - enum rcar_mipi_dsi_hw_model model; - - const struct dsi_clk_config *clk_cfg; - - u8 clockset2_m_offset; - - u8 n_min; - u8 n_max; - u8 n_mul; - unsigned long fpfd_min; - unsigned long fpfd_max; - u16 m_min; - u16 m_max; - unsigned long fout_min; - unsigned long fout_max; -}; - -struct rcar_mipi_dsi { - struct device *dev; - const struct rcar_mipi_dsi_device_info *info; - struct reset_control *rstc; - - struct mipi_dsi_host host; - struct drm_bridge bridge; - struct drm_bridge *next_bridge; - struct drm_connector connector; - - void __iomem *mmio; - struct { - struct clk *mod; - struct clk *pll; - struct clk *dsi; - } clocks; - - enum mipi_dsi_pixel_format format; - unsigned int num_data_lanes; - unsigned int lanes; -}; - -struct dsi_setup_info { - unsigned long hsfreq; - u16 hsfreqrange; - - unsigned long fout; - u16 m; - u16 n; - u16 vclk_divider; - const struct dsi_clk_config *clkset; -}; - -static inline struct rcar_mipi_dsi * -bridge_to_rcar_mipi_dsi(struct drm_bridge *bridge) -{ - return container_of(bridge, struct rcar_mipi_dsi, bridge); -} - -static inline struct rcar_mipi_dsi * -host_to_rcar_mipi_dsi(struct mipi_dsi_host *host) -{ - return container_of(host, struct rcar_mipi_dsi, host); -} - -static const u32 hsfreqrange_table[][2] = { - { MHZ(80), 0x00 }, { MHZ(90), 0x10 }, { MHZ(100), 0x20 }, - { MHZ(110), 0x30 }, { MHZ(120), 0x01 }, { MHZ(130), 0x11 }, - { MHZ(140), 0x21 }, { MHZ(150), 0x31 }, { MHZ(160), 0x02 }, - { MHZ(170), 0x12 }, { MHZ(180), 0x22 }, { MHZ(190), 0x32 }, - { MHZ(205), 0x03 }, { MHZ(220), 0x13 }, { MHZ(235), 0x23 }, - { MHZ(250), 0x33 }, { MHZ(275), 0x04 }, { MHZ(300), 0x14 }, - { MHZ(325), 0x25 }, { MHZ(350), 0x35 }, { MHZ(400), 0x05 }, - { MHZ(450), 0x16 }, { MHZ(500), 0x26 }, { MHZ(550), 0x37 }, - { MHZ(600), 0x07 }, { MHZ(650), 0x18 }, { MHZ(700), 0x28 }, - { MHZ(750), 0x39 }, { MHZ(800), 0x09 }, { MHZ(850), 0x19 }, - { MHZ(900), 0x29 }, { MHZ(950), 0x3a }, { MHZ(1000), 0x0a }, - { MHZ(1050), 0x1a }, { MHZ(1100), 0x2a }, { MHZ(1150), 0x3b }, - { MHZ(1200), 0x0b }, { MHZ(1250), 0x1b }, { MHZ(1300), 0x2b }, - { MHZ(1350), 0x3c }, { MHZ(1400), 0x0c }, { MHZ(1450), 0x1c }, - { MHZ(1500), 0x2c }, { MHZ(1550), 0x3d }, { MHZ(1600), 0x0d }, - { MHZ(1650), 0x1d }, { MHZ(1700), 0x2e }, { MHZ(1750), 0x3e }, - { MHZ(1800), 0x0e }, { MHZ(1850), 0x1e }, { MHZ(1900), 0x2f }, - { MHZ(1950), 0x3f }, { MHZ(2000), 0x0f }, { MHZ(2050), 0x40 }, - { MHZ(2100), 0x41 }, { MHZ(2150), 0x42 }, { MHZ(2200), 0x43 }, - { MHZ(2250), 0x44 }, { MHZ(2300), 0x45 }, { MHZ(2350), 0x46 }, - { MHZ(2400), 0x47 }, { MHZ(2450), 0x48 }, { MHZ(2500), 0x49 }, - { /* sentinel */ }, -}; - -struct dsi_clk_config { - u32 min_freq; - u32 max_freq; - u8 vco_cntrl; - u8 cpbias_cntrl; - u8 gmp_cntrl; - u8 int_cntrl; - u8 prop_cntrl; -}; - -static const struct dsi_clk_config dsi_clk_cfg_v3u[] = { - { MHZ(40), MHZ(55), 0x3f, 0x10, 0x01, 0x00, 0x0b }, - { MHZ(52.5), MHZ(80), 0x39, 0x10, 0x01, 0x00, 0x0b }, - { MHZ(80), MHZ(110), 0x2f, 0x10, 0x01, 0x00, 0x0b }, - { MHZ(105), MHZ(160), 0x29, 0x10, 0x01, 0x00, 0x0b }, - { MHZ(160), MHZ(220), 0x1f, 0x10, 0x01, 0x00, 0x0b }, - { MHZ(210), MHZ(320), 0x19, 0x10, 0x01, 0x00, 0x0b }, - { MHZ(320), MHZ(440), 0x0f, 0x10, 0x01, 0x00, 0x0b }, - { MHZ(420), MHZ(660), 0x09, 0x10, 0x01, 0x00, 0x0b }, - { MHZ(630), MHZ(1149), 0x03, 0x10, 0x01, 0x00, 0x0b }, - { MHZ(1100), MHZ(1152), 0x01, 0x10, 0x01, 0x00, 0x0b }, - { MHZ(1150), MHZ(1250), 0x01, 0x10, 0x01, 0x00, 0x0c }, - { /* sentinel */ }, -}; - -static const struct dsi_clk_config dsi_clk_cfg_v4h[] = { - { MHZ(40), MHZ(45.31), 0x2b, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(45.31), MHZ(54.66), 0x28, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(54.66), MHZ(62.5), 0x28, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(62.5), MHZ(75), 0x27, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(75), MHZ(90.63), 0x23, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(90.63), MHZ(109.37), 0x20, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(109.37), MHZ(125), 0x20, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(125), MHZ(150), 0x1f, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(150), MHZ(181.25), 0x1b, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(181.25), MHZ(218.75), 0x18, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(218.75), MHZ(250), 0x18, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(250), MHZ(300), 0x17, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(300), MHZ(362.5), 0x13, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(362.5), MHZ(455.48), 0x10, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(455.48), MHZ(500), 0x10, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(500), MHZ(600), 0x0f, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(600), MHZ(725), 0x0b, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(725), MHZ(875), 0x08, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(875), MHZ(1000), 0x08, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(1000), MHZ(1200), 0x07, 0x00, 0x00, 0x08, 0x0a }, - { MHZ(1200), MHZ(1250), 0x03, 0x00, 0x00, 0x08, 0x0a }, - { /* sentinel */ }, -}; - -static void rcar_mipi_dsi_write(struct rcar_mipi_dsi *dsi, u32 reg, u32 data) -{ - iowrite32(data, dsi->mmio + reg); -} - -static u32 rcar_mipi_dsi_read(struct rcar_mipi_dsi *dsi, u32 reg) -{ - return ioread32(dsi->mmio + reg); -} - -static void rcar_mipi_dsi_clr(struct rcar_mipi_dsi *dsi, u32 reg, u32 clr) -{ - rcar_mipi_dsi_write(dsi, reg, rcar_mipi_dsi_read(dsi, reg) & ~clr); -} - -static void rcar_mipi_dsi_set(struct rcar_mipi_dsi *dsi, u32 reg, u32 set) -{ - rcar_mipi_dsi_write(dsi, reg, rcar_mipi_dsi_read(dsi, reg) | set); -} - -static int rcar_mipi_dsi_write_phtw(struct rcar_mipi_dsi *dsi, u32 phtw) -{ - u32 status; - int ret; - - rcar_mipi_dsi_write(dsi, PHTW, phtw); - - ret = read_poll_timeout(rcar_mipi_dsi_read, status, - !(status & (PHTW_DWEN | PHTW_CWEN)), - 2000, 10000, false, dsi, PHTW); - if (ret < 0) { - dev_err(dsi->dev, "PHY test interface write timeout (0x%08x)\n", - phtw); - return ret; - } - - return ret; -} - -static int rcar_mipi_dsi_write_phtw_arr(struct rcar_mipi_dsi *dsi, - const u32 *phtw, unsigned int size) -{ - for (unsigned int i = 0; i < size; i++) { - int ret = rcar_mipi_dsi_write_phtw(dsi, phtw[i]); - - if (ret < 0) - return ret; - } - - return 0; -} - -#define WRITE_PHTW(...) \ - ({ \ - static const u32 phtw[] = { __VA_ARGS__ }; \ - int ret; \ - ret = rcar_mipi_dsi_write_phtw_arr(dsi, phtw, \ - ARRAY_SIZE(phtw)); \ - ret; \ - }) - -static int rcar_mipi_dsi_init_phtw_v3u(struct rcar_mipi_dsi *dsi) -{ - return WRITE_PHTW(0x01020114, 0x01600115, 0x01030116, 0x0102011d, - 0x011101a4, 0x018601a4, 0x014201a0, 0x010001a3, - 0x0101011f); -} - -static int rcar_mipi_dsi_post_init_phtw_v3u(struct rcar_mipi_dsi *dsi) -{ - return WRITE_PHTW(0x010c0130, 0x010c0140, 0x010c0150, 0x010c0180, - 0x010c0190, 0x010a0160, 0x010a0170, 0x01800164, - 0x01800174); -} - -static int rcar_mipi_dsi_init_phtw_v4h(struct rcar_mipi_dsi *dsi, - const struct dsi_setup_info *setup_info) -{ - int ret; - - if (setup_info->hsfreq < MHZ(450)) { - ret = WRITE_PHTW(0x01010100, 0x011b01ac); - if (ret) - return ret; - } - - ret = WRITE_PHTW(0x01010100, 0x01030173, 0x01000174, 0x01500175, - 0x01030176, 0x01040166, 0x010201ad); - if (ret) - return ret; - - if (setup_info->hsfreq <= MHZ(1000)) - ret = WRITE_PHTW(0x01020100, 0x01910170, 0x01020171, - 0x01110172); - else if (setup_info->hsfreq <= MHZ(1500)) - ret = WRITE_PHTW(0x01020100, 0x01980170, 0x01030171, - 0x01100172); - else if (setup_info->hsfreq <= MHZ(2500)) - ret = WRITE_PHTW(0x01020100, 0x0144016b, 0x01000172); - else - return -EINVAL; - - if (ret) - return ret; - - if (dsi->lanes <= 1) { - ret = WRITE_PHTW(0x01070100, 0x010e010b); - if (ret) - return ret; - } - - if (dsi->lanes <= 2) { - ret = WRITE_PHTW(0x01090100, 0x010e010b); - if (ret) - return ret; - } - - if (dsi->lanes <= 3) { - ret = WRITE_PHTW(0x010b0100, 0x010e010b); - if (ret) - return ret; - } - - if (setup_info->hsfreq <= MHZ(1500)) { - ret = WRITE_PHTW(0x01010100, 0x01c0016e); - if (ret) - return ret; - } - - return 0; -} - -static int -rcar_mipi_dsi_post_init_phtw_v4h(struct rcar_mipi_dsi *dsi, - const struct dsi_setup_info *setup_info) -{ - u32 status; - int ret; - - if (setup_info->hsfreq <= MHZ(1500)) { - WRITE_PHTW(0x01020100, 0x00000180); - - ret = read_poll_timeout(rcar_mipi_dsi_read, status, - status & PHTR_TEST, 2000, 10000, false, - dsi, PHTR); - if (ret < 0) { - dev_err(dsi->dev, "failed to test PHTR\n"); - return ret; - } - - WRITE_PHTW(0x01010100, 0x0100016e); - } - - return 0; -} - -/* ----------------------------------------------------------------------------- - * Hardware Setup - */ - -static void rcar_mipi_dsi_pll_calc(struct rcar_mipi_dsi *dsi, - unsigned long fin_rate, - unsigned long fout_target, - struct dsi_setup_info *setup_info) -{ - unsigned int best_err = -1; - const struct rcar_mipi_dsi_device_info *info = dsi->info; - - for (unsigned int n = info->n_min; n <= info->n_max; n++) { - unsigned long fpfd; - - fpfd = fin_rate / n; - - if (fpfd < info->fpfd_min || fpfd > info->fpfd_max) - continue; - - for (unsigned int m = info->m_min; m <= info->m_max; m++) { - unsigned int err; - u64 fout; - - fout = div64_u64((u64)fpfd * m, dsi->info->n_mul); - - if (fout < info->fout_min || fout > info->fout_max) - continue; - - fout = div64_u64(fout, setup_info->vclk_divider); - - if (fout < setup_info->clkset->min_freq || - fout > setup_info->clkset->max_freq) - continue; - - err = abs((long)(fout - fout_target) * 10000 / - (long)fout_target); - if (err < best_err) { - setup_info->m = m; - setup_info->n = n; - setup_info->fout = (unsigned long)fout; - best_err = err; - - if (err == 0) - return; - } - } - } -} - -static void rcar_mipi_dsi_parameters_calc(struct rcar_mipi_dsi *dsi, - struct clk *clk, unsigned long target, - struct dsi_setup_info *setup_info) -{ - - const struct dsi_clk_config *clk_cfg; - unsigned long fout_target; - unsigned long fin_rate; - unsigned int i; - unsigned int err; - - /* - * Calculate Fout = dot clock * ColorDepth / (2 * Lane Count) - * The range out Fout is [40 - 1250] Mhz - */ - fout_target = target * mipi_dsi_pixel_format_to_bpp(dsi->format) - / (2 * dsi->lanes); - if (fout_target < MHZ(40) || fout_target > MHZ(1250)) - return; - - /* Find PLL settings */ - for (clk_cfg = dsi->info->clk_cfg; clk_cfg->min_freq != 0; clk_cfg++) { - if (fout_target > clk_cfg->min_freq && - fout_target <= clk_cfg->max_freq) { - setup_info->clkset = clk_cfg; - break; - } - } - - fin_rate = clk_get_rate(clk); - - switch (dsi->info->model) { - case RCAR_DSI_V3U: - default: - setup_info->vclk_divider = 1 << ((clk_cfg->vco_cntrl >> 4) & 0x3); - break; - - case RCAR_DSI_V4H: - setup_info->vclk_divider = 1 << (((clk_cfg->vco_cntrl >> 3) & 0x7) + 1); - break; - } - - rcar_mipi_dsi_pll_calc(dsi, fin_rate, fout_target, setup_info); - - /* Find hsfreqrange */ - setup_info->hsfreq = setup_info->fout * 2; - for (i = 0; i < ARRAY_SIZE(hsfreqrange_table); i++) { - if (hsfreqrange_table[i][0] >= setup_info->hsfreq) { - setup_info->hsfreqrange = hsfreqrange_table[i][1]; - break; - } - } - - err = abs((long)(setup_info->fout - fout_target) * 10000 / (long)fout_target); - - dev_dbg(dsi->dev, - "Fout = %u * %lu / (%u * %u * %u) = %lu (target %lu Hz, error %d.%02u%%)\n", - setup_info->m, fin_rate, dsi->info->n_mul, setup_info->n, - setup_info->vclk_divider, setup_info->fout, fout_target, - err / 100, err % 100); - - dev_dbg(dsi->dev, - "vco_cntrl = 0x%x\tprop_cntrl = 0x%x\thsfreqrange = 0x%x\n", - clk_cfg->vco_cntrl, clk_cfg->prop_cntrl, - setup_info->hsfreqrange); -} - -static void rcar_mipi_dsi_set_display_timing(struct rcar_mipi_dsi *dsi, - const struct drm_display_mode *mode) -{ - u32 setr; - u32 vprmset0r; - u32 vprmset1r; - u32 vprmset2r; - u32 vprmset3r; - u32 vprmset4r; - - /* Configuration for Pixel Stream and Packet Header */ - if (mipi_dsi_pixel_format_to_bpp(dsi->format) == 24) - rcar_mipi_dsi_write(dsi, TXVMPSPHSETR, TXVMPSPHSETR_DT_RGB24); - else if (mipi_dsi_pixel_format_to_bpp(dsi->format) == 18) - rcar_mipi_dsi_write(dsi, TXVMPSPHSETR, TXVMPSPHSETR_DT_RGB18); - else if (mipi_dsi_pixel_format_to_bpp(dsi->format) == 16) - rcar_mipi_dsi_write(dsi, TXVMPSPHSETR, TXVMPSPHSETR_DT_RGB16); - else { - dev_warn(dsi->dev, "unsupported format"); - return; - } - - /* Configuration for Blanking sequence and Input Pixel */ - setr = TXVMSETR_HSABPEN_EN | TXVMSETR_HBPBPEN_EN - | TXVMSETR_HFPBPEN_EN | TXVMSETR_SYNSEQ_PULSES - | TXVMSETR_PIXWDTH | TXVMSETR_VSTPM; - rcar_mipi_dsi_write(dsi, TXVMSETR, setr); - - /* Configuration for Video Parameters */ - vprmset0r = (mode->flags & DRM_MODE_FLAG_PVSYNC ? - TXVMVPRMSET0R_VSPOL_HIG : TXVMVPRMSET0R_VSPOL_LOW) - | (mode->flags & DRM_MODE_FLAG_PHSYNC ? - TXVMVPRMSET0R_HSPOL_HIG : TXVMVPRMSET0R_HSPOL_LOW) - | TXVMVPRMSET0R_CSPC_RGB | TXVMVPRMSET0R_BPP_24; - - vprmset1r = TXVMVPRMSET1R_VACTIVE(mode->vdisplay) - | TXVMVPRMSET1R_VSA(mode->vsync_end - mode->vsync_start); - - vprmset2r = TXVMVPRMSET2R_VFP(mode->vsync_start - mode->vdisplay) - | TXVMVPRMSET2R_VBP(mode->vtotal - mode->vsync_end); - - vprmset3r = TXVMVPRMSET3R_HACTIVE(mode->hdisplay) - | TXVMVPRMSET3R_HSA(mode->hsync_end - mode->hsync_start); - - vprmset4r = TXVMVPRMSET4R_HFP(mode->hsync_start - mode->hdisplay) - | TXVMVPRMSET4R_HBP(mode->htotal - mode->hsync_end); - - rcar_mipi_dsi_write(dsi, TXVMVPRMSET0R, vprmset0r); - rcar_mipi_dsi_write(dsi, TXVMVPRMSET1R, vprmset1r); - rcar_mipi_dsi_write(dsi, TXVMVPRMSET2R, vprmset2r); - rcar_mipi_dsi_write(dsi, TXVMVPRMSET3R, vprmset3r); - rcar_mipi_dsi_write(dsi, TXVMVPRMSET4R, vprmset4r); -} - -static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi, - const struct drm_display_mode *mode) -{ - struct dsi_setup_info setup_info = {}; - unsigned int timeout; - int ret; - int dsi_format; - u32 phy_setup; - u32 clockset2, clockset3; - u32 ppisetr; - u32 vclkset; - - /* Checking valid format */ - dsi_format = mipi_dsi_pixel_format_to_bpp(dsi->format); - if (dsi_format < 0) { - dev_warn(dsi->dev, "invalid format"); - return -EINVAL; - } - - /* Parameters Calculation */ - rcar_mipi_dsi_parameters_calc(dsi, dsi->clocks.pll, - mode->clock * 1000, &setup_info); - - /* LPCLK enable */ - rcar_mipi_dsi_set(dsi, LPCLKSET, LPCLKSET_CKEN); - - /* CFGCLK enabled */ - rcar_mipi_dsi_set(dsi, CFGCLKSET, CFGCLKSET_CKEN); - - rcar_mipi_dsi_clr(dsi, PHYSETUP, PHYSETUP_RSTZ); - rcar_mipi_dsi_clr(dsi, PHYSETUP, PHYSETUP_SHUTDOWNZ); - - rcar_mipi_dsi_set(dsi, PHTC, PHTC_TESTCLR); - rcar_mipi_dsi_clr(dsi, PHTC, PHTC_TESTCLR); - - /* PHY setting */ - phy_setup = rcar_mipi_dsi_read(dsi, PHYSETUP); - phy_setup &= ~PHYSETUP_HSFREQRANGE_MASK; - phy_setup |= PHYSETUP_HSFREQRANGE(setup_info.hsfreqrange); - rcar_mipi_dsi_write(dsi, PHYSETUP, phy_setup); - - switch (dsi->info->model) { - case RCAR_DSI_V3U: - default: - ret = rcar_mipi_dsi_init_phtw_v3u(dsi); - if (ret < 0) - return ret; - break; - - case RCAR_DSI_V4H: - ret = rcar_mipi_dsi_init_phtw_v4h(dsi, &setup_info); - if (ret < 0) - return ret; - break; - } - - /* PLL Clock Setting */ - rcar_mipi_dsi_clr(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR); - rcar_mipi_dsi_set(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR); - rcar_mipi_dsi_clr(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR); - - clockset2 = CLOCKSET2_M(setup_info.m - dsi->info->clockset2_m_offset) - | CLOCKSET2_N(setup_info.n - 1) - | CLOCKSET2_VCO_CNTRL(setup_info.clkset->vco_cntrl); - clockset3 = CLOCKSET3_PROP_CNTRL(setup_info.clkset->prop_cntrl) - | CLOCKSET3_INT_CNTRL(setup_info.clkset->int_cntrl) - | CLOCKSET3_CPBIAS_CNTRL(setup_info.clkset->cpbias_cntrl) - | CLOCKSET3_GMP_CNTRL(setup_info.clkset->gmp_cntrl); - rcar_mipi_dsi_write(dsi, CLOCKSET2, clockset2); - rcar_mipi_dsi_write(dsi, CLOCKSET3, clockset3); - - rcar_mipi_dsi_clr(dsi, CLOCKSET1, CLOCKSET1_UPDATEPLL); - rcar_mipi_dsi_set(dsi, CLOCKSET1, CLOCKSET1_UPDATEPLL); - udelay(10); - rcar_mipi_dsi_clr(dsi, CLOCKSET1, CLOCKSET1_UPDATEPLL); - - ppisetr = PPISETR_DLEN_3 | PPISETR_CLEN; - rcar_mipi_dsi_write(dsi, PPISETR, ppisetr); - - rcar_mipi_dsi_set(dsi, PHYSETUP, PHYSETUP_SHUTDOWNZ); - rcar_mipi_dsi_set(dsi, PHYSETUP, PHYSETUP_RSTZ); - usleep_range(400, 500); - - /* Checking PPI clock status register */ - for (timeout = 10; timeout > 0; --timeout) { - if ((rcar_mipi_dsi_read(dsi, PPICLSR) & PPICLSR_STPST) && - (rcar_mipi_dsi_read(dsi, PPIDLSR) & PPIDLSR_STPST) && - (rcar_mipi_dsi_read(dsi, CLOCKSET1) & CLOCKSET1_LOCK)) - break; - - usleep_range(1000, 2000); - } - - if (!timeout) { - dev_err(dsi->dev, "failed to enable PPI clock\n"); - return -ETIMEDOUT; - } - - switch (dsi->info->model) { - case RCAR_DSI_V3U: - default: - ret = rcar_mipi_dsi_post_init_phtw_v3u(dsi); - if (ret < 0) - return ret; - break; - - case RCAR_DSI_V4H: - ret = rcar_mipi_dsi_post_init_phtw_v4h(dsi, &setup_info); - if (ret < 0) - return ret; - break; - } - - /* Enable DOT clock */ - vclkset = VCLKSET_CKEN; - rcar_mipi_dsi_write(dsi, VCLKSET, vclkset); - - if (dsi_format == 24) - vclkset |= VCLKSET_BPP_24; - else if (dsi_format == 18) - vclkset |= VCLKSET_BPP_18; - else if (dsi_format == 16) - vclkset |= VCLKSET_BPP_16; - else { - dev_warn(dsi->dev, "unsupported format"); - return -EINVAL; - } - - vclkset |= VCLKSET_COLOR_RGB | VCLKSET_LANE(dsi->lanes - 1); - - switch (dsi->info->model) { - case RCAR_DSI_V3U: - default: - vclkset |= VCLKSET_DIV_V3U(__ffs(setup_info.vclk_divider)); - break; - - case RCAR_DSI_V4H: - vclkset |= VCLKSET_DIV_V4H(__ffs(setup_info.vclk_divider) - 1); - break; - } - - rcar_mipi_dsi_write(dsi, VCLKSET, vclkset); - - /* After setting VCLKSET register, enable VCLKEN */ - rcar_mipi_dsi_set(dsi, VCLKEN, VCLKEN_CKEN); - - dev_dbg(dsi->dev, "DSI device is started\n"); - - return 0; -} - -static void rcar_mipi_dsi_shutdown(struct rcar_mipi_dsi *dsi) -{ - /* Disable VCLKEN */ - rcar_mipi_dsi_write(dsi, VCLKSET, 0); - - /* Disable DOT clock */ - rcar_mipi_dsi_write(dsi, VCLKSET, 0); - - rcar_mipi_dsi_clr(dsi, PHYSETUP, PHYSETUP_RSTZ); - rcar_mipi_dsi_clr(dsi, PHYSETUP, PHYSETUP_SHUTDOWNZ); - - /* CFGCLK disable */ - rcar_mipi_dsi_clr(dsi, CFGCLKSET, CFGCLKSET_CKEN); - - /* LPCLK disable */ - rcar_mipi_dsi_clr(dsi, LPCLKSET, LPCLKSET_CKEN); - - dev_dbg(dsi->dev, "DSI device is shutdown\n"); -} - -static int rcar_mipi_dsi_clk_enable(struct rcar_mipi_dsi *dsi) -{ - int ret; - - reset_control_deassert(dsi->rstc); - - ret = clk_prepare_enable(dsi->clocks.mod); - if (ret < 0) - goto err_reset; - - ret = clk_prepare_enable(dsi->clocks.dsi); - if (ret < 0) - goto err_clock; - - return 0; - -err_clock: - clk_disable_unprepare(dsi->clocks.mod); -err_reset: - reset_control_assert(dsi->rstc); - return ret; -} - -static void rcar_mipi_dsi_clk_disable(struct rcar_mipi_dsi *dsi) -{ - clk_disable_unprepare(dsi->clocks.dsi); - clk_disable_unprepare(dsi->clocks.mod); - - reset_control_assert(dsi->rstc); -} - -static int rcar_mipi_dsi_start_hs_clock(struct rcar_mipi_dsi *dsi) -{ - /* - * In HW manual, we need to check TxDDRClkHS-Q Stable? but it dont - * write how to check. So we skip this check in this patch - */ - u32 status; - int ret; - - /* Start HS clock. */ - rcar_mipi_dsi_set(dsi, PPICLCR, PPICLCR_TXREQHS); - - ret = read_poll_timeout(rcar_mipi_dsi_read, status, - status & PPICLSR_TOHS, - 2000, 10000, false, dsi, PPICLSR); - if (ret < 0) { - dev_err(dsi->dev, "failed to enable HS clock\n"); - return ret; - } - - rcar_mipi_dsi_set(dsi, PPICLSCR, PPICLSCR_TOHS); - - return 0; -} - -static int rcar_mipi_dsi_start_video(struct rcar_mipi_dsi *dsi) -{ - u32 status; - int ret; - - /* Wait for the link to be ready. */ - ret = read_poll_timeout(rcar_mipi_dsi_read, status, - !(status & (LINKSR_LPBUSY | LINKSR_HSBUSY)), - 2000, 10000, false, dsi, LINKSR); - if (ret < 0) { - dev_err(dsi->dev, "Link failed to become ready\n"); - return ret; - } - - /* De-assert video FIFO clear. */ - rcar_mipi_dsi_clr(dsi, TXVMCR, TXVMCR_VFCLR); - - ret = read_poll_timeout(rcar_mipi_dsi_read, status, - status & TXVMSR_VFRDY, - 2000, 10000, false, dsi, TXVMSR); - if (ret < 0) { - dev_err(dsi->dev, "Failed to de-assert video FIFO clear\n"); - return ret; - } - - /* Enable transmission in video mode. */ - rcar_mipi_dsi_set(dsi, TXVMCR, TXVMCR_EN_VIDEO); - - ret = read_poll_timeout(rcar_mipi_dsi_read, status, - status & TXVMSR_RDY, - 2000, 10000, false, dsi, TXVMSR); - if (ret < 0) { - dev_err(dsi->dev, "Failed to enable video transmission\n"); - return ret; - } - - return 0; -} - -static void rcar_mipi_dsi_stop_video(struct rcar_mipi_dsi *dsi) -{ - u32 status; - int ret; - - /* Disable transmission in video mode. */ - rcar_mipi_dsi_clr(dsi, TXVMCR, TXVMCR_EN_VIDEO); - - ret = read_poll_timeout(rcar_mipi_dsi_read, status, - !(status & TXVMSR_ACT), - 2000, 100000, false, dsi, TXVMSR); - if (ret < 0) { - dev_err(dsi->dev, "Failed to disable video transmission\n"); - return; - } - - /* Assert video FIFO clear. */ - rcar_mipi_dsi_set(dsi, TXVMCR, TXVMCR_VFCLR); - - ret = read_poll_timeout(rcar_mipi_dsi_read, status, - !(status & TXVMSR_VFRDY), - 2000, 100000, false, dsi, TXVMSR); - if (ret < 0) { - dev_err(dsi->dev, "Failed to assert video FIFO clear\n"); - return; - } -} - -/* ----------------------------------------------------------------------------- - * Bridge - */ - -static int rcar_mipi_dsi_attach(struct drm_bridge *bridge, - enum drm_bridge_attach_flags flags) -{ - struct rcar_mipi_dsi *dsi = bridge_to_rcar_mipi_dsi(bridge); - - return drm_bridge_attach(bridge->encoder, dsi->next_bridge, bridge, - flags); -} - -static void rcar_mipi_dsi_atomic_enable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) -{ - struct rcar_mipi_dsi *dsi = bridge_to_rcar_mipi_dsi(bridge); - - rcar_mipi_dsi_start_video(dsi); -} - -static void rcar_mipi_dsi_atomic_disable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) -{ - struct rcar_mipi_dsi *dsi = bridge_to_rcar_mipi_dsi(bridge); - - rcar_mipi_dsi_stop_video(dsi); -} - -void rcar_mipi_dsi_pclk_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) -{ - struct rcar_mipi_dsi *dsi = bridge_to_rcar_mipi_dsi(bridge); - const struct drm_display_mode *mode; - struct drm_connector *connector; - struct drm_crtc *crtc; - int ret; - - connector = drm_atomic_get_new_connector_for_encoder(state, - bridge->encoder); - crtc = drm_atomic_get_new_connector_state(state, connector)->crtc; - mode = &drm_atomic_get_new_crtc_state(state, crtc)->adjusted_mode; - - ret = rcar_mipi_dsi_clk_enable(dsi); - if (ret < 0) { - dev_err(dsi->dev, "failed to enable DSI clocks\n"); - return; - } - - ret = rcar_mipi_dsi_startup(dsi, mode); - if (ret < 0) - goto err_dsi_startup; - - rcar_mipi_dsi_set_display_timing(dsi, mode); - - ret = rcar_mipi_dsi_start_hs_clock(dsi); - if (ret < 0) - goto err_dsi_start_hs; - - return; - -err_dsi_start_hs: - rcar_mipi_dsi_shutdown(dsi); -err_dsi_startup: - rcar_mipi_dsi_clk_disable(dsi); -} -EXPORT_SYMBOL_GPL(rcar_mipi_dsi_pclk_enable); - -void rcar_mipi_dsi_pclk_disable(struct drm_bridge *bridge) -{ - struct rcar_mipi_dsi *dsi = bridge_to_rcar_mipi_dsi(bridge); - - rcar_mipi_dsi_shutdown(dsi); - rcar_mipi_dsi_clk_disable(dsi); -} -EXPORT_SYMBOL_GPL(rcar_mipi_dsi_pclk_disable); - -static enum drm_mode_status -rcar_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge, - const struct drm_display_info *info, - const struct drm_display_mode *mode) -{ - if (mode->clock > 297000) - return MODE_CLOCK_HIGH; - - return MODE_OK; -} - -static const struct drm_bridge_funcs rcar_mipi_dsi_bridge_ops = { - .attach = rcar_mipi_dsi_attach, - .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, - .atomic_reset = drm_atomic_helper_bridge_reset, - .atomic_enable = rcar_mipi_dsi_atomic_enable, - .atomic_disable = rcar_mipi_dsi_atomic_disable, - .mode_valid = rcar_mipi_dsi_bridge_mode_valid, -}; - -/* ----------------------------------------------------------------------------- - * Host setting - */ - -static int rcar_mipi_dsi_host_attach(struct mipi_dsi_host *host, - struct mipi_dsi_device *device) -{ - struct rcar_mipi_dsi *dsi = host_to_rcar_mipi_dsi(host); - int ret; - - if (device->lanes > dsi->num_data_lanes) - return -EINVAL; - - dsi->lanes = device->lanes; - dsi->format = device->format; - - dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, - 1, 0); - if (IS_ERR(dsi->next_bridge)) { - ret = PTR_ERR(dsi->next_bridge); - dev_err(dsi->dev, "failed to get next bridge: %d\n", ret); - return ret; - } - - /* Initialize the DRM bridge. */ - dsi->bridge.funcs = &rcar_mipi_dsi_bridge_ops; - dsi->bridge.of_node = dsi->dev->of_node; - drm_bridge_add(&dsi->bridge); - - return 0; -} - -static int rcar_mipi_dsi_host_detach(struct mipi_dsi_host *host, - struct mipi_dsi_device *device) -{ - struct rcar_mipi_dsi *dsi = host_to_rcar_mipi_dsi(host); - - drm_bridge_remove(&dsi->bridge); - - return 0; -} - -static const struct mipi_dsi_host_ops rcar_mipi_dsi_host_ops = { - .attach = rcar_mipi_dsi_host_attach, - .detach = rcar_mipi_dsi_host_detach, -}; - -/* ----------------------------------------------------------------------------- - * Probe & Remove - */ - -static int rcar_mipi_dsi_parse_dt(struct rcar_mipi_dsi *dsi) -{ - int ret; - - ret = drm_of_get_data_lanes_count_ep(dsi->dev->of_node, 1, 0, 1, 4); - if (ret < 0) { - dev_err(dsi->dev, "missing or invalid data-lanes property\n"); - return ret; - } - - dsi->num_data_lanes = ret; - return 0; -} - -static struct clk *rcar_mipi_dsi_get_clock(struct rcar_mipi_dsi *dsi, - const char *name, - bool optional) -{ - struct clk *clk; - - clk = devm_clk_get(dsi->dev, name); - if (!IS_ERR(clk)) - return clk; - - if (PTR_ERR(clk) == -ENOENT && optional) - return NULL; - - dev_err_probe(dsi->dev, PTR_ERR(clk), "failed to get %s clock\n", - name ? name : "module"); - - return clk; -} - -static int rcar_mipi_dsi_get_clocks(struct rcar_mipi_dsi *dsi) -{ - dsi->clocks.mod = rcar_mipi_dsi_get_clock(dsi, NULL, false); - if (IS_ERR(dsi->clocks.mod)) - return PTR_ERR(dsi->clocks.mod); - - dsi->clocks.pll = rcar_mipi_dsi_get_clock(dsi, "pll", true); - if (IS_ERR(dsi->clocks.pll)) - return PTR_ERR(dsi->clocks.pll); - - dsi->clocks.dsi = rcar_mipi_dsi_get_clock(dsi, "dsi", true); - if (IS_ERR(dsi->clocks.dsi)) - return PTR_ERR(dsi->clocks.dsi); - - if (!dsi->clocks.pll && !dsi->clocks.dsi) { - dev_err(dsi->dev, "no input clock (pll, dsi)\n"); - return -EINVAL; - } - - return 0; -} - -static int rcar_mipi_dsi_probe(struct platform_device *pdev) -{ - struct rcar_mipi_dsi *dsi; - struct resource *mem; - int ret; - - dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL); - if (dsi == NULL) - return -ENOMEM; - - platform_set_drvdata(pdev, dsi); - - dsi->dev = &pdev->dev; - dsi->info = of_device_get_match_data(&pdev->dev); - - ret = rcar_mipi_dsi_parse_dt(dsi); - if (ret < 0) - return ret; - - /* Acquire resources. */ - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dsi->mmio = devm_ioremap_resource(dsi->dev, mem); - if (IS_ERR(dsi->mmio)) - return PTR_ERR(dsi->mmio); - - ret = rcar_mipi_dsi_get_clocks(dsi); - if (ret < 0) - return ret; - - dsi->rstc = devm_reset_control_get(dsi->dev, NULL); - if (IS_ERR(dsi->rstc)) { - dev_err(dsi->dev, "failed to get cpg reset\n"); - return PTR_ERR(dsi->rstc); - } - - /* Initialize the DSI host. */ - dsi->host.dev = dsi->dev; - dsi->host.ops = &rcar_mipi_dsi_host_ops; - ret = mipi_dsi_host_register(&dsi->host); - if (ret < 0) - return ret; - - return 0; -} - -static int rcar_mipi_dsi_remove(struct platform_device *pdev) -{ - struct rcar_mipi_dsi *dsi = platform_get_drvdata(pdev); - - mipi_dsi_host_unregister(&dsi->host); - - return 0; -} - -static const struct rcar_mipi_dsi_device_info v3u_data = { - .model = RCAR_DSI_V3U, - .clk_cfg = dsi_clk_cfg_v3u, - .clockset2_m_offset = 2, - .n_min = 3, - .n_max = 8, - .n_mul = 1, - .fpfd_min = MHZ(2), - .fpfd_max = MHZ(8), - .m_min = 64, - .m_max = 625, - .fout_min = MHZ(320), - .fout_max = MHZ(1250), -}; - -static const struct rcar_mipi_dsi_device_info v4h_data = { - .model = RCAR_DSI_V4H, - .clk_cfg = dsi_clk_cfg_v4h, - .clockset2_m_offset = 0, - .n_min = 1, - .n_max = 8, - .n_mul = 2, - .fpfd_min = MHZ(8), - .fpfd_max = MHZ(24), - .m_min = 167, - .m_max = 1000, - .fout_min = MHZ(2000), - .fout_max = MHZ(4000), -}; - -static const struct of_device_id rcar_mipi_dsi_of_table[] = { - { .compatible = "renesas,r8a779a0-dsi-csi2-tx", .data = &v3u_data }, - { .compatible = "renesas,r8a779g0-dsi-csi2-tx", .data = &v4h_data }, - { } -}; - -MODULE_DEVICE_TABLE(of, rcar_mipi_dsi_of_table); - -static struct platform_driver rcar_mipi_dsi_platform_driver = { - .probe = rcar_mipi_dsi_probe, - .remove = rcar_mipi_dsi_remove, - .driver = { - .name = "rcar-mipi-dsi", - .of_match_table = rcar_mipi_dsi_of_table, - }, -}; - -module_platform_driver(rcar_mipi_dsi_platform_driver); - -MODULE_DESCRIPTION("Renesas R-Car MIPI DSI Encoder Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.h b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.h deleted file mode 100644 index 528a196e6edd..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * R-Car DSI Encoder - * - * Copyright (C) 2022 Renesas Electronics Corporation - * - * Contact: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> - */ - -#ifndef __RCAR_MIPI_DSI_H__ -#define __RCAR_MIPI_DSI_H__ - -struct drm_atomic_state; -struct drm_bridge; - -#if IS_ENABLED(CONFIG_DRM_RCAR_MIPI_DSI) -void rcar_mipi_dsi_pclk_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state); -void rcar_mipi_dsi_pclk_disable(struct drm_bridge *bridge); -#else -static inline void rcar_mipi_dsi_pclk_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) -{ -} - -static inline void rcar_mipi_dsi_pclk_disable(struct drm_bridge *bridge) -{ -} -#endif /* CONFIG_DRM_RCAR_MIPI_DSI */ - -#endif /* __RCAR_MIPI_DSI_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h deleted file mode 100644 index f8114d11f2d1..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h +++ /dev/null @@ -1,176 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * R-Car MIPI DSI Interface Registers Definitions - * - * Copyright (C) 2020 Renesas Electronics Corporation - */ - -#ifndef __RCAR_MIPI_DSI_REGS_H__ -#define __RCAR_MIPI_DSI_REGS_H__ - -#define LINKSR 0x010 -#define LINKSR_LPBUSY (1 << 1) -#define LINKSR_HSBUSY (1 << 0) - -/* - * Video Mode Register - */ -#define TXVMSETR 0x180 -#define TXVMSETR_SYNSEQ_PULSES (0 << 16) -#define TXVMSETR_SYNSEQ_EVENTS (1 << 16) -#define TXVMSETR_VSTPM (1 << 15) -#define TXVMSETR_PIXWDTH (1 << 8) -#define TXVMSETR_VSEN_EN (1 << 4) -#define TXVMSETR_VSEN_DIS (0 << 4) -#define TXVMSETR_HFPBPEN_EN (1 << 2) -#define TXVMSETR_HFPBPEN_DIS (0 << 2) -#define TXVMSETR_HBPBPEN_EN (1 << 1) -#define TXVMSETR_HBPBPEN_DIS (0 << 1) -#define TXVMSETR_HSABPEN_EN (1 << 0) -#define TXVMSETR_HSABPEN_DIS (0 << 0) - -#define TXVMCR 0x190 -#define TXVMCR_VFCLR (1 << 12) -#define TXVMCR_EN_VIDEO (1 << 0) - -#define TXVMSR 0x1a0 -#define TXVMSR_STR (1 << 16) -#define TXVMSR_VFRDY (1 << 12) -#define TXVMSR_ACT (1 << 8) -#define TXVMSR_RDY (1 << 0) - -#define TXVMSCR 0x1a4 -#define TXVMSCR_STR (1 << 16) - -#define TXVMPSPHSETR 0x1c0 -#define TXVMPSPHSETR_DT_RGB16 (0x0e << 16) -#define TXVMPSPHSETR_DT_RGB18 (0x1e << 16) -#define TXVMPSPHSETR_DT_RGB18_LS (0x2e << 16) -#define TXVMPSPHSETR_DT_RGB24 (0x3e << 16) -#define TXVMPSPHSETR_DT_YCBCR16 (0x2c << 16) - -#define TXVMVPRMSET0R 0x1d0 -#define TXVMVPRMSET0R_HSPOL_HIG (0 << 17) -#define TXVMVPRMSET0R_HSPOL_LOW (1 << 17) -#define TXVMVPRMSET0R_VSPOL_HIG (0 << 16) -#define TXVMVPRMSET0R_VSPOL_LOW (1 << 16) -#define TXVMVPRMSET0R_CSPC_RGB (0 << 4) -#define TXVMVPRMSET0R_CSPC_YCbCr (1 << 4) -#define TXVMVPRMSET0R_BPP_16 (0 << 0) -#define TXVMVPRMSET0R_BPP_18 (1 << 0) -#define TXVMVPRMSET0R_BPP_24 (2 << 0) - -#define TXVMVPRMSET1R 0x1d4 -#define TXVMVPRMSET1R_VACTIVE(x) (((x) & 0x7fff) << 16) -#define TXVMVPRMSET1R_VSA(x) (((x) & 0xfff) << 0) - -#define TXVMVPRMSET2R 0x1d8 -#define TXVMVPRMSET2R_VFP(x) (((x) & 0x1fff) << 16) -#define TXVMVPRMSET2R_VBP(x) (((x) & 0x1fff) << 0) - -#define TXVMVPRMSET3R 0x1dc -#define TXVMVPRMSET3R_HACTIVE(x) (((x) & 0x7fff) << 16) -#define TXVMVPRMSET3R_HSA(x) (((x) & 0xfff) << 0) - -#define TXVMVPRMSET4R 0x1e0 -#define TXVMVPRMSET4R_HFP(x) (((x) & 0x1fff) << 16) -#define TXVMVPRMSET4R_HBP(x) (((x) & 0x1fff) << 0) - -/* - * PHY-Protocol Interface (PPI) Registers - */ -#define PPISETR 0x700 -#define PPISETR_DLEN_0 (0x1 << 0) -#define PPISETR_DLEN_1 (0x3 << 0) -#define PPISETR_DLEN_2 (0x7 << 0) -#define PPISETR_DLEN_3 (0xf << 0) -#define PPISETR_CLEN (1 << 8) - -#define PPICLCR 0x710 -#define PPICLCR_TXREQHS (1 << 8) -#define PPICLCR_TXULPSEXT (1 << 1) -#define PPICLCR_TXULPSCLK (1 << 0) - -#define PPICLSR 0x720 -#define PPICLSR_HSTOLP (1 << 27) -#define PPICLSR_TOHS (1 << 26) -#define PPICLSR_STPST (1 << 0) - -#define PPICLSCR 0x724 -#define PPICLSCR_HSTOLP (1 << 27) -#define PPICLSCR_TOHS (1 << 26) - -#define PPIDLSR 0x760 -#define PPIDLSR_STPST (0xf << 0) - -/* - * Clocks registers - */ -#define LPCLKSET 0x1000 -#define LPCLKSET_CKEN (1 << 8) -#define LPCLKSET_LPCLKDIV(x) (((x) & 0x3f) << 0) - -#define CFGCLKSET 0x1004 -#define CFGCLKSET_CKEN (1 << 8) -#define CFGCLKSET_CFGCLKDIV(x) (((x) & 0x3f) << 0) - -#define DOTCLKDIV 0x1008 -#define DOTCLKDIV_CKEN (1 << 8) -#define DOTCLKDIV_DOTCLKDIV(x) (((x) & 0x3f) << 0) - -#define VCLKSET 0x100c -#define VCLKSET_CKEN (1 << 16) -#define VCLKSET_COLOR_RGB (0 << 8) -#define VCLKSET_COLOR_YCC (1 << 8) -#define VCLKSET_DIV_V3U(x) (((x) & 0x3) << 4) -#define VCLKSET_DIV_V4H(x) (((x) & 0x7) << 4) -#define VCLKSET_BPP_16 (0 << 2) -#define VCLKSET_BPP_18 (1 << 2) -#define VCLKSET_BPP_18L (2 << 2) -#define VCLKSET_BPP_24 (3 << 2) -#define VCLKSET_LANE(x) (((x) & 0x3) << 0) - -#define VCLKEN 0x1010 -#define VCLKEN_CKEN (1 << 0) - -#define PHYSETUP 0x1014 -#define PHYSETUP_HSFREQRANGE(x) (((x) & 0x7f) << 16) -#define PHYSETUP_HSFREQRANGE_MASK (0x7f << 16) -#define PHYSETUP_CFGCLKFREQRANGE(x) (((x) & 0x3f) << 8) -#define PHYSETUP_SHUTDOWNZ (1 << 1) -#define PHYSETUP_RSTZ (1 << 0) - -#define CLOCKSET1 0x101c -#define CLOCKSET1_LOCK_PHY (1 << 17) -#define CLOCKSET1_LOCK (1 << 16) -#define CLOCKSET1_CLKSEL (1 << 8) -#define CLOCKSET1_CLKINSEL_EXTAL (0 << 2) -#define CLOCKSET1_CLKINSEL_DIG (1 << 2) -#define CLOCKSET1_CLKINSEL_DU (1 << 3) -#define CLOCKSET1_SHADOW_CLEAR (1 << 1) -#define CLOCKSET1_UPDATEPLL (1 << 0) - -#define CLOCKSET2 0x1020 -#define CLOCKSET2_M(x) (((x) & 0xfff) << 16) -#define CLOCKSET2_VCO_CNTRL(x) (((x) & 0x3f) << 8) -#define CLOCKSET2_N(x) (((x) & 0xf) << 0) - -#define CLOCKSET3 0x1024 -#define CLOCKSET3_PROP_CNTRL(x) (((x) & 0x3f) << 24) -#define CLOCKSET3_INT_CNTRL(x) (((x) & 0x3f) << 16) -#define CLOCKSET3_CPBIAS_CNTRL(x) (((x) & 0x7f) << 8) -#define CLOCKSET3_GMP_CNTRL(x) (((x) & 0x3) << 0) - -#define PHTW 0x1034 -#define PHTW_DWEN (1 << 24) -#define PHTW_TESTDIN_DATA(x) (((x) & 0xff) << 16) -#define PHTW_CWEN (1 << 8) -#define PHTW_TESTDIN_CODE(x) (((x) & 0xff) << 0) - -#define PHTR 0x1038 -#define PHTR_TEST (1 << 16) - -#define PHTC 0x103c -#define PHTC_TESTCLR (1 << 0) - -#endif /* __RCAR_MIPI_DSI_REGS_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi.c deleted file mode 100644 index aa95b85a2964..000000000000 --- a/drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi.c +++ /dev/null @@ -1,816 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * RZ/G2L MIPI DSI Encoder Driver - * - * Copyright (C) 2022 Renesas Electronics Corporation - */ -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/iopoll.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_graph.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> -#include <linux/reset.h> -#include <linux/slab.h> - -#include <drm/drm_atomic.h> -#include <drm/drm_atomic_helper.h> -#include <drm/drm_bridge.h> -#include <drm/drm_mipi_dsi.h> -#include <drm/drm_of.h> -#include <drm/drm_panel.h> -#include <drm/drm_probe_helper.h> - -#include "rzg2l_mipi_dsi_regs.h" - -struct rzg2l_mipi_dsi { - struct device *dev; - void __iomem *mmio; - - struct reset_control *rstc; - struct reset_control *arstc; - struct reset_control *prstc; - - struct mipi_dsi_host host; - struct drm_bridge bridge; - struct drm_bridge *next_bridge; - - struct clk *vclk; - - enum mipi_dsi_pixel_format format; - unsigned int num_data_lanes; - unsigned int lanes; - unsigned long mode_flags; -}; - -static inline struct rzg2l_mipi_dsi * -bridge_to_rzg2l_mipi_dsi(struct drm_bridge *bridge) -{ - return container_of(bridge, struct rzg2l_mipi_dsi, bridge); -} - -static inline struct rzg2l_mipi_dsi * -host_to_rzg2l_mipi_dsi(struct mipi_dsi_host *host) -{ - return container_of(host, struct rzg2l_mipi_dsi, host); -} - -struct rzg2l_mipi_dsi_timings { - unsigned long hsfreq_max; - u32 t_init; - u32 tclk_prepare; - u32 ths_prepare; - u32 tclk_zero; - u32 tclk_pre; - u32 tclk_post; - u32 tclk_trail; - u32 ths_zero; - u32 ths_trail; - u32 ths_exit; - u32 tlpx; -}; - -static const struct rzg2l_mipi_dsi_timings rzg2l_mipi_dsi_global_timings[] = { - { - .hsfreq_max = 80000, - .t_init = 79801, - .tclk_prepare = 8, - .ths_prepare = 13, - .tclk_zero = 33, - .tclk_pre = 24, - .tclk_post = 94, - .tclk_trail = 10, - .ths_zero = 23, - .ths_trail = 17, - .ths_exit = 13, - .tlpx = 6, - }, - { - .hsfreq_max = 125000, - .t_init = 79801, - .tclk_prepare = 8, - .ths_prepare = 12, - .tclk_zero = 33, - .tclk_pre = 15, - .tclk_post = 94, - .tclk_trail = 10, - .ths_zero = 23, - .ths_trail = 17, - .ths_exit = 13, - .tlpx = 6, - }, - { - .hsfreq_max = 250000, - .t_init = 79801, - .tclk_prepare = 8, - .ths_prepare = 12, - .tclk_zero = 33, - .tclk_pre = 13, - .tclk_post = 94, - .tclk_trail = 10, - .ths_zero = 23, - .ths_trail = 16, - .ths_exit = 13, - .tlpx = 6, - }, - { - .hsfreq_max = 360000, - .t_init = 79801, - .tclk_prepare = 8, - .ths_prepare = 10, - .tclk_zero = 33, - .tclk_pre = 4, - .tclk_post = 35, - .tclk_trail = 7, - .ths_zero = 16, - .ths_trail = 9, - .ths_exit = 13, - .tlpx = 6, - }, - { - .hsfreq_max = 720000, - .t_init = 79801, - .tclk_prepare = 8, - .ths_prepare = 9, - .tclk_zero = 33, - .tclk_pre = 4, - .tclk_post = 35, - .tclk_trail = 7, - .ths_zero = 16, - .ths_trail = 9, - .ths_exit = 13, - .tlpx = 6, - }, - { - .hsfreq_max = 1500000, - .t_init = 79801, - .tclk_prepare = 8, - .ths_prepare = 9, - .tclk_zero = 33, - .tclk_pre = 4, - .tclk_post = 35, - .tclk_trail = 7, - .ths_zero = 16, - .ths_trail = 9, - .ths_exit = 13, - .tlpx = 6, - }, -}; - -static void rzg2l_mipi_dsi_phy_write(struct rzg2l_mipi_dsi *dsi, u32 reg, u32 data) -{ - iowrite32(data, dsi->mmio + reg); -} - -static void rzg2l_mipi_dsi_link_write(struct rzg2l_mipi_dsi *dsi, u32 reg, u32 data) -{ - iowrite32(data, dsi->mmio + LINK_REG_OFFSET + reg); -} - -static u32 rzg2l_mipi_dsi_phy_read(struct rzg2l_mipi_dsi *dsi, u32 reg) -{ - return ioread32(dsi->mmio + reg); -} - -static u32 rzg2l_mipi_dsi_link_read(struct rzg2l_mipi_dsi *dsi, u32 reg) -{ - return ioread32(dsi->mmio + LINK_REG_OFFSET + reg); -} - -/* ----------------------------------------------------------------------------- - * Hardware Setup - */ - -static int rzg2l_mipi_dsi_dphy_init(struct rzg2l_mipi_dsi *dsi, - unsigned long hsfreq) -{ - const struct rzg2l_mipi_dsi_timings *dphy_timings; - unsigned int i; - u32 dphyctrl0; - u32 dphytim0; - u32 dphytim1; - u32 dphytim2; - u32 dphytim3; - int ret; - - /* All DSI global operation timings are set with recommended setting */ - for (i = 0; i < ARRAY_SIZE(rzg2l_mipi_dsi_global_timings); ++i) { - dphy_timings = &rzg2l_mipi_dsi_global_timings[i]; - if (hsfreq <= dphy_timings->hsfreq_max) - break; - } - - /* Initializing DPHY before accessing LINK */ - dphyctrl0 = DSIDPHYCTRL0_CAL_EN_HSRX_OFS | DSIDPHYCTRL0_CMN_MASTER_EN | - DSIDPHYCTRL0_RE_VDD_DETVCCQLV18 | DSIDPHYCTRL0_EN_BGR; - - rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYCTRL0, dphyctrl0); - usleep_range(20, 30); - - dphyctrl0 |= DSIDPHYCTRL0_EN_LDO1200; - rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYCTRL0, dphyctrl0); - usleep_range(10, 20); - - dphytim0 = DSIDPHYTIM0_TCLK_MISS(0) | - DSIDPHYTIM0_T_INIT(dphy_timings->t_init); - dphytim1 = DSIDPHYTIM1_THS_PREPARE(dphy_timings->ths_prepare) | - DSIDPHYTIM1_TCLK_PREPARE(dphy_timings->tclk_prepare) | - DSIDPHYTIM1_THS_SETTLE(0) | - DSIDPHYTIM1_TCLK_SETTLE(0); - dphytim2 = DSIDPHYTIM2_TCLK_TRAIL(dphy_timings->tclk_trail) | - DSIDPHYTIM2_TCLK_POST(dphy_timings->tclk_post) | - DSIDPHYTIM2_TCLK_PRE(dphy_timings->tclk_pre) | - DSIDPHYTIM2_TCLK_ZERO(dphy_timings->tclk_zero); - dphytim3 = DSIDPHYTIM3_TLPX(dphy_timings->tlpx) | - DSIDPHYTIM3_THS_EXIT(dphy_timings->ths_exit) | - DSIDPHYTIM3_THS_TRAIL(dphy_timings->ths_trail) | - DSIDPHYTIM3_THS_ZERO(dphy_timings->ths_zero); - - rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYTIM0, dphytim0); - rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYTIM1, dphytim1); - rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYTIM2, dphytim2); - rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYTIM3, dphytim3); - - ret = reset_control_deassert(dsi->rstc); - if (ret < 0) - return ret; - - udelay(1); - - return 0; -} - -static void rzg2l_mipi_dsi_dphy_exit(struct rzg2l_mipi_dsi *dsi) -{ - u32 dphyctrl0; - - dphyctrl0 = rzg2l_mipi_dsi_phy_read(dsi, DSIDPHYCTRL0); - - dphyctrl0 &= ~(DSIDPHYCTRL0_EN_LDO1200 | DSIDPHYCTRL0_EN_BGR); - rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYCTRL0, dphyctrl0); - - reset_control_assert(dsi->rstc); -} - -static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi, - const struct drm_display_mode *mode) -{ - unsigned long hsfreq; - unsigned int bpp; - u32 txsetr; - u32 clstptsetr; - u32 lptrnstsetr; - u32 clkkpt; - u32 clkbfht; - u32 clkstpt; - u32 golpbkt; - int ret; - - /* - * Relationship between hsclk and vclk must follow - * vclk * bpp = hsclk * 8 * lanes - * where vclk: video clock (Hz) - * bpp: video pixel bit depth - * hsclk: DSI HS Byte clock frequency (Hz) - * lanes: number of data lanes - * - * hsclk(bit) = hsclk(byte) * 8 - */ - bpp = mipi_dsi_pixel_format_to_bpp(dsi->format); - hsfreq = (mode->clock * bpp * 8) / (8 * dsi->lanes); - - ret = pm_runtime_resume_and_get(dsi->dev); - if (ret < 0) - return ret; - - clk_set_rate(dsi->vclk, mode->clock * 1000); - - ret = rzg2l_mipi_dsi_dphy_init(dsi, hsfreq); - if (ret < 0) - goto err_phy; - - /* Enable Data lanes and Clock lanes */ - txsetr = TXSETR_DLEN | TXSETR_NUMLANEUSE(dsi->lanes - 1) | TXSETR_CLEN; - rzg2l_mipi_dsi_link_write(dsi, TXSETR, txsetr); - - /* - * Global timings characteristic depends on high speed Clock Frequency - * Currently MIPI DSI-IF just supports maximum FHD@60 with: - * - videoclock = 148.5 (MHz) - * - bpp: maximum 24bpp - * - data lanes: maximum 4 lanes - * Therefore maximum hsclk will be 891 Mbps. - */ - if (hsfreq > 445500) { - clkkpt = 12; - clkbfht = 15; - clkstpt = 48; - golpbkt = 75; - } else if (hsfreq > 250000) { - clkkpt = 7; - clkbfht = 8; - clkstpt = 27; - golpbkt = 40; - } else { - clkkpt = 8; - clkbfht = 6; - clkstpt = 24; - golpbkt = 29; - } - - clstptsetr = CLSTPTSETR_CLKKPT(clkkpt) | CLSTPTSETR_CLKBFHT(clkbfht) | - CLSTPTSETR_CLKSTPT(clkstpt); - rzg2l_mipi_dsi_link_write(dsi, CLSTPTSETR, clstptsetr); - - lptrnstsetr = LPTRNSTSETR_GOLPBKT(golpbkt); - rzg2l_mipi_dsi_link_write(dsi, LPTRNSTSETR, lptrnstsetr); - - return 0; - -err_phy: - rzg2l_mipi_dsi_dphy_exit(dsi); - pm_runtime_put(dsi->dev); - - return ret; -} - -static void rzg2l_mipi_dsi_stop(struct rzg2l_mipi_dsi *dsi) -{ - rzg2l_mipi_dsi_dphy_exit(dsi); - pm_runtime_put(dsi->dev); -} - -static void rzg2l_mipi_dsi_set_display_timing(struct rzg2l_mipi_dsi *dsi, - const struct drm_display_mode *mode) -{ - u32 vich1ppsetr; - u32 vich1vssetr; - u32 vich1vpsetr; - u32 vich1hssetr; - u32 vich1hpsetr; - int dsi_format; - u32 delay[2]; - u8 index; - - /* Configuration for Pixel Packet */ - dsi_format = mipi_dsi_pixel_format_to_bpp(dsi->format); - switch (dsi_format) { - case 24: - vich1ppsetr = VICH1PPSETR_DT_RGB24; - break; - case 18: - vich1ppsetr = VICH1PPSETR_DT_RGB18; - break; - } - - if ((dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) && - !(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)) - vich1ppsetr |= VICH1PPSETR_TXESYNC_PULSE; - - rzg2l_mipi_dsi_link_write(dsi, VICH1PPSETR, vich1ppsetr); - - /* Configuration for Video Parameters */ - vich1vssetr = VICH1VSSETR_VACTIVE(mode->vdisplay) | - VICH1VSSETR_VSA(mode->vsync_end - mode->vsync_start); - vich1vssetr |= (mode->flags & DRM_MODE_FLAG_PVSYNC) ? - VICH1VSSETR_VSPOL_HIGH : VICH1VSSETR_VSPOL_LOW; - - vich1vpsetr = VICH1VPSETR_VFP(mode->vsync_start - mode->vdisplay) | - VICH1VPSETR_VBP(mode->vtotal - mode->vsync_end); - - vich1hssetr = VICH1HSSETR_HACTIVE(mode->hdisplay) | - VICH1HSSETR_HSA(mode->hsync_end - mode->hsync_start); - vich1hssetr |= (mode->flags & DRM_MODE_FLAG_PHSYNC) ? - VICH1HSSETR_HSPOL_HIGH : VICH1HSSETR_HSPOL_LOW; - - vich1hpsetr = VICH1HPSETR_HFP(mode->hsync_start - mode->hdisplay) | - VICH1HPSETR_HBP(mode->htotal - mode->hsync_end); - - rzg2l_mipi_dsi_link_write(dsi, VICH1VSSETR, vich1vssetr); - rzg2l_mipi_dsi_link_write(dsi, VICH1VPSETR, vich1vpsetr); - rzg2l_mipi_dsi_link_write(dsi, VICH1HSSETR, vich1hssetr); - rzg2l_mipi_dsi_link_write(dsi, VICH1HPSETR, vich1hpsetr); - - /* - * Configuration for Delay Value - * Delay value based on 2 ranges of video clock. - * 74.25MHz is videoclock of HD@60p or FHD@30p - */ - if (mode->clock > 74250) { - delay[0] = 231; - delay[1] = 216; - } else { - delay[0] = 220; - delay[1] = 212; - } - - if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) - index = 0; - else - index = 1; - - rzg2l_mipi_dsi_link_write(dsi, VICH1SET1R, - VICH1SET1R_DLY(delay[index])); -} - -static int rzg2l_mipi_dsi_start_hs_clock(struct rzg2l_mipi_dsi *dsi) -{ - bool is_clk_cont; - u32 hsclksetr; - u32 status; - int ret; - - is_clk_cont = !(dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS); - - /* Start HS clock */ - hsclksetr = HSCLKSETR_HSCLKRUN_HS | (is_clk_cont ? - HSCLKSETR_HSCLKMODE_CONT : - HSCLKSETR_HSCLKMODE_NON_CONT); - rzg2l_mipi_dsi_link_write(dsi, HSCLKSETR, hsclksetr); - - if (is_clk_cont) { - ret = read_poll_timeout(rzg2l_mipi_dsi_link_read, status, - status & PLSR_CLLP2HS, - 2000, 20000, false, dsi, PLSR); - if (ret < 0) { - dev_err(dsi->dev, "failed to start HS clock\n"); - return ret; - } - } - - dev_dbg(dsi->dev, "Start High Speed Clock with %s clock mode", - is_clk_cont ? "continuous" : "non-continuous"); - - return 0; -} - -static int rzg2l_mipi_dsi_stop_hs_clock(struct rzg2l_mipi_dsi *dsi) -{ - bool is_clk_cont; - u32 status; - int ret; - - is_clk_cont = !(dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS); - - /* Stop HS clock */ - rzg2l_mipi_dsi_link_write(dsi, HSCLKSETR, - is_clk_cont ? HSCLKSETR_HSCLKMODE_CONT : - HSCLKSETR_HSCLKMODE_NON_CONT); - - if (is_clk_cont) { - ret = read_poll_timeout(rzg2l_mipi_dsi_link_read, status, - status & PLSR_CLHS2LP, - 2000, 20000, false, dsi, PLSR); - if (ret < 0) { - dev_err(dsi->dev, "failed to stop HS clock\n"); - return ret; - } - } - - return 0; -} - -static int rzg2l_mipi_dsi_start_video(struct rzg2l_mipi_dsi *dsi) -{ - u32 vich1set0r; - u32 status; - int ret; - - /* Configuration for Blanking sequence and start video input*/ - vich1set0r = VICH1SET0R_HFPNOLP | VICH1SET0R_HBPNOLP | - VICH1SET0R_HSANOLP | VICH1SET0R_VSTART; - rzg2l_mipi_dsi_link_write(dsi, VICH1SET0R, vich1set0r); - - ret = read_poll_timeout(rzg2l_mipi_dsi_link_read, status, - status & VICH1SR_VIRDY, - 2000, 20000, false, dsi, VICH1SR); - if (ret < 0) - dev_err(dsi->dev, "Failed to start video signal input\n"); - - return ret; -} - -static int rzg2l_mipi_dsi_stop_video(struct rzg2l_mipi_dsi *dsi) -{ - u32 status; - int ret; - - rzg2l_mipi_dsi_link_write(dsi, VICH1SET0R, VICH1SET0R_VSTPAFT); - ret = read_poll_timeout(rzg2l_mipi_dsi_link_read, status, - (status & VICH1SR_STOP) && (!(status & VICH1SR_RUNNING)), - 2000, 20000, false, dsi, VICH1SR); - if (ret < 0) - goto err; - - ret = read_poll_timeout(rzg2l_mipi_dsi_link_read, status, - !(status & LINKSR_HSBUSY), - 2000, 20000, false, dsi, LINKSR); - if (ret < 0) - goto err; - - return 0; - -err: - dev_err(dsi->dev, "Failed to stop video signal input\n"); - return ret; -} - -/* ----------------------------------------------------------------------------- - * Bridge - */ - -static int rzg2l_mipi_dsi_attach(struct drm_bridge *bridge, - enum drm_bridge_attach_flags flags) -{ - struct rzg2l_mipi_dsi *dsi = bridge_to_rzg2l_mipi_dsi(bridge); - - return drm_bridge_attach(bridge->encoder, dsi->next_bridge, bridge, - flags); -} - -static void rzg2l_mipi_dsi_atomic_enable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) -{ - struct drm_atomic_state *state = old_bridge_state->base.state; - struct rzg2l_mipi_dsi *dsi = bridge_to_rzg2l_mipi_dsi(bridge); - const struct drm_display_mode *mode; - struct drm_connector *connector; - struct drm_crtc *crtc; - int ret; - - connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); - crtc = drm_atomic_get_new_connector_state(state, connector)->crtc; - mode = &drm_atomic_get_new_crtc_state(state, crtc)->adjusted_mode; - - ret = rzg2l_mipi_dsi_startup(dsi, mode); - if (ret < 0) - return; - - rzg2l_mipi_dsi_set_display_timing(dsi, mode); - - ret = rzg2l_mipi_dsi_start_hs_clock(dsi); - if (ret < 0) - goto err_stop; - - ret = rzg2l_mipi_dsi_start_video(dsi); - if (ret < 0) - goto err_stop_clock; - - return; - -err_stop_clock: - rzg2l_mipi_dsi_stop_hs_clock(dsi); -err_stop: - rzg2l_mipi_dsi_stop(dsi); -} - -static void rzg2l_mipi_dsi_atomic_disable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) -{ - struct rzg2l_mipi_dsi *dsi = bridge_to_rzg2l_mipi_dsi(bridge); - - rzg2l_mipi_dsi_stop_video(dsi); - rzg2l_mipi_dsi_stop_hs_clock(dsi); - rzg2l_mipi_dsi_stop(dsi); -} - -static enum drm_mode_status -rzg2l_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge, - const struct drm_display_info *info, - const struct drm_display_mode *mode) -{ - if (mode->clock > 148500) - return MODE_CLOCK_HIGH; - - return MODE_OK; -} - -static const struct drm_bridge_funcs rzg2l_mipi_dsi_bridge_ops = { - .attach = rzg2l_mipi_dsi_attach, - .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, - .atomic_reset = drm_atomic_helper_bridge_reset, - .atomic_enable = rzg2l_mipi_dsi_atomic_enable, - .atomic_disable = rzg2l_mipi_dsi_atomic_disable, - .mode_valid = rzg2l_mipi_dsi_bridge_mode_valid, -}; - -/* ----------------------------------------------------------------------------- - * Host setting - */ - -static int rzg2l_mipi_dsi_host_attach(struct mipi_dsi_host *host, - struct mipi_dsi_device *device) -{ - struct rzg2l_mipi_dsi *dsi = host_to_rzg2l_mipi_dsi(host); - int ret; - - if (device->lanes > dsi->num_data_lanes) { - dev_err(dsi->dev, - "Number of lines of device (%u) exceeds host (%u)\n", - device->lanes, dsi->num_data_lanes); - return -EINVAL; - } - - switch (mipi_dsi_pixel_format_to_bpp(device->format)) { - case 24: - case 18: - break; - default: - dev_err(dsi->dev, "Unsupported format 0x%04x\n", device->format); - return -EINVAL; - } - - dsi->lanes = device->lanes; - dsi->format = device->format; - dsi->mode_flags = device->mode_flags; - - dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, - 1, 0); - if (IS_ERR(dsi->next_bridge)) { - ret = PTR_ERR(dsi->next_bridge); - dev_err(dsi->dev, "failed to get next bridge: %d\n", ret); - return ret; - } - - drm_bridge_add(&dsi->bridge); - - return 0; -} - -static int rzg2l_mipi_dsi_host_detach(struct mipi_dsi_host *host, - struct mipi_dsi_device *device) -{ - struct rzg2l_mipi_dsi *dsi = host_to_rzg2l_mipi_dsi(host); - - drm_bridge_remove(&dsi->bridge); - - return 0; -} - -static const struct mipi_dsi_host_ops rzg2l_mipi_dsi_host_ops = { - .attach = rzg2l_mipi_dsi_host_attach, - .detach = rzg2l_mipi_dsi_host_detach, -}; - -/* ----------------------------------------------------------------------------- - * Power Management - */ - -static int __maybe_unused rzg2l_mipi_pm_runtime_suspend(struct device *dev) -{ - struct rzg2l_mipi_dsi *dsi = dev_get_drvdata(dev); - - reset_control_assert(dsi->prstc); - reset_control_assert(dsi->arstc); - - return 0; -} - -static int __maybe_unused rzg2l_mipi_pm_runtime_resume(struct device *dev) -{ - struct rzg2l_mipi_dsi *dsi = dev_get_drvdata(dev); - int ret; - - ret = reset_control_deassert(dsi->arstc); - if (ret < 0) - return ret; - - ret = reset_control_deassert(dsi->prstc); - if (ret < 0) - reset_control_assert(dsi->arstc); - - return ret; -} - -static const struct dev_pm_ops rzg2l_mipi_pm_ops = { - SET_RUNTIME_PM_OPS(rzg2l_mipi_pm_runtime_suspend, rzg2l_mipi_pm_runtime_resume, NULL) -}; - -/* ----------------------------------------------------------------------------- - * Probe & Remove - */ - -static int rzg2l_mipi_dsi_probe(struct platform_device *pdev) -{ - unsigned int num_data_lanes; - struct rzg2l_mipi_dsi *dsi; - u32 txsetr; - int ret; - - dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL); - if (!dsi) - return -ENOMEM; - - platform_set_drvdata(pdev, dsi); - dsi->dev = &pdev->dev; - - ret = drm_of_get_data_lanes_count_ep(dsi->dev->of_node, 1, 0, 1, 4); - if (ret < 0) - return dev_err_probe(dsi->dev, ret, - "missing or invalid data-lanes property\n"); - - num_data_lanes = ret; - - dsi->mmio = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(dsi->mmio)) - return PTR_ERR(dsi->mmio); - - dsi->vclk = devm_clk_get(dsi->dev, "vclk"); - if (IS_ERR(dsi->vclk)) - return PTR_ERR(dsi->vclk); - - dsi->rstc = devm_reset_control_get_exclusive(dsi->dev, "rst"); - if (IS_ERR(dsi->rstc)) - return dev_err_probe(dsi->dev, PTR_ERR(dsi->rstc), - "failed to get rst\n"); - - dsi->arstc = devm_reset_control_get_exclusive(dsi->dev, "arst"); - if (IS_ERR(dsi->arstc)) - return dev_err_probe(&pdev->dev, PTR_ERR(dsi->arstc), - "failed to get arst\n"); - - dsi->prstc = devm_reset_control_get_exclusive(dsi->dev, "prst"); - if (IS_ERR(dsi->prstc)) - return dev_err_probe(dsi->dev, PTR_ERR(dsi->prstc), - "failed to get prst\n"); - - platform_set_drvdata(pdev, dsi); - - pm_runtime_enable(dsi->dev); - - ret = pm_runtime_resume_and_get(dsi->dev); - if (ret < 0) - goto err_pm_disable; - - /* - * TXSETR register can be read only after DPHY init. But during probe - * mode->clock and format are not available. So initialize DPHY with - * timing parameters for 80Mbps. - */ - ret = rzg2l_mipi_dsi_dphy_init(dsi, 80000); - if (ret < 0) - goto err_phy; - - txsetr = rzg2l_mipi_dsi_link_read(dsi, TXSETR); - dsi->num_data_lanes = min(((txsetr >> 16) & 3) + 1, num_data_lanes); - rzg2l_mipi_dsi_dphy_exit(dsi); - pm_runtime_put(dsi->dev); - - /* Initialize the DRM bridge. */ - dsi->bridge.funcs = &rzg2l_mipi_dsi_bridge_ops; - dsi->bridge.of_node = dsi->dev->of_node; - - /* Init host device */ - dsi->host.dev = dsi->dev; - dsi->host.ops = &rzg2l_mipi_dsi_host_ops; - ret = mipi_dsi_host_register(&dsi->host); - if (ret < 0) - goto err_pm_disable; - - return 0; - -err_phy: - rzg2l_mipi_dsi_dphy_exit(dsi); - pm_runtime_put(dsi->dev); -err_pm_disable: - pm_runtime_disable(dsi->dev); - return ret; -} - -static int rzg2l_mipi_dsi_remove(struct platform_device *pdev) -{ - struct rzg2l_mipi_dsi *dsi = platform_get_drvdata(pdev); - - mipi_dsi_host_unregister(&dsi->host); - pm_runtime_disable(&pdev->dev); - - return 0; -} - -static const struct of_device_id rzg2l_mipi_dsi_of_table[] = { - { .compatible = "renesas,rzg2l-mipi-dsi" }, - { /* sentinel */ } -}; - -MODULE_DEVICE_TABLE(of, rzg2l_mipi_dsi_of_table); - -static struct platform_driver rzg2l_mipi_dsi_platform_driver = { - .probe = rzg2l_mipi_dsi_probe, - .remove = rzg2l_mipi_dsi_remove, - .driver = { - .name = "rzg2l-mipi-dsi", - .pm = &rzg2l_mipi_pm_ops, - .of_match_table = rzg2l_mipi_dsi_of_table, - }, -}; - -module_platform_driver(rzg2l_mipi_dsi_platform_driver); - -MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>"); -MODULE_DESCRIPTION("Renesas RZ/G2L MIPI DSI Encoder Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi_regs.h b/drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi_regs.h deleted file mode 100644 index 1dbc16ec64a4..000000000000 --- a/drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi_regs.h +++ /dev/null @@ -1,151 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * RZ/G2L MIPI DSI Interface Registers Definitions - * - * Copyright (C) 2022 Renesas Electronics Corporation - */ - -#ifndef __RZG2L_MIPI_DSI_REGS_H__ -#define __RZG2L_MIPI_DSI_REGS_H__ - -#include <linux/bits.h> - -/* DPHY Registers */ -#define DSIDPHYCTRL0 0x00 -#define DSIDPHYCTRL0_CAL_EN_HSRX_OFS BIT(16) -#define DSIDPHYCTRL0_CMN_MASTER_EN BIT(8) -#define DSIDPHYCTRL0_RE_VDD_DETVCCQLV18 BIT(2) -#define DSIDPHYCTRL0_EN_LDO1200 BIT(1) -#define DSIDPHYCTRL0_EN_BGR BIT(0) - -#define DSIDPHYTIM0 0x04 -#define DSIDPHYTIM0_TCLK_MISS(x) ((x) << 24) -#define DSIDPHYTIM0_T_INIT(x) ((x) << 0) - -#define DSIDPHYTIM1 0x08 -#define DSIDPHYTIM1_THS_PREPARE(x) ((x) << 24) -#define DSIDPHYTIM1_TCLK_PREPARE(x) ((x) << 16) -#define DSIDPHYTIM1_THS_SETTLE(x) ((x) << 8) -#define DSIDPHYTIM1_TCLK_SETTLE(x) ((x) << 0) - -#define DSIDPHYTIM2 0x0c -#define DSIDPHYTIM2_TCLK_TRAIL(x) ((x) << 24) -#define DSIDPHYTIM2_TCLK_POST(x) ((x) << 16) -#define DSIDPHYTIM2_TCLK_PRE(x) ((x) << 8) -#define DSIDPHYTIM2_TCLK_ZERO(x) ((x) << 0) - -#define DSIDPHYTIM3 0x10 -#define DSIDPHYTIM3_TLPX(x) ((x) << 24) -#define DSIDPHYTIM3_THS_EXIT(x) ((x) << 16) -#define DSIDPHYTIM3_THS_TRAIL(x) ((x) << 8) -#define DSIDPHYTIM3_THS_ZERO(x) ((x) << 0) - -/* --------------------------------------------------------*/ -/* Link Registers */ -#define LINK_REG_OFFSET 0x10000 - -/* Link Status Register */ -#define LINKSR 0x10 -#define LINKSR_LPBUSY BIT(13) -#define LINKSR_HSBUSY BIT(12) -#define LINKSR_VICHRUN1 BIT(8) -#define LINKSR_SQCHRUN1 BIT(4) -#define LINKSR_SQCHRUN0 BIT(0) - -/* Tx Set Register */ -#define TXSETR 0x100 -#define TXSETR_NUMLANECAP (0x3 << 16) -#define TXSETR_DLEN (1 << 9) -#define TXSETR_CLEN (1 << 8) -#define TXSETR_NUMLANEUSE(x) (((x) & 0x3) << 0) - -/* HS Clock Set Register */ -#define HSCLKSETR 0x104 -#define HSCLKSETR_HSCLKMODE_CONT (1 << 1) -#define HSCLKSETR_HSCLKMODE_NON_CONT (0 << 1) -#define HSCLKSETR_HSCLKRUN_HS (1 << 0) -#define HSCLKSETR_HSCLKRUN_LP (0 << 0) - -/* Reset Control Register */ -#define RSTCR 0x110 -#define RSTCR_SWRST BIT(0) -#define RSTCR_FCETXSTP BIT(16) - -/* Reset Status Register */ -#define RSTSR 0x114 -#define RSTSR_DL0DIR (1 << 15) -#define RSTSR_DLSTPST (0xf << 8) -#define RSTSR_SWRSTV1 (1 << 4) -#define RSTSR_SWRSTIB (1 << 3) -#define RSTSR_SWRSTAPB (1 << 2) -#define RSTSR_SWRSTLP (1 << 1) -#define RSTSR_SWRSTHS (1 << 0) - -/* Clock Lane Stop Time Set Register */ -#define CLSTPTSETR 0x314 -#define CLSTPTSETR_CLKKPT(x) ((x) << 24) -#define CLSTPTSETR_CLKBFHT(x) ((x) << 16) -#define CLSTPTSETR_CLKSTPT(x) ((x) << 2) - -/* LP Transition Time Set Register */ -#define LPTRNSTSETR 0x318 -#define LPTRNSTSETR_GOLPBKT(x) ((x) << 0) - -/* Physical Lane Status Register */ -#define PLSR 0x320 -#define PLSR_CLHS2LP BIT(27) -#define PLSR_CLLP2HS BIT(26) - -/* Video-Input Channel 1 Set 0 Register */ -#define VICH1SET0R 0x400 -#define VICH1SET0R_VSEN BIT(12) -#define VICH1SET0R_HFPNOLP BIT(10) -#define VICH1SET0R_HBPNOLP BIT(9) -#define VICH1SET0R_HSANOLP BIT(8) -#define VICH1SET0R_VSTPAFT BIT(1) -#define VICH1SET0R_VSTART BIT(0) - -/* Video-Input Channel 1 Set 1 Register */ -#define VICH1SET1R 0x404 -#define VICH1SET1R_DLY(x) (((x) & 0xfff) << 2) - -/* Video-Input Channel 1 Status Register */ -#define VICH1SR 0x410 -#define VICH1SR_VIRDY BIT(3) -#define VICH1SR_RUNNING BIT(2) -#define VICH1SR_STOP BIT(1) -#define VICH1SR_START BIT(0) - -/* Video-Input Channel 1 Pixel Packet Set Register */ -#define VICH1PPSETR 0x420 -#define VICH1PPSETR_DT_RGB18 (0x1e << 16) -#define VICH1PPSETR_DT_RGB18_LS (0x2e << 16) -#define VICH1PPSETR_DT_RGB24 (0x3e << 16) -#define VICH1PPSETR_TXESYNC_PULSE (1 << 15) -#define VICH1PPSETR_VC(x) ((x) << 22) - -/* Video-Input Channel 1 Vertical Size Set Register */ -#define VICH1VSSETR 0x428 -#define VICH1VSSETR_VACTIVE(x) (((x) & 0x7fff) << 16) -#define VICH1VSSETR_VSPOL_LOW (1 << 15) -#define VICH1VSSETR_VSPOL_HIGH (0 << 15) -#define VICH1VSSETR_VSA(x) (((x) & 0xfff) << 0) - -/* Video-Input Channel 1 Vertical Porch Set Register */ -#define VICH1VPSETR 0x42c -#define VICH1VPSETR_VFP(x) (((x) & 0x1fff) << 16) -#define VICH1VPSETR_VBP(x) (((x) & 0x1fff) << 0) - -/* Video-Input Channel 1 Horizontal Size Set Register */ -#define VICH1HSSETR 0x430 -#define VICH1HSSETR_HACTIVE(x) (((x) & 0x7fff) << 16) -#define VICH1HSSETR_HSPOL_LOW (1 << 15) -#define VICH1HSSETR_HSPOL_HIGH (0 << 15) -#define VICH1HSSETR_HSA(x) (((x) & 0xfff) << 0) - -/* Video-Input Channel 1 Horizontal Porch Set Register */ -#define VICH1HPSETR 0x434 -#define VICH1HPSETR_HFP(x) (((x) & 0x1fff) << 16) -#define VICH1HPSETR_HBP(x) (((x) & 0x1fff) << 0) - -#endif /* __RZG2L_MIPI_DSI_REGS_H__ */ |