You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
drm/msm: Add SDM845 DPU support
SDM845 SoC includes the Mobile Display Sub System (MDSS) which is a
top level wrapper consisting of Display Processing Unit (DPU) and
display peripheral modules such as Display Serial Interface (DSI)
and DisplayPort (DP).
MDSS functions essentially as a back-end composition engine. It blends
video and graphic images stored in the frame buffers and scans out the
composed image to a display sink (over DSI/DP).
The following diagram represents hardware blocks for a simple pipeline
(two planes are present on a given crtc which is connected to a DSI
connector):
MDSS
+---------------------------------+
| +-----------------------------+ |
| | DPU | |
| | +--------+ +--------+ | |
| | | SSPP | | SSPP | | |
| | +----+---+ +----+---+ | |
| | | | | |
| | +----v-----------v---+ | |
| | | Layer Mixer (LM) | | |
| | +--------------------+ | |
| | +--------------------+ | |
| | | PingPong (PP) | | |
| | +--------------------+ | |
| | +--------------------+ | |
| | | INTERFACE (VIDEO) | | |
| | +---+----------------+ | |
| +------|----------------------+ |
| | |
| +------|---------------------+ |
| | | DISPLAY PERIPHERALS | |
| | +---v-+ +-----+ | |
| | | DSI | | DP | | |
| | +-----+ +-----+ | |
| +----------------------------+ |
+---------------------------------+
The number of DPU sub-blocks (i.e. SSPPs, LMs, PP blocks and INTFs)
depends on SoC capabilities.
Overview of DPU sub-blocks:
---------------------------
* Source Surface Processor (SSPP):
Refers to any of hardware pipes like ViG, DMA etc. Only ViG pipes are
capable of performing format conversion, scaling and quality improvement
for source surfaces.
* Layer Mixer (LM):
Blend source surfaces together (in requested zorder)
* PingPong (PP):
This block controls frame done interrupt output, EOL and EOF generation,
overflow/underflow control.
* Display interface (INTF):
Timing generator and interface connecting the display peripherals.
DRM components mapping to DPU architecture:
------------------------------------------
PLANEs maps to SSPPs
CRTC maps to LMs
Encoder maps to PPs, INTFs
Data flow setup:
---------------
MDSS hardware can support various data flows (e.g.):
- Dual pipe: Output from two LMs combined to single display.
- Split display: Output from two LMs connected to two separate
interfaces.
The hardware capabilities determine the number of concurrent data paths
possible. Any control path (i.e. pipeline w/i DPU) can be routed to any
of the hardware data paths. A given control path can be triggered,
flushed and controlled independently.
Changes in v3:
- Move msm_media_info.h from uapi to dpu/ subdir
- Remove preclose callback dpu (it's handled in core)
- Fix kbuild warnings with parent_ops
- Remove unused functions from dpu_core_irq
- Rename mdss_phys to mdss
- Rename mdp_phys address space to mdp
- Drop _phys from vbif and regdma binding names
Signed-off-by: Abhinav Kumar <abhinavk@codeaurora.org>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Signed-off-by: Chandan Uddaraju <chandanu@codeaurora.org>
Signed-off-by: Jeykumar Sankaran <jsanka@codeaurora.org>
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
Signed-off-by: Rajesh Yadav <ryadav@codeaurora.org>
Signed-off-by: Sravanthi Kollukuduru <skolluku@codeaurora.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
[robclark minor rebase]
Signed-off-by: Rob Clark <robdclark@gmail.com>
This commit is contained in:
committed by
Sean Paul
parent
036bfeb33b
commit
25fdd5933e
@@ -1,5 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
ccflags-y := -Idrivers/gpu/drm/msm
|
||||
ccflags-y += -Idrivers/gpu/drm/msm/disp/dpu1
|
||||
ccflags-$(CONFIG_DRM_MSM_DSI) += -Idrivers/gpu/drm/msm/dsi
|
||||
|
||||
msm-y := \
|
||||
@@ -45,6 +46,34 @@ msm-y := \
|
||||
disp/mdp5/mdp5_mixer.o \
|
||||
disp/mdp5/mdp5_plane.o \
|
||||
disp/mdp5/mdp5_smp.o \
|
||||
disp/dpu1/dpu_core_irq.o \
|
||||
disp/dpu1/dpu_core_perf.o \
|
||||
disp/dpu1/dpu_crtc.o \
|
||||
disp/dpu1/dpu_encoder.o \
|
||||
disp/dpu1/dpu_encoder_phys_cmd.o \
|
||||
disp/dpu1/dpu_encoder_phys_vid.o \
|
||||
disp/dpu1/dpu_formats.o \
|
||||
disp/dpu1/dpu_hw_blk.o \
|
||||
disp/dpu1/dpu_hw_catalog.o \
|
||||
disp/dpu1/dpu_hw_cdm.o \
|
||||
disp/dpu1/dpu_hw_ctl.o \
|
||||
disp/dpu1/dpu_hw_interrupts.o \
|
||||
disp/dpu1/dpu_hw_intf.o \
|
||||
disp/dpu1/dpu_hw_lm.o \
|
||||
disp/dpu1/dpu_hw_pingpong.o \
|
||||
disp/dpu1/dpu_hw_sspp.o \
|
||||
disp/dpu1/dpu_hw_top.o \
|
||||
disp/dpu1/dpu_hw_util.o \
|
||||
disp/dpu1/dpu_hw_vbif.o \
|
||||
disp/dpu1/dpu_io_util.o \
|
||||
disp/dpu1/dpu_irq.o \
|
||||
disp/dpu1/dpu_kms.o \
|
||||
disp/dpu1/dpu_kms_utils.o \
|
||||
disp/dpu1/dpu_mdss.o \
|
||||
disp/dpu1/dpu_plane.o \
|
||||
disp/dpu1/dpu_power_handle.o \
|
||||
disp/dpu1/dpu_rm.o \
|
||||
disp/dpu1/dpu_vbif.o \
|
||||
msm_atomic.o \
|
||||
msm_debugfs.o \
|
||||
msm_drv.o \
|
||||
@@ -62,7 +91,8 @@ msm-y := \
|
||||
msm_ringbuffer.o \
|
||||
msm_submitqueue.o
|
||||
|
||||
msm-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o
|
||||
msm-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o \
|
||||
disp/dpu1/dpu_dbg.o
|
||||
|
||||
msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
|
||||
msm-$(CONFIG_COMMON_CLK) += disp/mdp4/mdp4_lvds_pll.o
|
||||
|
||||
479
drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c
Normal file
479
drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c
Normal file
@@ -0,0 +1,479 @@
|
||||
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kthread.h>
|
||||
|
||||
#include "dpu_core_irq.h"
|
||||
#include "dpu_trace.h"
|
||||
|
||||
/**
|
||||
* dpu_core_irq_callback_handler - dispatch core interrupts
|
||||
* @arg: private data of callback handler
|
||||
* @irq_idx: interrupt index
|
||||
*/
|
||||
static void dpu_core_irq_callback_handler(void *arg, int irq_idx)
|
||||
{
|
||||
struct dpu_kms *dpu_kms = arg;
|
||||
struct dpu_irq *irq_obj = &dpu_kms->irq_obj;
|
||||
struct dpu_irq_callback *cb;
|
||||
unsigned long irq_flags;
|
||||
|
||||
pr_debug("irq_idx=%d\n", irq_idx);
|
||||
|
||||
if (list_empty(&irq_obj->irq_cb_tbl[irq_idx])) {
|
||||
DRM_ERROR("no registered cb, idx:%d enable_count:%d\n", irq_idx,
|
||||
atomic_read(&dpu_kms->irq_obj.enable_counts[irq_idx]));
|
||||
}
|
||||
|
||||
atomic_inc(&irq_obj->irq_counts[irq_idx]);
|
||||
|
||||
/*
|
||||
* Perform registered function callback
|
||||
*/
|
||||
spin_lock_irqsave(&dpu_kms->irq_obj.cb_lock, irq_flags);
|
||||
list_for_each_entry(cb, &irq_obj->irq_cb_tbl[irq_idx], list)
|
||||
if (cb->func)
|
||||
cb->func(cb->arg, irq_idx);
|
||||
spin_unlock_irqrestore(&dpu_kms->irq_obj.cb_lock, irq_flags);
|
||||
|
||||
/*
|
||||
* Clear pending interrupt status in HW.
|
||||
* NOTE: dpu_core_irq_callback_handler is protected by top-level
|
||||
* spinlock, so it is safe to clear any interrupt status here.
|
||||
*/
|
||||
dpu_kms->hw_intr->ops.clear_intr_status_nolock(
|
||||
dpu_kms->hw_intr,
|
||||
irq_idx);
|
||||
}
|
||||
|
||||
int dpu_core_irq_idx_lookup(struct dpu_kms *dpu_kms,
|
||||
enum dpu_intr_type intr_type, u32 instance_idx)
|
||||
{
|
||||
if (!dpu_kms || !dpu_kms->hw_intr ||
|
||||
!dpu_kms->hw_intr->ops.irq_idx_lookup)
|
||||
return -EINVAL;
|
||||
|
||||
return dpu_kms->hw_intr->ops.irq_idx_lookup(intr_type,
|
||||
instance_idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* _dpu_core_irq_enable - enable core interrupt given by the index
|
||||
* @dpu_kms: Pointer to dpu kms context
|
||||
* @irq_idx: interrupt index
|
||||
*/
|
||||
static int _dpu_core_irq_enable(struct dpu_kms *dpu_kms, int irq_idx)
|
||||
{
|
||||
unsigned long irq_flags;
|
||||
int ret = 0, enable_count;
|
||||
|
||||
if (!dpu_kms || !dpu_kms->hw_intr ||
|
||||
!dpu_kms->irq_obj.enable_counts ||
|
||||
!dpu_kms->irq_obj.irq_counts) {
|
||||
DPU_ERROR("invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->irq_idx_tbl_size) {
|
||||
DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
enable_count = atomic_read(&dpu_kms->irq_obj.enable_counts[irq_idx]);
|
||||
DRM_DEBUG_KMS("irq_idx=%d enable_count=%d\n", irq_idx, enable_count);
|
||||
trace_dpu_core_irq_enable_idx(irq_idx, enable_count);
|
||||
|
||||
if (atomic_inc_return(&dpu_kms->irq_obj.enable_counts[irq_idx]) == 1) {
|
||||
ret = dpu_kms->hw_intr->ops.enable_irq(
|
||||
dpu_kms->hw_intr,
|
||||
irq_idx);
|
||||
if (ret)
|
||||
DPU_ERROR("Fail to enable IRQ for irq_idx:%d\n",
|
||||
irq_idx);
|
||||
|
||||
DPU_DEBUG("irq_idx=%d ret=%d\n", irq_idx, ret);
|
||||
|
||||
spin_lock_irqsave(&dpu_kms->irq_obj.cb_lock, irq_flags);
|
||||
/* empty callback list but interrupt is enabled */
|
||||
if (list_empty(&dpu_kms->irq_obj.irq_cb_tbl[irq_idx]))
|
||||
DPU_ERROR("irq_idx=%d enabled with no callback\n",
|
||||
irq_idx);
|
||||
spin_unlock_irqrestore(&dpu_kms->irq_obj.cb_lock, irq_flags);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dpu_core_irq_enable(struct dpu_kms *dpu_kms, int *irq_idxs, u32 irq_count)
|
||||
{
|
||||
int i, ret = 0, counts;
|
||||
|
||||
if (!dpu_kms || !irq_idxs || !irq_count) {
|
||||
DPU_ERROR("invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
counts = atomic_read(&dpu_kms->irq_obj.enable_counts[irq_idxs[0]]);
|
||||
if (counts)
|
||||
DRM_ERROR("irq_idx=%d enable_count=%d\n", irq_idxs[0], counts);
|
||||
|
||||
for (i = 0; (i < irq_count) && !ret; i++)
|
||||
ret = _dpu_core_irq_enable(dpu_kms, irq_idxs[i]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* _dpu_core_irq_disable - disable core interrupt given by the index
|
||||
* @dpu_kms: Pointer to dpu kms context
|
||||
* @irq_idx: interrupt index
|
||||
*/
|
||||
static int _dpu_core_irq_disable(struct dpu_kms *dpu_kms, int irq_idx)
|
||||
{
|
||||
int ret = 0, enable_count;
|
||||
|
||||
if (!dpu_kms || !dpu_kms->hw_intr || !dpu_kms->irq_obj.enable_counts) {
|
||||
DPU_ERROR("invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->irq_idx_tbl_size) {
|
||||
DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
enable_count = atomic_read(&dpu_kms->irq_obj.enable_counts[irq_idx]);
|
||||
DRM_DEBUG_KMS("irq_idx=%d enable_count=%d\n", irq_idx, enable_count);
|
||||
trace_dpu_core_irq_disable_idx(irq_idx, enable_count);
|
||||
|
||||
if (atomic_dec_return(&dpu_kms->irq_obj.enable_counts[irq_idx]) == 0) {
|
||||
ret = dpu_kms->hw_intr->ops.disable_irq(
|
||||
dpu_kms->hw_intr,
|
||||
irq_idx);
|
||||
if (ret)
|
||||
DPU_ERROR("Fail to disable IRQ for irq_idx:%d\n",
|
||||
irq_idx);
|
||||
DPU_DEBUG("irq_idx=%d ret=%d\n", irq_idx, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dpu_core_irq_disable(struct dpu_kms *dpu_kms, int *irq_idxs, u32 irq_count)
|
||||
{
|
||||
int i, ret = 0, counts;
|
||||
|
||||
if (!dpu_kms || !irq_idxs || !irq_count) {
|
||||
DPU_ERROR("invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
counts = atomic_read(&dpu_kms->irq_obj.enable_counts[irq_idxs[0]]);
|
||||
if (counts == 2)
|
||||
DRM_ERROR("irq_idx=%d enable_count=%d\n", irq_idxs[0], counts);
|
||||
|
||||
for (i = 0; (i < irq_count) && !ret; i++)
|
||||
ret = _dpu_core_irq_disable(dpu_kms, irq_idxs[i]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 dpu_core_irq_read(struct dpu_kms *dpu_kms, int irq_idx, bool clear)
|
||||
{
|
||||
if (!dpu_kms || !dpu_kms->hw_intr ||
|
||||
!dpu_kms->hw_intr->ops.get_interrupt_status)
|
||||
return 0;
|
||||
|
||||
if (irq_idx < 0) {
|
||||
DPU_ERROR("[%pS] invalid irq_idx=%d\n",
|
||||
__builtin_return_address(0), irq_idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dpu_kms->hw_intr->ops.get_interrupt_status(dpu_kms->hw_intr,
|
||||
irq_idx, clear);
|
||||
}
|
||||
|
||||
int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms, int irq_idx,
|
||||
struct dpu_irq_callback *register_irq_cb)
|
||||
{
|
||||
unsigned long irq_flags;
|
||||
|
||||
if (!dpu_kms || !dpu_kms->irq_obj.irq_cb_tbl) {
|
||||
DPU_ERROR("invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!register_irq_cb || !register_irq_cb->func) {
|
||||
DPU_ERROR("invalid irq_cb:%d func:%d\n",
|
||||
register_irq_cb != NULL,
|
||||
register_irq_cb ?
|
||||
register_irq_cb->func != NULL : -1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->irq_idx_tbl_size) {
|
||||
DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DPU_DEBUG("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx);
|
||||
|
||||
spin_lock_irqsave(&dpu_kms->irq_obj.cb_lock, irq_flags);
|
||||
trace_dpu_core_irq_register_callback(irq_idx, register_irq_cb);
|
||||
list_del_init(®ister_irq_cb->list);
|
||||
list_add_tail(®ister_irq_cb->list,
|
||||
&dpu_kms->irq_obj.irq_cb_tbl[irq_idx]);
|
||||
spin_unlock_irqrestore(&dpu_kms->irq_obj.cb_lock, irq_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms, int irq_idx,
|
||||
struct dpu_irq_callback *register_irq_cb)
|
||||
{
|
||||
unsigned long irq_flags;
|
||||
|
||||
if (!dpu_kms || !dpu_kms->irq_obj.irq_cb_tbl) {
|
||||
DPU_ERROR("invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!register_irq_cb || !register_irq_cb->func) {
|
||||
DPU_ERROR("invalid irq_cb:%d func:%d\n",
|
||||
register_irq_cb != NULL,
|
||||
register_irq_cb ?
|
||||
register_irq_cb->func != NULL : -1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->irq_idx_tbl_size) {
|
||||
DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DPU_DEBUG("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx);
|
||||
|
||||
spin_lock_irqsave(&dpu_kms->irq_obj.cb_lock, irq_flags);
|
||||
trace_dpu_core_irq_unregister_callback(irq_idx, register_irq_cb);
|
||||
list_del_init(®ister_irq_cb->list);
|
||||
/* empty callback list but interrupt is still enabled */
|
||||
if (list_empty(&dpu_kms->irq_obj.irq_cb_tbl[irq_idx]) &&
|
||||
atomic_read(&dpu_kms->irq_obj.enable_counts[irq_idx]))
|
||||
DPU_ERROR("irq_idx=%d enabled with no callback\n", irq_idx);
|
||||
spin_unlock_irqrestore(&dpu_kms->irq_obj.cb_lock, irq_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dpu_clear_all_irqs(struct dpu_kms *dpu_kms)
|
||||
{
|
||||
if (!dpu_kms || !dpu_kms->hw_intr ||
|
||||
!dpu_kms->hw_intr->ops.clear_all_irqs)
|
||||
return;
|
||||
|
||||
dpu_kms->hw_intr->ops.clear_all_irqs(dpu_kms->hw_intr);
|
||||
}
|
||||
|
||||
static void dpu_disable_all_irqs(struct dpu_kms *dpu_kms)
|
||||
{
|
||||
if (!dpu_kms || !dpu_kms->hw_intr ||
|
||||
!dpu_kms->hw_intr->ops.disable_all_irqs)
|
||||
return;
|
||||
|
||||
dpu_kms->hw_intr->ops.disable_all_irqs(dpu_kms->hw_intr);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
#define DEFINE_DPU_DEBUGFS_SEQ_FOPS(__prefix) \
|
||||
static int __prefix ## _open(struct inode *inode, struct file *file) \
|
||||
{ \
|
||||
return single_open(file, __prefix ## _show, inode->i_private); \
|
||||
} \
|
||||
static const struct file_operations __prefix ## _fops = { \
|
||||
.owner = THIS_MODULE, \
|
||||
.open = __prefix ## _open, \
|
||||
.release = single_release, \
|
||||
.read = seq_read, \
|
||||
.llseek = seq_lseek, \
|
||||
}
|
||||
|
||||
static int dpu_debugfs_core_irq_show(struct seq_file *s, void *v)
|
||||
{
|
||||
struct dpu_irq *irq_obj = s->private;
|
||||
struct dpu_irq_callback *cb;
|
||||
unsigned long irq_flags;
|
||||
int i, irq_count, enable_count, cb_count;
|
||||
|
||||
if (!irq_obj || !irq_obj->enable_counts || !irq_obj->irq_cb_tbl) {
|
||||
DPU_ERROR("invalid parameters\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < irq_obj->total_irqs; i++) {
|
||||
spin_lock_irqsave(&irq_obj->cb_lock, irq_flags);
|
||||
cb_count = 0;
|
||||
irq_count = atomic_read(&irq_obj->irq_counts[i]);
|
||||
enable_count = atomic_read(&irq_obj->enable_counts[i]);
|
||||
list_for_each_entry(cb, &irq_obj->irq_cb_tbl[i], list)
|
||||
cb_count++;
|
||||
spin_unlock_irqrestore(&irq_obj->cb_lock, irq_flags);
|
||||
|
||||
if (irq_count || enable_count || cb_count)
|
||||
seq_printf(s, "idx:%d irq:%d enable:%d cb:%d\n",
|
||||
i, irq_count, enable_count, cb_count);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_DPU_DEBUGFS_SEQ_FOPS(dpu_debugfs_core_irq);
|
||||
|
||||
int dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms,
|
||||
struct dentry *parent)
|
||||
{
|
||||
dpu_kms->irq_obj.debugfs_file = debugfs_create_file("core_irq", 0600,
|
||||
parent, &dpu_kms->irq_obj,
|
||||
&dpu_debugfs_core_irq_fops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dpu_debugfs_core_irq_destroy(struct dpu_kms *dpu_kms)
|
||||
{
|
||||
debugfs_remove(dpu_kms->irq_obj.debugfs_file);
|
||||
dpu_kms->irq_obj.debugfs_file = NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
int dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms,
|
||||
struct dentry *parent)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dpu_debugfs_core_irq_destroy(struct dpu_kms *dpu_kms)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
void dpu_core_irq_preinstall(struct dpu_kms *dpu_kms)
|
||||
{
|
||||
struct msm_drm_private *priv;
|
||||
int i;
|
||||
|
||||
if (!dpu_kms) {
|
||||
DPU_ERROR("invalid dpu_kms\n");
|
||||
return;
|
||||
} else if (!dpu_kms->dev) {
|
||||
DPU_ERROR("invalid drm device\n");
|
||||
return;
|
||||
} else if (!dpu_kms->dev->dev_private) {
|
||||
DPU_ERROR("invalid device private\n");
|
||||
return;
|
||||
}
|
||||
priv = dpu_kms->dev->dev_private;
|
||||
|
||||
pm_runtime_get_sync(&dpu_kms->pdev->dev);
|
||||
dpu_clear_all_irqs(dpu_kms);
|
||||
dpu_disable_all_irqs(dpu_kms);
|
||||
pm_runtime_put_sync(&dpu_kms->pdev->dev);
|
||||
|
||||
spin_lock_init(&dpu_kms->irq_obj.cb_lock);
|
||||
|
||||
/* Create irq callbacks for all possible irq_idx */
|
||||
dpu_kms->irq_obj.total_irqs = dpu_kms->hw_intr->irq_idx_tbl_size;
|
||||
dpu_kms->irq_obj.irq_cb_tbl = kcalloc(dpu_kms->irq_obj.total_irqs,
|
||||
sizeof(struct list_head), GFP_KERNEL);
|
||||
dpu_kms->irq_obj.enable_counts = kcalloc(dpu_kms->irq_obj.total_irqs,
|
||||
sizeof(atomic_t), GFP_KERNEL);
|
||||
dpu_kms->irq_obj.irq_counts = kcalloc(dpu_kms->irq_obj.total_irqs,
|
||||
sizeof(atomic_t), GFP_KERNEL);
|
||||
for (i = 0; i < dpu_kms->irq_obj.total_irqs; i++) {
|
||||
INIT_LIST_HEAD(&dpu_kms->irq_obj.irq_cb_tbl[i]);
|
||||
atomic_set(&dpu_kms->irq_obj.enable_counts[i], 0);
|
||||
atomic_set(&dpu_kms->irq_obj.irq_counts[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
int dpu_core_irq_postinstall(struct dpu_kms *dpu_kms)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dpu_core_irq_uninstall(struct dpu_kms *dpu_kms)
|
||||
{
|
||||
struct msm_drm_private *priv;
|
||||
int i;
|
||||
|
||||
if (!dpu_kms) {
|
||||
DPU_ERROR("invalid dpu_kms\n");
|
||||
return;
|
||||
} else if (!dpu_kms->dev) {
|
||||
DPU_ERROR("invalid drm device\n");
|
||||
return;
|
||||
} else if (!dpu_kms->dev->dev_private) {
|
||||
DPU_ERROR("invalid device private\n");
|
||||
return;
|
||||
}
|
||||
priv = dpu_kms->dev->dev_private;
|
||||
|
||||
pm_runtime_get_sync(&dpu_kms->pdev->dev);
|
||||
for (i = 0; i < dpu_kms->irq_obj.total_irqs; i++)
|
||||
if (atomic_read(&dpu_kms->irq_obj.enable_counts[i]) ||
|
||||
!list_empty(&dpu_kms->irq_obj.irq_cb_tbl[i]))
|
||||
DPU_ERROR("irq_idx=%d still enabled/registered\n", i);
|
||||
|
||||
dpu_clear_all_irqs(dpu_kms);
|
||||
dpu_disable_all_irqs(dpu_kms);
|
||||
pm_runtime_put_sync(&dpu_kms->pdev->dev);
|
||||
|
||||
kfree(dpu_kms->irq_obj.irq_cb_tbl);
|
||||
kfree(dpu_kms->irq_obj.enable_counts);
|
||||
kfree(dpu_kms->irq_obj.irq_counts);
|
||||
dpu_kms->irq_obj.irq_cb_tbl = NULL;
|
||||
dpu_kms->irq_obj.enable_counts = NULL;
|
||||
dpu_kms->irq_obj.irq_counts = NULL;
|
||||
dpu_kms->irq_obj.total_irqs = 0;
|
||||
}
|
||||
|
||||
irqreturn_t dpu_core_irq(struct dpu_kms *dpu_kms)
|
||||
{
|
||||
/*
|
||||
* Read interrupt status from all sources. Interrupt status are
|
||||
* stored within hw_intr.
|
||||
* Function will also clear the interrupt status after reading.
|
||||
* Individual interrupt status bit will only get stored if it
|
||||
* is enabled.
|
||||
*/
|
||||
dpu_kms->hw_intr->ops.get_interrupt_statuses(dpu_kms->hw_intr);
|
||||
|
||||
/*
|
||||
* Dispatch to HW driver to handle interrupt lookup that is being
|
||||
* fired. When matching interrupt is located, HW driver will call to
|
||||
* dpu_core_irq_callback_handler with the irq_idx from the lookup table.
|
||||
* dpu_core_irq_callback_handler will perform the registered function
|
||||
* callback, and do the interrupt status clearing once the registered
|
||||
* callback is finished.
|
||||
*/
|
||||
dpu_kms->hw_intr->ops.dispatch_irqs(
|
||||
dpu_kms->hw_intr,
|
||||
dpu_core_irq_callback_handler,
|
||||
dpu_kms);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
153
drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h
Normal file
153
drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h
Normal file
@@ -0,0 +1,153 @@
|
||||
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __DPU_CORE_IRQ_H__
|
||||
#define __DPU_CORE_IRQ_H__
|
||||
|
||||
#include "dpu_kms.h"
|
||||
#include "dpu_hw_interrupts.h"
|
||||
|
||||
/**
|
||||
* dpu_core_irq_preinstall - perform pre-installation of core IRQ handler
|
||||
* @dpu_kms: DPU handle
|
||||
* @return: none
|
||||
*/
|
||||
void dpu_core_irq_preinstall(struct dpu_kms *dpu_kms);
|
||||
|
||||
/**
|
||||
* dpu_core_irq_postinstall - perform post-installation of core IRQ handler
|
||||
* @dpu_kms: DPU handle
|
||||
* @return: 0 if success; error code otherwise
|
||||
*/
|
||||
int dpu_core_irq_postinstall(struct dpu_kms *dpu_kms);
|
||||
|
||||
/**
|
||||
* dpu_core_irq_uninstall - uninstall core IRQ handler
|
||||
* @dpu_kms: DPU handle
|
||||
* @return: none
|
||||
*/
|
||||
void dpu_core_irq_uninstall(struct dpu_kms *dpu_kms);
|
||||
|
||||
/**
|
||||
* dpu_core_irq - core IRQ handler
|
||||
* @dpu_kms: DPU handle
|
||||
* @return: interrupt handling status
|
||||
*/
|
||||
irqreturn_t dpu_core_irq(struct dpu_kms *dpu_kms);
|
||||
|
||||
/**
|
||||
* dpu_core_irq_idx_lookup - IRQ helper function for lookup irq_idx from HW
|
||||
* interrupt mapping table.
|
||||
* @dpu_kms: DPU handle
|
||||
* @intr_type: DPU HW interrupt type for lookup
|
||||
* @instance_idx: DPU HW block instance defined in dpu_hw_mdss.h
|
||||
* @return: irq_idx or -EINVAL when fail to lookup
|
||||
*/
|
||||
int dpu_core_irq_idx_lookup(
|
||||
struct dpu_kms *dpu_kms,
|
||||
enum dpu_intr_type intr_type,
|
||||
uint32_t instance_idx);
|
||||
|
||||
/**
|
||||
* dpu_core_irq_enable - IRQ helper function for enabling one or more IRQs
|
||||
* @dpu_kms: DPU handle
|
||||
* @irq_idxs: Array of irq index
|
||||
* @irq_count: Number of irq_idx provided in the array
|
||||
* @return: 0 for success enabling IRQ, otherwise failure
|
||||
*
|
||||
* This function increments count on each enable and decrements on each
|
||||
* disable. Interrupts is enabled if count is 0 before increment.
|
||||
*/
|
||||
int dpu_core_irq_enable(
|
||||
struct dpu_kms *dpu_kms,
|
||||
int *irq_idxs,
|
||||
uint32_t irq_count);
|
||||
|
||||
/**
|
||||
* dpu_core_irq_disable - IRQ helper function for disabling one of more IRQs
|
||||
* @dpu_kms: DPU handle
|
||||
* @irq_idxs: Array of irq index
|
||||
* @irq_count: Number of irq_idx provided in the array
|
||||
* @return: 0 for success disabling IRQ, otherwise failure
|
||||
*
|
||||
* This function increments count on each enable and decrements on each
|
||||
* disable. Interrupts is disabled if count is 0 after decrement.
|
||||
*/
|
||||
int dpu_core_irq_disable(
|
||||
struct dpu_kms *dpu_kms,
|
||||
int *irq_idxs,
|
||||
uint32_t irq_count);
|
||||
|
||||
/**
|
||||
* dpu_core_irq_read - IRQ helper function for reading IRQ status
|
||||
* @dpu_kms: DPU handle
|
||||
* @irq_idx: irq index
|
||||
* @clear: True to clear the irq after read
|
||||
* @return: non-zero if irq detected; otherwise no irq detected
|
||||
*/
|
||||
u32 dpu_core_irq_read(
|
||||
struct dpu_kms *dpu_kms,
|
||||
int irq_idx,
|
||||
bool clear);
|
||||
|
||||
/**
|
||||
* dpu_core_irq_register_callback - For registering callback function on IRQ
|
||||
* interrupt
|
||||
* @dpu_kms: DPU handle
|
||||
* @irq_idx: irq index
|
||||
* @irq_cb: IRQ callback structure, containing callback function
|
||||
* and argument. Passing NULL for irq_cb will unregister
|
||||
* the callback for the given irq_idx
|
||||
* This must exist until un-registration.
|
||||
* @return: 0 for success registering callback, otherwise failure
|
||||
*
|
||||
* This function supports registration of multiple callbacks for each interrupt.
|
||||
*/
|
||||
int dpu_core_irq_register_callback(
|
||||
struct dpu_kms *dpu_kms,
|
||||
int irq_idx,
|
||||
struct dpu_irq_callback *irq_cb);
|
||||
|
||||
/**
|
||||
* dpu_core_irq_unregister_callback - For unregistering callback function on IRQ
|
||||
* interrupt
|
||||
* @dpu_kms: DPU handle
|
||||
* @irq_idx: irq index
|
||||
* @irq_cb: IRQ callback structure, containing callback function
|
||||
* and argument. Passing NULL for irq_cb will unregister
|
||||
* the callback for the given irq_idx
|
||||
* This must match with registration.
|
||||
* @return: 0 for success registering callback, otherwise failure
|
||||
*
|
||||
* This function supports registration of multiple callbacks for each interrupt.
|
||||
*/
|
||||
int dpu_core_irq_unregister_callback(
|
||||
struct dpu_kms *dpu_kms,
|
||||
int irq_idx,
|
||||
struct dpu_irq_callback *irq_cb);
|
||||
|
||||
/**
|
||||
* dpu_debugfs_core_irq_init - register core irq debugfs
|
||||
* @dpu_kms: pointer to kms
|
||||
* @parent: debugfs directory root
|
||||
* @Return: 0 on success
|
||||
*/
|
||||
int dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms,
|
||||
struct dentry *parent);
|
||||
|
||||
/**
|
||||
* dpu_debugfs_core_irq_destroy - deregister core irq debugfs
|
||||
* @dpu_kms: pointer to kms
|
||||
*/
|
||||
void dpu_debugfs_core_irq_destroy(struct dpu_kms *dpu_kms);
|
||||
|
||||
#endif /* __DPU_CORE_IRQ_H__ */
|
||||
637
drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c
Normal file
637
drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c
Normal file
File diff suppressed because it is too large
Load Diff
133
drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h
Normal file
133
drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _DPU_CORE_PERF_H_
|
||||
#define _DPU_CORE_PERF_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
|
||||
#include "dpu_hw_catalog.h"
|
||||
#include "dpu_power_handle.h"
|
||||
|
||||
#define DPU_PERF_DEFAULT_MAX_CORE_CLK_RATE 412500000
|
||||
|
||||
/**
|
||||
* struct dpu_core_perf_params - definition of performance parameters
|
||||
* @max_per_pipe_ib: maximum instantaneous bandwidth request
|
||||
* @bw_ctl: arbitrated bandwidth request
|
||||
* @core_clk_rate: core clock rate request
|
||||
*/
|
||||
struct dpu_core_perf_params {
|
||||
u64 max_per_pipe_ib[DPU_POWER_HANDLE_DBUS_ID_MAX];
|
||||
u64 bw_ctl[DPU_POWER_HANDLE_DBUS_ID_MAX];
|
||||
u64 core_clk_rate;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpu_core_perf_tune - definition of performance tuning control
|
||||
* @mode: performance mode
|
||||
* @min_core_clk: minimum core clock
|
||||
* @min_bus_vote: minimum bus vote
|
||||
*/
|
||||
struct dpu_core_perf_tune {
|
||||
u32 mode;
|
||||
u64 min_core_clk;
|
||||
u64 min_bus_vote;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpu_core_perf - definition of core performance context
|
||||
* @dev: Pointer to drm device
|
||||
* @debugfs_root: top level debug folder
|
||||
* @catalog: Pointer to catalog configuration
|
||||
* @phandle: Pointer to power handler
|
||||
* @core_clk: Pointer to core clock structure
|
||||
* @core_clk_rate: current core clock rate
|
||||
* @max_core_clk_rate: maximum allowable core clock rate
|
||||
* @perf_tune: debug control for performance tuning
|
||||
* @enable_bw_release: debug control for bandwidth release
|
||||
* @fix_core_clk_rate: fixed core clock request in Hz used in mode 2
|
||||
* @fix_core_ib_vote: fixed core ib vote in bps used in mode 2
|
||||
* @fix_core_ab_vote: fixed core ab vote in bps used in mode 2
|
||||
*/
|
||||
struct dpu_core_perf {
|
||||
struct drm_device *dev;
|
||||
struct dentry *debugfs_root;
|
||||
struct dpu_mdss_cfg *catalog;
|
||||
struct dpu_power_handle *phandle;
|
||||
struct dss_clk *core_clk;
|
||||
u64 core_clk_rate;
|
||||
u64 max_core_clk_rate;
|
||||
struct dpu_core_perf_tune perf_tune;
|
||||
u32 enable_bw_release;
|
||||
u64 fix_core_clk_rate;
|
||||
u64 fix_core_ib_vote;
|
||||
u64 fix_core_ab_vote;
|
||||
};
|
||||
|
||||
/**
|
||||
* dpu_core_perf_crtc_check - validate performance of the given crtc state
|
||||
* @crtc: Pointer to crtc
|
||||
* @state: Pointer to new crtc state
|
||||
* return: zero if success, or error code otherwise
|
||||
*/
|
||||
int dpu_core_perf_crtc_check(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *state);
|
||||
|
||||
/**
|
||||
* dpu_core_perf_crtc_update - update performance of the given crtc
|
||||
* @crtc: Pointer to crtc
|
||||
* @params_changed: true if crtc parameters are modified
|
||||
* @stop_req: true if this is a stop request
|
||||
* return: zero if success, or error code otherwise
|
||||
*/
|
||||
int dpu_core_perf_crtc_update(struct drm_crtc *crtc,
|
||||
int params_changed, bool stop_req);
|
||||
|
||||
/**
|
||||
* dpu_core_perf_crtc_release_bw - release bandwidth of the given crtc
|
||||
* @crtc: Pointer to crtc
|
||||
*/
|
||||
void dpu_core_perf_crtc_release_bw(struct drm_crtc *crtc);
|
||||
|
||||
/**
|
||||
* dpu_core_perf_destroy - destroy the given core performance context
|
||||
* @perf: Pointer to core performance context
|
||||
*/
|
||||
void dpu_core_perf_destroy(struct dpu_core_perf *perf);
|
||||
|
||||
/**
|
||||
* dpu_core_perf_init - initialize the given core performance context
|
||||
* @perf: Pointer to core performance context
|
||||
* @dev: Pointer to drm device
|
||||
* @catalog: Pointer to catalog
|
||||
* @phandle: Pointer to power handle
|
||||
* @core_clk: pointer to core clock
|
||||
*/
|
||||
int dpu_core_perf_init(struct dpu_core_perf *perf,
|
||||
struct drm_device *dev,
|
||||
struct dpu_mdss_cfg *catalog,
|
||||
struct dpu_power_handle *phandle,
|
||||
struct dss_clk *core_clk);
|
||||
|
||||
/**
|
||||
* dpu_core_perf_debugfs_init - initialize debugfs for core performance context
|
||||
* @perf: Pointer to core performance context
|
||||
* @debugfs_parent: Pointer to parent debugfs
|
||||
*/
|
||||
int dpu_core_perf_debugfs_init(struct dpu_core_perf *perf,
|
||||
struct dentry *parent);
|
||||
|
||||
#endif /* _DPU_CORE_PERF_H_ */
|
||||
2504
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
Normal file
2504
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
Normal file
File diff suppressed because it is too large
Load Diff
484
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
Normal file
484
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
Normal file
@@ -0,0 +1,484 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2018 The Linux Foundation. All rights reserved.
|
||||
* Copyright (C) 2013 Red Hat
|
||||
* Author: Rob Clark <robdclark@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _DPU_CRTC_H_
|
||||
#define _DPU_CRTC_H_
|
||||
|
||||
#include <linux/kthread.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include "dpu_kms.h"
|
||||
#include "dpu_core_perf.h"
|
||||
#include "dpu_hw_blk.h"
|
||||
|
||||
#define DPU_CRTC_NAME_SIZE 12
|
||||
|
||||
/* define the maximum number of in-flight frame events */
|
||||
#define DPU_CRTC_FRAME_EVENT_SIZE 4
|
||||
|
||||
/**
|
||||
* enum dpu_crtc_client_type: crtc client type
|
||||
* @RT_CLIENT: RealTime client like video/cmd mode display
|
||||
* voting through apps rsc
|
||||
* @NRT_CLIENT: Non-RealTime client like WB display
|
||||
* voting through apps rsc
|
||||
*/
|
||||
enum dpu_crtc_client_type {
|
||||
RT_CLIENT,
|
||||
NRT_CLIENT,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dpu_crtc_smmu_state: smmu state
|
||||
* @ATTACHED: all the context banks are attached.
|
||||
* @DETACHED: all the context banks are detached.
|
||||
* @ATTACH_ALL_REQ: transient state of attaching context banks.
|
||||
* @DETACH_ALL_REQ: transient state of detaching context banks.
|
||||
*/
|
||||
enum dpu_crtc_smmu_state {
|
||||
ATTACHED = 0,
|
||||
DETACHED,
|
||||
ATTACH_ALL_REQ,
|
||||
DETACH_ALL_REQ,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dpu_crtc_smmu_state_transition_type: state transition type
|
||||
* @NONE: no pending state transitions
|
||||
* @PRE_COMMIT: state transitions should be done before processing the commit
|
||||
* @POST_COMMIT: state transitions to be done after processing the commit.
|
||||
*/
|
||||
enum dpu_crtc_smmu_state_transition_type {
|
||||
NONE,
|
||||
PRE_COMMIT,
|
||||
POST_COMMIT
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpu_crtc_smmu_state_data: stores the smmu state and transition type
|
||||
* @state: current state of smmu context banks
|
||||
* @transition_type: transition request type
|
||||
* @transition_error: whether there is error while transitioning the state
|
||||
*/
|
||||
struct dpu_crtc_smmu_state_data {
|
||||
uint32_t state;
|
||||
uint32_t transition_type;
|
||||
uint32_t transition_error;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpu_crtc_mixer: stores the map for each virtual pipeline in the CRTC
|
||||
* @hw_lm: LM HW Driver context
|
||||
* @hw_ctl: CTL Path HW driver context
|
||||
* @encoder: Encoder attached to this lm & ctl
|
||||
* @mixer_op_mode: mixer blending operation mode
|
||||
* @flush_mask: mixer flush mask for ctl, mixer and pipe
|
||||
*/
|
||||
struct dpu_crtc_mixer {
|
||||
struct dpu_hw_mixer *hw_lm;
|
||||
struct dpu_hw_ctl *hw_ctl;
|
||||
struct drm_encoder *encoder;
|
||||
u32 mixer_op_mode;
|
||||
u32 flush_mask;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpu_crtc_frame_event: stores crtc frame event for crtc processing
|
||||
* @work: base work structure
|
||||
* @crtc: Pointer to crtc handling this event
|
||||
* @list: event list
|
||||
* @ts: timestamp at queue entry
|
||||
* @event: event identifier
|
||||
*/
|
||||
struct dpu_crtc_frame_event {
|
||||
struct kthread_work work;
|
||||
struct drm_crtc *crtc;
|
||||
struct list_head list;
|
||||
ktime_t ts;
|
||||
u32 event;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpu_crtc_event - event callback tracking structure
|
||||
* @list: Linked list tracking node
|
||||
* @kt_work: Kthread worker structure
|
||||
* @dpu_crtc: Pointer to associated dpu_crtc structure
|
||||
* @cb_func: Pointer to callback function
|
||||
* @usr: Pointer to user data to be provided to the callback
|
||||
*/
|
||||
struct dpu_crtc_event {
|
||||
struct list_head list;
|
||||
struct kthread_work kt_work;
|
||||
void *dpu_crtc;
|
||||
|
||||
void (*cb_func)(struct drm_crtc *crtc, void *usr);
|
||||
void *usr;
|
||||
};
|
||||
|
||||
/*
|
||||
* Maximum number of free event structures to cache
|
||||
*/
|
||||
#define DPU_CRTC_MAX_EVENT_COUNT 16
|
||||
|
||||
/**
|
||||
* struct dpu_crtc - virtualized CRTC data structure
|
||||
* @base : Base drm crtc structure
|
||||
* @name : ASCII description of this crtc
|
||||
* @num_ctls : Number of ctl paths in use
|
||||
* @num_mixers : Number of mixers in use
|
||||
* @mixers_swapped: Whether the mixers have been swapped for left/right update
|
||||
* especially in the case of DSC Merge.
|
||||
* @mixers : List of active mixers
|
||||
* @event : Pointer to last received drm vblank event. If there is a
|
||||
* pending vblank event, this will be non-null.
|
||||
* @vsync_count : Running count of received vsync events
|
||||
* @drm_requested_vblank : Whether vblanks have been enabled in the encoder
|
||||
* @property_info : Opaque structure for generic property support
|
||||
* @property_defaults : Array of default values for generic property support
|
||||
* @stage_cfg : H/w mixer stage configuration
|
||||
* @debugfs_root : Parent of debugfs node
|
||||
* @vblank_cb_count : count of vblank callback since last reset
|
||||
* @play_count : frame count between crtc enable and disable
|
||||
* @vblank_cb_time : ktime at vblank count reset
|
||||
* @vblank_requested : whether the user has requested vblank events
|
||||
* @suspend : whether or not a suspend operation is in progress
|
||||
* @enabled : whether the DPU CRTC is currently enabled. updated in the
|
||||
* commit-thread, not state-swap time which is earlier, so
|
||||
* safe to make decisions on during VBLANK on/off work
|
||||
* @feature_list : list of color processing features supported on a crtc
|
||||
* @active_list : list of color processing features are active
|
||||
* @dirty_list : list of color processing features are dirty
|
||||
* @ad_dirty: list containing ad properties that are dirty
|
||||
* @ad_active: list containing ad properties that are active
|
||||
* @crtc_lock : crtc lock around create, destroy and access.
|
||||
* @frame_pending : Whether or not an update is pending
|
||||
* @frame_events : static allocation of in-flight frame events
|
||||
* @frame_event_list : available frame event list
|
||||
* @spin_lock : spin lock for frame event, transaction status, etc...
|
||||
* @frame_done_comp : for frame_event_done synchronization
|
||||
* @event_thread : Pointer to event handler thread
|
||||
* @event_worker : Event worker queue
|
||||
* @event_cache : Local cache of event worker structures
|
||||
* @event_free_list : List of available event structures
|
||||
* @event_lock : Spinlock around event handling code
|
||||
* @misr_enable : boolean entry indicates misr enable/disable status.
|
||||
* @misr_frame_count : misr frame count provided by client
|
||||
* @misr_data : store misr data before turning off the clocks.
|
||||
* @phandle: Pointer to power handler
|
||||
* @power_event : registered power event handle
|
||||
* @cur_perf : current performance committed to clock/bandwidth driver
|
||||
* @rp_lock : serialization lock for resource pool
|
||||
* @rp_head : list of active resource pool
|
||||
* @scl3_cfg_lut : qseed3 lut config
|
||||
*/
|
||||
struct dpu_crtc {
|
||||
struct drm_crtc base;
|
||||
char name[DPU_CRTC_NAME_SIZE];
|
||||
|
||||
/* HW Resources reserved for the crtc */
|
||||
u32 num_ctls;
|
||||
u32 num_mixers;
|
||||
bool mixers_swapped;
|
||||
struct dpu_crtc_mixer mixers[CRTC_DUAL_MIXERS];
|
||||
struct dpu_hw_scaler3_lut_cfg *scl3_lut_cfg;
|
||||
|
||||
struct drm_pending_vblank_event *event;
|
||||
u32 vsync_count;
|
||||
|
||||
struct dpu_hw_stage_cfg stage_cfg;
|
||||
struct dentry *debugfs_root;
|
||||
|
||||
u32 vblank_cb_count;
|
||||
u64 play_count;
|
||||
ktime_t vblank_cb_time;
|
||||
bool vblank_requested;
|
||||
bool suspend;
|
||||
bool enabled;
|
||||
|
||||
struct list_head feature_list;
|
||||
struct list_head active_list;
|
||||
struct list_head dirty_list;
|
||||
struct list_head ad_dirty;
|
||||
struct list_head ad_active;
|
||||
|
||||
struct mutex crtc_lock;
|
||||
|
||||
atomic_t frame_pending;
|
||||
struct dpu_crtc_frame_event frame_events[DPU_CRTC_FRAME_EVENT_SIZE];
|
||||
struct list_head frame_event_list;
|
||||
spinlock_t spin_lock;
|
||||
struct completion frame_done_comp;
|
||||
|
||||
/* for handling internal event thread */
|
||||
struct dpu_crtc_event event_cache[DPU_CRTC_MAX_EVENT_COUNT];
|
||||
struct list_head event_free_list;
|
||||
spinlock_t event_lock;
|
||||
bool misr_enable;
|
||||
u32 misr_frame_count;
|
||||
u32 misr_data[CRTC_DUAL_MIXERS];
|
||||
|
||||
struct dpu_power_handle *phandle;
|
||||
struct dpu_power_event *power_event;
|
||||
|
||||
struct dpu_core_perf_params cur_perf;
|
||||
|
||||
struct mutex rp_lock;
|
||||
struct list_head rp_head;
|
||||
|
||||
struct dpu_crtc_smmu_state_data smmu_state;
|
||||
};
|
||||
|
||||
#define to_dpu_crtc(x) container_of(x, struct dpu_crtc, base)
|
||||
|
||||
/**
|
||||
* struct dpu_crtc_res_ops - common operations for crtc resources
|
||||
* @get: get given resource
|
||||
* @put: put given resource
|
||||
*/
|
||||
struct dpu_crtc_res_ops {
|
||||
void *(*get)(void *val, u32 type, u64 tag);
|
||||
void (*put)(void *val);
|
||||
};
|
||||
|
||||
#define DPU_CRTC_RES_FLAG_FREE BIT(0)
|
||||
|
||||
/**
|
||||
* struct dpu_crtc_res - definition of crtc resources
|
||||
* @list: list of crtc resource
|
||||
* @type: crtc resource type
|
||||
* @tag: unique identifier per type
|
||||
* @refcount: reference/usage count
|
||||
* @ops: callback operations
|
||||
* @val: resource handle associated with type/tag
|
||||
* @flags: customization flags
|
||||
*/
|
||||
struct dpu_crtc_res {
|
||||
struct list_head list;
|
||||
u32 type;
|
||||
u64 tag;
|
||||
atomic_t refcount;
|
||||
struct dpu_crtc_res_ops ops;
|
||||
void *val;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* dpu_crtc_respool - crtc resource pool
|
||||
* @rp_lock: pointer to serialization lock
|
||||
* @rp_head: pointer to head of active resource pools of this crtc
|
||||
* @rp_list: list of crtc resource pool
|
||||
* @sequence_id: sequence identifier, incremented per state duplication
|
||||
* @res_list: list of resource managed by this resource pool
|
||||
* @ops: resource operations for parent resource pool
|
||||
*/
|
||||
struct dpu_crtc_respool {
|
||||
struct mutex *rp_lock;
|
||||
struct list_head *rp_head;
|
||||
struct list_head rp_list;
|
||||
u32 sequence_id;
|
||||
struct list_head res_list;
|
||||
struct dpu_crtc_res_ops ops;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpu_crtc_state - dpu container for atomic crtc state
|
||||
* @base: Base drm crtc state structure
|
||||
* @is_ppsplit : Whether current topology requires PPSplit special handling
|
||||
* @bw_control : true if bw/clk controlled by core bw/clk properties
|
||||
* @bw_split_vote : true if bw controlled by llcc/dram bw properties
|
||||
* @lm_bounds : LM boundaries based on current mode full resolution, no ROI.
|
||||
* Origin top left of CRTC.
|
||||
* @property_state: Local storage for msm_prop properties
|
||||
* @property_values: Current crtc property values
|
||||
* @input_fence_timeout_ns : Cached input fence timeout, in ns
|
||||
* @new_perf: new performance state being requested
|
||||
*/
|
||||
struct dpu_crtc_state {
|
||||
struct drm_crtc_state base;
|
||||
|
||||
bool bw_control;
|
||||
bool bw_split_vote;
|
||||
|
||||
bool is_ppsplit;
|
||||
struct drm_rect lm_bounds[CRTC_DUAL_MIXERS];
|
||||
|
||||
uint64_t input_fence_timeout_ns;
|
||||
|
||||
struct dpu_core_perf_params new_perf;
|
||||
struct dpu_crtc_respool rp;
|
||||
};
|
||||
|
||||
#define to_dpu_crtc_state(x) \
|
||||
container_of(x, struct dpu_crtc_state, base)
|
||||
|
||||
/**
|
||||
* dpu_crtc_get_mixer_width - get the mixer width
|
||||
* Mixer width will be same as panel width(/2 for split)
|
||||
*/
|
||||
static inline int dpu_crtc_get_mixer_width(struct dpu_crtc *dpu_crtc,
|
||||
struct dpu_crtc_state *cstate, struct drm_display_mode *mode)
|
||||
{
|
||||
u32 mixer_width;
|
||||
|
||||
if (!dpu_crtc || !cstate || !mode)
|
||||
return 0;
|
||||
|
||||
mixer_width = (dpu_crtc->num_mixers == CRTC_DUAL_MIXERS ?
|
||||
mode->hdisplay / CRTC_DUAL_MIXERS : mode->hdisplay);
|
||||
|
||||
return mixer_width;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpu_crtc_get_mixer_height - get the mixer height
|
||||
* Mixer height will be same as panel height
|
||||
*/
|
||||
static inline int dpu_crtc_get_mixer_height(struct dpu_crtc *dpu_crtc,
|
||||
struct dpu_crtc_state *cstate, struct drm_display_mode *mode)
|
||||
{
|
||||
if (!dpu_crtc || !cstate || !mode)
|
||||
return 0;
|
||||
|
||||
return mode->vdisplay;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpu_crtc_frame_pending - retun the number of pending frames
|
||||
* @crtc: Pointer to drm crtc object
|
||||
*/
|
||||
static inline int dpu_crtc_frame_pending(struct drm_crtc *crtc)
|
||||
{
|
||||
struct dpu_crtc *dpu_crtc;
|
||||
|
||||
if (!crtc)
|
||||
return -EINVAL;
|
||||
|
||||
dpu_crtc = to_dpu_crtc(crtc);
|
||||
return atomic_read(&dpu_crtc->frame_pending);
|
||||
}
|
||||
|
||||
/**
|
||||
* dpu_crtc_vblank - enable or disable vblanks for this crtc
|
||||
* @crtc: Pointer to drm crtc object
|
||||
* @en: true to enable vblanks, false to disable
|
||||
*/
|
||||
int dpu_crtc_vblank(struct drm_crtc *crtc, bool en);
|
||||
|
||||
/**
|
||||
* dpu_crtc_commit_kickoff - trigger kickoff of the commit for this crtc
|
||||
* @crtc: Pointer to drm crtc object
|
||||
*/
|
||||
void dpu_crtc_commit_kickoff(struct drm_crtc *crtc);
|
||||
|
||||
/**
|
||||
* dpu_crtc_complete_commit - callback signalling completion of current commit
|
||||
* @crtc: Pointer to drm crtc object
|
||||
* @old_state: Pointer to drm crtc old state object
|
||||
*/
|
||||
void dpu_crtc_complete_commit(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_state);
|
||||
|
||||
/**
|
||||
* dpu_crtc_init - create a new crtc object
|
||||
* @dev: dpu device
|
||||
* @plane: base plane
|
||||
* @Return: new crtc object or error
|
||||
*/
|
||||
struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane);
|
||||
|
||||
/**
|
||||
* dpu_crtc_register_custom_event - api for enabling/disabling crtc event
|
||||
* @kms: Pointer to dpu_kms
|
||||
* @crtc_drm: Pointer to crtc object
|
||||
* @event: Event that client is interested
|
||||
* @en: Flag to enable/disable the event
|
||||
*/
|
||||
int dpu_crtc_register_custom_event(struct dpu_kms *kms,
|
||||
struct drm_crtc *crtc_drm, u32 event, bool en);
|
||||
|
||||
/**
|
||||
* dpu_crtc_get_intf_mode - get interface mode of the given crtc
|
||||
* @crtc: Pointert to crtc
|
||||
*/
|
||||
enum dpu_intf_mode dpu_crtc_get_intf_mode(struct drm_crtc *crtc);
|
||||
|
||||
/**
|
||||
* dpu_crtc_get_client_type - check the crtc type- rt, nrt etc.
|
||||
* @crtc: Pointer to crtc
|
||||
*/
|
||||
static inline enum dpu_crtc_client_type dpu_crtc_get_client_type(
|
||||
struct drm_crtc *crtc)
|
||||
{
|
||||
struct dpu_crtc_state *cstate =
|
||||
crtc ? to_dpu_crtc_state(crtc->state) : NULL;
|
||||
|
||||
if (!cstate)
|
||||
return NRT_CLIENT;
|
||||
|
||||
return RT_CLIENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpu_crtc_is_enabled - check if dpu crtc is enabled or not
|
||||
* @crtc: Pointer to crtc
|
||||
*/
|
||||
static inline bool dpu_crtc_is_enabled(struct drm_crtc *crtc)
|
||||
{
|
||||
return crtc ? crtc->enabled : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpu_crtc_event_queue - request event callback
|
||||
* @crtc: Pointer to drm crtc structure
|
||||
* @func: Pointer to callback function
|
||||
* @usr: Pointer to user data to be passed to callback
|
||||
* Returns: Zero on success
|
||||
*/
|
||||
int dpu_crtc_event_queue(struct drm_crtc *crtc,
|
||||
void (*func)(struct drm_crtc *crtc, void *usr), void *usr);
|
||||
|
||||
/**
|
||||
* dpu_crtc_res_add - add given resource to resource pool in crtc state
|
||||
* @state: Pointer to drm crtc state
|
||||
* @type: Resource type
|
||||
* @tag: Search tag for given resource
|
||||
* @val: Resource handle
|
||||
* @ops: Resource callback operations
|
||||
* return: 0 if success; error code otherwise
|
||||
*/
|
||||
int dpu_crtc_res_add(struct drm_crtc_state *state, u32 type, u64 tag,
|
||||
void *val, struct dpu_crtc_res_ops *ops);
|
||||
|
||||
/**
|
||||
* dpu_crtc_res_get - get given resource from resource pool in crtc state
|
||||
* @state: Pointer to drm crtc state
|
||||
* @type: Resource type
|
||||
* @tag: Search tag for given resource
|
||||
* return: Resource handle if success; pointer error or null otherwise
|
||||
*/
|
||||
void *dpu_crtc_res_get(struct drm_crtc_state *state, u32 type, u64 tag);
|
||||
|
||||
/**
|
||||
* dpu_crtc_res_put - return given resource to resource pool in crtc state
|
||||
* @state: Pointer to drm crtc state
|
||||
* @type: Resource type
|
||||
* @tag: Search tag for given resource
|
||||
* return: None
|
||||
*/
|
||||
void dpu_crtc_res_put(struct drm_crtc_state *state, u32 type, u64 tag);
|
||||
|
||||
#endif /* _DPU_CRTC_H_ */
|
||||
2393
drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c
Normal file
2393
drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c
Normal file
File diff suppressed because it is too large
Load Diff
103
drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.h
Normal file
103
drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef DPU_DBG_H_
|
||||
#define DPU_DBG_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
enum dpu_dbg_dump_flag {
|
||||
DPU_DBG_DUMP_IN_LOG = BIT(0),
|
||||
DPU_DBG_DUMP_IN_MEM = BIT(1),
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
|
||||
/**
|
||||
* dpu_dbg_init_dbg_buses - initialize debug bus dumping support for the chipset
|
||||
* @hwversion: Chipset revision
|
||||
*/
|
||||
void dpu_dbg_init_dbg_buses(u32 hwversion);
|
||||
|
||||
/**
|
||||
* dpu_dbg_init - initialize global dpu debug facilities: regdump
|
||||
* @dev: device handle
|
||||
* Returns: 0 or -ERROR
|
||||
*/
|
||||
int dpu_dbg_init(struct device *dev);
|
||||
|
||||
/**
|
||||
* dpu_dbg_debugfs_register - register entries at the given debugfs dir
|
||||
* @debugfs_root: debugfs root in which to create dpu debug entries
|
||||
* Returns: 0 or -ERROR
|
||||
*/
|
||||
int dpu_dbg_debugfs_register(struct dentry *debugfs_root);
|
||||
|
||||
/**
|
||||
* dpu_dbg_destroy - destroy the global dpu debug facilities
|
||||
* Returns: none
|
||||
*/
|
||||
void dpu_dbg_destroy(void);
|
||||
|
||||
/**
|
||||
* dpu_dbg_dump - trigger dumping of all dpu_dbg facilities
|
||||
* @queue_work: whether to queue the dumping work to the work_struct
|
||||
* @name: string indicating origin of dump
|
||||
* @dump_dbgbus: dump the dpu debug bus
|
||||
* @dump_vbif_rt: dump the vbif rt bus
|
||||
* Returns: none
|
||||
*/
|
||||
void dpu_dbg_dump(bool queue_work, const char *name, bool dump_dbgbus_dpu,
|
||||
bool dump_dbgbus_vbif_rt);
|
||||
|
||||
/**
|
||||
* dpu_dbg_set_dpu_top_offset - set the target specific offset from mdss base
|
||||
* address of the top registers. Used for accessing debug bus controls.
|
||||
* @blk_off: offset from mdss base of the top block
|
||||
*/
|
||||
void dpu_dbg_set_dpu_top_offset(u32 blk_off);
|
||||
|
||||
#else
|
||||
|
||||
static inline void dpu_dbg_init_dbg_buses(u32 hwversion)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int dpu_dbg_init(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int dpu_dbg_debugfs_register(struct dentry *debugfs_root)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void dpu_dbg_destroy(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dpu_dbg_dump(bool queue_work, const char *name,
|
||||
bool dump_dbgbus_dpu, bool dump_dbgbus_vbif_rt)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dpu_dbg_set_dpu_top_offset(u32 blk_off)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_DEBUG_FS) */
|
||||
|
||||
|
||||
#endif /* DPU_DBG_H_ */
|
||||
2575
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
Normal file
2575
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
Normal file
File diff suppressed because it is too large
Load Diff
191
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
Normal file
191
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
|
||||
* Copyright (C) 2013 Red Hat
|
||||
* Author: Rob Clark <robdclark@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __DPU_ENCODER_H__
|
||||
#define __DPU_ENCODER_H__
|
||||
|
||||
#include <drm/drm_crtc.h>
|
||||
#include "dpu_hw_mdss.h"
|
||||
|
||||
#define DPU_ENCODER_FRAME_EVENT_DONE BIT(0)
|
||||
#define DPU_ENCODER_FRAME_EVENT_ERROR BIT(1)
|
||||
#define DPU_ENCODER_FRAME_EVENT_PANEL_DEAD BIT(2)
|
||||
#define DPU_ENCODER_FRAME_EVENT_IDLE BIT(3)
|
||||
|
||||
#define IDLE_TIMEOUT (66 - 16/2)
|
||||
|
||||
/**
|
||||
* Encoder functions and data types
|
||||
* @intfs: Interfaces this encoder is using, INTF_MODE_NONE if unused
|
||||
* @needs_cdm: Encoder requests a CDM based on pixel format conversion needs
|
||||
* @display_num_of_h_tiles: Number of horizontal tiles in case of split
|
||||
* interface
|
||||
* @topology: Topology of the display
|
||||
*/
|
||||
struct dpu_encoder_hw_resources {
|
||||
enum dpu_intf_mode intfs[INTF_MAX];
|
||||
bool needs_cdm;
|
||||
u32 display_num_of_h_tiles;
|
||||
};
|
||||
|
||||
/**
|
||||
* dpu_encoder_kickoff_params - info encoder requires at kickoff
|
||||
* @affected_displays: bitmask, bit set means the ROI of the commit lies within
|
||||
* the bounds of the physical display at the bit index
|
||||
*/
|
||||
struct dpu_encoder_kickoff_params {
|
||||
unsigned long affected_displays;
|
||||
};
|
||||
|
||||
/**
|
||||
* dpu_encoder_get_hw_resources - Populate table of required hardware resources
|
||||
* @encoder: encoder pointer
|
||||
* @hw_res: resource table to populate with encoder required resources
|
||||
* @conn_state: report hw reqs based on this proposed connector state
|
||||
*/
|
||||
void dpu_encoder_get_hw_resources(struct drm_encoder *encoder,
|
||||
struct dpu_encoder_hw_resources *hw_res,
|
||||
struct drm_connector_state *conn_state);
|
||||
|
||||
/**
|
||||
* dpu_encoder_register_vblank_callback - provide callback to encoder that
|
||||
* will be called on the next vblank.
|
||||
* @encoder: encoder pointer
|
||||
* @cb: callback pointer, provide NULL to deregister and disable IRQs
|
||||
* @data: user data provided to callback
|
||||
*/
|
||||
void dpu_encoder_register_vblank_callback(struct drm_encoder *encoder,
|
||||
void (*cb)(void *), void *data);
|
||||
|
||||
/**
|
||||
* dpu_encoder_register_frame_event_callback - provide callback to encoder that
|
||||
* will be called after the request is complete, or other events.
|
||||
* @encoder: encoder pointer
|
||||
* @cb: callback pointer, provide NULL to deregister
|
||||
* @data: user data provided to callback
|
||||
*/
|
||||
void dpu_encoder_register_frame_event_callback(struct drm_encoder *encoder,
|
||||
void (*cb)(void *, u32), void *data);
|
||||
|
||||
/**
|
||||
* dpu_encoder_prepare_for_kickoff - schedule double buffer flip of the ctl
|
||||
* path (i.e. ctl flush and start) at next appropriate time.
|
||||
* Immediately: if no previous commit is outstanding.
|
||||
* Delayed: Block until next trigger can be issued.
|
||||
* @encoder: encoder pointer
|
||||
* @params: kickoff time parameters
|
||||
*/
|
||||
void dpu_encoder_prepare_for_kickoff(struct drm_encoder *encoder,
|
||||
struct dpu_encoder_kickoff_params *params);
|
||||
|
||||
/**
|
||||
* dpu_encoder_trigger_kickoff_pending - Clear the flush bits from previous
|
||||
* kickoff and trigger the ctl prepare progress for command mode display.
|
||||
* @encoder: encoder pointer
|
||||
*/
|
||||
void dpu_encoder_trigger_kickoff_pending(struct drm_encoder *encoder);
|
||||
|
||||
/**
|
||||
* dpu_encoder_kickoff - trigger a double buffer flip of the ctl path
|
||||
* (i.e. ctl flush and start) immediately.
|
||||
* @encoder: encoder pointer
|
||||
*/
|
||||
void dpu_encoder_kickoff(struct drm_encoder *encoder);
|
||||
|
||||
/**
|
||||
* dpu_encoder_wait_for_event - Waits for encoder events
|
||||
* @encoder: encoder pointer
|
||||
* @event: event to wait for
|
||||
* MSM_ENC_COMMIT_DONE - Wait for hardware to have flushed the current pending
|
||||
* frames to hardware at a vblank or ctl_start
|
||||
* Encoders will map this differently depending on the
|
||||
* panel type.
|
||||
* vid mode -> vsync_irq
|
||||
* cmd mode -> ctl_start
|
||||
* MSM_ENC_TX_COMPLETE - Wait for the hardware to transfer all the pixels to
|
||||
* the panel. Encoders will map this differently
|
||||
* depending on the panel type.
|
||||
* vid mode -> vsync_irq
|
||||
* cmd mode -> pp_done
|
||||
* Returns: 0 on success, -EWOULDBLOCK if already signaled, error otherwise
|
||||
*/
|
||||
int dpu_encoder_wait_for_event(struct drm_encoder *drm_encoder,
|
||||
enum msm_event_wait event);
|
||||
|
||||
/*
|
||||
* dpu_encoder_get_intf_mode - get interface mode of the given encoder
|
||||
* @encoder: Pointer to drm encoder object
|
||||
*/
|
||||
enum dpu_intf_mode dpu_encoder_get_intf_mode(struct drm_encoder *encoder);
|
||||
|
||||
/**
|
||||
* dpu_encoder_virt_restore - restore the encoder configs
|
||||
* @encoder: encoder pointer
|
||||
*/
|
||||
void dpu_encoder_virt_restore(struct drm_encoder *encoder);
|
||||
|
||||
/**
|
||||
* dpu_encoder_check_mode - check if given mode is supported or not
|
||||
* @drm_enc: Pointer to drm encoder object
|
||||
* @mode: Mode to be checked
|
||||
* @Return: true if it is cmd mode
|
||||
*/
|
||||
bool dpu_encoder_check_mode(struct drm_encoder *drm_enc, u32 mode);
|
||||
|
||||
/**
|
||||
* dpu_encoder_init - initialize virtual encoder object
|
||||
* @dev: Pointer to drm device structure
|
||||
* @disp_info: Pointer to display information structure
|
||||
* Returns: Pointer to newly created drm encoder
|
||||
*/
|
||||
struct drm_encoder *dpu_encoder_init(
|
||||
struct drm_device *dev,
|
||||
int drm_enc_mode);
|
||||
|
||||
/**
|
||||
* dpu_encoder_setup - setup dpu_encoder for the display probed
|
||||
* @dev: Pointer to drm device structure
|
||||
* @enc: Pointer to the drm_encoder
|
||||
* @disp_info: Pointer to the display info
|
||||
*/
|
||||
int dpu_encoder_setup(struct drm_device *dev, struct drm_encoder *enc,
|
||||
struct msm_display_info *disp_info);
|
||||
|
||||
/**
|
||||
* dpu_encoder_destroy - destroy previously initialized virtual encoder
|
||||
* @drm_enc: Pointer to previously created drm encoder structure
|
||||
*/
|
||||
void dpu_encoder_destroy(struct drm_encoder *drm_enc);
|
||||
|
||||
/**
|
||||
* dpu_encoder_prepare_commit - prepare encoder at the very beginning of an
|
||||
* atomic commit, before any registers are written
|
||||
* @drm_enc: Pointer to previously created drm encoder structure
|
||||
*/
|
||||
void dpu_encoder_prepare_commit(struct drm_encoder *drm_enc);
|
||||
|
||||
/**
|
||||
* dpu_encoder_set_idle_timeout - set the idle timeout for video
|
||||
* and command mode encoders.
|
||||
* @drm_enc: Pointer to previously created drm encoder structure
|
||||
* @idle_timeout: idle timeout duration in milliseconds
|
||||
*/
|
||||
void dpu_encoder_set_idle_timeout(struct drm_encoder *drm_enc,
|
||||
u32 idle_timeout);
|
||||
|
||||
#endif /* __DPU_ENCODER_H__ */
|
||||
453
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
Normal file
453
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
Normal file
@@ -0,0 +1,453 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2018 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DPU_ENCODER_PHYS_H__
|
||||
#define __DPU_ENCODER_PHYS_H__
|
||||
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
#include "dpu_kms.h"
|
||||
#include "dpu_hw_intf.h"
|
||||
#include "dpu_hw_pingpong.h"
|
||||
#include "dpu_hw_ctl.h"
|
||||
#include "dpu_hw_top.h"
|
||||
#include "dpu_hw_cdm.h"
|
||||
#include "dpu_encoder.h"
|
||||
|
||||
#define DPU_ENCODER_NAME_MAX 16
|
||||
|
||||
/* wait for at most 2 vsync for lowest refresh rate (24hz) */
|
||||
#define KICKOFF_TIMEOUT_MS 84
|
||||
#define KICKOFF_TIMEOUT_JIFFIES msecs_to_jiffies(KICKOFF_TIMEOUT_MS)
|
||||
|
||||
/**
|
||||
* enum dpu_enc_split_role - Role this physical encoder will play in a
|
||||
* split-panel configuration, where one panel is master, and others slaves.
|
||||
* Masters have extra responsibilities, like managing the VBLANK IRQ.
|
||||
* @ENC_ROLE_SOLO: This is the one and only panel. This encoder is master.
|
||||
* @ENC_ROLE_MASTER: This encoder is the master of a split panel config.
|
||||
* @ENC_ROLE_SLAVE: This encoder is not the master of a split panel config.
|
||||
*/
|
||||
enum dpu_enc_split_role {
|
||||
ENC_ROLE_SOLO,
|
||||
ENC_ROLE_MASTER,
|
||||
ENC_ROLE_SLAVE,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dpu_enc_enable_state - current enabled state of the physical encoder
|
||||
* @DPU_ENC_DISABLING: Encoder transitioning to disable state
|
||||
* Events bounding transition are encoder type specific
|
||||
* @DPU_ENC_DISABLED: Encoder is disabled
|
||||
* @DPU_ENC_ENABLING: Encoder transitioning to enabled
|
||||
* Events bounding transition are encoder type specific
|
||||
* @DPU_ENC_ENABLED: Encoder is enabled
|
||||
* @DPU_ENC_ERR_NEEDS_HW_RESET: Encoder is enabled, but requires a hw_reset
|
||||
* to recover from a previous error
|
||||
*/
|
||||
enum dpu_enc_enable_state {
|
||||
DPU_ENC_DISABLING,
|
||||
DPU_ENC_DISABLED,
|
||||
DPU_ENC_ENABLING,
|
||||
DPU_ENC_ENABLED,
|
||||
DPU_ENC_ERR_NEEDS_HW_RESET
|
||||
};
|
||||
|
||||
struct dpu_encoder_phys;
|
||||
|
||||
/**
|
||||
* struct dpu_encoder_virt_ops - Interface the containing virtual encoder
|
||||
* provides for the physical encoders to use to callback.
|
||||
* @handle_vblank_virt: Notify virtual encoder of vblank IRQ reception
|
||||
* Note: This is called from IRQ handler context.
|
||||
* @handle_underrun_virt: Notify virtual encoder of underrun IRQ reception
|
||||
* Note: This is called from IRQ handler context.
|
||||
* @handle_frame_done: Notify virtual encoder that this phys encoder
|
||||
* completes last request frame.
|
||||
*/
|
||||
struct dpu_encoder_virt_ops {
|
||||
void (*handle_vblank_virt)(struct drm_encoder *,
|
||||
struct dpu_encoder_phys *phys);
|
||||
void (*handle_underrun_virt)(struct drm_encoder *,
|
||||
struct dpu_encoder_phys *phys);
|
||||
void (*handle_frame_done)(struct drm_encoder *,
|
||||
struct dpu_encoder_phys *phys, u32 event);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpu_encoder_phys_ops - Interface the physical encoders provide to
|
||||
* the containing virtual encoder.
|
||||
* @late_register: DRM Call. Add Userspace interfaces, debugfs.
|
||||
* @prepare_commit: MSM Atomic Call, start of atomic commit sequence
|
||||
* @is_master: Whether this phys_enc is the current master
|
||||
* encoder. Can be switched at enable time. Based
|
||||
* on split_role and current mode (CMD/VID).
|
||||
* @mode_fixup: DRM Call. Fixup a DRM mode.
|
||||
* @mode_set: DRM Call. Set a DRM mode.
|
||||
* This likely caches the mode, for use at enable.
|
||||
* @enable: DRM Call. Enable a DRM mode.
|
||||
* @disable: DRM Call. Disable mode.
|
||||
* @atomic_check: DRM Call. Atomic check new DRM state.
|
||||
* @destroy: DRM Call. Destroy and release resources.
|
||||
* @get_hw_resources: Populate the structure with the hardware
|
||||
* resources that this phys_enc is using.
|
||||
* Expect no overlap between phys_encs.
|
||||
* @control_vblank_irq Register/Deregister for VBLANK IRQ
|
||||
* @wait_for_commit_done: Wait for hardware to have flushed the
|
||||
* current pending frames to hardware
|
||||
* @wait_for_tx_complete: Wait for hardware to transfer the pixels
|
||||
* to the panel
|
||||
* @wait_for_vblank: Wait for VBLANK, for sub-driver internal use
|
||||
* @prepare_for_kickoff: Do any work necessary prior to a kickoff
|
||||
* For CMD encoder, may wait for previous tx done
|
||||
* @handle_post_kickoff: Do any work necessary post-kickoff work
|
||||
* @trigger_start: Process start event on physical encoder
|
||||
* @needs_single_flush: Whether encoder slaves need to be flushed
|
||||
* @setup_misr: Sets up MISR, enable and disables based on sysfs
|
||||
* @collect_misr: Collects MISR data on frame update
|
||||
* @hw_reset: Issue HW recovery such as CTL reset and clear
|
||||
* DPU_ENC_ERR_NEEDS_HW_RESET state
|
||||
* @irq_control: Handler to enable/disable all the encoder IRQs
|
||||
* @prepare_idle_pc: phys encoder can update the vsync_enable status
|
||||
* on idle power collapse prepare
|
||||
* @restore: Restore all the encoder configs.
|
||||
* @get_line_count: Obtain current vertical line count
|
||||
*/
|
||||
|
||||
struct dpu_encoder_phys_ops {
|
||||
int (*late_register)(struct dpu_encoder_phys *encoder,
|
||||
struct dentry *debugfs_root);
|
||||
void (*prepare_commit)(struct dpu_encoder_phys *encoder);
|
||||
bool (*is_master)(struct dpu_encoder_phys *encoder);
|
||||
bool (*mode_fixup)(struct dpu_encoder_phys *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
void (*mode_set)(struct dpu_encoder_phys *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
void (*enable)(struct dpu_encoder_phys *encoder);
|
||||
void (*disable)(struct dpu_encoder_phys *encoder);
|
||||
int (*atomic_check)(struct dpu_encoder_phys *encoder,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state);
|
||||
void (*destroy)(struct dpu_encoder_phys *encoder);
|
||||
void (*get_hw_resources)(struct dpu_encoder_phys *encoder,
|
||||
struct dpu_encoder_hw_resources *hw_res,
|
||||
struct drm_connector_state *conn_state);
|
||||
int (*control_vblank_irq)(struct dpu_encoder_phys *enc, bool enable);
|
||||
int (*wait_for_commit_done)(struct dpu_encoder_phys *phys_enc);
|
||||
int (*wait_for_tx_complete)(struct dpu_encoder_phys *phys_enc);
|
||||
int (*wait_for_vblank)(struct dpu_encoder_phys *phys_enc);
|
||||
void (*prepare_for_kickoff)(struct dpu_encoder_phys *phys_enc,
|
||||
struct dpu_encoder_kickoff_params *params);
|
||||
void (*handle_post_kickoff)(struct dpu_encoder_phys *phys_enc);
|
||||
void (*trigger_start)(struct dpu_encoder_phys *phys_enc);
|
||||
bool (*needs_single_flush)(struct dpu_encoder_phys *phys_enc);
|
||||
|
||||
void (*setup_misr)(struct dpu_encoder_phys *phys_encs,
|
||||
bool enable, u32 frame_count);
|
||||
u32 (*collect_misr)(struct dpu_encoder_phys *phys_enc);
|
||||
void (*hw_reset)(struct dpu_encoder_phys *phys_enc);
|
||||
void (*irq_control)(struct dpu_encoder_phys *phys, bool enable);
|
||||
void (*prepare_idle_pc)(struct dpu_encoder_phys *phys_enc);
|
||||
void (*restore)(struct dpu_encoder_phys *phys);
|
||||
int (*get_line_count)(struct dpu_encoder_phys *phys);
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dpu_intr_idx - dpu encoder interrupt index
|
||||
* @INTR_IDX_VSYNC: Vsync interrupt for video mode panel
|
||||
* @INTR_IDX_PINGPONG: Pingpong done unterrupt for cmd mode panel
|
||||
* @INTR_IDX_UNDERRUN: Underrun unterrupt for video and cmd mode panel
|
||||
* @INTR_IDX_RDPTR: Readpointer done unterrupt for cmd mode panel
|
||||
*/
|
||||
enum dpu_intr_idx {
|
||||
INTR_IDX_VSYNC,
|
||||
INTR_IDX_PINGPONG,
|
||||
INTR_IDX_UNDERRUN,
|
||||
INTR_IDX_CTL_START,
|
||||
INTR_IDX_RDPTR,
|
||||
INTR_IDX_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* dpu_encoder_irq - tracking structure for interrupts
|
||||
* @name: string name of interrupt
|
||||
* @intr_type: Encoder interrupt type
|
||||
* @intr_idx: Encoder interrupt enumeration
|
||||
* @hw_idx: HW Block ID
|
||||
* @irq_idx: IRQ interface lookup index from DPU IRQ framework
|
||||
* will be -EINVAL if IRQ is not registered
|
||||
* @irq_cb: interrupt callback
|
||||
*/
|
||||
struct dpu_encoder_irq {
|
||||
const char *name;
|
||||
enum dpu_intr_type intr_type;
|
||||
enum dpu_intr_idx intr_idx;
|
||||
int hw_idx;
|
||||
int irq_idx;
|
||||
struct dpu_irq_callback cb;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpu_encoder_phys - physical encoder that drives a single INTF block
|
||||
* tied to a specific panel / sub-panel. Abstract type, sub-classed by
|
||||
* phys_vid or phys_cmd for video mode or command mode encs respectively.
|
||||
* @parent: Pointer to the containing virtual encoder
|
||||
* @connector: If a mode is set, cached pointer to the active connector
|
||||
* @ops: Operations exposed to the virtual encoder
|
||||
* @parent_ops: Callbacks exposed by the parent to the phys_enc
|
||||
* @hw_mdptop: Hardware interface to the top registers
|
||||
* @hw_ctl: Hardware interface to the ctl registers
|
||||
* @hw_cdm: Hardware interface to the cdm registers
|
||||
* @cdm_cfg: Chroma-down hardware configuration
|
||||
* @hw_pp: Hardware interface to the ping pong registers
|
||||
* @dpu_kms: Pointer to the dpu_kms top level
|
||||
* @cached_mode: DRM mode cached at mode_set time, acted on in enable
|
||||
* @enabled: Whether the encoder has enabled and running a mode
|
||||
* @split_role: Role to play in a split-panel configuration
|
||||
* @intf_mode: Interface mode
|
||||
* @intf_idx: Interface index on dpu hardware
|
||||
* @topology_name: topology selected for the display
|
||||
* @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes
|
||||
* @enable_state: Enable state tracking
|
||||
* @vblank_refcount: Reference count of vblank request
|
||||
* @vsync_cnt: Vsync count for the physical encoder
|
||||
* @underrun_cnt: Underrun count for the physical encoder
|
||||
* @pending_kickoff_cnt: Atomic counter tracking the number of kickoffs
|
||||
* vs. the number of done/vblank irqs. Should hover
|
||||
* between 0-2 Incremented when a new kickoff is
|
||||
* scheduled. Decremented in irq handler
|
||||
* @pending_ctlstart_cnt: Atomic counter tracking the number of ctl start
|
||||
* pending.
|
||||
* @pending_kickoff_wq: Wait queue for blocking until kickoff completes
|
||||
* @irq: IRQ tracking structures
|
||||
*/
|
||||
struct dpu_encoder_phys {
|
||||
struct drm_encoder *parent;
|
||||
struct drm_connector *connector;
|
||||
struct dpu_encoder_phys_ops ops;
|
||||
const struct dpu_encoder_virt_ops *parent_ops;
|
||||
struct dpu_hw_mdp *hw_mdptop;
|
||||
struct dpu_hw_ctl *hw_ctl;
|
||||
struct dpu_hw_cdm *hw_cdm;
|
||||
struct dpu_hw_cdm_cfg cdm_cfg;
|
||||
struct dpu_hw_pingpong *hw_pp;
|
||||
struct dpu_kms *dpu_kms;
|
||||
struct drm_display_mode cached_mode;
|
||||
enum dpu_enc_split_role split_role;
|
||||
enum dpu_intf_mode intf_mode;
|
||||
enum dpu_intf intf_idx;
|
||||
enum dpu_rm_topology_name topology_name;
|
||||
spinlock_t *enc_spinlock;
|
||||
enum dpu_enc_enable_state enable_state;
|
||||
atomic_t vblank_refcount;
|
||||
atomic_t vsync_cnt;
|
||||
atomic_t underrun_cnt;
|
||||
atomic_t pending_ctlstart_cnt;
|
||||
atomic_t pending_kickoff_cnt;
|
||||
wait_queue_head_t pending_kickoff_wq;
|
||||
struct dpu_encoder_irq irq[INTR_IDX_MAX];
|
||||
};
|
||||
|
||||
static inline int dpu_encoder_phys_inc_pending(struct dpu_encoder_phys *phys)
|
||||
{
|
||||
atomic_inc_return(&phys->pending_ctlstart_cnt);
|
||||
return atomic_inc_return(&phys->pending_kickoff_cnt);
|
||||
}
|
||||
|
||||
/**
|
||||
* struct dpu_encoder_phys_vid - sub-class of dpu_encoder_phys to handle video
|
||||
* mode specific operations
|
||||
* @base: Baseclass physical encoder structure
|
||||
* @hw_intf: Hardware interface to the intf registers
|
||||
* @timing_params: Current timing parameter
|
||||
*/
|
||||
struct dpu_encoder_phys_vid {
|
||||
struct dpu_encoder_phys base;
|
||||
struct dpu_hw_intf *hw_intf;
|
||||
struct intf_timing_params timing_params;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpu_encoder_phys_cmd - sub-class of dpu_encoder_phys to handle command
|
||||
* mode specific operations
|
||||
* @base: Baseclass physical encoder structure
|
||||
* @intf_idx: Intf Block index used by this phys encoder
|
||||
* @stream_sel: Stream selection for multi-stream interfaces
|
||||
* @serialize_wait4pp: serialize wait4pp feature waits for pp_done interrupt
|
||||
* after ctl_start instead of before next frame kickoff
|
||||
* @pp_timeout_report_cnt: number of pingpong done irq timeout errors
|
||||
* @pending_vblank_cnt: Atomic counter tracking pending wait for VBLANK
|
||||
* @pending_vblank_wq: Wait queue for blocking until VBLANK received
|
||||
*/
|
||||
struct dpu_encoder_phys_cmd {
|
||||
struct dpu_encoder_phys base;
|
||||
int stream_sel;
|
||||
bool serialize_wait4pp;
|
||||
int pp_timeout_report_cnt;
|
||||
atomic_t pending_vblank_cnt;
|
||||
wait_queue_head_t pending_vblank_wq;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpu_enc_phys_init_params - initialization parameters for phys encs
|
||||
* @dpu_kms: Pointer to the dpu_kms top level
|
||||
* @parent: Pointer to the containing virtual encoder
|
||||
* @parent_ops: Callbacks exposed by the parent to the phys_enc
|
||||
* @split_role: Role to play in a split-panel configuration
|
||||
* @intf_idx: Interface index this phys_enc will control
|
||||
* @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes
|
||||
*/
|
||||
struct dpu_enc_phys_init_params {
|
||||
struct dpu_kms *dpu_kms;
|
||||
struct drm_encoder *parent;
|
||||
const struct dpu_encoder_virt_ops *parent_ops;
|
||||
enum dpu_enc_split_role split_role;
|
||||
enum dpu_intf intf_idx;
|
||||
spinlock_t *enc_spinlock;
|
||||
};
|
||||
|
||||
/**
|
||||
* dpu_encoder_wait_info - container for passing arguments to irq wait functions
|
||||
* @wq: wait queue structure
|
||||
* @atomic_cnt: wait until atomic_cnt equals zero
|
||||
* @timeout_ms: timeout value in milliseconds
|
||||
*/
|
||||
struct dpu_encoder_wait_info {
|
||||
wait_queue_head_t *wq;
|
||||
atomic_t *atomic_cnt;
|
||||
s64 timeout_ms;
|
||||
};
|
||||
|
||||
/**
|
||||
* dpu_encoder_phys_vid_init - Construct a new video mode physical encoder
|
||||
* @p: Pointer to init params structure
|
||||
* Return: Error code or newly allocated encoder
|
||||
*/
|
||||
struct dpu_encoder_phys *dpu_encoder_phys_vid_init(
|
||||
struct dpu_enc_phys_init_params *p);
|
||||
|
||||
/**
|
||||
* dpu_encoder_phys_cmd_init - Construct a new command mode physical encoder
|
||||
* @p: Pointer to init params structure
|
||||
* Return: Error code or newly allocated encoder
|
||||
*/
|
||||
struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(
|
||||
struct dpu_enc_phys_init_params *p);
|
||||
|
||||
/**
|
||||
* dpu_encoder_helper_trigger_start - control start helper function
|
||||
* This helper function may be optionally specified by physical
|
||||
* encoders if they require ctl_start triggering.
|
||||
* @phys_enc: Pointer to physical encoder structure
|
||||
*/
|
||||
void dpu_encoder_helper_trigger_start(struct dpu_encoder_phys *phys_enc);
|
||||
|
||||
/**
|
||||
* dpu_encoder_helper_wait_event_timeout - wait for event with timeout
|
||||
* taking into account that jiffies may jump between reads leading to
|
||||
* incorrectly detected timeouts. Prevent failure in this scenario by
|
||||
* making sure that elapsed time during wait is valid.
|
||||
* @drm_id: drm object id for logging
|
||||
* @hw_id: hw instance id for logging
|
||||
* @info: wait info structure
|
||||
*/
|
||||
int dpu_encoder_helper_wait_event_timeout(
|
||||
int32_t drm_id,
|
||||
int32_t hw_id,
|
||||
struct dpu_encoder_wait_info *info);
|
||||
|
||||
/**
|
||||
* dpu_encoder_helper_hw_reset - issue ctl hw reset
|
||||
* This helper function may be optionally specified by physical
|
||||
* encoders if they require ctl hw reset. If state is currently
|
||||
* DPU_ENC_ERR_NEEDS_HW_RESET, it is set back to DPU_ENC_ENABLED.
|
||||
* @phys_enc: Pointer to physical encoder structure
|
||||
*/
|
||||
void dpu_encoder_helper_hw_reset(struct dpu_encoder_phys *phys_enc);
|
||||
|
||||
static inline enum dpu_3d_blend_mode dpu_encoder_helper_get_3d_blend_mode(
|
||||
struct dpu_encoder_phys *phys_enc)
|
||||
{
|
||||
if (!phys_enc || phys_enc->enable_state == DPU_ENC_DISABLING)
|
||||
return BLEND_3D_NONE;
|
||||
|
||||
if (phys_enc->split_role == ENC_ROLE_SOLO &&
|
||||
phys_enc->topology_name == DPU_RM_TOPOLOGY_DUALPIPE_3DMERGE)
|
||||
return BLEND_3D_H_ROW_INT;
|
||||
|
||||
return BLEND_3D_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpu_encoder_helper_split_config - split display configuration helper function
|
||||
* This helper function may be used by physical encoders to configure
|
||||
* the split display related registers.
|
||||
* @phys_enc: Pointer to physical encoder structure
|
||||
* @interface: enum dpu_intf setting
|
||||
*/
|
||||
void dpu_encoder_helper_split_config(
|
||||
struct dpu_encoder_phys *phys_enc,
|
||||
enum dpu_intf interface);
|
||||
|
||||
/**
|
||||
* dpu_encoder_helper_hw_release - prepare for h/w reset during disable
|
||||
* @phys_enc: Pointer to physical encoder structure
|
||||
* @fb: Optional fb for specifying new mixer output resolution, may be NULL
|
||||
* Return: Zero on success
|
||||
*/
|
||||
int dpu_encoder_helper_hw_release(struct dpu_encoder_phys *phys_enc,
|
||||
struct drm_framebuffer *fb);
|
||||
|
||||
/**
|
||||
* dpu_encoder_helper_report_irq_timeout - utility to report error that irq has
|
||||
* timed out, including reporting frame error event to crtc and debug dump
|
||||
* @phys_enc: Pointer to physical encoder structure
|
||||
* @intr_idx: Failing interrupt index
|
||||
*/
|
||||
void dpu_encoder_helper_report_irq_timeout(struct dpu_encoder_phys *phys_enc,
|
||||
enum dpu_intr_idx intr_idx);
|
||||
|
||||
/**
|
||||
* dpu_encoder_helper_wait_for_irq - utility to wait on an irq.
|
||||
* note: will call dpu_encoder_helper_wait_for_irq on timeout
|
||||
* @phys_enc: Pointer to physical encoder structure
|
||||
* @intr_idx: encoder interrupt index
|
||||
* @wait_info: wait info struct
|
||||
* @Return: 0 or -ERROR
|
||||
*/
|
||||
int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc,
|
||||
enum dpu_intr_idx intr_idx,
|
||||
struct dpu_encoder_wait_info *wait_info);
|
||||
|
||||
/**
|
||||
* dpu_encoder_helper_register_irq - register and enable an irq
|
||||
* @phys_enc: Pointer to physical encoder structure
|
||||
* @intr_idx: encoder interrupt index
|
||||
* @Return: 0 or -ERROR
|
||||
*/
|
||||
int dpu_encoder_helper_register_irq(struct dpu_encoder_phys *phys_enc,
|
||||
enum dpu_intr_idx intr_idx);
|
||||
|
||||
/**
|
||||
* dpu_encoder_helper_unregister_irq - unregister and disable an irq
|
||||
* @phys_enc: Pointer to physical encoder structure
|
||||
* @intr_idx: encoder interrupt index
|
||||
* @Return: 0 or -ERROR
|
||||
*/
|
||||
int dpu_encoder_helper_unregister_irq(struct dpu_encoder_phys *phys_enc,
|
||||
enum dpu_intr_idx intr_idx);
|
||||
|
||||
#endif /* __dpu_encoder_phys_H__ */
|
||||
905
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
Normal file
905
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
Normal file
File diff suppressed because it is too large
Load Diff
922
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
Normal file
922
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
Normal file
File diff suppressed because it is too large
Load Diff
1214
drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
Normal file
1214
drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
Normal file
File diff suppressed because it is too large
Load Diff
136
drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h
Normal file
136
drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h
Normal file
@@ -0,0 +1,136 @@
|
||||
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _DPU_FORMATS_H
|
||||
#define _DPU_FORMATS_H
|
||||
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include "msm_gem.h"
|
||||
#include "dpu_hw_mdss.h"
|
||||
|
||||
/**
|
||||
* dpu_get_dpu_format_ext() - Returns dpu format structure pointer.
|
||||
* @format: DRM FourCC Code
|
||||
* @modifiers: format modifier array from client, one per plane
|
||||
*/
|
||||
const struct dpu_format *dpu_get_dpu_format_ext(
|
||||
const uint32_t format,
|
||||
const uint64_t modifier);
|
||||
|
||||
#define dpu_get_dpu_format(f) dpu_get_dpu_format_ext(f, 0)
|
||||
|
||||
/**
|
||||
* dpu_get_msm_format - get an dpu_format by its msm_format base
|
||||
* callback function registers with the msm_kms layer
|
||||
* @kms: kms driver
|
||||
* @format: DRM FourCC Code
|
||||
* @modifiers: data layout modifier
|
||||
*/
|
||||
const struct msm_format *dpu_get_msm_format(
|
||||
struct msm_kms *kms,
|
||||
const uint32_t format,
|
||||
const uint64_t modifiers);
|
||||
|
||||
/**
|
||||
* dpu_populate_formats - populate the given array with fourcc codes supported
|
||||
* @format_list: pointer to list of possible formats
|
||||
* @pixel_formats: array to populate with fourcc codes
|
||||
* @pixel_modifiers: array to populate with drm modifiers, can be NULL
|
||||
* @pixel_formats_max: length of pixel formats array
|
||||
* Return: number of elements populated
|
||||
*/
|
||||
uint32_t dpu_populate_formats(
|
||||
const struct dpu_format_extended *format_list,
|
||||
uint32_t *pixel_formats,
|
||||
uint64_t *pixel_modifiers,
|
||||
uint32_t pixel_formats_max);
|
||||
|
||||
/**
|
||||
* dpu_format_get_plane_sizes - calculate size and layout of given buffer format
|
||||
* @fmt: pointer to dpu_format
|
||||
* @w: width of the buffer
|
||||
* @h: height of the buffer
|
||||
* @layout: layout of the buffer
|
||||
* @pitches: array of size [DPU_MAX_PLANES] to populate
|
||||
* pitch for each plane
|
||||
*
|
||||
* Return: size of the buffer
|
||||
*/
|
||||
int dpu_format_get_plane_sizes(
|
||||
const struct dpu_format *fmt,
|
||||
const uint32_t w,
|
||||
const uint32_t h,
|
||||
struct dpu_hw_fmt_layout *layout,
|
||||
const uint32_t *pitches);
|
||||
|
||||
/**
|
||||
* dpu_format_get_block_size - get block size of given format when
|
||||
* operating in block mode
|
||||
* @fmt: pointer to dpu_format
|
||||
* @w: pointer to width of the block
|
||||
* @h: pointer to height of the block
|
||||
*
|
||||
* Return: 0 if success; error oode otherwise
|
||||
*/
|
||||
int dpu_format_get_block_size(const struct dpu_format *fmt,
|
||||
uint32_t *w, uint32_t *h);
|
||||
|
||||
/**
|
||||
* dpu_format_check_modified_format - validate format and buffers for
|
||||
* dpu non-standard, i.e. modified format
|
||||
* @kms: kms driver
|
||||
* @msm_fmt: pointer to the msm_fmt base pointer of an dpu_format
|
||||
* @cmd: fb_cmd2 structure user request
|
||||
* @bos: gem buffer object list
|
||||
*
|
||||
* Return: error code on failure, 0 on success
|
||||
*/
|
||||
int dpu_format_check_modified_format(
|
||||
const struct msm_kms *kms,
|
||||
const struct msm_format *msm_fmt,
|
||||
const struct drm_mode_fb_cmd2 *cmd,
|
||||
struct drm_gem_object **bos);
|
||||
|
||||
/**
|
||||
* dpu_format_populate_layout - populate the given format layout based on
|
||||
* mmu, fb, and format found in the fb
|
||||
* @aspace: address space pointer
|
||||
* @fb: framebuffer pointer
|
||||
* @fmtl: format layout structure to populate
|
||||
*
|
||||
* Return: error code on failure, -EAGAIN if success but the addresses
|
||||
* are the same as before or 0 if new addresses were populated
|
||||
*/
|
||||
int dpu_format_populate_layout(
|
||||
struct msm_gem_address_space *aspace,
|
||||
struct drm_framebuffer *fb,
|
||||
struct dpu_hw_fmt_layout *fmtl);
|
||||
|
||||
/**
|
||||
* dpu_format_get_framebuffer_size - get framebuffer memory size
|
||||
* @format: DRM pixel format
|
||||
* @width: pixel width
|
||||
* @height: pixel height
|
||||
* @pitches: array of size [DPU_MAX_PLANES] to populate
|
||||
* pitch for each plane
|
||||
* @modifiers: drm modifier
|
||||
*
|
||||
* Return: memory size required for frame buffer
|
||||
*/
|
||||
uint32_t dpu_format_get_framebuffer_size(
|
||||
const uint32_t format,
|
||||
const uint32_t width,
|
||||
const uint32_t height,
|
||||
const uint32_t *pitches,
|
||||
const uint64_t modifiers);
|
||||
|
||||
#endif /*_DPU_FORMATS_H */
|
||||
155
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_blk.c
Normal file
155
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_blk.c
Normal file
@@ -0,0 +1,155 @@
|
||||
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "dpu_hw_mdss.h"
|
||||
#include "dpu_hw_blk.h"
|
||||
|
||||
/* Serialization lock for dpu_hw_blk_list */
|
||||
static DEFINE_MUTEX(dpu_hw_blk_lock);
|
||||
|
||||
/* List of all hw block objects */
|
||||
static LIST_HEAD(dpu_hw_blk_list);
|
||||
|
||||
/**
|
||||
* dpu_hw_blk_init - initialize hw block object
|
||||
* @type: hw block type - enum dpu_hw_blk_type
|
||||
* @id: instance id of the hw block
|
||||
* @ops: Pointer to block operations
|
||||
* return: 0 if success; error code otherwise
|
||||
*/
|
||||
int dpu_hw_blk_init(struct dpu_hw_blk *hw_blk, u32 type, int id,
|
||||
struct dpu_hw_blk_ops *ops)
|
||||
{
|
||||
if (!hw_blk) {
|
||||
pr_err("invalid parameters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&hw_blk->list);
|
||||
hw_blk->type = type;
|
||||
hw_blk->id = id;
|
||||
atomic_set(&hw_blk->refcount, 0);
|
||||
|
||||
if (ops)
|
||||
hw_blk->ops = *ops;
|
||||
|
||||
mutex_lock(&dpu_hw_blk_lock);
|
||||
list_add(&hw_blk->list, &dpu_hw_blk_list);
|
||||
mutex_unlock(&dpu_hw_blk_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpu_hw_blk_destroy - destroy hw block object.
|
||||
* @hw_blk: pointer to hw block object
|
||||
* return: none
|
||||
*/
|
||||
void dpu_hw_blk_destroy(struct dpu_hw_blk *hw_blk)
|
||||
{
|
||||
if (!hw_blk) {
|
||||
pr_err("invalid parameters\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (atomic_read(&hw_blk->refcount))
|
||||
pr_err("hw_blk:%d.%d invalid refcount\n", hw_blk->type,
|
||||
hw_blk->id);
|
||||
|
||||
mutex_lock(&dpu_hw_blk_lock);
|
||||
list_del(&hw_blk->list);
|
||||
mutex_unlock(&dpu_hw_blk_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* dpu_hw_blk_get - get hw_blk from free pool
|
||||
* @hw_blk: if specified, increment reference count only
|
||||
* @type: if hw_blk is not specified, allocate the next available of this type
|
||||
* @id: if specified (>= 0), allocate the given instance of the above type
|
||||
* return: pointer to hw block object
|
||||
*/
|
||||
struct dpu_hw_blk *dpu_hw_blk_get(struct dpu_hw_blk *hw_blk, u32 type, int id)
|
||||
{
|
||||
struct dpu_hw_blk *curr;
|
||||
int rc, refcount;
|
||||
|
||||
if (!hw_blk) {
|
||||
mutex_lock(&dpu_hw_blk_lock);
|
||||
list_for_each_entry(curr, &dpu_hw_blk_list, list) {
|
||||
if ((curr->type != type) ||
|
||||
(id >= 0 && curr->id != id) ||
|
||||
(id < 0 &&
|
||||
atomic_read(&curr->refcount)))
|
||||
continue;
|
||||
|
||||
hw_blk = curr;
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&dpu_hw_blk_lock);
|
||||
}
|
||||
|
||||
if (!hw_blk) {
|
||||
pr_debug("no hw_blk:%d\n", type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
refcount = atomic_inc_return(&hw_blk->refcount);
|
||||
|
||||
if (refcount == 1 && hw_blk->ops.start) {
|
||||
rc = hw_blk->ops.start(hw_blk);
|
||||
if (rc) {
|
||||
pr_err("failed to start hw_blk:%d rc:%d\n", type, rc);
|
||||
goto error_start;
|
||||
}
|
||||
}
|
||||
|
||||
pr_debug("hw_blk:%d.%d refcount:%d\n", hw_blk->type,
|
||||
hw_blk->id, refcount);
|
||||
return hw_blk;
|
||||
|
||||
error_start:
|
||||
dpu_hw_blk_put(hw_blk);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
/**
|
||||
* dpu_hw_blk_put - put hw_blk to free pool if decremented refcount is zero
|
||||
* @hw_blk: hw block to be freed
|
||||
* @free_blk: function to be called when reference count goes to zero
|
||||
*/
|
||||
void dpu_hw_blk_put(struct dpu_hw_blk *hw_blk)
|
||||
{
|
||||
if (!hw_blk) {
|
||||
pr_err("invalid parameters\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pr_debug("hw_blk:%d.%d refcount:%d\n", hw_blk->type, hw_blk->id,
|
||||
atomic_read(&hw_blk->refcount));
|
||||
|
||||
if (!atomic_read(&hw_blk->refcount)) {
|
||||
pr_err("hw_blk:%d.%d invalid put\n", hw_blk->type, hw_blk->id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (atomic_dec_return(&hw_blk->refcount))
|
||||
return;
|
||||
|
||||
if (hw_blk->ops.stop)
|
||||
hw_blk->ops.stop(hw_blk);
|
||||
}
|
||||
53
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_blk.h
Normal file
53
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_blk.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _DPU_HW_BLK_H
|
||||
#define _DPU_HW_BLK_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/atomic.h>
|
||||
|
||||
struct dpu_hw_blk;
|
||||
|
||||
/**
|
||||
* struct dpu_hw_blk_ops - common hardware block operations
|
||||
* @start: start operation on first get
|
||||
* @stop: stop operation on last put
|
||||
*/
|
||||
struct dpu_hw_blk_ops {
|
||||
int (*start)(struct dpu_hw_blk *);
|
||||
void (*stop)(struct dpu_hw_blk *);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpu_hw_blk - definition of hardware block object
|
||||
* @list: list of hardware blocks
|
||||
* @type: hardware block type
|
||||
* @id: instance id
|
||||
* @refcount: reference/usage count
|
||||
*/
|
||||
struct dpu_hw_blk {
|
||||
struct list_head list;
|
||||
u32 type;
|
||||
int id;
|
||||
atomic_t refcount;
|
||||
struct dpu_hw_blk_ops ops;
|
||||
};
|
||||
|
||||
int dpu_hw_blk_init(struct dpu_hw_blk *hw_blk, u32 type, int id,
|
||||
struct dpu_hw_blk_ops *ops);
|
||||
void dpu_hw_blk_destroy(struct dpu_hw_blk *hw_blk);
|
||||
|
||||
struct dpu_hw_blk *dpu_hw_blk_get(struct dpu_hw_blk *hw_blk, u32 type, int id);
|
||||
void dpu_hw_blk_put(struct dpu_hw_blk *hw_blk);
|
||||
#endif /*_DPU_HW_BLK_H */
|
||||
511
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
Normal file
511
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
Normal file
File diff suppressed because it is too large
Load Diff
804
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
Normal file
804
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user