// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/host1x.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_blend.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_probe_helper.h>
#include "drm.h"
#include "dc.h"
#include "plane.h"
#define NFB 24
static const u32 tegra_shared_plane_formats[] = {
DRM_FORMAT_ARGB1555,
DRM_FORMAT_RGB565,
DRM_FORMAT_RGBA5551,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_ABGR8888,
/* new on Tegra114 */
DRM_FORMAT_ABGR4444,
DRM_FORMAT_ABGR1555,
DRM_FORMAT_BGRA5551,
DRM_FORMAT_XRGB1555,
DRM_FORMAT_RGBX5551,
DRM_FORMAT_XBGR1555,
DRM_FORMAT_BGRX5551,
DRM_FORMAT_BGR565,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_XBGR8888,
/* planar formats */
DRM_FORMAT_UYVY,
DRM_FORMAT_YUYV,
DRM_FORMAT_YUV420,
DRM_FORMAT_YUV422,
};
static const u64 tegra_shared_plane_modifiers[] = {
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0),
DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1),
DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2),
DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3),
DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4),
DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5),
/*
* The GPU sector layout is only supported on Tegra194, but these will
* be filtered out later on by ->format_mod_supported() on SoCs where
* it isn't supported.
*/
DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT,
DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT,
DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT,
DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT,
DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT,
DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT,
/* sentinel */
DRM_FORMAT_MOD_INVALID
};
static inline unsigned int tegra_plane_offset(struct tegra_plane *plane,
unsigned int offset)
{
if (offset >= 0x500 && offset <= 0x581) {
offset = 0x000 + (offset - 0x500);
return plane->offset + offset;
}
if (offset >= 0x700 && offset <= 0x73c) {
offset = 0x180 + (offset - 0x700);
return plane->offset + offset;
}
if (offset >= 0x800 && offset <= 0x83e) {
offset = 0x1c0 + (offset - 0x800);
return plane->offset + offset;
}
dev_WARN(plane->dc->dev, "invalid offset: %x\n", offset);
return plane->offset + offset;
}
static inline u32 tegra_plane_readl(struct tegra_plane *plane,
unsigned int offset)
{
return tegra_dc_readl(plane->dc, tegra_plane_offset(plane, offset));
}
static inline void tegra_plane_writel(struct tegra_plane *plane, u32 value,
unsigned int offset)
{
tegra_dc_writel(plane->dc, value, tegra_plane_offset(plane, offset));
}
static int tegra_windowgroup_enable(struct tegra_windowgroup *wgrp)
{
int err = 0;
mutex_lock(&wgrp->lock);
if (wgrp->usecount == 0) {
err = host1x_client_resume(wgrp->parent);
if (err < 0) {
dev_err(wgrp->parent->dev, "failed to resume: %d\n", err);
goto unlock;
}
reset_control_deassert(wgrp->rst);
}
wgrp->usecount++;
unlock:
mutex_unlock(&wgrp->lock);
return err;
}
static void tegra_windowgroup_disable(struct tegra_windo