Files
android_kernel_samsung_sm86…/msm/sde/sde_hw_catalog.c
Nilaan Gunabalachandran f73f15ae39 disp: msm: sde: enable 32bit intf te registers
This change adds support for INTF TE using 32 bit values and
single update per TE. These features help ensure that during
QSync mode the TE does not overrun in certain late trigger uses.

Change-Id: I893d0cde81320c3f17604694a4d8ee52b29a9425
Signed-off-by: Nilaan Gunabalachandran <quic_ngunabal@quicinc.com>
2022-10-06 13:51:35 -07:00

5591 行
163 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
*/
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/soc/qcom/llcc-qcom.h>
#include <linux/pm_qos.h>
#include <soc/qcom/of_common.h>
#include "sde_hw_mdss.h"
#include "sde_hw_catalog.h"
#include "sde_hw_catalog_format.h"
#include "sde_kms.h"
#include "sde_hw_uidle.h"
#include "sde_connector.h"
/*************************************************************
* MACRO DEFINITION
*************************************************************/
/**
* Max hardware block in certain hardware. For ex: sspp pipes
* can have QSEED, pcc, igc, pa, csc, qos entries, etc. This count is
* 64 based on software design. It should be increased if any of the
* hardware block has more subblocks.
*/
#define MAX_SDE_HW_BLK 64
/* each entry will have register address and bit offset in that register */
#define MAX_BIT_OFFSET 2
/* max table size for dts property lists, increase if tables grow larger */
#define MAX_SDE_DT_TABLE_SIZE 64
/* default line width for sspp, mixer, ds (input), dsc, wb */
#define DEFAULT_SDE_LINE_WIDTH 2048
/* default output line width for ds */
#define DEFAULT_SDE_OUTPUT_LINE_WIDTH 2560
/* max mixer blend stages */
#define DEFAULT_SDE_MIXER_BLENDSTAGES 7
/*
* max bank bit for macro tile and ubwc format.
* this value is left shifted and written to register
*/
#define DEFAULT_SDE_HIGHEST_BANK_BIT 0x02
/* No UBWC */
#define DEFAULT_SDE_UBWC_NONE 0x0
/* default ubwc static config register value */
#define DEFAULT_SDE_UBWC_STATIC 0x0
/* default ubwc swizzle register value */
#define DEFAULT_SDE_UBWC_SWIZZLE 0x0
/* default ubwc macrotile mode value */
#define DEFAULT_SDE_UBWC_MACROTILE_MODE 0x0
/* default hardware block size if dtsi entry is not present */
#define DEFAULT_SDE_HW_BLOCK_LEN 0x100
/* total number of intf - dp, dsi, hdmi */
#define INTF_COUNT 3
#define MAX_UPSCALE_RATIO 20
#define MAX_DOWNSCALE_RATIO 4
#define SSPP_UNITY_SCALE 1
#define MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_NUMERATOR 11
#define MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_DENOMINATOR 5
#define MAX_DOWNSCALE_RATIO_INROT_PD_RT_NUMERATOR 4
#define MAX_DOWNSCALE_RATIO_INROT_PD_RT_DENOMINATOR 1
#define MAX_DOWNSCALE_RATIO_INROT_NRT_DEFAULT 4
#define MAX_PRE_ROT_HEIGHT_INLINE_ROT_DEFAULT 1088
#define MAX_HORZ_DECIMATION 4
#define MAX_VERT_DECIMATION 4
#define MAX_SPLIT_DISPLAY_CTL 2
#define MAX_PP_SPLIT_DISPLAY_CTL 1
#define MDSS_BASE_OFFSET 0x0
#define ROT_LM_OFFSET 3
#define LINE_LM_OFFSET 5
#define LINE_MODE_WB_OFFSET 2
/**
* these configurations are decided based on max mdp clock. It accounts
* for max and min display resolution based on virtual hardware resource
* support.
*/
#define MAX_DISPLAY_HEIGHT_WITH_DECIMATION 2160
#define MAX_DISPLAY_HEIGHT 5760
#define MIN_DISPLAY_HEIGHT 0
#define MIN_DISPLAY_WIDTH 0
/* maximum XIN halt timeout in usec */
#define VBIF_XIN_HALT_TIMEOUT 0x4000
#define DEFAULT_PIXEL_RAM_SIZE (50 * 1024)
/* access property value based on prop_type and hardware index */
#define PROP_VALUE_ACCESS(p, i, j) ((p + i)->value[j])
/*
* access element within PROP_TYPE_BIT_OFFSET_ARRAYs based on prop_type,
* hardware index and offset array index
*/
#define PROP_BITVALUE_ACCESS(p, i, j, k) ((p + i)->bit_value[j][k])
#define DEFAULT_SBUF_HEADROOM (20)
#define DEFAULT_SBUF_PREFILL (128)
/*
* Default parameter values
*/
#define DEFAULT_MAX_BW_HIGH 7000000
#define DEFAULT_MAX_BW_LOW 7000000
#define DEFAULT_UNDERSIZED_PREFILL_LINES 2
#define DEFAULT_XTRA_PREFILL_LINES 2
#define DEFAULT_DEST_SCALE_PREFILL_LINES 3
#define DEFAULT_MACROTILE_PREFILL_LINES 4
#define DEFAULT_YUV_NV12_PREFILL_LINES 8
#define DEFAULT_LINEAR_PREFILL_LINES 1
#define DEFAULT_DOWNSCALING_PREFILL_LINES 1
#define DEFAULT_CORE_IB_FF "6.0"
#define DEFAULT_CORE_CLK_FF "1.0"
#define DEFAULT_COMP_RATIO_RT \
"NV12/5/1/1.23 AB24/5/1/1.23 XB24/5/1/1.23"
#define DEFAULT_COMP_RATIO_NRT \
"NV12/5/1/1.25 AB24/5/1/1.25 XB24/5/1/1.25"
#define DEFAULT_MAX_PER_PIPE_BW 2400000
#define DEFAULT_AMORTIZABLE_THRESHOLD 25
#define DEFAULT_NUM_DDR_CHANNELS 4
#define DEFAULT_DRAM_EFFICIENCY 64
#define DEFAULT_MNOC_PORTS 2
#define DEFAULT_AXI_BUS_WIDTH 32
#define DEFAULT_CPU_MASK 0
#define DEFAULT_CPU_DMA_LATENCY PM_QOS_DEFAULT_VALUE
/* Uidle values */
#define SDE_UIDLE_FAL10_EXIT_CNT 128
#define SDE_UIDLE_FAL10_EXIT_DANGER 4
#define SDE_UIDLE_FAL10_DANGER 6
#define SDE_UIDLE_FAL10_TARGET_IDLE 50
#define SDE_UIDLE_FAL1_TARGET_IDLE 40
#define SDE_UIDLE_FAL1_MAX_THRESHOLD 15
#define SDE_UIDLE_FAL1_MAX_THRESHOLD_EXT_REV_102 255
#define SDE_UIDLE_FAL1_MAX_THRESHOLD_EXT_REV_103 255
#define SDE_UIDLE_FAL10_THRESHOLD_60 12
#define SDE_UIDLE_FAL10_THRESHOLD_90 13
#define SDE_UIDLE_MAX_DWNSCALE 1500
#define SDE_UIDLE_MAX_FPS_60 60
#define SDE_UIDLE_MAX_FPS_90 90
#define SDE_UIDLE_MAX_FPS_120 120
#define SDE_UIDLE_MAX_FPS_240 240
/* Unmult Offsets */
#define SDE_VIG_UNMULT 0x1EA0
#define SDE_DGM_UNMULT 0x804
#define SDE_DGM_UNMULT_2 0xE04
#define SSPP_GET_REGDMA_BASE(blk_base, top_off) ((blk_base) >= (top_off) ?\
(blk_base) - (top_off) : (blk_base))
/*************************************************************
* DTSI PROPERTY INDEX
*************************************************************/
enum {
SDE_HW_VERSION,
SDE_HW_FENCE_VERSION,
SDE_HW_PROP_MAX,
};
enum {
HW_OFF,
HW_LEN,
HW_DISP,
HW_PROP_MAX,
};
enum sde_prop {
SDE_OFF,
SDE_LEN,
SSPP_LINEWIDTH,
VIG_SSPP_LINEWIDTH,
SCALING_LINEWIDTH,
MIXER_LINEWIDTH,
MIXER_BLEND,
WB_LINEWIDTH,
WB_LINEWIDTH_LINEAR,
BANK_BIT,
UBWC_VERSION,
UBWC_STATIC,
UBWC_SWIZZLE,
QSEED_SW_LIB_REV,
QSEED_HW_VERSION,
CSC_TYPE,
PANIC_PER_PIPE,
SRC_SPLIT,
DIM_LAYER,
SMART_DMA_REV,
IDLE_PC,
WAKEUP_WITH_TOUCH,
DEST_SCALER,
SMART_PANEL_ALIGN_MODE,
MACROTILE_MODE,
UBWC_BW_CALC_VERSION,
PIPE_ORDER_VERSION,
SEC_SID_MASK,
BASE_LAYER,
TRUSTED_VM_ENV,
MAX_TRUSTED_VM_DISPLAYS,
TVM_INCLUDE_REG,
IPCC_PROTOCOL_ID,
SDE_EMULATED_ENV,
SDE_PROP_MAX,
};
enum {
PERF_MAX_BW_LOW,
PERF_MAX_BW_HIGH,
PERF_MIN_CORE_IB,
PERF_MIN_LLCC_IB,
PERF_MIN_DRAM_IB,
PERF_CORE_IB_FF,
PERF_CORE_CLK_FF,
PERF_COMP_RATIO_RT,
PERF_COMP_RATIO_NRT,
PERF_UNDERSIZED_PREFILL_LINES,
PERF_DEST_SCALE_PREFILL_LINES,
PERF_MACROTILE_PREFILL_LINES,
PERF_YUV_NV12_PREFILL_LINES,
PERF_LINEAR_PREFILL_LINES,
PERF_DOWNSCALING_PREFILL_LINES,
PERF_XTRA_PREFILL_LINES,
PERF_NUM_DDR_CHANNELS,
PERF_DRAM_EFFICIENCY,
PERF_AMORTIZABLE_THRESHOLD,
PERF_NUM_MNOC_PORTS,
PERF_AXI_BUS_WIDTH,
PERF_CDP_SETTING,
PERF_CPU_MASK,
CPU_MASK_PERF,
PERF_CPU_DMA_LATENCY,
PERF_CPU_IRQ_LATENCY,
PERF_PROP_MAX,
};
enum {
QOS_REFRESH_RATES,
QOS_DANGER_LUT,
QOS_SAFE_LUT,
QOS_CREQ_LUT,
QOS_PROP_MAX,
};
enum {
SSPP_OFF,
SSPP_SIZE,
SSPP_TYPE,
SSPP_XIN,
SSPP_CLK_CTRL,
SSPP_CLK_STATUS,
SSPP_SCALE_SIZE,
SSPP_VIG_BLOCKS,
SSPP_DMA_BLOCKS,
SSPP_EXCL_RECT,
SSPP_SMART_DMA,
SSPP_MAX_PER_PIPE_BW,
SSPP_MAX_PER_PIPE_BW_HIGH,
SSPP_PROP_MAX,
};
enum {
VIG_SUBBLOCK_INDEX,
VIG_TOP_OFF,
VIG_QSEED_OFF,
VIG_QSEED_LEN,
VIG_CSC_OFF,
VIG_HSIC_PROP,
VIG_MEMCOLOR_PROP,
VIG_PCC_PROP,
VIG_GAMUT_PROP,
VIG_IGC_PROP,
VIG_INVERSE_PMA,
VIG_FP16_IGC_PROP,
VIG_FP16_GC_PROP,
VIG_FP16_CSC_PROP,
VIG_FP16_UNMULT_PROP,
VIG_PROP_MAX,
};
enum {
DMA_SUBBLOCK_INDEX,
DMA_TOP_OFF,
DMA_IGC_PROP,
DMA_GC_PROP,
DMA_DGM_INVERSE_PMA,
DMA_CSC_OFF,
DMA_FP16_IGC_PROP,
DMA_FP16_GC_PROP,
DMA_FP16_CSC_PROP,
DMA_FP16_UNMULT_PROP,
DMA_PROP_MAX,
};
enum {
INTF_OFF,
INTF_LEN,
INTF_PREFETCH,
INTF_TYPE,
INTF_TE_IRQ,
INTF_PROP_MAX,
};
enum {
PP_OFF,
PP_LEN,
PP_CWB,
TE_OFF,
TE_LEN,
TE2_OFF,
TE2_LEN,
PP_SLAVE,
DITHER_OFF,
DITHER_LEN,
DITHER_VER,
CWB_DITHER,
PP_MERGE_3D_ID,
PP_PROP_MAX,
};
enum {
DSC_OFF,
DSC_LEN,
DSC_PAIR_MASK,
DSC_REV,
DSC_ENC,
DSC_ENC_LEN,
DSC_CTL,
DSC_CTL_LEN,
DSC_422,
DSC_LINEWIDTH,
DSC_PROP_MAX,
};
enum {
VDC_OFF,
VDC_LEN,
VDC_REV,
VDC_ENC,
VDC_ENC_LEN,
VDC_CTL,
VDC_CTL_LEN,
VDC_PROP_MAX,
};
enum {
DNSC_BLUR_OFF,
DNSC_BLUR_LEN,
DNSC_BLUR_VERSION,
DNSC_BLUR_GAUS_LUT_OFF,
DNSC_BLUR_GAUS_LUT_LEN,
DNSC_BLUR_DITHER_OFF,
DNSC_BLUR_DITHER_LEN,
DNSC_BLUR_PROP_MAX,
};
enum {
DS_TOP_OFF,
DS_TOP_LEN,
DS_TOP_INPUT_LINEWIDTH,
DS_TOP_OUTPUT_LINEWIDTH,
DS_TOP_PROP_MAX,
};
enum {
DS_OFF,
DS_LEN,
DS_PROP_MAX,
};
enum {
DSPP_TOP_OFF,
DSPP_TOP_SIZE,
DSPP_TOP_PROP_MAX,
};
enum {
DSPP_OFF,
DSPP_SIZE,
DSPP_BLOCKS,
DSPP_PROP_MAX,
};
enum {
DSPP_IGC_PROP,
DSPP_PCC_PROP,
DSPP_GC_PROP,
DSPP_HSIC_PROP,
DSPP_MEMCOLOR_PROP,
DSPP_SIXZONE_PROP,
DSPP_GAMUT_PROP,
DSPP_DITHER_PROP,
DSPP_HIST_PROP,
DSPP_VLUT_PROP,
DSPP_BLOCKS_PROP_MAX,
};
enum {
AD_OFF,
AD_VERSION,
AD_PROP_MAX,
};
enum {
LTM_OFF,
LTM_VERSION,
LTM_PROP_MAX,
};
enum {
RC_OFF,
RC_LEN,
RC_VERSION,
RC_MEM_TOTAL_SIZE,
RC_MIN_REGION_WIDTH,
RC_PROP_MAX,
};
enum {
SPR_OFF,
SPR_LEN,
SPR_VERSION,
SPR_PROP_MAX,
};
enum {
DEMURA_OFF,
DEMURA_LEN,
DEMURA_VERSION,
DEMURA_PROP_MAX,
};
enum {
MIXER_OFF,
MIXER_LEN,
MIXER_PAIR_MASK,
MIXER_BLOCKS,
MIXER_DISP,
MIXER_CWB,
MIXER_DCWB,
MIXER_PROP_MAX,
};
enum {
MIXER_GC_PROP,
MIXER_BLOCKS_PROP_MAX,
};
enum {
MIXER_BLEND_OP_OFF,
MIXER_BLEND_PROP_MAX,
};
enum {
WB_OFF,
WB_LEN,
WB_ID,
WB_XIN_ID,
WB_CLK_CTRL,
WB_CLK_STATUS,
WB_PROP_MAX,
};
enum {
VBIF_OFF,
VBIF_LEN,
VBIF_ID,
VBIF_DEFAULT_OT_RD_LIMIT,
VBIF_DEFAULT_OT_WR_LIMIT,
VBIF_DYNAMIC_OT_RD_LIMIT,
VBIF_DYNAMIC_OT_WR_LIMIT,
VBIF_MEMTYPE_0,
VBIF_MEMTYPE_1,
VBIF_QOS_RT_REMAP,
VBIF_QOS_NRT_REMAP,
VBIF_QOS_CWB_REMAP,
VBIF_QOS_LUTDMA_REMAP,
VBIF_QOS_CNOC_REMAP,
VBIF_QOS_OFFLINE_WB_REMAP,
VBIF_PROP_MAX,
};
enum {
UIDLE_OFF,
UIDLE_LEN,
UIDLE_PROP_MAX,
};
enum {
REG_DMA_OFF,
REG_DMA_ID,
REG_DMA_VERSION,
REG_DMA_TRIGGER_OFF,
REG_DMA_BROADCAST_DISABLED,
REG_DMA_XIN_ID,
REG_DMA_CLK_CTRL,
REG_DMA_PROP_MAX
};
enum {
NOISE_LAYER_OFF,
NOISE_LAYER_VERSION,
NOISEL_LAYER_PROP_MAX
};
/*************************************************************
* dts property definition
*************************************************************/
enum prop_type {
PROP_TYPE_BOOL,
PROP_TYPE_U32,
PROP_TYPE_U32_ARRAY,
PROP_TYPE_STRING,
PROP_TYPE_STRING_ARRAY,
PROP_TYPE_BIT_OFFSET_ARRAY,
PROP_TYPE_NODE,
};
struct sde_prop_type {
/* use property index from enum property for readability purpose */
u8 id;
/* it should be property name based on dtsi documentation */
char *prop_name;
/**
* if property is marked mandatory then it will fail parsing
* when property is not present
*/
u32 is_mandatory;
/* property type based on "enum prop_type" */
enum prop_type type;
};
struct sde_prop_value {
u32 value[MAX_SDE_HW_BLK];
u32 bit_value[MAX_SDE_HW_BLK][MAX_BIT_OFFSET];
};
/**
* struct sde_dt_props - stores dts properties read from a sde_prop_type table
* @exists: Array of bools indicating if the given prop name was present
* @counts: Count of the number of valid values for the property
* @values: Array storing the count[i] property values
*
* Must use the sde_[get|put]_dt_props APIs to allocate/free this object.
*/
struct sde_dt_props {
bool exists[MAX_SDE_DT_TABLE_SIZE];
int counts[MAX_SDE_DT_TABLE_SIZE];
struct sde_prop_value *values;
};
/*************************************************************
* dts property list
*************************************************************/
static struct sde_prop_type sde_hw_prop[] = {
{SDE_HW_VERSION, "qcom,sde-hw-version", false, PROP_TYPE_U32},
{SDE_HW_FENCE_VERSION, "qcom,hw-fence-sw-version", false, PROP_TYPE_U32},
};
static struct sde_prop_type sde_prop[] = {
{SDE_OFF, "qcom,sde-off", true, PROP_TYPE_U32},
{SDE_LEN, "qcom,sde-len", false, PROP_TYPE_U32},
{SSPP_LINEWIDTH, "qcom,sde-sspp-linewidth", false, PROP_TYPE_U32},
{VIG_SSPP_LINEWIDTH, "qcom,sde-vig-sspp-linewidth", false, PROP_TYPE_U32},
{SCALING_LINEWIDTH, "qcom,sde-scaling-linewidth", false, PROP_TYPE_U32},
{MIXER_LINEWIDTH, "qcom,sde-mixer-linewidth", false, PROP_TYPE_U32},
{MIXER_BLEND, "qcom,sde-mixer-blendstages", false, PROP_TYPE_U32},
{WB_LINEWIDTH, "qcom,sde-wb-linewidth", false, PROP_TYPE_U32},
{WB_LINEWIDTH_LINEAR, "qcom,sde-wb-linewidth-linear",
false, PROP_TYPE_U32},
{BANK_BIT, "qcom,sde-highest-bank-bit", false,
PROP_TYPE_BIT_OFFSET_ARRAY},
{UBWC_VERSION, "qcom,sde-ubwc-version", false, PROP_TYPE_U32},
{UBWC_STATIC, "qcom,sde-ubwc-static", false, PROP_TYPE_U32},
{UBWC_SWIZZLE, "qcom,sde-ubwc-swizzle", false, PROP_TYPE_U32},
{QSEED_SW_LIB_REV, "qcom,sde-qseed-sw-lib-rev", false,
PROP_TYPE_STRING},
{QSEED_HW_VERSION, "qcom,sde-qseed-scalar-version", false,
PROP_TYPE_U32},
{CSC_TYPE, "qcom,sde-csc-type", false, PROP_TYPE_STRING},
{PANIC_PER_PIPE, "qcom,sde-panic-per-pipe", false, PROP_TYPE_BOOL},
{SRC_SPLIT, "qcom,sde-has-src-split", false, PROP_TYPE_BOOL},
{DIM_LAYER, "qcom,sde-has-dim-layer", false, PROP_TYPE_BOOL},
{SMART_DMA_REV, "qcom,sde-smart-dma-rev", false, PROP_TYPE_STRING},
{IDLE_PC, "qcom,sde-has-idle-pc", false, PROP_TYPE_BOOL},
{WAKEUP_WITH_TOUCH, "qcom,sde-wakeup-with-touch", false,
PROP_TYPE_BOOL},
{DEST_SCALER, "qcom,sde-has-dest-scaler", false, PROP_TYPE_BOOL},
{SMART_PANEL_ALIGN_MODE, "qcom,sde-smart-panel-align-mode",
false, PROP_TYPE_U32},
{MACROTILE_MODE, "qcom,sde-macrotile-mode", false, PROP_TYPE_U32},
{UBWC_BW_CALC_VERSION, "qcom,sde-ubwc-bw-calc-version", false,
PROP_TYPE_U32},
{PIPE_ORDER_VERSION, "qcom,sde-pipe-order-version", false,
PROP_TYPE_U32},
{SEC_SID_MASK, "qcom,sde-secure-sid-mask", false, PROP_TYPE_U32_ARRAY},
{BASE_LAYER, "qcom,sde-mixer-stage-base-layer", false, PROP_TYPE_BOOL},
{TRUSTED_VM_ENV, "qcom,sde-trusted-vm-env", false, PROP_TYPE_BOOL},
{MAX_TRUSTED_VM_DISPLAYS, "qcom,sde-max-trusted-vm-displays", false,
PROP_TYPE_U32},
{TVM_INCLUDE_REG, "qcom,tvm-include-reg", false, PROP_TYPE_U32_ARRAY},
{IPCC_PROTOCOL_ID, "qcom,sde-ipcc-protocol-id", false, PROP_TYPE_U32},
{SDE_EMULATED_ENV, "qcom,sde-emulated-env", false, PROP_TYPE_BOOL},
};
static struct sde_prop_type sde_perf_prop[] = {
{PERF_MAX_BW_LOW, "qcom,sde-max-bw-low-kbps", false, PROP_TYPE_U32},
{PERF_MAX_BW_HIGH, "qcom,sde-max-bw-high-kbps", false, PROP_TYPE_U32},
{PERF_MIN_CORE_IB, "qcom,sde-min-core-ib-kbps", false, PROP_TYPE_U32},
{PERF_MIN_LLCC_IB, "qcom,sde-min-llcc-ib-kbps", false, PROP_TYPE_U32},
{PERF_MIN_DRAM_IB, "qcom,sde-min-dram-ib-kbps", false, PROP_TYPE_U32},
{PERF_CORE_IB_FF, "qcom,sde-core-ib-ff", false, PROP_TYPE_STRING},
{PERF_CORE_CLK_FF, "qcom,sde-core-clk-ff", false, PROP_TYPE_STRING},
{PERF_COMP_RATIO_RT, "qcom,sde-comp-ratio-rt", false,
PROP_TYPE_STRING},
{PERF_COMP_RATIO_NRT, "qcom,sde-comp-ratio-nrt", false,
PROP_TYPE_STRING},
{PERF_UNDERSIZED_PREFILL_LINES, "qcom,sde-undersizedprefill-lines",
false, PROP_TYPE_U32},
{PERF_DEST_SCALE_PREFILL_LINES, "qcom,sde-dest-scaleprefill-lines",
false, PROP_TYPE_U32},
{PERF_MACROTILE_PREFILL_LINES, "qcom,sde-macrotileprefill-lines",
false, PROP_TYPE_U32},
{PERF_YUV_NV12_PREFILL_LINES, "qcom,sde-yuv-nv12prefill-lines",
false, PROP_TYPE_U32},
{PERF_LINEAR_PREFILL_LINES, "qcom,sde-linearprefill-lines",
false, PROP_TYPE_U32},
{PERF_DOWNSCALING_PREFILL_LINES, "qcom,sde-downscalingprefill-lines",
false, PROP_TYPE_U32},
{PERF_XTRA_PREFILL_LINES, "qcom,sde-xtra-prefill-lines",
false, PROP_TYPE_U32},
{PERF_NUM_DDR_CHANNELS, "qcom,sde-num-ddr-channels", false, PROP_TYPE_U32},
{PERF_DRAM_EFFICIENCY, "qcom,sde-dram-efficiency", false, PROP_TYPE_U32},
{PERF_AMORTIZABLE_THRESHOLD, "qcom,sde-amortizable-threshold",
false, PROP_TYPE_U32},
{PERF_NUM_MNOC_PORTS, "qcom,sde-num-mnoc-ports",
false, PROP_TYPE_U32},
{PERF_AXI_BUS_WIDTH, "qcom,sde-axi-bus-width",
false, PROP_TYPE_U32},
{PERF_CDP_SETTING, "qcom,sde-cdp-setting", false,
PROP_TYPE_U32_ARRAY},
{PERF_CPU_MASK, "qcom,sde-qos-cpu-mask", false, PROP_TYPE_U32},
{CPU_MASK_PERF, "qcom,sde-qos-cpu-mask-performance", false,
PROP_TYPE_U32},
{PERF_CPU_DMA_LATENCY, "qcom,sde-qos-cpu-dma-latency", false,
PROP_TYPE_U32},
{PERF_CPU_IRQ_LATENCY, "qcom,sde-qos-cpu-irq-latency", false,
PROP_TYPE_U32},
};
static struct sde_prop_type sde_qos_prop[] = {
{QOS_REFRESH_RATES, "qcom,sde-qos-refresh-rates", false,
PROP_TYPE_U32_ARRAY},
{QOS_DANGER_LUT, "qcom,sde-danger-lut", false, PROP_TYPE_U32_ARRAY},
{QOS_SAFE_LUT, "qcom,sde-safe-lut", false, PROP_TYPE_U32_ARRAY},
{QOS_CREQ_LUT, "qcom,sde-creq-lut", false, PROP_TYPE_U32_ARRAY},
};
static struct sde_prop_type sspp_prop[] = {
{SSPP_OFF, "qcom,sde-sspp-off", true, PROP_TYPE_U32_ARRAY},
{SSPP_SIZE, "qcom,sde-sspp-src-size", false, PROP_TYPE_U32},
{SSPP_TYPE, "qcom,sde-sspp-type", true, PROP_TYPE_STRING_ARRAY},
{SSPP_XIN, "qcom,sde-sspp-xin-id", true, PROP_TYPE_U32_ARRAY},
{SSPP_CLK_CTRL, "qcom,sde-sspp-clk-ctrl", false,
PROP_TYPE_BIT_OFFSET_ARRAY},
{SSPP_CLK_STATUS, "qcom,sde-sspp-clk-status", false,
PROP_TYPE_BIT_OFFSET_ARRAY},
{SSPP_SCALE_SIZE, "qcom,sde-sspp-scale-size", false, PROP_TYPE_U32},
{SSPP_VIG_BLOCKS, "qcom,sde-sspp-vig-blocks", false, PROP_TYPE_NODE},
{SSPP_DMA_BLOCKS, "qcom,sde-sspp-dma-blocks", false, PROP_TYPE_NODE},
{SSPP_EXCL_RECT, "qcom,sde-sspp-excl-rect", false, PROP_TYPE_U32_ARRAY},
{SSPP_SMART_DMA, "qcom,sde-sspp-smart-dma-priority", false,
PROP_TYPE_U32_ARRAY},
{SSPP_MAX_PER_PIPE_BW, "qcom,sde-max-per-pipe-bw-kbps", false,
PROP_TYPE_U32_ARRAY},
{SSPP_MAX_PER_PIPE_BW_HIGH, "qcom,sde-max-per-pipe-bw-high-kbps", false,
PROP_TYPE_U32_ARRAY},
};
static struct sde_prop_type vig_prop[] = {
[VIG_SUBBLOCK_INDEX] = {VIG_SUBBLOCK_INDEX, "cell-index", false,
PROP_TYPE_U32},
[VIG_TOP_OFF] = {VIG_TOP_OFF, "qcom,sde-vig-top-off", false,
PROP_TYPE_U32},
[VIG_QSEED_OFF] = {VIG_QSEED_OFF, "qcom,sde-vig-qseed-off", false,
PROP_TYPE_U32},
[VIG_QSEED_LEN] = {VIG_QSEED_LEN, "qcom,sde-vig-qseed-size", false,
PROP_TYPE_U32},
[VIG_CSC_OFF] = {VIG_CSC_OFF, "qcom,sde-vig-csc-off", false,
PROP_TYPE_U32},
[VIG_HSIC_PROP] = {VIG_HSIC_PROP, "qcom,sde-vig-hsic", false,
PROP_TYPE_U32_ARRAY},
[VIG_MEMCOLOR_PROP] = {VIG_MEMCOLOR_PROP, "qcom,sde-vig-memcolor",
false, PROP_TYPE_U32_ARRAY},
[VIG_PCC_PROP] = {VIG_PCC_PROP, "qcom,sde-vig-pcc", false,
PROP_TYPE_U32_ARRAY},
[VIG_GAMUT_PROP] = {VIG_GAMUT_PROP, "qcom,sde-vig-gamut", false,
PROP_TYPE_U32_ARRAY},
[VIG_IGC_PROP] = {VIG_IGC_PROP, "qcom,sde-vig-igc", false,
PROP_TYPE_U32_ARRAY},
[VIG_INVERSE_PMA] = {VIG_INVERSE_PMA, "qcom,sde-vig-inverse-pma", false,
PROP_TYPE_BOOL},
[VIG_FP16_IGC_PROP] = {VIG_FP16_IGC_PROP, "qcom,sde-fp16-igc", false,
PROP_TYPE_U32_ARRAY},
[VIG_FP16_GC_PROP] = {VIG_FP16_GC_PROP, "qcom,sde-fp16-gc", false,
PROP_TYPE_U32_ARRAY},
[VIG_FP16_CSC_PROP] = {VIG_FP16_CSC_PROP, "qcom,sde-fp16-csc", false,
PROP_TYPE_U32_ARRAY},
[VIG_FP16_UNMULT_PROP] = {VIG_FP16_UNMULT_PROP, "qcom,sde-fp16-unmult",
false, PROP_TYPE_U32_ARRAY},
};
static struct sde_prop_type dma_prop[] = {
[DMA_SUBBLOCK_INDEX] = {DMA_SUBBLOCK_INDEX, "cell-index", false,
PROP_TYPE_U32},
[DMA_TOP_OFF] = {DMA_TOP_OFF, "qcom,sde-dma-top-off", false,
PROP_TYPE_U32},
[DMA_IGC_PROP] = {DMA_IGC_PROP, "qcom,sde-dma-igc", false,
PROP_TYPE_U32_ARRAY},
[DMA_GC_PROP] = {DMA_GC_PROP, "qcom,sde-dma-gc", false,
PROP_TYPE_U32_ARRAY},
[DMA_DGM_INVERSE_PMA] = {DMA_DGM_INVERSE_PMA,
"qcom,sde-dma-inverse-pma", false, PROP_TYPE_BOOL},
[DMA_CSC_OFF] = {DMA_CSC_OFF, "qcom,sde-dma-csc-off", false,
PROP_TYPE_U32},
[DMA_FP16_IGC_PROP] = {DMA_FP16_IGC_PROP, "qcom,sde-fp16-igc", false,
PROP_TYPE_U32_ARRAY},
[DMA_FP16_GC_PROP] = {DMA_FP16_GC_PROP, "qcom,sde-fp16-gc", false,
PROP_TYPE_U32_ARRAY},
[DMA_FP16_CSC_PROP] = {DMA_FP16_CSC_PROP, "qcom,sde-fp16-csc", false,
PROP_TYPE_U32_ARRAY},
[DMA_FP16_UNMULT_PROP] = {DMA_FP16_UNMULT_PROP, "qcom,sde-fp16-unmult",
false, PROP_TYPE_U32_ARRAY},
};
static struct sde_prop_type ctl_prop[] = {
{HW_OFF, "qcom,sde-ctl-off", true, PROP_TYPE_U32_ARRAY},
{HW_LEN, "qcom,sde-ctl-size", false, PROP_TYPE_U32},
{HW_DISP, "qcom,sde-ctl-display-pref", false, PROP_TYPE_STRING_ARRAY},
};
struct sde_prop_type mixer_blend_prop[] = {
{MIXER_BLEND_OP_OFF, "qcom,sde-mixer-blend-op-off", true,
PROP_TYPE_U32_ARRAY},
};
static struct sde_prop_type mixer_prop[] = {
{MIXER_OFF, "qcom,sde-mixer-off", true, PROP_TYPE_U32_ARRAY},
{MIXER_LEN, "qcom,sde-mixer-size", false, PROP_TYPE_U32},
{MIXER_PAIR_MASK, "qcom,sde-mixer-pair-mask", true,
PROP_TYPE_U32_ARRAY},
{MIXER_BLOCKS, "qcom,sde-mixer-blocks", false, PROP_TYPE_NODE},
{MIXER_DISP, "qcom,sde-mixer-display-pref", false,
PROP_TYPE_STRING_ARRAY},
{MIXER_CWB, "qcom,sde-mixer-cwb-pref", false,
PROP_TYPE_STRING_ARRAY},
{MIXER_DCWB, "qcom,sde-mixer-dcwb-pref", false,
PROP_TYPE_STRING_ARRAY},
};
static struct sde_prop_type mixer_blocks_prop[] = {
{MIXER_GC_PROP, "qcom,sde-mixer-gc", false, PROP_TYPE_U32_ARRAY},
};
static struct sde_prop_type dspp_top_prop[] = {
{DSPP_TOP_OFF, "qcom,sde-dspp-top-off", true, PROP_TYPE_U32},
{DSPP_TOP_SIZE, "qcom,sde-dspp-top-size", false, PROP_TYPE_U32},
};
static struct sde_prop_type dspp_prop[] = {
{DSPP_OFF, "qcom,sde-dspp-off", true, PROP_TYPE_U32_ARRAY},
{DSPP_SIZE, "qcom,sde-dspp-size", false, PROP_TYPE_U32},
{DSPP_BLOCKS, "qcom,sde-dspp-blocks", false, PROP_TYPE_NODE},
};
static struct sde_prop_type dspp_blocks_prop[] = {
{DSPP_IGC_PROP, "qcom,sde-dspp-igc", false, PROP_TYPE_U32_ARRAY},
{DSPP_PCC_PROP, "qcom,sde-dspp-pcc", false, PROP_TYPE_U32_ARRAY},
{DSPP_GC_PROP, "qcom,sde-dspp-gc", false, PROP_TYPE_U32_ARRAY},
{DSPP_HSIC_PROP, "qcom,sde-dspp-hsic", false, PROP_TYPE_U32_ARRAY},
{DSPP_MEMCOLOR_PROP, "qcom,sde-dspp-memcolor", false,
PROP_TYPE_U32_ARRAY},
{DSPP_SIXZONE_PROP, "qcom,sde-dspp-sixzone", false,
PROP_TYPE_U32_ARRAY},
{DSPP_GAMUT_PROP, "qcom,sde-dspp-gamut", false, PROP_TYPE_U32_ARRAY},
{DSPP_DITHER_PROP, "qcom,sde-dspp-dither", false, PROP_TYPE_U32_ARRAY},
{DSPP_HIST_PROP, "qcom,sde-dspp-hist", false, PROP_TYPE_U32_ARRAY},
{DSPP_VLUT_PROP, "qcom,sde-dspp-vlut", false, PROP_TYPE_U32_ARRAY},
};
static struct sde_prop_type ad_prop[] = {
{AD_OFF, "qcom,sde-dspp-ad-off", false, PROP_TYPE_U32_ARRAY},
{AD_VERSION, "qcom,sde-dspp-ad-version", false, PROP_TYPE_U32},
};
static struct sde_prop_type ltm_prop[] = {
{LTM_OFF, "qcom,sde-dspp-ltm-off", false, PROP_TYPE_U32_ARRAY},
{LTM_VERSION, "qcom,sde-dspp-ltm-version", false, PROP_TYPE_U32},
};
static struct sde_prop_type rc_prop[] = {
{RC_OFF, "qcom,sde-dspp-rc-off", false, PROP_TYPE_U32_ARRAY},
{RC_LEN, "qcom,sde-dspp-rc-size", false, PROP_TYPE_U32},
{RC_VERSION, "qcom,sde-dspp-rc-version", false, PROP_TYPE_U32},
{RC_MEM_TOTAL_SIZE, "qcom,sde-dspp-rc-mem-size", false, PROP_TYPE_U32},
{RC_MIN_REGION_WIDTH, "qcom,sde-dspp-rc-min-region-width", false, PROP_TYPE_U32},
};
static struct sde_prop_type spr_prop[] = {
{SPR_OFF, "qcom,sde-dspp-spr-off", false, PROP_TYPE_U32_ARRAY},
{SPR_LEN, "qcom,sde-dspp-spr-size", false, PROP_TYPE_U32},
{SPR_VERSION, "qcom,sde-dspp-spr-version", false, PROP_TYPE_U32},
};
static struct sde_prop_type ds_top_prop[] = {
{DS_TOP_OFF, "qcom,sde-dest-scaler-top-off", false, PROP_TYPE_U32},
{DS_TOP_LEN, "qcom,sde-dest-scaler-top-size", false, PROP_TYPE_U32},
{DS_TOP_INPUT_LINEWIDTH, "qcom,sde-max-dest-scaler-input-linewidth",
false, PROP_TYPE_U32},
{DS_TOP_OUTPUT_LINEWIDTH, "qcom,sde-max-dest-scaler-output-linewidth",
false, PROP_TYPE_U32},
};
static struct sde_prop_type ds_prop[] = {
{DS_OFF, "qcom,sde-dest-scaler-off", false, PROP_TYPE_U32_ARRAY},
{DS_LEN, "qcom,sde-dest-scaler-size", false, PROP_TYPE_U32},
};
static struct sde_prop_type pp_prop[] = {
{PP_OFF, "qcom,sde-pp-off", true, PROP_TYPE_U32_ARRAY},
{PP_LEN, "qcom,sde-pp-size", false, PROP_TYPE_U32},
{PP_CWB, "qcom,sde-pp-cwb", false, PROP_TYPE_U32_ARRAY},
{TE_OFF, "qcom,sde-te-off", false, PROP_TYPE_U32_ARRAY},
{TE_LEN, "qcom,sde-te-size", false, PROP_TYPE_U32},
{TE2_OFF, "qcom,sde-te2-off", false, PROP_TYPE_U32_ARRAY},
{TE2_LEN, "qcom,sde-te2-size", false, PROP_TYPE_U32},
{PP_SLAVE, "qcom,sde-pp-slave", false, PROP_TYPE_U32_ARRAY},
{DITHER_OFF, "qcom,sde-dither-off", false, PROP_TYPE_U32_ARRAY},
{DITHER_LEN, "qcom,sde-dither-size", false, PROP_TYPE_U32},
{DITHER_VER, "qcom,sde-dither-version", false, PROP_TYPE_U32},
{CWB_DITHER, "qcom,sde-cwb-dither", false, PROP_TYPE_U32_ARRAY},
{PP_MERGE_3D_ID, "qcom,sde-pp-merge-3d-id", false, PROP_TYPE_U32_ARRAY},
};
static struct sde_prop_type dsc_prop[] = {
{DSC_OFF, "qcom,sde-dsc-off", false, PROP_TYPE_U32_ARRAY},
{DSC_LEN, "qcom,sde-dsc-size", false, PROP_TYPE_U32},
{DSC_PAIR_MASK, "qcom,sde-dsc-pair-mask", false, PROP_TYPE_U32_ARRAY},
{DSC_REV, "qcom,sde-dsc-hw-rev", false, PROP_TYPE_STRING},
{DSC_ENC, "qcom,sde-dsc-enc", false, PROP_TYPE_U32_ARRAY},
{DSC_ENC_LEN, "qcom,sde-dsc-enc-size", false, PROP_TYPE_U32},
{DSC_CTL, "qcom,sde-dsc-ctl", false, PROP_TYPE_U32_ARRAY},
{DSC_CTL_LEN, "qcom,sde-dsc-ctl-size", false, PROP_TYPE_U32},
{DSC_422, "qcom,sde-dsc-native422-supp", false, PROP_TYPE_U32_ARRAY},
{DSC_LINEWIDTH, "qcom,sde-dsc-linewidth", false, PROP_TYPE_U32},
};
static struct sde_prop_type vdc_prop[] = {
{VDC_OFF, "qcom,sde-vdc-off", false, PROP_TYPE_U32_ARRAY},
{VDC_LEN, "qcom,sde-vdc-size", false, PROP_TYPE_U32},
{VDC_REV, "qcom,sde-vdc-hw-rev", false, PROP_TYPE_STRING},
{VDC_ENC, "qcom,sde-vdc-enc", false, PROP_TYPE_U32_ARRAY},
{VDC_ENC_LEN, "qcom,sde-vdc-enc-size", false, PROP_TYPE_U32},
{VDC_CTL, "qcom,sde-vdc-ctl", false, PROP_TYPE_U32_ARRAY},
{VDC_CTL_LEN, "qcom,sde-vdc-ctl-size", false, PROP_TYPE_U32},
};
static struct sde_prop_type cdm_prop[] = {
{HW_OFF, "qcom,sde-cdm-off", false, PROP_TYPE_U32_ARRAY},
{HW_LEN, "qcom,sde-cdm-size", false, PROP_TYPE_U32},
};
static struct sde_prop_type intf_prop[] = {
{INTF_OFF, "qcom,sde-intf-off", true, PROP_TYPE_U32_ARRAY},
{INTF_LEN, "qcom,sde-intf-size", false, PROP_TYPE_U32},
{INTF_PREFETCH, "qcom,sde-intf-max-prefetch-lines", false,
PROP_TYPE_U32_ARRAY},
{INTF_TYPE, "qcom,sde-intf-type", false, PROP_TYPE_STRING_ARRAY},
{INTF_TE_IRQ, "qcom,sde-intf-tear-irq-off", false, PROP_TYPE_U32_ARRAY},
};
static struct sde_prop_type wb_prop[] = {
{WB_OFF, "qcom,sde-wb-off", false, PROP_TYPE_U32_ARRAY},
{WB_LEN, "qcom,sde-wb-size", false, PROP_TYPE_U32},
{WB_ID, "qcom,sde-wb-id", false, PROP_TYPE_U32_ARRAY},
{WB_XIN_ID, "qcom,sde-wb-xin-id", false, PROP_TYPE_U32_ARRAY},
{WB_CLK_CTRL, "qcom,sde-wb-clk-ctrl", false,
PROP_TYPE_BIT_OFFSET_ARRAY},
{WB_CLK_STATUS, "qcom,sde-wb-clk-status", false,
PROP_TYPE_BIT_OFFSET_ARRAY},
};
static struct sde_prop_type dnsc_blur_prop[] = {
{DNSC_BLUR_OFF, "qcom,sde-dnsc-blur-off", false, PROP_TYPE_U32_ARRAY},
{DNSC_BLUR_LEN, "qcom,sde-dnsc-blur-size", false, PROP_TYPE_U32},
{DNSC_BLUR_VERSION, "qcom,sde-dnsc-blur-version", false, PROP_TYPE_U32},
{DNSC_BLUR_GAUS_LUT_OFF, "qcom,sde-dnsc-blur-gaus-lut-off", false, PROP_TYPE_U32_ARRAY},
{DNSC_BLUR_GAUS_LUT_LEN, "qcom,sde-dnsc-blur-gaus-lut-size", false, PROP_TYPE_U32},
{DNSC_BLUR_DITHER_OFF, "qcom,sde-dnsc-blur-dither-off", false, PROP_TYPE_U32_ARRAY},
{DNSC_BLUR_DITHER_LEN, "qcom,sde-dnsc-blur-dither-size", false, PROP_TYPE_U32},
};
static struct sde_prop_type vbif_prop[] = {
{VBIF_OFF, "qcom,sde-vbif-off", true, PROP_TYPE_U32_ARRAY},
{VBIF_LEN, "qcom,sde-vbif-size", false, PROP_TYPE_U32},
{VBIF_ID, "qcom,sde-vbif-id", false, PROP_TYPE_U32_ARRAY},
{VBIF_DEFAULT_OT_RD_LIMIT, "qcom,sde-vbif-default-ot-rd-limit", false, PROP_TYPE_U32},
{VBIF_DEFAULT_OT_WR_LIMIT, "qcom,sde-vbif-default-ot-wr-limit", false, PROP_TYPE_U32},
{VBIF_DYNAMIC_OT_RD_LIMIT, "qcom,sde-vbif-dynamic-ot-rd-limit", false, PROP_TYPE_U32_ARRAY},
{VBIF_DYNAMIC_OT_WR_LIMIT, "qcom,sde-vbif-dynamic-ot-wr-limit", false, PROP_TYPE_U32_ARRAY},
{VBIF_MEMTYPE_0, "qcom,sde-vbif-memtype-0", false, PROP_TYPE_U32_ARRAY},
{VBIF_MEMTYPE_1, "qcom,sde-vbif-memtype-1", false, PROP_TYPE_U32_ARRAY},
{VBIF_QOS_RT_REMAP, "qcom,sde-vbif-qos-rt-remap", false, PROP_TYPE_U32_ARRAY},
{VBIF_QOS_NRT_REMAP, "qcom,sde-vbif-qos-nrt-remap", false, PROP_TYPE_U32_ARRAY},
{VBIF_QOS_CWB_REMAP, "qcom,sde-vbif-qos-cwb-remap", false, PROP_TYPE_U32_ARRAY},
{VBIF_QOS_LUTDMA_REMAP, "qcom,sde-vbif-qos-lutdma-remap", false, PROP_TYPE_U32_ARRAY},
{VBIF_QOS_CNOC_REMAP, "qcom,sde-vbif-qos-cnoc-remap", false, PROP_TYPE_U32_ARRAY},
{VBIF_QOS_OFFLINE_WB_REMAP, "qcom,sde-vbif-qos-offline-wb-remap", false,
PROP_TYPE_U32_ARRAY},
};
static struct sde_prop_type uidle_prop[] = {
{UIDLE_OFF, "qcom,sde-uidle-off", false, PROP_TYPE_U32},
{UIDLE_LEN, "qcom,sde-uidle-size", false, PROP_TYPE_U32},
};
static struct sde_prop_type reg_dma_prop[REG_DMA_PROP_MAX] = {
[REG_DMA_OFF] = {REG_DMA_OFF, "qcom,sde-reg-dma-off", false,
PROP_TYPE_U32_ARRAY},
[REG_DMA_ID] = {REG_DMA_ID, "qcom,sde-reg-dma-id", false,
PROP_TYPE_U32_ARRAY},
[REG_DMA_VERSION] = {REG_DMA_VERSION, "qcom,sde-reg-dma-version",
false, PROP_TYPE_U32},
[REG_DMA_TRIGGER_OFF] = {REG_DMA_TRIGGER_OFF,
"qcom,sde-reg-dma-trigger-off", false,
PROP_TYPE_U32},
[REG_DMA_BROADCAST_DISABLED] = {REG_DMA_BROADCAST_DISABLED,
"qcom,sde-reg-dma-broadcast-disabled", false, PROP_TYPE_BOOL},
[REG_DMA_XIN_ID] = {REG_DMA_XIN_ID,
"qcom,sde-reg-dma-xin-id", false, PROP_TYPE_U32},
[REG_DMA_CLK_CTRL] = {REG_DMA_CLK_CTRL,
"qcom,sde-reg-dma-clk-ctrl", false, PROP_TYPE_BIT_OFFSET_ARRAY},
};
static struct sde_prop_type merge_3d_prop[] = {
{HW_OFF, "qcom,sde-merge-3d-off", false, PROP_TYPE_U32_ARRAY},
{HW_LEN, "qcom,sde-merge-3d-size", false, PROP_TYPE_U32},
};
static struct sde_prop_type qdss_prop[] = {
{HW_OFF, "qcom,sde-qdss-off", false, PROP_TYPE_U32_ARRAY},
{HW_LEN, "qcom,sde-qdss-size", false, PROP_TYPE_U32},
};
static struct sde_prop_type demura_prop[] = {
[DEMURA_OFF] = {DEMURA_OFF, "qcom,sde-dspp-demura-off", false,
PROP_TYPE_U32_ARRAY},
[DEMURA_LEN] = {DEMURA_LEN, "qcom,sde-dspp-demura-size", false,
PROP_TYPE_U32},
[DEMURA_VERSION] = {DEMURA_VERSION, "qcom,sde-dspp-demura-version",
false, PROP_TYPE_U32},
};
static struct sde_prop_type noise_layer_prop[] = {
[NOISE_LAYER_OFF] = {NOISE_LAYER_OFF, "qcom,sde-lm-noise-off",
false, PROP_TYPE_U32},
[NOISE_LAYER_VERSION] = {NOISE_LAYER_VERSION,
"qcom,sde-lm-noise-version", false, PROP_TYPE_U32},
};
/*************************************************************
* static API list
*************************************************************/
static int _sde_lm_noise_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg);
static int _parse_dt_u32_handler(struct device_node *np,
char *prop_name, u32 *offsets, int len, bool mandatory)
{
int rc = -EINVAL;
if (len > MAX_SDE_HW_BLK) {
SDE_ERROR(
"prop: %s tries out of bound access for u32 array read len: %d\n",
prop_name, len);
return -E2BIG;
}
rc = of_property_read_u32_array(np, prop_name, offsets, len);
if (rc && mandatory)
SDE_ERROR("mandatory prop: %s u32 array read len:%d\n",
prop_name, len);
else if (rc)
SDE_DEBUG("optional prop: %s u32 array read len:%d\n",
prop_name, len);
return rc;
}
static int _parse_dt_bit_offset(struct device_node *np,
char *prop_name, struct sde_prop_value *prop_value, u32 prop_index,
u32 count, bool mandatory)
{
int rc = 0, len, i, j;
const u32 *arr;
arr = of_get_property(np, prop_name, &len);
if (arr) {
len /= sizeof(u32);
len &= ~0x1;
if (len > (MAX_SDE_HW_BLK * MAX_BIT_OFFSET)) {
SDE_ERROR(
"prop: %s len: %d will lead to out of bound access\n",
prop_name, len / MAX_BIT_OFFSET);
return -E2BIG;
}
for (i = 0, j = 0; i < len; j++) {
PROP_BITVALUE_ACCESS(prop_value, prop_index, j, 0) =
be32_to_cpu(arr[i]);
i++;
PROP_BITVALUE_ACCESS(prop_value, prop_index, j, 1) =
be32_to_cpu(arr[i]);
i++;
}
} else {
if (mandatory) {
SDE_ERROR("error mandatory property '%s' not found\n",
prop_name);
rc = -EINVAL;
} else {
SDE_DEBUG("error optional property '%s' not found\n",
prop_name);
}
}
return rc;
}
static int _validate_dt_entry(struct device_node *np,
struct sde_prop_type *sde_prop, u32 prop_size, int *prop_count,
int *off_count)
{
int rc = 0, i, val;
struct device_node *snp = NULL;
if (off_count) {
*off_count = of_property_count_u32_elems(np,
sde_prop[0].prop_name);
if ((*off_count > MAX_BLOCKS) || (*off_count < 0)) {
if (sde_prop[0].is_mandatory) {
SDE_ERROR(
"invalid hw offset prop name:%s count: %d\n",
sde_prop[0].prop_name, *off_count);
rc = -EINVAL;
}
*off_count = 0;
memset(prop_count, 0, sizeof(int) * prop_size);
return rc;
}
}
for (i = 0; i < prop_size; i++) {
switch (sde_prop[i].type) {
case PROP_TYPE_U32:
rc = of_property_read_u32(np, sde_prop[i].prop_name,
&val);
if (!rc)
prop_count[i] = 1;
break;
case PROP_TYPE_U32_ARRAY:
prop_count[i] = of_property_count_u32_elems(np,
sde_prop[i].prop_name);
if (prop_count[i] < 0)
rc = prop_count[i];
break;
case PROP_TYPE_STRING_ARRAY:
prop_count[i] = of_property_count_strings(np,
sde_prop[i].prop_name);
if (prop_count[i] < 0)
rc = prop_count[i];
break;
case PROP_TYPE_BIT_OFFSET_ARRAY:
of_get_property(np, sde_prop[i].prop_name, &val);
prop_count[i] = val / (MAX_BIT_OFFSET * sizeof(u32));
break;
case PROP_TYPE_NODE:
snp = of_get_child_by_name(np,
sde_prop[i].prop_name);
if (!snp)
rc = -EINVAL;
break;
case PROP_TYPE_BOOL:
/**
* No special handling for bool properties here.
* They will always exist, with value indicating
* if the given key is present or not.
*/
prop_count[i] = 1;
break;
default:
SDE_DEBUG("invalid property type:%d\n",
sde_prop[i].type);
break;
}
SDE_DEBUG(
"prop id:%d prop name:%s prop type:%d prop_count:%d\n",
i, sde_prop[i].prop_name,
sde_prop[i].type, prop_count[i]);
if (rc && sde_prop[i].is_mandatory &&
((sde_prop[i].type == PROP_TYPE_U32) ||
(sde_prop[i].type == PROP_TYPE_NODE))) {
SDE_ERROR("prop:%s not present\n",
sde_prop[i].prop_name);
goto end;
} else if (sde_prop[i].type == PROP_TYPE_U32 ||
sde_prop[i].type == PROP_TYPE_BOOL ||
sde_prop[i].type == PROP_TYPE_NODE) {
rc = 0;
continue;
}
if (off_count && (prop_count[i] != *off_count) &&
sde_prop[i].is_mandatory) {
SDE_ERROR(
"prop:%s count:%d is different compared to offset array:%d\n",
sde_prop[i].prop_name,
prop_count[i], *off_count);
rc = -EINVAL;
goto end;
} else if (off_count && prop_count[i] != *off_count) {
SDE_DEBUG(
"prop:%s count:%d is different compared to offset array:%d\n",
sde_prop[i].prop_name,
prop_count[i], *off_count);
rc = 0;
}
if (prop_count[i] < 0) {
prop_count[i] = 0;
if (sde_prop[i].is_mandatory) {
SDE_ERROR("prop:%s count:%d is negative\n",
sde_prop[i].prop_name, prop_count[i]);
rc = -EINVAL;
} else {
rc = 0;
SDE_DEBUG("prop:%s count:%d is negative\n",
sde_prop[i].prop_name, prop_count[i]);
}
}
}
end:
return rc;
}
static int _read_dt_entry(struct device_node *np,
struct sde_prop_type *sde_prop, u32 prop_size, int *prop_count,
bool *prop_exists,
struct sde_prop_value *prop_value)
{
int rc = 0, i, j;
for (i = 0; i < prop_size; i++) {
prop_exists[i] = true;
switch (sde_prop[i].type) {
case PROP_TYPE_U32:
rc = of_property_read_u32(np, sde_prop[i].prop_name,
&PROP_VALUE_ACCESS(prop_value, i, 0));
SDE_DEBUG(
"prop id:%d prop name:%s prop type:%d value:0x%x\n",
i, sde_prop[i].prop_name,
sde_prop[i].type,
PROP_VALUE_ACCESS(prop_value, i, 0));
if (rc)
prop_exists[i] = false;
break;
case PROP_TYPE_BOOL:
PROP_VALUE_ACCESS(prop_value, i, 0) =
of_property_read_bool(np,
sde_prop[i].prop_name);
SDE_DEBUG(
"prop id:%d prop name:%s prop type:%d value:0x%x\n",
i, sde_prop[i].prop_name,
sde_prop[i].type,
PROP_VALUE_ACCESS(prop_value, i, 0));
break;
case PROP_TYPE_U32_ARRAY:
rc = _parse_dt_u32_handler(np, sde_prop[i].prop_name,
&PROP_VALUE_ACCESS(prop_value, i, 0),
prop_count[i], sde_prop[i].is_mandatory);
if (rc && sde_prop[i].is_mandatory) {
SDE_ERROR(
"%s prop validation success but read failed\n",
sde_prop[i].prop_name);
prop_exists[i] = false;
goto end;
} else {
if (rc)
prop_exists[i] = false;
/* only for debug purpose */
SDE_DEBUG(
"prop id:%d prop name:%s prop type:%d",
i, sde_prop[i].prop_name,
sde_prop[i].type);
for (j = 0; j < prop_count[i]; j++)
SDE_DEBUG(" value[%d]:0x%x ", j,
PROP_VALUE_ACCESS(prop_value, i,
j));
SDE_DEBUG("\n");
}
break;
case PROP_TYPE_BIT_OFFSET_ARRAY:
rc = _parse_dt_bit_offset(np, sde_prop[i].prop_name,
prop_value, i, prop_count[i],
sde_prop[i].is_mandatory);
if (rc && sde_prop[i].is_mandatory) {
SDE_ERROR(
"%s prop validation success but read failed\n",
sde_prop[i].prop_name);
prop_exists[i] = false;
goto end;
} else {
if (rc)
prop_exists[i] = false;
SDE_DEBUG(
"prop id:%d prop name:%s prop type:%d",
i, sde_prop[i].prop_name,
sde_prop[i].type);
for (j = 0; j < prop_count[i]; j++)
SDE_DEBUG(
"count[%d]: bit:0x%x off:0x%x\n", j,
PROP_BITVALUE_ACCESS(prop_value,
i, j, 0),
PROP_BITVALUE_ACCESS(prop_value,
i, j, 1));
SDE_DEBUG("\n");
}
break;
case PROP_TYPE_NODE:
/* Node will be parsed in calling function */
rc = 0;
break;
default:
SDE_DEBUG("invalid property type:%d\n",
sde_prop[i].type);
break;
}
rc = 0;
}
end:
return rc;
}
/**
* sde_get_dt_props - allocate and return prop counts, exists & values arrays
* @np - device node
* @prop_max - <BLK>_PROP_MAX enum, this will be number of values allocated
* @sde_prop - pointer to prop table
* @prop_size - size of prop table
* @off_count - pointer to callers off_count
*
* @Returns - valid pointer or -ve error code (can never return NULL)
* If a non-NULL off_count pointer is given, the value it points to will be
* updated with the number of elements in the offset array (entry 0 in table).
* Caller MUST free this object using sde_put_dt_props after parsing values.
*/
static struct sde_dt_props *sde_get_dt_props(struct device_node *np,
size_t prop_max, struct sde_prop_type *sde_prop,
u32 prop_size, u32 *off_count)
{
struct sde_dt_props *props;
int rc = -ENOMEM;
props = kzalloc(sizeof(*props), GFP_KERNEL);
if (!props)
return ERR_PTR(rc);
props->values = kcalloc(prop_max, sizeof(*props->values),
GFP_KERNEL);
if (!props->values)
goto free_props;
rc = _validate_dt_entry(np, sde_prop, prop_size, props->counts,
off_count);
if (rc)
goto free_vals;
rc = _read_dt_entry(np, sde_prop, prop_size, props->counts,
props->exists, props->values);
if (rc)
goto free_vals;
return props;
free_vals:
kfree(props->values);
free_props:
kfree(props);
return ERR_PTR(rc);
}
/* sde_put_dt_props - free an sde_dt_props object obtained with "get" */
static void sde_put_dt_props(struct sde_dt_props *props)
{
if (!props)
return;
kfree(props->values);
kfree(props);
}
static int _add_to_irq_offset_list(struct sde_mdss_cfg *sde_cfg,
enum sde_intr_hwblk_type blk_type, u32 instance, u32 offset)
{
struct sde_intr_irq_offsets *item = NULL;
bool err = false;
switch (blk_type) {
case SDE_INTR_HWBLK_TOP:
if (instance >= SDE_INTR_TOP_MAX)
err = true;
break;
case SDE_INTR_HWBLK_INTF:
if (instance >= INTF_MAX)
err = true;
break;
case SDE_INTR_HWBLK_AD4:
if (instance >= AD_MAX)
err = true;
break;
case SDE_INTR_HWBLK_INTF_TEAR:
if (instance >= INTF_MAX)
err = true;
break;
case SDE_INTR_HWBLK_LTM:
if (instance >= LTM_MAX)
err = true;
break;
case SDE_INTR_HWBLK_WB:
if (instance >= WB_MAX)
err = true;
break;
default:
SDE_ERROR("invalid hwblk_type: %d", blk_type);
return -EINVAL;
}
if (err) {
SDE_ERROR("unable to map instance %d for blk type %d",
instance, blk_type);
return -EINVAL;
}
/* Check for existing list entry */
item = sde_hw_intr_list_lookup(sde_cfg, blk_type, instance);
if (IS_ERR_OR_NULL(item)) {
SDE_DEBUG("adding intr type %d idx %d offset 0x%x\n",
blk_type, instance, offset);
} else if (item->base_offset == offset) {
SDE_INFO("duplicate intr %d/%d offset 0x%x, skipping\n",
blk_type, instance, offset);
return 0;
} else {
SDE_ERROR("type %d, idx %d in list with offset 0x%x != 0x%x\n",
blk_type, instance, item->base_offset, offset);
return -EINVAL;
}
item = kzalloc(sizeof(*item), GFP_KERNEL);
if (!item) {
SDE_ERROR("memory allocation failed!\n");
return -ENOMEM;
}
INIT_LIST_HEAD(&item->list);
item->type = blk_type;
item->instance_idx = instance;
item->base_offset = offset;
list_add_tail(&item->list, &sde_cfg->irq_offset_list);
return 0;
}
/* VIG color management (VCM) feature setup */
static bool _sde_sspp_setup_vcm(struct sde_sspp_cfg *sspp,
const struct sde_dt_props *props, const char *name,
struct sde_pp_blk *blk, u32 type, u32 prop, bool versioned)
{
bool exists = props->exists[prop];
if (exists) {
blk->id = type;
blk->len = 0;
set_bit(type, (unsigned long *) &sspp->features_ext);
blk->base = PROP_VALUE_ACCESS(props->values, prop, 0);
blk->regdma_base = SSPP_GET_REGDMA_BASE(blk->base, sspp->sblk->top_off);
snprintf(blk->name, SDE_HW_BLK_NAME_LEN, "%s%u", name,
sspp->id - SSPP_VIG0);
if (versioned)
blk->version = PROP_VALUE_ACCESS(props->values,
prop, 1);
} else {
blk->id = 0;
}
return exists;
}
static void _sde_sspp_setup_vigs_pp(struct sde_dt_props *props,
struct sde_mdss_cfg *sde_cfg, struct sde_sspp_cfg *sspp)
{
struct sde_sspp_sub_blks *sblk = sspp->sblk;
if (!props)
return;
if (sde_cfg->csc_type == SDE_SSPP_CSC)
_sde_sspp_setup_vcm(sspp, props, "sspp_csc", &sblk->csc_blk,
SDE_SSPP_CSC, VIG_CSC_OFF, false);
else if (sde_cfg->csc_type == SDE_SSPP_CSC_10BIT)
_sde_sspp_setup_vcm(sspp, props, "sspp_csc", &sblk->csc_blk,
SDE_SSPP_CSC_10BIT, VIG_CSC_OFF, false);
_sde_sspp_setup_vcm(sspp, props, "sspp_hsic", &sblk->hsic_blk,
SDE_SSPP_HSIC, VIG_HSIC_PROP, true);
_sde_sspp_setup_vcm(sspp, props, "sspp_memcolor", &sblk->memcolor_blk,
SDE_SSPP_MEMCOLOR, VIG_MEMCOLOR_PROP, true);
_sde_sspp_setup_vcm(sspp, props, "sspp_pcc", &sblk->pcc_blk,
SDE_SSPP_PCC, VIG_PCC_PROP, true);
_sde_sspp_setup_vcm(sspp, props, "sspp_vig_gamut", &sblk->gamut_blk,
SDE_SSPP_VIG_GAMUT, VIG_GAMUT_PROP, true);
_sde_sspp_setup_vcm(sspp, props, "sspp_vig_igc", &sblk->igc_blk[0],
SDE_SSPP_VIG_IGC, VIG_IGC_PROP, true);
if (props->exists[VIG_INVERSE_PMA]) {
set_bit(SDE_SSPP_INVERSE_PMA, &sspp->features);
sblk->unmult_offset[0] = SDE_VIG_UNMULT;
}
}
static int _sde_sspp_setup_vigs(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int i = 0, j = 0, rc = 0;
struct sde_dt_props *props[SSPP_SUBBLK_COUNT_MAX] = {NULL, NULL};
struct sde_dt_props *props_tmp = NULL;
struct device_node *snp = NULL;
int vig_count = 0, vcm_count = 0;
const char *type;
snp = of_get_child_by_name(np, sspp_prop[SSPP_VIG_BLOCKS].prop_name);
if (!snp)
return 0;
/* Assume sub nodes are in rect order */
vcm_count = of_get_child_count(snp);
if (vcm_count > 0) {
struct device_node *vcm_snp;
if (vcm_count > SSPP_SUBBLK_COUNT_MAX) {
SDE_ERROR("exceeded max vcm sub-block count!");
vcm_count = SSPP_SUBBLK_COUNT_MAX;
}
for_each_child_of_node(snp, vcm_snp) {
props_tmp = sde_get_dt_props(vcm_snp,
VIG_PROP_MAX, vig_prop,
ARRAY_SIZE(vig_prop), NULL);
if (IS_ERR(props_tmp)) {
rc = PTR_ERR(props_tmp);
props_tmp = NULL;
goto end;
}
if (!props_tmp->exists[VIG_SUBBLOCK_INDEX]) {
SDE_ERROR("vcm rect index must be specified!");
goto end;
}
i = PROP_VALUE_ACCESS(props_tmp->values, VIG_SUBBLOCK_INDEX, 0);
if (i >= SSPP_SUBBLK_COUNT_MAX) {
SDE_ERROR("invalid vcm rect index: %d", i);
goto end;
} else if (props[i] != NULL) {
SDE_ERROR("vcm rect index must be unique! repeat: %d", i);
goto end;
}
props[i] = props_tmp;
props_tmp = NULL;
}
} else {
props[0] = sde_get_dt_props(snp, VIG_PROP_MAX, vig_prop,
ARRAY_SIZE(vig_prop), NULL);
}
for (i = 0; i < sde_cfg->sspp_count; ++i) {
struct sde_sspp_cfg *sspp = sde_cfg->sspp + i;
struct sde_sspp_sub_blks *sblk = sspp->sblk;
of_property_read_string_index(np,
sspp_prop[SSPP_TYPE].prop_name, i, &type);
if (strcmp(type, "vig"))
continue;
sblk->maxlinewidth = sde_cfg->vig_sspp_linewidth;
sblk->scaling_linewidth = sde_cfg->scaling_linewidth;
sblk->maxupscale = MAX_UPSCALE_RATIO;
sblk->maxdwnscale = MAX_DOWNSCALE_RATIO;
sspp->id = SSPP_VIG0 + vig_count;
snprintf(sspp->name, SDE_HW_BLK_NAME_LEN, "sspp_%u",
sspp->id - SSPP_VIG0);
sspp->clk_ctrl = SDE_CLK_CTRL_VIG0 + vig_count;
sspp->type = SSPP_TYPE_VIG;
set_bit(SDE_PERF_SSPP_QOS, &sspp->perf_features);
if (sde_cfg->vbif_qos_nlvl == 8)
set_bit(SDE_PERF_SSPP_QOS_8LVL, &sspp->perf_features);
vig_count++;
/* Obtain sub block top, or maintain backwards compatibility */
if (props[0] && props[0]->exists[VIG_TOP_OFF])
sblk->top_off = PROP_VALUE_ACCESS(props[0]->values, VIG_TOP_OFF, 0);
else
sblk->top_off = 0x200;
sblk->format_list = sde_cfg->vig_formats;
sblk->virt_format_list = sde_cfg->virt_vig_formats;
sblk->num_fp16_igc_blk = 0;
sblk->num_fp16_gc_blk = 0;
sblk->num_fp16_csc_blk = 0;
sblk->num_fp16_unmult_blk = 0;
for (j = 0; j < SSPP_SUBBLK_COUNT_MAX; j++) {
if (!props[j])
continue;
if (_sde_sspp_setup_vcm(sspp, props[j],
"sspp_vig_fp16_igc",
&sblk->fp16_igc_blk[j],
SDE_SSPP_FP16_IGC, VIG_FP16_IGC_PROP,
true))
sblk->num_fp16_igc_blk += 1;
if (_sde_sspp_setup_vcm(sspp, props[j],
"sspp_vig_fp16_gc",
&sblk->fp16_gc_blk[j],
SDE_SSPP_FP16_GC, VIG_FP16_GC_PROP,
true))
sblk->num_fp16_gc_blk += 1;
if (_sde_sspp_setup_vcm(sspp, props[j],
"sspp_vig_fp16_csc",
&sblk->fp16_csc_blk[j],
SDE_SSPP_FP16_CSC, VIG_FP16_CSC_PROP,
true))
sblk->num_fp16_csc_blk += 1;
if (_sde_sspp_setup_vcm(sspp, props[j],
"sspp_vig_fp16_unmult",
&sblk->fp16_unmult_blk[j],
SDE_SSPP_FP16_UNMULT,
VIG_FP16_UNMULT_PROP, true))
sblk->num_fp16_unmult_blk += 1;
}
/* PP + scaling only supported on VIG rect 0 */
if (props[0] && ((sde_cfg->qseed_sw_lib_rev == SDE_SSPP_SCALER_QSEED2) ||
(sde_cfg->qseed_sw_lib_rev == SDE_SSPP_SCALER_QSEED3) ||
(sde_cfg->qseed_sw_lib_rev == SDE_SSPP_SCALER_QSEED3LITE))) {
set_bit(sde_cfg->qseed_sw_lib_rev, &sspp->features);
sblk->scaler_blk.id = sde_cfg->qseed_sw_lib_rev;
sblk->scaler_blk.base = PROP_VALUE_ACCESS(
props[0]->values, VIG_QSEED_OFF, 0);
sblk->scaler_blk.len = PROP_VALUE_ACCESS(
props[0]->values, VIG_QSEED_LEN, 0);
sblk->scaler_blk.regdma_base = SSPP_GET_REGDMA_BASE(sblk->scaler_blk.base,
sblk->top_off);
snprintf(sblk->scaler_blk.name, SDE_HW_BLK_NAME_LEN,
"sspp_scaler%u", sspp->id - SSPP_VIG0);
}
_sde_sspp_setup_vigs_pp(props[0], sde_cfg, sspp);
if (sde_cfg->true_inline_rot_rev > 0) {
set_bit(SDE_SSPP_TRUE_INLINE_ROT, &sspp->features);
sblk->in_rot_format_list = sde_cfg->inline_rot_formats;
sblk->in_rot_maxheight =
MAX_PRE_ROT_HEIGHT_INLINE_ROT_DEFAULT;
}
if (IS_SDE_INLINE_ROT_REV_200(sde_cfg->true_inline_rot_rev) ||
IS_SDE_INLINE_ROT_REV_201(sde_cfg->true_inline_rot_rev)) {
set_bit(SDE_SSPP_PREDOWNSCALE, &sspp->features);
sblk->in_rot_maxdwnscale_rt_num =
MAX_DOWNSCALE_RATIO_INROT_PD_RT_NUMERATOR;
sblk->in_rot_maxdwnscale_rt_denom =
MAX_DOWNSCALE_RATIO_INROT_PD_RT_DENOMINATOR;
sblk->in_rot_maxdwnscale_nrt =
MAX_DOWNSCALE_RATIO_INROT_NRT_DEFAULT;
sblk->in_rot_maxdwnscale_rt_nopd_num =
MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_NUMERATOR;
sblk->in_rot_maxdwnscale_rt_nopd_denom =
MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_DENOMINATOR;
} else if (IS_SDE_INLINE_ROT_REV_100(
sde_cfg->true_inline_rot_rev)) {
sblk->in_rot_maxdwnscale_rt_num =
MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_NUMERATOR;
sblk->in_rot_maxdwnscale_rt_denom =
MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_DENOMINATOR;
sblk->in_rot_maxdwnscale_nrt =
MAX_DOWNSCALE_RATIO_INROT_NRT_DEFAULT;
}
if (test_bit(SDE_FEATURE_INLINE_DISABLE_CONST_CLR, sde_cfg->features))
set_bit(SDE_SSPP_INLINE_CONST_CLR, &sspp->features);
}
end:
sde_put_dt_props(props_tmp);
for (i = 0; i < SSPP_SUBBLK_COUNT_MAX; i++)
sde_put_dt_props(props[i]);
return rc;
}
static void _sde_sspp_setup_dgm(struct sde_sspp_cfg *sspp,
const struct sde_dt_props *props, const char *name,
struct sde_pp_blk *blk, u32 type, u32 prop, bool versioned)
{
blk->id = type;
blk->len = 0;
set_bit(type, &sspp->features);
blk->base = PROP_VALUE_ACCESS(props->values, prop, 0);
blk->regdma_base = SSPP_GET_REGDMA_BASE(blk->base, sspp->sblk->top_off);
snprintf(blk->name, SDE_HW_BLK_NAME_LEN, "%s%u", name,
sspp->id - SSPP_DMA0);
if (versioned)
blk->version = PROP_VALUE_ACCESS(props->values, prop, 1);
}
static int _sde_sspp_setup_dmas(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int i = 0, j;
int rc = 0, dma_count = 0, dgm_count = 0;
struct sde_dt_props *props[SSPP_SUBBLK_COUNT_MAX] = {NULL, NULL};
struct sde_dt_props *props_tmp = NULL;
struct device_node *snp = NULL;
const char *type;
snp = of_get_child_by_name(np, sspp_prop[SSPP_DMA_BLOCKS].prop_name);
if (snp) {
dgm_count = of_get_child_count(snp);
if (dgm_count > 0) {
struct device_node *dgm_snp;
if (dgm_count > SSPP_SUBBLK_COUNT_MAX) {
SDE_ERROR("too many dgm subblocks defined");
goto end;
}
for_each_child_of_node(snp, dgm_snp) {
props_tmp = sde_get_dt_props(dgm_snp,
DMA_PROP_MAX, dma_prop,
ARRAY_SIZE(dma_prop), NULL);
if (IS_ERR(props_tmp)) {
rc = PTR_ERR(props_tmp);
props_tmp = NULL;
goto end;
} else if (!props_tmp->exists[DMA_SUBBLOCK_INDEX]) {
SDE_ERROR("dgm sub-block index must be defined");
goto end;
}
i = PROP_VALUE_ACCESS(props_tmp->values, DMA_SUBBLOCK_INDEX, 0);
if (i >= SSPP_SUBBLK_COUNT_MAX) {
SDE_ERROR("dgm sub-block index greater than max: %d", i);
goto end;
} else if (props[i] != NULL) {
SDE_ERROR("dgm sub-block index already defined: %d", i);
goto end;
}
props[i] = props_tmp;
props_tmp = NULL;
}
}
}
for (i = 0; i < sde_cfg->sspp_count; ++i) {
struct sde_sspp_cfg *sspp = sde_cfg->sspp + i;
struct sde_sspp_sub_blks *sblk = sspp->sblk;
of_property_read_string_index(np,
sspp_prop[SSPP_TYPE].prop_name, i, &type);
if (strcmp(type, "dma"))
continue;
sblk->maxupscale = SSPP_UNITY_SCALE;
sblk->maxdwnscale = SSPP_UNITY_SCALE;
sblk->format_list = sde_cfg->dma_formats;
sblk->virt_format_list = sde_cfg->dma_formats;
sspp->id = SSPP_DMA0 + dma_count;
sspp->clk_ctrl = SDE_CLK_CTRL_DMA0 + dma_count;
snprintf(sspp->name, SDE_HW_BLK_NAME_LEN, "sspp_%u",
sspp->id - SSPP_VIG0);
sspp->type = SSPP_TYPE_DMA;
set_bit(SDE_PERF_SSPP_QOS, &sspp->perf_features);
if (sde_cfg->vbif_qos_nlvl == 8)
set_bit(SDE_PERF_SSPP_QOS_8LVL, &sspp->perf_features);
dma_count++;
/* Obtain sub block top, or maintain backwards compatibility */
if (props[0] && props[0]->exists[DMA_TOP_OFF])
sblk->top_off = PROP_VALUE_ACCESS(props[0]->values, DMA_TOP_OFF, 0);
else
sblk->top_off = 0x200;
sblk->num_igc_blk = dgm_count;
sblk->num_gc_blk = dgm_count;
sblk->num_dgm_csc_blk = dgm_count;
for (j = 0; j < SSPP_SUBBLK_COUNT_MAX; j++) {
if (props[j] == NULL)
continue;
if (props[j]->exists[DMA_IGC_PROP])
_sde_sspp_setup_dgm(sspp, props[j],
"sspp_dma_igc", &sblk->igc_blk[j],
SDE_SSPP_DMA_IGC, DMA_IGC_PROP, true);
if (props[j]->exists[DMA_GC_PROP])
_sde_sspp_setup_dgm(sspp, props[j],
"sspp_dma_gc", &sblk->gc_blk[j],
SDE_SSPP_DMA_GC, DMA_GC_PROP, true);
if (PROP_VALUE_ACCESS(props[j]->values,
DMA_DGM_INVERSE_PMA, 0)) {
set_bit(SDE_SSPP_DGM_INVERSE_PMA,
&sspp->features);
if (sde_cfg->hw_rev >= SDE_HW_VER_810)
sblk->unmult_offset[j] = SDE_DGM_UNMULT_2 + j*0x1000;
else
sblk->unmult_offset[j] = SDE_DGM_UNMULT + j*0x1000;
}
if (props[j]->exists[DMA_CSC_OFF])
_sde_sspp_setup_dgm(sspp, props[j],
"sspp_dgm_csc", &sblk->dgm_csc_blk[j],
SDE_SSPP_DGM_CSC, DMA_CSC_OFF, false);
if (props[j]->exists[DMA_FP16_IGC_PROP])
_sde_sspp_setup_dgm(sspp, props[j],
"sspp_dma_fp16_igc",
&sblk->fp16_igc_blk[j],
SDE_SSPP_FP16_IGC,
DMA_FP16_IGC_PROP, true);
if (props[j]->exists[DMA_FP16_GC_PROP])
_sde_sspp_setup_dgm(sspp, props[j],
"sspp_dma_fp16_gc",
&sblk->fp16_gc_blk[j],
SDE_SSPP_FP16_GC,
DMA_FP16_GC_PROP, true);
if (props[j]->exists[DMA_FP16_CSC_PROP])
_sde_sspp_setup_dgm(sspp, props[j],
"sspp_dma_fp16_csc",
&sblk->fp16_csc_blk[j],
SDE_SSPP_FP16_CSC,
DMA_FP16_CSC_PROP, true);
if (props[j]->exists[DMA_FP16_UNMULT_PROP])
_sde_sspp_setup_dgm(sspp, props[j],
"sspp_dma_fp16_unmult",
&sblk->fp16_unmult_blk[j],
SDE_SSPP_FP16_UNMULT,
DMA_FP16_UNMULT_PROP, true);
}
}
end:
for (i = 0; i < SSPP_SUBBLK_COUNT_MAX; i++)
sde_put_dt_props(props[i]);
sde_put_dt_props(props_tmp);
return rc;
}
static void sde_sspp_set_features(struct sde_mdss_cfg *sde_cfg,
const struct sde_dt_props *props)
{
int i;
for (i = 0; i < sde_cfg->sspp_count; ++i) {
struct sde_sspp_cfg *sspp = sde_cfg->sspp + i;
struct sde_sspp_sub_blks *sblk = sspp->sblk;
sblk->maxlinewidth = sde_cfg->max_sspp_linewidth;
if (sde_cfg->has_line_insertion)
set_bit(SDE_SSPP_LINE_INSERTION, &sspp->features);
sblk->smart_dma_priority =
PROP_VALUE_ACCESS(props->values, SSPP_SMART_DMA, i);
if (sblk->smart_dma_priority && sde_cfg->smart_dma_rev)
set_bit(sde_cfg->smart_dma_rev, &sspp->features);
sblk->src_blk.id = SDE_SSPP_SRC;
set_bit(SDE_SSPP_SRC, &sspp->features);
if (test_bit(SDE_FEATURE_CDP, sde_cfg->features))
set_bit(SDE_PERF_SSPP_CDP, &sspp->perf_features);
if (sde_cfg->ts_prefill_rev == 1) {
set_bit(SDE_PERF_SSPP_TS_PREFILL, &sspp->perf_features);
} else if (sde_cfg->ts_prefill_rev == 2) {
set_bit(SDE_PERF_SSPP_TS_PREFILL, &sspp->perf_features);
set_bit(SDE_PERF_SSPP_TS_PREFILL_REC1,
&sspp->perf_features);
}
if (sde_cfg->uidle_cfg.uidle_rev) {
set_bit(SDE_PERF_SSPP_UIDLE, &sspp->perf_features);
if (sde_cfg->uidle_cfg.uidle_rev >= SDE_UIDLE_VERSION_1_0_3)
set_bit(SDE_PERF_SSPP_UIDLE_FILL_LVL_SCALE, &sspp->perf_features);
}
if (test_bit(SDE_SYS_CACHE_DISP, sde_cfg->sde_sys_cache_type_map))
set_bit(SDE_PERF_SSPP_SYS_CACHE, &sspp->perf_features);
if (test_bit(SDE_FEATURE_MULTIRECT_ERROR, sde_cfg->features))
set_bit(SDE_SSPP_MULTIRECT_ERROR, &sspp->features);
if (test_bit(SDE_FEATURE_DECIMATION, sde_cfg->features)) {
sblk->maxhdeciexp = MAX_HORZ_DECIMATION;
sblk->maxvdeciexp = MAX_VERT_DECIMATION;
} else {
sblk->maxhdeciexp = 0;
sblk->maxvdeciexp = 0;
}
sblk->pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE;
if (PROP_VALUE_ACCESS(props->values, SSPP_EXCL_RECT, i) == 1)
set_bit(SDE_SSPP_EXCL_RECT, &sspp->features);
if (props->exists[SSPP_MAX_PER_PIPE_BW])
sblk->max_per_pipe_bw = PROP_VALUE_ACCESS(props->values,
SSPP_MAX_PER_PIPE_BW, i);
else
sblk->max_per_pipe_bw = DEFAULT_MAX_PER_PIPE_BW;
if (props->exists[SSPP_MAX_PER_PIPE_BW_HIGH])
sblk->max_per_pipe_bw_high =
PROP_VALUE_ACCESS(props->values,
SSPP_MAX_PER_PIPE_BW_HIGH, i);
else
sblk->max_per_pipe_bw_high = sblk->max_per_pipe_bw;
if (test_bit(SDE_FEATURE_UBWC_STATS, sde_cfg->features))
set_bit(SDE_SSPP_UBWC_STATS, &sspp->features);
if (SDE_HW_MAJOR(sde_cfg->hw_rev) >= SDE_HW_MAJOR(SDE_HW_VER_900))
set_bit(SDE_SSPP_SCALER_DE_LPF_BLEND, &sspp->features);
}
}
static int _sde_sspp_setup_cmn(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int rc = 0, off_count, i, j;
struct sde_dt_props *props;
struct sde_sspp_cfg *sspp;
struct sde_sspp_sub_blks *sblk;
props = sde_get_dt_props(np, SSPP_PROP_MAX, sspp_prop,
ARRAY_SIZE(sspp_prop), &off_count);
if (IS_ERR(props))
return PTR_ERR(props);
if (off_count > MAX_BLOCKS) {
SDE_ERROR("%d off_count exceeds MAX_BLOCKS, limiting to %d\n",
off_count, MAX_BLOCKS);
off_count = MAX_BLOCKS;
}
sde_cfg->sspp_count = off_count;
/* create all sub blocks before populating them */
for (i = 0; i < off_count; i++) {
sspp = sde_cfg->sspp + i;
sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
if (!sblk) {
rc = -ENOMEM;
/* catalog deinit will release the allocated blocks */
goto end;
}
sspp->sblk = sblk;
}
sde_sspp_set_features(sde_cfg, props);
for (i = 0; i < off_count; i++) {
sspp = sde_cfg->sspp + i;
sblk = sspp->sblk;
sspp->base = PROP_VALUE_ACCESS(props->values, SSPP_OFF, i);
sspp->len = PROP_VALUE_ACCESS(props->values, SSPP_SIZE, 0);
snprintf(sblk->src_blk.name, SDE_HW_BLK_NAME_LEN, "sspp_src_%u",
sspp->id - SSPP_VIG0);
if (sspp->clk_ctrl >= SDE_CLK_CTRL_MAX) {
SDE_ERROR("%s: invalid clk ctrl: %d\n",
sblk->src_blk.name, sspp->clk_ctrl);
rc = -EINVAL;
goto end;
}
sspp->xin_id = PROP_VALUE_ACCESS(props->values, SSPP_XIN, i);
sblk->src_blk.len = PROP_VALUE_ACCESS(props->values, SSPP_SIZE,
0);
if (!test_bit(SDE_FEATURE_VBIF_CLK_SPLIT, sde_cfg->features)) {
for (j = 0; j < sde_cfg->mdp_count; j++) {
sde_cfg->mdp[j].clk_ctrls[sspp->clk_ctrl].reg_off =
PROP_BITVALUE_ACCESS(props->values,
SSPP_CLK_CTRL, i, 0);
sde_cfg->mdp[j].clk_ctrls[sspp->clk_ctrl].bit_off =
PROP_BITVALUE_ACCESS(props->values,
SSPP_CLK_CTRL, i, 1);
sde_cfg->mdp[j].clk_status[sspp->clk_ctrl].reg_off =
PROP_BITVALUE_ACCESS(props->values,
SSPP_CLK_STATUS, i, 0);
sde_cfg->mdp[j].clk_status[sspp->clk_ctrl].bit_off =
PROP_BITVALUE_ACCESS(props->values,
SSPP_CLK_STATUS, i, 1);
}
SDE_DEBUG("xin:%d ram:%d clk%d:%x/%d\n",
sspp->xin_id, sblk->pixel_ram_size, sspp->clk_ctrl,
sde_cfg->mdp[0].clk_ctrls[sspp->clk_ctrl].reg_off,
sde_cfg->mdp[0].clk_ctrls[sspp->clk_ctrl].bit_off);
}
}
end:
sde_put_dt_props(props);
return rc;
}
static int sde_sspp_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int rc;
rc = _sde_sspp_setup_cmn(np, sde_cfg);
if (rc)
return rc;
rc = _sde_sspp_setup_vigs(np, sde_cfg);
if (rc)
return rc;
rc = _sde_sspp_setup_dmas(np, sde_cfg);
return rc;
}
static int sde_ctl_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int i;
struct sde_dt_props *props;
struct sde_ctl_cfg *ctl;
u32 off_count;
if (!sde_cfg) {
SDE_ERROR("invalid argument input param\n");
return -EINVAL;
}
props = sde_get_dt_props(np, HW_PROP_MAX, ctl_prop,
ARRAY_SIZE(ctl_prop), &off_count);
if (IS_ERR(props))
return PTR_ERR(props);
sde_cfg->ctl_count = off_count;
for (i = 0; i < off_count; i++) {
const char *disp_pref = NULL;
ctl = sde_cfg->ctl + i;
ctl->base = PROP_VALUE_ACCESS(props->values, HW_OFF, i);
ctl->len = PROP_VALUE_ACCESS(props->values, HW_LEN, 0);
ctl->id = CTL_0 + i;
snprintf(ctl->name, SDE_HW_BLK_NAME_LEN, "ctl_%u",
ctl->id - CTL_0);
of_property_read_string_index(np,
ctl_prop[HW_DISP].prop_name, i, &disp_pref);
if (disp_pref && !strcmp(disp_pref, "primary"))
set_bit(SDE_CTL_PRIMARY_PREF, &ctl->features);
if ((i < MAX_SPLIT_DISPLAY_CTL) &&
!(IS_SDE_CTL_REV_100(sde_cfg->ctl_rev)))
set_bit(SDE_CTL_SPLIT_DISPLAY, &ctl->features);
if (i < MAX_PP_SPLIT_DISPLAY_CTL)
set_bit(SDE_CTL_PINGPONG_SPLIT, &ctl->features);
if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev))
set_bit(SDE_CTL_ACTIVE_CFG, &ctl->features);
if (SDE_UIDLE_MAJOR(sde_cfg->uidle_cfg.uidle_rev))
set_bit(SDE_CTL_UIDLE, &ctl->features);
if (SDE_HW_MAJOR(sde_cfg->hw_rev) >= SDE_HW_MAJOR(SDE_HW_VER_700))
set_bit(SDE_CTL_UNIFIED_DSPP_FLUSH, &ctl->features);
}
sde_put_dt_props(props);
return 0;
}
u32 sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm,
uint32_t disp_type)
{
u32 i, cnt = 0, sec_cnt = 0, lm_mask = 0;
if (disp_type == SDE_CONNECTOR_PRIMARY) {
for (i = 0; i < sde_cfg->mixer_count; i++) {
/* Check if lm was previously set for secondary */
/* Clear pref, primary has higher priority */
if (sde_cfg->mixer[i].features &
BIT(SDE_DISP_SECONDARY_PREF)) {
clear_bit(SDE_DISP_SECONDARY_PREF,
&sde_cfg->mixer[i].features);
sec_cnt++;
}
clear_bit(SDE_DISP_PRIMARY_PREF,
&sde_cfg->mixer[i].features);
/* Set lm for primary pref */
if (cnt < num_lm) {
set_bit(SDE_DISP_PRIMARY_PREF,
&sde_cfg->mixer[i].features);
lm_mask |= BIT(sde_cfg->mixer[i].id - 1);
cnt++;
}
/*
* When all primary prefs have been set,
* and if 2 lms are required for secondary
* preference must be set with an lm pair
*/
if (cnt == num_lm && sec_cnt > 1 &&
!test_bit(sde_cfg->mixer[i+1].id,
&sde_cfg->mixer[i].lm_pair_mask))
continue;
/* After primary pref is set, now re apply secondary */
if (cnt >= num_lm && cnt < (num_lm + sec_cnt)) {
set_bit(SDE_DISP_SECONDARY_PREF,
&sde_cfg->mixer[i].features);
cnt++;
}
}
} else if (disp_type == SDE_CONNECTOR_SECONDARY) {
for (i = 0; i < sde_cfg->mixer_count; i++) {
clear_bit(SDE_DISP_SECONDARY_PREF,
&sde_cfg->mixer[i].features);
/*
* If 2 lms are required for secondary
* preference must be set with an lm pair
*/
if (cnt == 0 && num_lm > 1 &&
!test_bit(sde_cfg->mixer[i+1].id,
&sde_cfg->mixer[i].lm_pair_mask))
continue;
if (cnt < num_lm && !(sde_cfg->mixer[i].features &
BIT(SDE_DISP_PRIMARY_PREF))) {
set_bit(SDE_DISP_SECONDARY_PREF,
&sde_cfg->mixer[i].features);
lm_mask |= BIT(sde_cfg->mixer[i].id - 1);
cnt++;
}
}
}
return lm_mask;
}
static int sde_mixer_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg)
{
int rc = 0, i, j;
u32 off_count, blend_off_count, max_blendstages, lm_pair_mask;
struct sde_lm_cfg *mixer;
struct sde_lm_sub_blks *sblk;
int pp_count, dspp_count, ds_count, mixer_count;
u32 pp_idx, dspp_idx, ds_idx;
u32 mixer_base;
struct device_node *snp = NULL;
struct sde_dt_props *props, *blend_props, *blocks_props = NULL;
if (!sde_cfg) {
SDE_ERROR("invalid argument input param\n");
return -EINVAL;
}
max_blendstages = sde_cfg->max_mixer_blendstages;
props = sde_get_dt_props(np, MIXER_PROP_MAX, mixer_prop,
ARRAY_SIZE(mixer_prop), &off_count);
if (IS_ERR(props))
return PTR_ERR(props);
pp_count = sde_cfg->pingpong_count;
dspp_count = sde_cfg->dspp_count;
ds_count = sde_cfg->ds_count;
/* get mixer feature dt properties if they exist */
snp = of_get_child_by_name(np, mixer_prop[MIXER_BLOCKS].prop_name);
if (snp) {
blocks_props = sde_get_dt_props(snp, MIXER_PROP_MAX,
mixer_blocks_prop,
ARRAY_SIZE(mixer_blocks_prop), NULL);
if (IS_ERR(blocks_props)) {
rc = PTR_ERR(blocks_props);
goto put_props;
}
}
/* get the blend_op register offsets */
blend_props = sde_get_dt_props(np, MIXER_BLEND_PROP_MAX,
mixer_blend_prop, ARRAY_SIZE(mixer_blend_prop),
&blend_off_count);
if (IS_ERR(blend_props)) {
rc = PTR_ERR(blend_props);
goto put_blocks;
}
for (i = 0, mixer_count = 0, pp_idx = 0, dspp_idx = 0,
ds_idx = 0; i < off_count; i++) {
const char *disp_pref = NULL;
const char *cwb_pref = NULL;
const char *dcwb_pref = NULL;
u32 dummy_mixer_base = 0x0f0f;
mixer_base = PROP_VALUE_ACCESS(props->values, MIXER_OFF, i);
if (!mixer_base)
continue;
mixer = sde_cfg->mixer + mixer_count;
sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
if (!sblk) {
rc = -ENOMEM;
/* catalog deinit will release the allocated blocks */
goto end;
}
mixer->sblk = sblk;
mixer->base = mixer_base;
mixer->len = !props->exists[MIXER_LEN] ?
DEFAULT_SDE_HW_BLOCK_LEN :
PROP_VALUE_ACCESS(props->values, MIXER_LEN, 0);
mixer->id = LM_0 + i;
snprintf(mixer->name, SDE_HW_BLK_NAME_LEN, "lm_%u",
mixer->id - LM_0);
lm_pair_mask = PROP_VALUE_ACCESS(props->values,
MIXER_PAIR_MASK, i);
if (lm_pair_mask)
mixer->lm_pair_mask = 1 << lm_pair_mask;
sblk->maxblendstages = max_blendstages;
sblk->maxwidth = sde_cfg->max_mixer_width;
for (j = 0; j < blend_off_count; j++)
sblk->blendstage_base[j] =
PROP_VALUE_ACCESS(blend_props->values,
MIXER_BLEND_OP_OFF, j);
if (test_bit(SDE_FEATURE_SRC_SPLIT, sde_cfg->features))
set_bit(SDE_MIXER_SOURCESPLIT, &mixer->features);
if (test_bit(SDE_FEATURE_DIM_LAYER, sde_cfg->features))
set_bit(SDE_DIM_LAYER, &mixer->features);
if (test_bit(SDE_FEATURE_COMBINED_ALPHA, sde_cfg->features))
set_bit(SDE_MIXER_COMBINED_ALPHA, &mixer->features);
of_property_read_string_index(np,
mixer_prop[MIXER_DISP].prop_name, i, &disp_pref);
if (disp_pref && !strcmp(disp_pref, "primary"))
set_bit(SDE_DISP_PRIMARY_PREF, &mixer->features);
of_property_read_string_index(np,
mixer_prop[MIXER_CWB].prop_name, i, &cwb_pref);
if (cwb_pref && !strcmp(cwb_pref, "cwb"))
set_bit(SDE_DISP_CWB_PREF, &mixer->features);
of_property_read_string_index(np,
mixer_prop[MIXER_DCWB].prop_name, i, &dcwb_pref);
if (dcwb_pref && !strcmp(dcwb_pref, "dcwb")) {
set_bit(SDE_DISP_DCWB_PREF, &mixer->features);
if (mixer->base == dummy_mixer_base) {
mixer->base = 0x0;
mixer->len = 0;
mixer->dummy_mixer = true;
}
}
mixer->pingpong = pp_count > 0 ? pp_idx + PINGPONG_0
: PINGPONG_MAX;
mixer->dspp = dspp_count > 0 ? dspp_idx + DSPP_0
: DSPP_MAX;
mixer->ds = ds_count > 0 ? ds_idx + DS_0 : DS_MAX;
pp_count--;
dspp_count--;
ds_count--;
pp_idx++;
dspp_idx++;
ds_idx++;
mixer_count++;
sblk->gc.id = SDE_MIXER_GC;
if (blocks_props && blocks_props->exists[MIXER_GC_PROP]) {
sblk->gc.base = PROP_VALUE_ACCESS(blocks_props->values,
MIXER_GC_PROP, 0);
sblk->gc.version = PROP_VALUE_ACCESS(
blocks_props->values, MIXER_GC_PROP,
1);
sblk->gc.len = 0;
set_bit(SDE_MIXER_GC, &mixer->features);
}
}
sde_cfg->mixer_count = mixer_count;
_sde_lm_noise_parse_dt(np, sde_cfg);
end:
sde_put_dt_props(blend_props);
put_blocks:
sde_put_dt_props(blocks_props);
put_props:
sde_put_dt_props(props);
return rc;
}
static int sde_intf_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int rc, prop_count[INTF_PROP_MAX], i;
struct sde_prop_value *prop_value = NULL;
bool prop_exists[INTF_PROP_MAX];
u32 off_count;
u32 dsi_count = 0, none_count = 0, hdmi_count = 0, dp_count = 0;
const char *type;
struct sde_intf_cfg *intf;
if (!sde_cfg) {
SDE_ERROR("invalid argument\n");
rc = -EINVAL;
goto end;
}
prop_value = kzalloc(INTF_PROP_MAX *
sizeof(struct sde_prop_value), GFP_KERNEL);
if (!prop_value) {
rc = -ENOMEM;
goto end;
}
rc = _validate_dt_entry(np, intf_prop, ARRAY_SIZE(intf_prop),
prop_count, &off_count);
if (rc)
goto end;
sde_cfg->intf_count = off_count;
rc = _read_dt_entry(np, intf_prop, ARRAY_SIZE(intf_prop), prop_count,
prop_exists, prop_value);
if (rc)
goto end;
for (i = 0; i < off_count; i++) {
intf = sde_cfg->intf + i;
intf->base = PROP_VALUE_ACCESS(prop_value, INTF_OFF, i);
intf->len = PROP_VALUE_ACCESS(prop_value, INTF_LEN, 0);
intf->id = INTF_0 + i;
snprintf(intf->name, SDE_HW_BLK_NAME_LEN, "intf_%u",
intf->id - INTF_0);
if (!prop_exists[INTF_LEN])
intf->len = DEFAULT_SDE_HW_BLOCK_LEN;
rc = _add_to_irq_offset_list(sde_cfg, SDE_INTR_HWBLK_INTF,
intf->id, intf->base);
if (rc)
goto end;
intf->prog_fetch_lines_worst_case =
!prop_exists[INTF_PREFETCH] ?
sde_cfg->perf.min_prefill_lines :
PROP_VALUE_ACCESS(prop_value, INTF_PREFETCH, i);
of_property_read_string_index(np,
intf_prop[INTF_TYPE].prop_name, i, &type);
if (!strcmp(type, "dsi")) {
intf->type = INTF_DSI;
intf->controller_id = dsi_count;
dsi_count++;
} else if (!strcmp(type, "hdmi")) {
intf->type = INTF_HDMI;
intf->controller_id = hdmi_count;
hdmi_count++;
} else if (!strcmp(type, "dp")) {
intf->type = INTF_DP;
intf->controller_id = dp_count;
dp_count++;
} else {
intf->type = INTF_NONE;
intf->controller_id = none_count;
none_count++;
}
if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev))
set_bit(SDE_INTF_INPUT_CTRL, &intf->features);
if (prop_exists[INTF_TE_IRQ])
intf->te_irq_offset = PROP_VALUE_ACCESS(prop_value,
INTF_TE_IRQ, i);
if (intf->te_irq_offset) {
rc = _add_to_irq_offset_list(sde_cfg,
SDE_INTR_HWBLK_INTF_TEAR,
intf->id, intf->te_irq_offset);
if (rc)
goto end;
set_bit(SDE_INTF_TE, &intf->features);
}
if (SDE_HW_MAJOR(sde_cfg->hw_rev) >= SDE_HW_MAJOR(SDE_HW_VER_500))
set_bit(SDE_INTF_STATUS, &intf->features);
if (SDE_HW_MAJOR(sde_cfg->hw_rev) >= SDE_HW_MAJOR(SDE_HW_VER_700))
set_bit(SDE_INTF_TE_ALIGN_VSYNC, &intf->features);
if (SDE_HW_MAJOR(sde_cfg->hw_rev) >= SDE_HW_MAJOR(SDE_HW_VER_810)) {
set_bit(SDE_INTF_WD_TIMER, &intf->features);
set_bit(SDE_INTF_RESET_COUNTER, &intf->features);
set_bit(SDE_INTF_PANEL_VSYNC_TS, &intf->features);
set_bit(SDE_INTF_AVR_STATUS, &intf->features);
}
if (SDE_HW_MAJOR(sde_cfg->hw_rev) >= SDE_HW_MAJOR(SDE_HW_VER_900)) {
set_bit(SDE_INTF_MDP_VSYNC_TS, &intf->features);
set_bit(SDE_INTF_WD_JITTER, &intf->features);
}
if (SDE_HW_MAJOR(sde_cfg->hw_rev) >= SDE_HW_MAJOR(SDE_HW_VER_A00)) {
set_bit(SDE_INTF_MDP_VSYNC_FC, &intf->features);
set_bit(SDE_INTF_TE_32BIT, &intf->features);
set_bit(SDE_INTF_TE_SINGLE_UPDATE, &intf->features);
}
}
end:
kfree(prop_value);
return rc;
}
static int sde_wb_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg)
{
int rc, prop_count[WB_PROP_MAX], i, j;
struct sde_prop_value *prop_value = NULL;
bool prop_exists[WB_PROP_MAX];
u32 off_count, major_version;
struct sde_wb_cfg *wb;
struct sde_wb_sub_blocks *sblk;
if (!sde_cfg) {
SDE_ERROR("invalid argument\n");
rc = -EINVAL;
goto end;
}
prop_value = kzalloc(WB_PROP_MAX *
sizeof(struct sde_prop_value), GFP_KERNEL);
if (!prop_value) {
rc = -ENOMEM;
goto end;
}
rc = _validate_dt_entry(np, wb_prop, ARRAY_SIZE(wb_prop), prop_count,
&off_count);
if (rc)
goto end;
sde_cfg->wb_count = off_count;
rc = _read_dt_entry(np, wb_prop, ARRAY_SIZE(wb_prop), prop_count,
prop_exists, prop_value);
if (rc)
goto end;
major_version = SDE_HW_MAJOR(sde_cfg->hw_rev);
for (i = 0; i < off_count; i++) {
wb = sde_cfg->wb + i;
sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
if (!sblk) {
rc = -ENOMEM;
/* catalog deinit will release the allocated blocks */
goto end;
}
wb->sblk = sblk;
wb->base = PROP_VALUE_ACCESS(prop_value, WB_OFF, i);
wb->id = WB_0 + PROP_VALUE_ACCESS(prop_value, WB_ID, i);
snprintf(wb->name, SDE_HW_BLK_NAME_LEN, "wb_%u",
wb->id - WB_0);
wb->clk_ctrl = SDE_CLK_CTRL_WB0 +
PROP_VALUE_ACCESS(prop_value, WB_ID, i);
wb->xin_id = PROP_VALUE_ACCESS(prop_value, WB_XIN_ID, i);
if (wb->clk_ctrl >= SDE_CLK_CTRL_MAX) {
SDE_ERROR("%s: invalid clk ctrl: %d\n",
wb->name, wb->clk_ctrl);
rc = -EINVAL;
goto end;
}
if (IS_SDE_MAJOR_MINOR_SAME((sde_cfg->hw_rev), SDE_HW_VER_170))
wb->vbif_idx = VBIF_NRT;
else
wb->vbif_idx = VBIF_RT;
wb->len = PROP_VALUE_ACCESS(prop_value, WB_LEN, 0);
if (!prop_exists[WB_LEN])
wb->len = DEFAULT_SDE_HW_BLOCK_LEN;
sblk->maxlinewidth = sde_cfg->max_wb_linewidth;
sblk->maxlinewidth_linear = sde_cfg->max_wb_linewidth_linear;
if (wb->id >= LINE_MODE_WB_OFFSET)
set_bit(SDE_WB_LINE_MODE, &wb->features);
else
set_bit(SDE_WB_BLOCK_MODE, &wb->features);
if (test_bit(SDE_FEATURE_CDP, sde_cfg->features))
set_bit(SDE_WB_CDP, &wb->features);
if (sde_cfg->vbif_qos_nlvl == 8)
set_bit(SDE_WB_QOS_8LVL, &wb->features);
if (test_bit(SDE_FEATURE_WB_UBWC, sde_cfg->features))
set_bit(SDE_WB_UBWC, &wb->features);
if (test_bit(SDE_FEATURE_CWB_CROP, sde_cfg->features))
set_bit(SDE_WB_CROP, &wb->features);
if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev))
set_bit(SDE_WB_INPUT_CTRL, &wb->features);
if (SDE_HW_MAJOR(sde_cfg->hw_rev) >= SDE_HW_MAJOR(SDE_HW_VER_900)) {
set_bit(SDE_WB_PROG_LINE, &wb->features);
set_bit(SDE_WB_SYS_CACHE, &wb->features);
}
rc = _add_to_irq_offset_list(sde_cfg, SDE_INTR_HWBLK_WB, wb->id, wb->base);
if (test_bit(SDE_FEATURE_DEDICATED_CWB, sde_cfg->features)) {
set_bit(SDE_WB_HAS_DCWB, &wb->features);
if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev))
set_bit(SDE_WB_DCWB_CTRL, &wb->features);
if (major_version >= SDE_HW_MAJOR(SDE_HW_VER_900)) {
sde_cfg->cwb_blk_off = 0x67200;
sde_cfg->cwb_blk_stride = 0x400;
} else if (major_version >= SDE_HW_MAJOR(SDE_HW_VER_810)) {
sde_cfg->cwb_blk_off = 0x66A00;
sde_cfg->cwb_blk_stride = 0x400;
} else {
sde_cfg->cwb_blk_off = 0x83000;
sde_cfg->cwb_blk_stride = 0x100;
}
if (test_bit(SDE_FEATURE_CWB_DITHER, sde_cfg->features))
set_bit(SDE_WB_CWB_DITHER_CTRL, &wb->features);
} else if (test_bit(SDE_FEATURE_CWB, sde_cfg->features)) {
set_bit(SDE_WB_HAS_CWB, &wb->features);
if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev))
set_bit(SDE_WB_CWB_CTRL, &wb->features);
if (major_version >= SDE_HW_MAJOR(SDE_HW_VER_700)) {
sde_cfg->cwb_blk_off = 0x6A200;
sde_cfg->cwb_blk_stride = 0x1000;
} else {
sde_cfg->cwb_blk_off = 0x83000;
sde_cfg->cwb_blk_stride = 0x100;
}
}
if (!test_bit(SDE_FEATURE_VBIF_CLK_SPLIT, sde_cfg->features)) {
for (j = 0; j < sde_cfg->mdp_count; j++) {
sde_cfg->mdp[j].clk_ctrls[wb->clk_ctrl].reg_off =
PROP_BITVALUE_ACCESS(prop_value,
WB_CLK_CTRL, i, 0);
sde_cfg->mdp[j].clk_ctrls[wb->clk_ctrl].bit_off =
PROP_BITVALUE_ACCESS(prop_value,
WB_CLK_CTRL, i, 1);
sde_cfg->mdp[j].clk_status[wb->clk_ctrl].reg_off =
PROP_BITVALUE_ACCESS(prop_value,
WB_CLK_STATUS, i, 0);
sde_cfg->mdp[j].clk_status[wb->clk_ctrl].bit_off =
PROP_BITVALUE_ACCESS(prop_value,
WB_CLK_STATUS, i, 1);
}
SDE_DEBUG("wb:%d xin:%d vbif:%d clk%d:%x/%d\n", wb->id - WB_0,
wb->xin_id, wb->vbif_idx, wb->clk_ctrl,
sde_cfg->mdp[0].clk_ctrls[wb->clk_ctrl].reg_off,
sde_cfg->mdp[0].clk_ctrls[wb->clk_ctrl].bit_off);
}
wb->format_list = sde_cfg->wb_formats;
}
end:
kfree(prop_value);
return rc;
}
static int sde_dspp_top_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int rc, prop_count[DSPP_TOP_PROP_MAX];
bool prop_exists[DSPP_TOP_PROP_MAX];
struct sde_prop_value *prop_value = NULL;
u32 off_count;
if (!sde_cfg) {
SDE_ERROR("invalid argument\n");
rc = -EINVAL;
goto end;
}
prop_value = kzalloc(DSPP_TOP_PROP_MAX *
sizeof(struct sde_prop_value), GFP_KERNEL);
if (!prop_value) {
rc = -ENOMEM;
goto end;
}
rc = _validate_dt_entry(np, dspp_top_prop, ARRAY_SIZE(dspp_top_prop),
prop_count, &off_count);
if (rc)
goto end;
rc = _read_dt_entry(np, dspp_top_prop, ARRAY_SIZE(dspp_top_prop),
prop_count, prop_exists, prop_value);
if (rc)
goto end;
if (off_count != 1) {
SDE_ERROR("invalid dspp_top off_count:%d\n", off_count);
rc = -EINVAL;
goto end;
}
sde_cfg->dspp_top.base =
PROP_VALUE_ACCESS(prop_value, DSPP_TOP_OFF, 0);
sde_cfg->dspp_top.len =
PROP_VALUE_ACCESS(prop_value, DSPP_TOP_SIZE, 0);
snprintf(sde_cfg->dspp_top.name, SDE_HW_BLK_NAME_LEN, "dspp_top");
end:
kfree(prop_value);
return rc;
}
static int _sde_ad_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int rc = 0;
int off_count, i;
struct sde_dt_props *props;
props = sde_get_dt_props(np, AD_PROP_MAX, ad_prop,
ARRAY_SIZE(ad_prop), &off_count);
if (IS_ERR(props))
return PTR_ERR(props);
sde_cfg->ad_count = off_count;
if (off_count > sde_cfg->dspp_count) {
SDE_ERROR("limiting %d AD blocks to %d DSPP instances\n",
off_count, sde_cfg->dspp_count);
sde_cfg->ad_count = sde_cfg->dspp_count;
}
for (i = 0; i < sde_cfg->dspp_count; i++) {
struct sde_dspp_cfg *dspp = &sde_cfg->dspp[i];
struct sde_dspp_sub_blks *sblk = sde_cfg->dspp[i].sblk;
sblk->ad.id = SDE_DSPP_AD;
if (!props->exists[AD_OFF])
continue;
if (i < off_count) {
sblk->ad.base = PROP_VALUE_ACCESS(props->values,
AD_OFF, i);
sblk->ad.version = PROP_VALUE_ACCESS(props->values,
AD_VERSION, 0);
set_bit(SDE_DSPP_AD, &dspp->features);
rc = _add_to_irq_offset_list(sde_cfg,
SDE_INTR_HWBLK_AD4, dspp->id,
dspp->base + sblk->ad.base);
if (rc)
goto end;
}
}
end:
sde_put_dt_props(props);
return rc;
}
static int _sde_ltm_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int rc = 0;
int off_count, i;
struct sde_dt_props *props;
props = sde_get_dt_props(np, LTM_PROP_MAX, ltm_prop,
ARRAY_SIZE(ltm_prop), &off_count);
if (IS_ERR(props))
return PTR_ERR(props);
sde_cfg->ltm_count = off_count;
if (off_count > sde_cfg->dspp_count) {
SDE_ERROR("limiting %d LTM blocks to %d DSPP instances\n",
off_count, sde_cfg->dspp_count);
sde_cfg->ltm_count = sde_cfg->dspp_count;
}
for (i = 0; i < sde_cfg->dspp_count; i++) {
struct sde_dspp_cfg *dspp = &sde_cfg->dspp[i];
struct sde_dspp_sub_blks *sblk = sde_cfg->dspp[i].sblk;
sblk->ltm.id = SDE_DSPP_LTM;
if (!props->exists[LTM_OFF])
continue;
if (i < off_count) {
sblk->ltm.base = PROP_VALUE_ACCESS(props->values,
LTM_OFF, i);
sblk->ltm.version = PROP_VALUE_ACCESS(props->values,
LTM_VERSION, 0);
set_bit(SDE_DSPP_LTM, &dspp->features);
rc = _add_to_irq_offset_list(sde_cfg,
SDE_INTR_HWBLK_LTM, dspp->id,
dspp->base + sblk->ltm.base);
if (rc)
goto end;
}
}
end:
sde_put_dt_props(props);
return rc;
}
static int _sde_dspp_demura_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int off_count, i;
struct sde_dt_props *props;
struct sde_dspp_cfg *dspp;
struct sde_dspp_sub_blks *sblk;
props = sde_get_dt_props(np, DEMURA_PROP_MAX, demura_prop,
ARRAY_SIZE(demura_prop), &off_count);
if (IS_ERR(props))
return PTR_ERR(props);
sde_cfg->demura_count = off_count;
if (off_count > sde_cfg->dspp_count) {
SDE_ERROR("limiting %d demura blocks to %d DSPP instances\n",
off_count, sde_cfg->dspp_count);
sde_cfg->demura_count = sde_cfg->dspp_count;
}
for (i = 0; i < sde_cfg->dspp_count; i++) {
dspp = &sde_cfg->dspp[i];
sblk = sde_cfg->dspp[i].sblk;
sblk->demura.id = SDE_DSPP_DEMURA;
if (props->exists[DEMURA_OFF] && i < off_count) {
sblk->demura.base = PROP_VALUE_ACCESS(props->values,
DEMURA_OFF, i);
sblk->demura.len = PROP_VALUE_ACCESS(props->values,
DEMURA_LEN, 0);
sblk->demura.version = PROP_VALUE_ACCESS(props->values,
DEMURA_VERSION, 0);
set_bit(SDE_DSPP_DEMURA, &dspp->features);
}
}
sde_put_dt_props(props);
return 0;
}
static int _sde_dspp_spr_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int off_count, i;
struct sde_dt_props *props;
struct sde_dspp_cfg *dspp;
struct sde_dspp_sub_blks *sblk;
props = sde_get_dt_props(np, SPR_PROP_MAX, spr_prop,
ARRAY_SIZE(spr_prop), &off_count);
if (IS_ERR(props))
return PTR_ERR(props);
sde_cfg->spr_count = off_count;
if (off_count > sde_cfg->dspp_count) {
SDE_ERROR("limiting %d spr blocks to %d DSPP instances\n",
off_count, sde_cfg->dspp_count);
sde_cfg->spr_count = sde_cfg->dspp_count;
}
for (i = 0; i < sde_cfg->dspp_count; i++) {
dspp = &sde_cfg->dspp[i];
sblk = sde_cfg->dspp[i].sblk;
sblk->spr.id = SDE_DSPP_SPR;
if (props->exists[SPR_OFF] && i < off_count) {
sblk->spr.base = PROP_VALUE_ACCESS(props->values,
SPR_OFF, i);
sblk->spr.len = PROP_VALUE_ACCESS(props->values,
SPR_LEN, 0);
sblk->spr.version = PROP_VALUE_ACCESS(props->values,
SPR_VERSION, 0);
set_bit(SDE_DSPP_SPR, &dspp->features);
}
}
sde_put_dt_props(props);
return 0;
}
static int _sde_rc_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int off_count, i;
struct sde_dt_props *props;
props = sde_get_dt_props(np, RC_PROP_MAX, rc_prop,
ARRAY_SIZE(rc_prop), &off_count);
if (IS_ERR(props))
return PTR_ERR(props);
sde_cfg->rc_count = off_count;
if (off_count > sde_cfg->dspp_count) {
SDE_ERROR("limiting %d RC blocks to %d DSPP instances\n",
off_count, sde_cfg->dspp_count);
sde_cfg->rc_count = sde_cfg->dspp_count;
}
for (i = 0; i < sde_cfg->dspp_count; i++) {
struct sde_dspp_cfg *dspp = &sde_cfg->dspp[i];
struct sde_dspp_sub_blks *sblk = sde_cfg->dspp[i].sblk;
sblk->rc.id = SDE_DSPP_RC;
if (!props->exists[RC_OFF])
continue;
if (i < off_count) {
sblk->rc.base = PROP_VALUE_ACCESS(props->values,
RC_OFF, i);
sblk->rc.len = PROP_VALUE_ACCESS(props->values,
RC_LEN, 0);
sblk->rc.version = PROP_VALUE_ACCESS(props->values,
RC_VERSION, 0);
sblk->rc.mem_total_size = PROP_VALUE_ACCESS(
props->values, RC_MEM_TOTAL_SIZE, 0);
if (!props->exists[RC_MIN_REGION_WIDTH])
sblk->rc.min_region_width = 4;
else
sblk->rc.min_region_width = PROP_VALUE_ACCESS(
props->values, RC_MIN_REGION_WIDTH, 0);
sblk->rc.idx = i;
set_bit(SDE_DSPP_RC, &dspp->features);
}
}
sde_put_dt_props(props);
return 0;
}
static int _sde_lm_noise_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int off_count, i;
struct sde_dt_props *props;
props = sde_get_dt_props(np, NOISEL_LAYER_PROP_MAX, noise_layer_prop,
ARRAY_SIZE(noise_layer_prop), &off_count);
if (IS_ERR(props)) {
SDE_ERROR("noise: failed to get dt props\n");
return PTR_ERR(props);
}
if (!props->exists[NOISE_LAYER_OFF] ||
!props->exists[NOISE_LAYER_VERSION]) {
SDE_INFO("noise: prop doesnt exist %d %d\n",
props->exists[NOISE_LAYER_OFF],
props->exists[NOISE_LAYER_VERSION]);
goto exit;
}
for (i = 0; i < sde_cfg->mixer_count; i++) {
struct sde_lm_cfg *lm = &sde_cfg->mixer[i];
struct sde_lm_sub_blks *sblk = lm->sblk;
sblk->nlayer.base = PROP_VALUE_ACCESS(props->values,
NOISE_LAYER_OFF, 0);
sblk->nlayer.version = PROP_VALUE_ACCESS(props->values,
NOISE_LAYER_VERSION, 0);
sblk->nlayer.len = sizeof(u32);
set_bit(SDE_MIXER_NOISE_LAYER, &lm->features);
}
exit:
sde_put_dt_props(props);
return 0;
}
static void _sde_init_dspp_sblk(struct sde_dspp_cfg *dspp,
struct sde_pp_blk *pp_blk, int prop_id, int blk_id,
struct sde_dt_props *props)
{
pp_blk->id = prop_id;
if (props->exists[blk_id]) {
pp_blk->base = PROP_VALUE_ACCESS(props->values,
blk_id, 0);
pp_blk->version = PROP_VALUE_ACCESS(props->values,
blk_id, 1);
pp_blk->len = 0;
set_bit(prop_id, &dspp->features);
}
}
static int _sde_dspp_sblks_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int i;
struct device_node *snp = NULL;
struct sde_dt_props *props;
snp = of_get_child_by_name(np, dspp_prop[DSPP_BLOCKS].prop_name);
if (!snp)
return 0;
props = sde_get_dt_props(snp, DSPP_BLOCKS_PROP_MAX,
dspp_blocks_prop, ARRAY_SIZE(dspp_blocks_prop),
NULL);
if (IS_ERR(props))
return PTR_ERR(props);
for (i = 0; i < sde_cfg->dspp_count; i++) {
struct sde_dspp_cfg *dspp = &sde_cfg->dspp[i];
struct sde_dspp_sub_blks *sblk = sde_cfg->dspp[i].sblk;
_sde_init_dspp_sblk(dspp, &sblk->igc, SDE_DSPP_IGC,
DSPP_IGC_PROP, props);
_sde_init_dspp_sblk(dspp, &sblk->pcc, SDE_DSPP_PCC,
DSPP_PCC_PROP, props);
_sde_init_dspp_sblk(dspp, &sblk->gc, SDE_DSPP_GC,
DSPP_GC_PROP, props);
_sde_init_dspp_sblk(dspp, &sblk->gamut, SDE_DSPP_GAMUT,
DSPP_GAMUT_PROP, props);
_sde_init_dspp_sblk(dspp, &sblk->dither, SDE_DSPP_DITHER,
DSPP_DITHER_PROP, props);
_sde_init_dspp_sblk(dspp, &sblk->hist, SDE_DSPP_HIST,
DSPP_HIST_PROP, props);
_sde_init_dspp_sblk(dspp, &sblk->hsic, SDE_DSPP_HSIC,
DSPP_HSIC_PROP, props);
_sde_init_dspp_sblk(dspp, &sblk->memcolor, SDE_DSPP_MEMCOLOR,
DSPP_MEMCOLOR_PROP, props);
_sde_init_dspp_sblk(dspp, &sblk->sixzone, SDE_DSPP_SIXZONE,
DSPP_SIXZONE_PROP, props);
_sde_init_dspp_sblk(dspp, &sblk->vlut, SDE_DSPP_VLUT,
DSPP_VLUT_PROP, props);
}
sde_put_dt_props(props);
return 0;
}
static int _sde_dspp_cmn_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int rc = 0;
int i, off_count;
struct sde_dt_props *props;
struct sde_dspp_sub_blks *sblk;
props = sde_get_dt_props(np, DSPP_PROP_MAX, dspp_prop,
ARRAY_SIZE(dspp_prop), &off_count);
if (IS_ERR(props))
return PTR_ERR(props);
if (off_count > MAX_BLOCKS) {
SDE_ERROR("off_count %d exceeds MAX_BLOCKS, limiting to %d\n",
off_count, MAX_BLOCKS);
off_count = MAX_BLOCKS;
}
sde_cfg->dspp_count = off_count;
for (i = 0; i < sde_cfg->dspp_count; i++) {
sde_cfg->dspp[i].base = PROP_VALUE_ACCESS(props->values,
DSPP_OFF, i);
sde_cfg->dspp[i].len = PROP_VALUE_ACCESS(props->values,
DSPP_SIZE, 0);
sde_cfg->dspp[i].id = DSPP_0 + i;
snprintf(sde_cfg->dspp[i].name, SDE_HW_BLK_NAME_LEN, "dspp_%d",
i);
/* create an empty sblk for each dspp */
sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
if (!sblk) {
rc = -ENOMEM;
/* catalog deinit will release the allocated blocks */
goto end;
}
sde_cfg->dspp[i].sblk = sblk;
}
end:
sde_put_dt_props(props);
return rc;
}
static int sde_dspp_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int rc;
rc = _sde_dspp_cmn_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = _sde_dspp_sblks_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = _sde_ad_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = _sde_ltm_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = _sde_dspp_spr_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = _sde_dspp_demura_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = _sde_rc_parse_dt(np, sde_cfg);
end:
return rc;
}
static int sde_ds_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int rc, prop_count[DS_PROP_MAX], top_prop_count[DS_TOP_PROP_MAX], i;
struct sde_prop_value *prop_value = NULL, *top_prop_value = NULL;
bool prop_exists[DS_PROP_MAX], top_prop_exists[DS_TOP_PROP_MAX];
u32 off_count = 0, top_off_count = 0;
struct sde_ds_cfg *ds;
struct sde_ds_top_cfg *ds_top = NULL;
if (!sde_cfg) {
SDE_ERROR("invalid argument\n");
rc = -EINVAL;
goto end;
}
if (!sde_cfg->mdp[0].has_dest_scaler) {
SDE_DEBUG("dest scaler feature not supported\n");
rc = 0;
goto end;
}
/* Parse the dest scaler top register offset and capabilities */
top_prop_value = kzalloc(DS_TOP_PROP_MAX *
sizeof(struct sde_prop_value), GFP_KERNEL);
if (!top_prop_value) {
rc = -ENOMEM;
goto end;
}
rc = _validate_dt_entry(np, ds_top_prop,
ARRAY_SIZE(ds_top_prop),
top_prop_count, &top_off_count);
if (rc)
goto end;
rc = _read_dt_entry(np, ds_top_prop,
ARRAY_SIZE(ds_top_prop), top_prop_count,
top_prop_exists, top_prop_value);
if (rc)
goto end;
/* Parse the offset of each dest scaler block */
prop_value = kcalloc(DS_PROP_MAX,
sizeof(struct sde_prop_value), GFP_KERNEL);
if (!prop_value) {
rc = -ENOMEM;
goto end;
}
rc = _validate_dt_entry(np, ds_prop, ARRAY_SIZE(ds_prop), prop_count,
&off_count);
if (rc)
goto end;
sde_cfg->ds_count = off_count;
rc = _read_dt_entry(np, ds_prop, ARRAY_SIZE(ds_prop), prop_count,
prop_exists, prop_value);
if (rc)
goto end;
if (!off_count)
goto end;
ds_top = kzalloc(sizeof(struct sde_ds_top_cfg), GFP_KERNEL);
if (!ds_top) {
rc = -ENOMEM;
goto end;
}
ds_top->id = DS_TOP;
snprintf(ds_top->name, SDE_HW_BLK_NAME_LEN, "ds_top_%u",
ds_top->id - DS_TOP);
ds_top->base = PROP_VALUE_ACCESS(top_prop_value, DS_TOP_OFF, 0);
ds_top->len = PROP_VALUE_ACCESS(top_prop_value, DS_TOP_LEN, 0);
ds_top->maxupscale = MAX_UPSCALE_RATIO;
ds_top->maxinputwidth = PROP_VALUE_ACCESS(top_prop_value,
DS_TOP_INPUT_LINEWIDTH, 0);
if (!top_prop_exists[DS_TOP_INPUT_LINEWIDTH])
ds_top->maxinputwidth = DEFAULT_SDE_LINE_WIDTH;
ds_top->maxoutputwidth = PROP_VALUE_ACCESS(top_prop_value,
DS_TOP_OUTPUT_LINEWIDTH, 0);
if (!top_prop_exists[DS_TOP_OUTPUT_LINEWIDTH])
ds_top->maxoutputwidth = DEFAULT_SDE_OUTPUT_LINE_WIDTH;
for (i = 0; i < off_count; i++) {
ds = sde_cfg->ds + i;
ds->top = ds_top;
ds->base = PROP_VALUE_ACCESS(prop_value, DS_OFF, i);
ds->id = DS_0 + i;
ds->len = PROP_VALUE_ACCESS(prop_value, DS_LEN, 0);
snprintf(ds->name, SDE_HW_BLK_NAME_LEN, "ds_%u",
ds->id - DS_0);
if (!prop_exists[DS_LEN])
ds->len = DEFAULT_SDE_HW_BLOCK_LEN;
if (sde_cfg->qseed_sw_lib_rev == SDE_SSPP_SCALER_QSEED3)
set_bit(SDE_SSPP_SCALER_QSEED3, &ds->features);
else if (sde_cfg->qseed_sw_lib_rev ==
SDE_SSPP_SCALER_QSEED3LITE)
set_bit(SDE_SSPP_SCALER_QSEED3LITE, &ds->features);
if (SDE_HW_MAJOR(sde_cfg->hw_rev) >= SDE_HW_MAJOR(SDE_HW_VER_900)) {
set_bit(SDE_DS_DE_LPF_BLEND, &ds->features);
set_bit(SDE_DS_MERGE_CTRL, &ds->features);
}
}
end:
kfree(top_prop_value);
kfree(prop_value);
return rc;
};
static int sde_dsc_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int rc, prop_count[MAX_BLOCKS], i;
struct sde_prop_value *prop_value;
bool prop_exists[DSC_PROP_MAX];
u32 off_count, dsc_pair_mask, dsc_rev;
const char *rev;
struct sde_dsc_cfg *dsc;
struct sde_dsc_sub_blks *sblk;
if (!sde_cfg) {
SDE_ERROR("invalid argument\n");
return -EINVAL;
}
prop_value = kzalloc(DSC_PROP_MAX *
sizeof(struct sde_prop_value), GFP_KERNEL);
if (!prop_value)
return -ENOMEM;
rc = _validate_dt_entry(np, dsc_prop, ARRAY_SIZE(dsc_prop), prop_count,
&off_count);
if (rc)
goto end;
sde_cfg->dsc_count = off_count;
rc = of_property_read_string(np, dsc_prop[DSC_REV].prop_name, &rev);
if (!rc && !strcmp(rev, "dsc_1_2"))
dsc_rev = SDE_DSC_HW_REV_1_2;
else if (!rc && !strcmp(rev, "dsc_1_1"))
dsc_rev = SDE_DSC_HW_REV_1_1;
else
/* default configuration */
dsc_rev = SDE_DSC_HW_REV_1_1;
rc = _read_dt_entry(np, dsc_prop, ARRAY_SIZE(dsc_prop), prop_count,
prop_exists, prop_value);
if (rc)
goto end;
sde_cfg->max_dsc_width = prop_exists[DSC_LINEWIDTH] ?
PROP_VALUE_ACCESS(prop_value, DSC_LINEWIDTH, 0) :
DEFAULT_SDE_LINE_WIDTH;
for (i = 0; i < off_count; i++) {
dsc = sde_cfg->dsc + i;
sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
if (!sblk) {
rc = -ENOMEM;
/* catalog deinit will release the allocated blocks */
goto end;
}
dsc->sblk = sblk;
dsc->base = PROP_VALUE_ACCESS(prop_value, DSC_OFF, i);
dsc->id = DSC_0 + i;
dsc->len = PROP_VALUE_ACCESS(prop_value, DSC_LEN, 0);
snprintf(dsc->name, SDE_HW_BLK_NAME_LEN, "dsc_%u",
dsc->id - DSC_0);
if (!prop_exists[DSC_LEN])
dsc->len = DEFAULT_SDE_HW_BLOCK_LEN;
if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev))
set_bit(SDE_DSC_OUTPUT_CTRL, &dsc->features);
dsc_pair_mask = PROP_VALUE_ACCESS(prop_value,
DSC_PAIR_MASK, i);
if (dsc_pair_mask)
set_bit(dsc_pair_mask, dsc->dsc_pair_mask);
if (dsc_rev == SDE_DSC_HW_REV_1_2) {
sblk->enc.base = PROP_VALUE_ACCESS(prop_value,
DSC_ENC, i);
sblk->enc.len = PROP_VALUE_ACCESS(prop_value,
DSC_ENC_LEN, 0);
sblk->ctl.base = PROP_VALUE_ACCESS(prop_value,
DSC_CTL, i);
sblk->ctl.len = PROP_VALUE_ACCESS(prop_value,
DSC_CTL_LEN, 0);
set_bit(SDE_DSC_HW_REV_1_2, &dsc->features);
if (PROP_VALUE_ACCESS(prop_value, DSC_422, i))
set_bit(SDE_DSC_NATIVE_422_EN,
&dsc->features);
if (SDE_HW_MAJOR(sde_cfg->hw_rev) >= SDE_HW_MAJOR(SDE_HW_VER_900))
set_bit(SDE_DSC_4HS, &dsc->features);
if (sde_cfg->has_reduced_ob_max)
set_bit(SDE_DSC_REDUCED_OB_MAX, &dsc->features);
} else {
set_bit(SDE_DSC_HW_REV_1_1, &dsc->features);
}
}
end:
kfree(prop_value);
return rc;
};
static int sde_vdc_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int rc, prop_count[MAX_BLOCKS], i;
struct sde_prop_value *prop_value = NULL;
bool prop_exists[VDC_PROP_MAX];
u32 off_count, vdc_rev;
const char *rev;
struct sde_vdc_cfg *vdc;
struct sde_vdc_sub_blks *sblk;
if (!sde_cfg) {
SDE_ERROR("invalid argument\n");
rc = -EINVAL;
goto end;
}
prop_value = kzalloc(VDC_PROP_MAX *
sizeof(struct sde_prop_value), GFP_KERNEL);
if (!prop_value) {
rc = -ENOMEM;
goto end;
}
rc = _validate_dt_entry(np, vdc_prop, ARRAY_SIZE(vdc_prop), prop_count,
&off_count);
if (rc)
goto end;
sde_cfg->vdc_count = off_count;
rc = of_property_read_string(np, vdc_prop[VDC_REV].prop_name, &rev);
if ((rc == -EINVAL) || (rc == -ENODATA)) {
vdc_rev = SDE_VDC_HW_REV_1_2;
rc = 0;
} else if (!rc && !strcmp(rev, "vdc_1_2")) {
vdc_rev = SDE_VDC_HW_REV_1_2;
rc = 0;
} else {
SDE_ERROR("invalid vdc configuration\n");
goto end;
}
rc = _read_dt_entry(np, vdc_prop, ARRAY_SIZE(vdc_prop), prop_count,
prop_exists, prop_value);
if (rc)
goto end;
for (i = 0; i < off_count; i++) {
vdc = sde_cfg->vdc + i;
sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
if (!sblk) {
rc = -ENOMEM;
/* catalog deinit will release the allocated blocks */
goto end;
}
vdc->sblk = sblk;
vdc->base = PROP_VALUE_ACCESS(prop_value, VDC_OFF, i);
vdc->id = VDC_0 + i;
vdc->len = PROP_VALUE_ACCESS(prop_value, VDC_LEN, 0);
snprintf(vdc->name, SDE_HW_BLK_NAME_LEN, "vdc_%u",
vdc->id - VDC_0);
if (!prop_exists[VDC_LEN])
vdc->len = DEFAULT_SDE_HW_BLOCK_LEN;
sblk->enc.base = PROP_VALUE_ACCESS(prop_value,
VDC_ENC, i);
sblk->enc.len = PROP_VALUE_ACCESS(prop_value,
VDC_ENC_LEN, 0);
sblk->ctl.base = PROP_VALUE_ACCESS(prop_value,
VDC_CTL, i);
sblk->ctl.len = PROP_VALUE_ACCESS(prop_value,
VDC_CTL_LEN, 0);
set_bit(vdc_rev, &vdc->features);
}
end:
kfree(prop_value);
return rc;
};
static int sde_cdm_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int rc, prop_count[HW_PROP_MAX], i, j;
struct sde_prop_value *prop_value = NULL;
bool prop_exists[HW_PROP_MAX];
u32 off_count;
struct sde_cdm_cfg *cdm;
if (!sde_cfg) {
SDE_ERROR("invalid argument\n");
rc = -EINVAL;
goto end;
}
prop_value = kzalloc(HW_PROP_MAX * sizeof(struct sde_prop_value), GFP_KERNEL);
if (!prop_value) {
rc = -ENOMEM;
goto end;
}
rc = _validate_dt_entry(np, cdm_prop, ARRAY_SIZE(cdm_prop), prop_count, &off_count);
if (rc)
goto end;
sde_cfg->cdm_count = off_count;
rc = _read_dt_entry(np, cdm_prop, ARRAY_SIZE(cdm_prop), prop_count,
prop_exists, prop_value);
if (rc)
goto end;
for (i = 0; i < off_count; i++) {
cdm = sde_cfg->cdm + i;
cdm->base = PROP_VALUE_ACCESS(prop_value, HW_OFF, i);
cdm->id = CDM_0 + i;
snprintf(cdm->name, SDE_HW_BLK_NAME_LEN, "cdm_%u", cdm->id - CDM_0);
cdm->len = PROP_VALUE_ACCESS(prop_value, HW_LEN, 0);
/* intf3 and wb(s) for cdm block */
for (j = 0; j < sde_cfg->wb_count; j++)
cdm->wb_connect |= BIT(sde_cfg->wb[j].id);
cdm->intf_connect = sde_cfg->intf_count ? BIT(INTF_3) : 0;
if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev))
set_bit(SDE_CDM_INPUT_CTRL, &cdm->features);
}
end:
kfree(prop_value);
return rc;
}
static int sde_dnsc_blur_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg)
{
int rc, prop_count[DNSC_BLUR_PROP_MAX], i, j;
struct sde_prop_value *prop_value = NULL;
bool prop_exists[DNSC_BLUR_PROP_MAX];
u32 off_count;
struct sde_dnsc_blur_cfg *dnsc_blur;
struct sde_dnsc_blur_sub_blks *sblk;
if (!sde_cfg) {
SDE_ERROR("invalid argument\n");
rc = -EINVAL;
goto end;
}
prop_value = kzalloc(DNSC_BLUR_PROP_MAX * sizeof(struct sde_prop_value), GFP_KERNEL);
if (!prop_value) {
rc = -ENOMEM;
goto end;
}
rc = _validate_dt_entry(np, dnsc_blur_prop, ARRAY_SIZE(dnsc_blur_prop),
prop_count, &off_count);
if (rc)
goto end;
if (off_count > DNSC_BLUR_MAX_COUNT) {
SDE_ERROR("invalid dnsc_blur block count:%d\n", off_count);
rc = -EINVAL;
goto end;
}
sde_cfg->dnsc_blur_count = off_count;
rc = _read_dt_entry(np, dnsc_blur_prop, ARRAY_SIZE(dnsc_blur_prop), prop_count,
prop_exists, prop_value);
if (rc)
goto end;
for (i = 0; i < sde_cfg->dnsc_blur_count; i++) {
dnsc_blur = sde_cfg->dnsc_blur + i;
sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
if (!sblk) {
rc = -ENOMEM;
/* catalog deinit will release the allocated blocks */
goto end;
}
dnsc_blur->sblk = sblk;
dnsc_blur->base = PROP_VALUE_ACCESS(prop_value, DNSC_BLUR_OFF, i);
dnsc_blur->id = DNSC_BLUR_0 + i;
dnsc_blur->len = PROP_VALUE_ACCESS(prop_value, DNSC_BLUR_LEN, 0);
snprintf(dnsc_blur->name, SDE_HW_BLK_NAME_LEN, "dnsc_blur_%u",
dnsc_blur->id - DNSC_BLUR_0);
sde_cfg->dnsc_blur_rev = PROP_VALUE_ACCESS(prop_value, DNSC_BLUR_VERSION, 0);
sblk->gaus_lut.base = PROP_VALUE_ACCESS(prop_value, DNSC_BLUR_GAUS_LUT_OFF, i);
sblk->gaus_lut.len = PROP_VALUE_ACCESS(prop_value, DNSC_BLUR_GAUS_LUT_LEN, 0);
snprintf(sblk->gaus_lut.name, SDE_HW_BLK_NAME_LEN, "dnsc_blur_lut_%u",
dnsc_blur->id - DNSC_BLUR_0);
sblk->dither.base = PROP_VALUE_ACCESS(prop_value, DNSC_BLUR_DITHER_OFF, i);
sblk->dither.len = PROP_VALUE_ACCESS(prop_value, DNSC_BLUR_DITHER_LEN, 0);
snprintf(sblk->dither.name, SDE_HW_BLK_NAME_LEN, "dnsc_blur_dit_%u",
dnsc_blur->id - DNSC_BLUR_0);
for (j = 0; j < sde_cfg->wb_count; j++)
dnsc_blur->wb_connect |= BIT(sde_cfg->wb[j].id);
}
end:
kfree(prop_value);
return rc;
}
static int sde_uidle_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int rc = 0, prop_count[UIDLE_PROP_MAX];
bool prop_exists[UIDLE_PROP_MAX];
struct sde_prop_value *prop_value = NULL;
u32 off_count;
if (!sde_cfg) {
SDE_ERROR("invalid argument\n");
return -EINVAL;
}
if (!sde_cfg->uidle_cfg.uidle_rev)
return 0;
prop_value = kcalloc(UIDLE_PROP_MAX,
sizeof(struct sde_prop_value), GFP_KERNEL);
if (!prop_value)
return -ENOMEM;
rc = _validate_dt_entry(np, uidle_prop, ARRAY_SIZE(uidle_prop),
prop_count, &off_count);
if (rc)
goto end;
rc = _read_dt_entry(np, uidle_prop, ARRAY_SIZE(uidle_prop), prop_count,
prop_exists, prop_value);
if (rc)
goto end;
if (!prop_exists[UIDLE_LEN] || !prop_exists[UIDLE_OFF]) {
SDE_DEBUG("offset/len missing, will disable uidle:%d,%d\n",
prop_exists[UIDLE_LEN], prop_exists[UIDLE_OFF]);
rc = -EINVAL;
goto end;
}
sde_cfg->uidle_cfg.id = UIDLE;
sde_cfg->uidle_cfg.base =
PROP_VALUE_ACCESS(prop_value, UIDLE_OFF, 0);
sde_cfg->uidle_cfg.len =
PROP_VALUE_ACCESS(prop_value, UIDLE_LEN, 0);
/* validate */
if (!sde_cfg->uidle_cfg.base || !sde_cfg->uidle_cfg.len) {
SDE_ERROR("invalid reg/len [%d, %d], will disable uidle\n",
sde_cfg->uidle_cfg.base, sde_cfg->uidle_cfg.len);
rc = -EINVAL;
}
end:
if (rc && sde_cfg->uidle_cfg.uidle_rev) {
SDE_DEBUG("wrong dt entries, will disable uidle\n");
sde_cfg->uidle_cfg.uidle_rev = 0;
}
kfree(prop_value);
/* optional feature, so always return success */
return 0;
}
static int sde_cache_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
struct llcc_slice_desc *slice;
struct device_node *llcc_node;
int i;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0))
const u32 sde_sys_cache_usecase_id[SDE_SYS_CACHE_MAX] = {
[SDE_SYS_CACHE_DISP] = LLCC_DISP,
[SDE_SYS_CACHE_DISP_1] = LLCC_DISP_1,
[SDE_SYS_CACHE_DISP_WB] = LLCC_DISP_WB,
};
#else
const u32 sde_sys_cache_usecase_id[SDE_SYS_CACHE_MAX] = {
[SDE_SYS_CACHE_DISP] = LLCC_DISP,
[SDE_SYS_CACHE_DISP_1] = 0,
[SDE_SYS_CACHE_DISP_WB] = 0,
};
#endif
if (!sde_cfg) {
SDE_ERROR("invalid argument\n");
return -EINVAL;
}
llcc_node = of_find_node_by_name(NULL, "cache-controller");
if (!llcc_node) {
SDE_DEBUG("cache controller missing, will disable img cache\n");
return 0;
}
for (i = 0; i < SDE_SYS_CACHE_MAX; i++) {
struct sde_sc_cfg *sc_cfg = &sde_cfg->sc_cfg[i];
u32 usecase_id = 0;
if (!test_bit(i, sde_cfg->sde_sys_cache_type_map))
continue;
usecase_id = sde_sys_cache_usecase_id[i];
if (!usecase_id) {
clear_bit(i, sde_cfg->sde_sys_cache_type_map);
SDE_DEBUG("invalid usecase-id for sys cache:%d\n", i);
continue;
}
slice = llcc_slice_getd(usecase_id);
if (IS_ERR_OR_NULL(slice)) {
SDE_ERROR("failed to get system cache %ld\n", PTR_ERR(slice));
return -EINVAL;
}
sc_cfg->llcc_uid = usecase_id;
sc_cfg->llcc_scid = llcc_get_slice_id(slice);
sc_cfg->llcc_slice_size = llcc_get_slice_size(slice);
SDE_DEBUG("img cache:%d usecase_id:%d, scid:%d slice_size:%zu kb\n",
i, usecase_id, sc_cfg->llcc_scid, sc_cfg->llcc_slice_size);
llcc_slice_putd(slice);
}
return 0;
}
static int _sde_vbif_populate_ot_parsing(struct sde_vbif_cfg *vbif,
struct sde_prop_value *prop_value, int *prop_count)
{
int j, k;
vbif->default_ot_rd_limit = PROP_VALUE_ACCESS(prop_value,
VBIF_DEFAULT_OT_RD_LIMIT, 0);
SDE_DEBUG("default_ot_rd_limit=%u\n",
vbif->default_ot_rd_limit);
vbif->default_ot_wr_limit = PROP_VALUE_ACCESS(prop_value,
VBIF_DEFAULT_OT_WR_LIMIT, 0);
SDE_DEBUG("default_ot_wr_limit=%u\n",
vbif->default_ot_wr_limit);
vbif->dynamic_ot_rd_tbl.count =
prop_count[VBIF_DYNAMIC_OT_RD_LIMIT] / 2;
SDE_DEBUG("dynamic_ot_rd_tbl.count=%u\n",
vbif->dynamic_ot_rd_tbl.count);
if (vbif->dynamic_ot_rd_tbl.count) {
vbif->dynamic_ot_rd_tbl.cfg = kcalloc(
vbif->dynamic_ot_rd_tbl.count,
sizeof(struct sde_vbif_dynamic_ot_cfg),
GFP_KERNEL);
if (!vbif->dynamic_ot_rd_tbl.cfg)
return -ENOMEM;
}
for (j = 0, k = 0; j < vbif->dynamic_ot_rd_tbl.count; j++) {
vbif->dynamic_ot_rd_tbl.cfg[j].pps = (u64)
PROP_VALUE_ACCESS(prop_value,
VBIF_DYNAMIC_OT_RD_LIMIT, k++);
vbif->dynamic_ot_rd_tbl.cfg[j].ot_limit =
PROP_VALUE_ACCESS(prop_value,
VBIF_DYNAMIC_OT_RD_LIMIT, k++);
SDE_DEBUG("dynamic_ot_rd_tbl[%d].cfg=<%llu %u>\n", j,
vbif->dynamic_ot_rd_tbl.cfg[j].pps,
vbif->dynamic_ot_rd_tbl.cfg[j].ot_limit);
}
vbif->dynamic_ot_wr_tbl.count =
prop_count[VBIF_DYNAMIC_OT_WR_LIMIT] / 2;
SDE_DEBUG("dynamic_ot_wr_tbl.count=%u\n",
vbif->dynamic_ot_wr_tbl.count);
if (vbif->dynamic_ot_wr_tbl.count) {
vbif->dynamic_ot_wr_tbl.cfg = kcalloc(
vbif->dynamic_ot_wr_tbl.count,
sizeof(struct sde_vbif_dynamic_ot_cfg),
GFP_KERNEL);
if (!vbif->dynamic_ot_wr_tbl.cfg)
return -ENOMEM;
}
for (j = 0, k = 0; j < vbif->dynamic_ot_wr_tbl.count; j++) {
vbif->dynamic_ot_wr_tbl.cfg[j].pps = (u64)
PROP_VALUE_ACCESS(prop_value,
VBIF_DYNAMIC_OT_WR_LIMIT, k++);
vbif->dynamic_ot_wr_tbl.cfg[j].ot_limit =
PROP_VALUE_ACCESS(prop_value,
VBIF_DYNAMIC_OT_WR_LIMIT, k++);
SDE_DEBUG("dynamic_ot_wr_tbl[%d].cfg=<%llu %u>\n", j,
vbif->dynamic_ot_wr_tbl.cfg[j].pps,
vbif->dynamic_ot_wr_tbl.cfg[j].ot_limit);
}
if (vbif->default_ot_rd_limit || vbif->default_ot_wr_limit ||
vbif->dynamic_ot_rd_tbl.count ||
vbif->dynamic_ot_wr_tbl.count)
set_bit(SDE_VBIF_QOS_OTLIM, &vbif->features);
return 0;
}
static int _sde_vbif_populate_qos_parsing(struct sde_mdss_cfg *sde_cfg,
struct sde_vbif_cfg *vbif, struct sde_prop_value *prop_value, int *prop_count)
{
int i, j, prop_index = VBIF_QOS_RT_REMAP;
u32 entries;
for (i = VBIF_RT_CLIENT; ((i < VBIF_MAX_CLIENT) && (prop_index < VBIF_PROP_MAX));
i++, prop_index++) {
vbif->qos_tbl[i].count = prop_count[prop_index];
SDE_DEBUG("qos_tbl[%d].count=%u\n", i, vbif->qos_tbl[i].count);
entries = 2 * sde_cfg->vbif_qos_nlvl;
if (vbif->qos_tbl[i].count == entries) {
vbif->qos_tbl[i].priority_lvl = kcalloc(entries, sizeof(u32), GFP_KERNEL);
if (!vbif->qos_tbl[i].priority_lvl) {
vbif->qos_tbl[i].count = 0;
return -ENOMEM;
}
} else if (vbif->qos_tbl[i].count) {
vbif->qos_tbl[i].count = 0;
vbif->qos_tbl[i].priority_lvl = NULL;
SDE_ERROR("invalid qos table for client:%d, prop:%d\n", i, prop_index);
continue;
}
for (j = 0; j < vbif->qos_tbl[i].count; j++) {
vbif->qos_tbl[i].priority_lvl[j] =
PROP_VALUE_ACCESS(prop_value, prop_index, j);
SDE_DEBUG("client:%d, prop:%d, lvl[%d]=%u\n", i, prop_index, j,
vbif->qos_tbl[i].priority_lvl[j]);
}
vbif->qos_tbl[i].count = entries;
set_bit(SDE_VBIF_QOS_REMAP, &vbif->features);
}
return 0;
}
static int _sde_vbif_populate(struct sde_mdss_cfg *sde_cfg,
struct sde_vbif_cfg *vbif, struct sde_prop_value *prop_value,
int *prop_count, u32 vbif_len, int i)
{
int j, k, rc;
vbif = sde_cfg->vbif + i;
vbif->base = PROP_VALUE_ACCESS(prop_value, VBIF_OFF, i);
vbif->len = vbif_len;
vbif->id = VBIF_0 + PROP_VALUE_ACCESS(prop_value, VBIF_ID, i);
snprintf(vbif->name, SDE_HW_BLK_NAME_LEN, "vbif_%u",
vbif->id - VBIF_0);
SDE_DEBUG("vbif:%d\n", vbif->id - VBIF_0);
vbif->xin_halt_timeout = VBIF_XIN_HALT_TIMEOUT;
rc = _sde_vbif_populate_ot_parsing(vbif, prop_value, prop_count);
if (rc)
return rc;
rc = _sde_vbif_populate_qos_parsing(sde_cfg, vbif, prop_value,
prop_count);
if (rc)
return rc;
vbif->memtype_count = prop_count[VBIF_MEMTYPE_0] +
prop_count[VBIF_MEMTYPE_1];
if (vbif->memtype_count > MAX_XIN_COUNT) {
vbif->memtype_count = 0;
SDE_ERROR("too many memtype defs, ignoring entries\n");
}
for (j = 0, k = 0; j < prop_count[VBIF_MEMTYPE_0]; j++)
vbif->memtype[k++] = PROP_VALUE_ACCESS(
prop_value, VBIF_MEMTYPE_0, j);
for (j = 0; j < prop_count[VBIF_MEMTYPE_1]; j++)
vbif->memtype[k++] = PROP_VALUE_ACCESS(
prop_value, VBIF_MEMTYPE_1, j);
if (test_bit(SDE_FEATURE_VBIF_DISABLE_SHAREABLE, sde_cfg->features))
set_bit(SDE_VBIF_DISABLE_SHAREABLE, &vbif->features);
return 0;
}
static int sde_vbif_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int rc, prop_count[VBIF_PROP_MAX], i;
struct sde_prop_value *prop_value = NULL;
bool prop_exists[VBIF_PROP_MAX];
u32 off_count, vbif_len;
struct sde_vbif_cfg *vbif = NULL;
if (!sde_cfg) {
SDE_ERROR("invalid argument\n");
rc = -EINVAL;
goto end;
}
prop_value = kzalloc(VBIF_PROP_MAX *
sizeof(struct sde_prop_value), GFP_KERNEL);
if (!prop_value) {
rc = -ENOMEM;
goto end;
}
rc = _validate_dt_entry(np, vbif_prop, ARRAY_SIZE(vbif_prop),
prop_count, &off_count);
if (rc)
goto end;
rc = _validate_dt_entry(np, &vbif_prop[VBIF_DYNAMIC_OT_RD_LIMIT], 1,
&prop_count[VBIF_DYNAMIC_OT_RD_LIMIT], NULL);
if (rc)
goto end;
rc = _validate_dt_entry(np, &vbif_prop[VBIF_DYNAMIC_OT_WR_LIMIT], 1,
&prop_count[VBIF_DYNAMIC_OT_WR_LIMIT], NULL);
if (rc)
goto end;
rc = _validate_dt_entry(np, &vbif_prop[VBIF_MEMTYPE_0], 1,
&prop_count[VBIF_MEMTYPE_0], NULL);
if (rc)
goto end;
rc = _validate_dt_entry(np, &vbif_prop[VBIF_MEMTYPE_1], 1,
&prop_count[VBIF_MEMTYPE_1], NULL);
if (rc)
goto end;
rc = _validate_dt_entry(np, &vbif_prop[VBIF_QOS_RT_REMAP], 1,
&prop_count[VBIF_QOS_RT_REMAP], NULL);
if (rc)
goto end;
rc = _validate_dt_entry(np, &vbif_prop[VBIF_QOS_NRT_REMAP], 1,
&prop_count[VBIF_QOS_NRT_REMAP], NULL);
if (rc)
goto end;
rc = _validate_dt_entry(np, &vbif_prop[VBIF_QOS_CWB_REMAP], 1,
&prop_count[VBIF_QOS_CWB_REMAP], NULL);
if (rc)
goto end;
rc = _validate_dt_entry(np, &vbif_prop[VBIF_QOS_LUTDMA_REMAP], 1,
&prop_count[VBIF_QOS_LUTDMA_REMAP], NULL);
if (rc)
goto end;
rc = _validate_dt_entry(np, &vbif_prop[VBIF_QOS_CNOC_REMAP], 1,
&prop_count[VBIF_QOS_CNOC_REMAP], NULL);
if (rc)
goto end;
rc = _validate_dt_entry(np, &vbif_prop[VBIF_QOS_OFFLINE_WB_REMAP], 1,
&prop_count[VBIF_QOS_OFFLINE_WB_REMAP], NULL);
if (rc)
goto end;
sde_cfg->vbif_count = off_count;
rc = _read_dt_entry(np, vbif_prop, ARRAY_SIZE(vbif_prop), prop_count,
prop_exists, prop_value);
if (rc)
goto end;
vbif_len = PROP_VALUE_ACCESS(prop_value, VBIF_LEN, 0);
if (!prop_exists[VBIF_LEN])
vbif_len = DEFAULT_SDE_HW_BLOCK_LEN;
for (i = 0; i < off_count; i++) {
rc = _sde_vbif_populate(sde_cfg, vbif, prop_value,
prop_count, vbif_len, i);
if (rc)
goto end;
}
end:
kfree(prop_value);
return rc;
}
static int sde_pp_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg)
{
int rc, prop_count[PP_PROP_MAX], i;
struct sde_prop_value *prop_value = NULL;
bool prop_exists[PP_PROP_MAX];
u32 off_count, major_version;
struct sde_pingpong_cfg *pp;
struct sde_pingpong_sub_blks *sblk;
if (!sde_cfg) {
SDE_ERROR("invalid argument\n");
rc = -EINVAL;
goto end;
}
prop_value = kzalloc(PP_PROP_MAX *
sizeof(struct sde_prop_value), GFP_KERNEL);
if (!prop_value) {
rc = -ENOMEM;
goto end;
}
rc = _validate_dt_entry(np, pp_prop, ARRAY_SIZE(pp_prop), prop_count,
&off_count);
if (rc)
goto end;
sde_cfg->pingpong_count = off_count;
rc = _read_dt_entry(np, pp_prop, ARRAY_SIZE(pp_prop), prop_count,
prop_exists, prop_value);
if (rc)
goto end;
major_version = SDE_HW_MAJOR(sde_cfg->hw_rev);
for (i = 0; i < off_count; i++) {
pp = sde_cfg->pingpong + i;
sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
if (!sblk) {
rc = -ENOMEM;
/* catalog deinit will release the allocated blocks */
goto end;
}
pp->sblk = sblk;
pp->base = PROP_VALUE_ACCESS(prop_value, PP_OFF, i);
pp->id = PINGPONG_0 + i;
snprintf(pp->name, SDE_HW_BLK_NAME_LEN, "pingpong_%u",
pp->id - PINGPONG_0);
pp->len = PROP_VALUE_ACCESS(prop_value, PP_LEN, 0);
sblk->te.base = PROP_VALUE_ACCESS(prop_value, TE_OFF, i);
sblk->te.id = SDE_PINGPONG_TE;
snprintf(sblk->te.name, SDE_HW_BLK_NAME_LEN, "te_%u",
pp->id - PINGPONG_0);
if (major_version < SDE_HW_MAJOR(SDE_HW_VER_500))
set_bit(SDE_PINGPONG_TE, &pp->features);
sblk->te2.base = PROP_VALUE_ACCESS(prop_value, TE2_OFF, i);
if (sblk->te2.base) {
sblk->te2.id = SDE_PINGPONG_TE2;
snprintf(sblk->te2.name, SDE_HW_BLK_NAME_LEN, "te2_%u",
pp->id - PINGPONG_0);
set_bit(SDE_PINGPONG_TE2, &pp->features);
set_bit(SDE_PINGPONG_SPLIT, &pp->features);
}
if (PROP_VALUE_ACCESS(prop_value, PP_SLAVE, i))
set_bit(SDE_PINGPONG_SLAVE, &pp->features);
if (PROP_VALUE_ACCESS(prop_value, PP_CWB, i)) {
set_bit(SDE_PINGPONG_CWB, &pp->features);
if (test_bit(SDE_FEATURE_DEDICATED_CWB, sde_cfg->features))
sde_cfg->dcwb_count++;
}
pp->dcwb_id = (sde_cfg->dcwb_count > 0) ? sde_cfg->dcwb_count : DCWB_MAX;
if (major_version < SDE_HW_MAJOR(SDE_HW_VER_700)) {
sblk->dsc.base = PROP_VALUE_ACCESS(prop_value,
DSC_OFF, i);
if (sblk->dsc.base) {
sblk->dsc.id = SDE_PINGPONG_DSC;
snprintf(sblk->dsc.name, SDE_HW_BLK_NAME_LEN,
"dsc_%u",
pp->id - PINGPONG_0);
set_bit(SDE_PINGPONG_DSC, &pp->features);
}
}
sblk->dither.base = PROP_VALUE_ACCESS(prop_value, DITHER_OFF,
i);
if (sblk->dither.base) {
sblk->dither.id = SDE_PINGPONG_DITHER;
snprintf(sblk->dither.name, SDE_HW_BLK_NAME_LEN,
"dither_%u", pp->id);
set_bit(SDE_PINGPONG_DITHER, &pp->features);
}
sblk->dither.len = PROP_VALUE_ACCESS(prop_value, DITHER_LEN, 0);
sblk->dither.version = PROP_VALUE_ACCESS(prop_value, DITHER_VER,
0);
if (test_bit(SDE_FEATURE_CWB_DITHER, sde_cfg->features) &&
PROP_VALUE_ACCESS(prop_value, CWB_DITHER, i)) {
set_bit(SDE_PINGPONG_CWB_DITHER, &pp->features);
}
if (test_bit(SDE_FEATURE_DITHER_LUMA_MODE, sde_cfg->features))
set_bit(SDE_PINGPONG_DITHER_LUMA, &pp->features);
if (prop_exists[PP_MERGE_3D_ID]) {
set_bit(SDE_PINGPONG_MERGE_3D, &pp->features);
pp->merge_3d_id = PROP_VALUE_ACCESS(prop_value,
PP_MERGE_3D_ID, i) + 1;
}
}
end:
kfree(prop_value);
return rc;
}
static void _sde_top_parse_dt_helper(struct sde_mdss_cfg *cfg,
struct sde_dt_props *props)
{
int i;
u32 ddr_type;
cfg->max_sspp_linewidth = props->exists[SSPP_LINEWIDTH] ?
PROP_VALUE_ACCESS(props->values, SSPP_LINEWIDTH, 0) :
DEFAULT_SDE_LINE_WIDTH;
cfg->vig_sspp_linewidth = props->exists[VIG_SSPP_LINEWIDTH] ?
PROP_VALUE_ACCESS(props->values, VIG_SSPP_LINEWIDTH,
0) : cfg->max_sspp_linewidth;
cfg->scaling_linewidth = props->exists[SCALING_LINEWIDTH] ?
PROP_VALUE_ACCESS(props->values, SCALING_LINEWIDTH,
0) : cfg->vig_sspp_linewidth;
cfg->max_wb_linewidth = props->exists[WB_LINEWIDTH] ?
PROP_VALUE_ACCESS(props->values, WB_LINEWIDTH, 0) :
DEFAULT_SDE_LINE_WIDTH;
/* if wb linear width is not defined use the line width as default */
cfg->max_wb_linewidth_linear = props->exists[WB_LINEWIDTH_LINEAR] ?
PROP_VALUE_ACCESS(props->values, WB_LINEWIDTH_LINEAR, 0)
: cfg->max_wb_linewidth;
cfg->max_mixer_width = props->exists[MIXER_LINEWIDTH] ?
PROP_VALUE_ACCESS(props->values, MIXER_LINEWIDTH, 0) :
DEFAULT_SDE_LINE_WIDTH;
cfg->max_mixer_blendstages = props->exists[MIXER_BLEND] ?
PROP_VALUE_ACCESS(props->values, MIXER_BLEND, 0) :
DEFAULT_SDE_MIXER_BLENDSTAGES;
cfg->ubwc_rev = props->exists[UBWC_VERSION] ?
PROP_VALUE_ACCESS(props->values,
UBWC_VERSION, 0) : DEFAULT_SDE_UBWC_NONE;
cfg->mdp[0].highest_bank_bit = DEFAULT_SDE_HIGHEST_BANK_BIT;
if (props->exists[BANK_BIT]) {
for (i = 0; i < props->counts[BANK_BIT]; i++) {
ddr_type = PROP_BITVALUE_ACCESS(props->values,
BANK_BIT, i, 0);
if (!ddr_type || (of_fdt_get_ddrtype() == ddr_type))
cfg->mdp[0].highest_bank_bit =
PROP_BITVALUE_ACCESS(props->values,
BANK_BIT, i, 1);
}
}
cfg->macrotile_mode = props->exists[MACROTILE_MODE] ?
PROP_VALUE_ACCESS(props->values, MACROTILE_MODE, 0) :
DEFAULT_SDE_UBWC_MACROTILE_MODE;
cfg->ubwc_bw_calc_rev = PROP_VALUE_ACCESS(props->values, UBWC_BW_CALC_VERSION, 0);
cfg->mdp[0].ubwc_static = props->exists[UBWC_STATIC] ?
PROP_VALUE_ACCESS(props->values, UBWC_STATIC, 0) :
DEFAULT_SDE_UBWC_STATIC;
cfg->mdp[0].ubwc_swizzle = props->exists[UBWC_SWIZZLE] ?
PROP_VALUE_ACCESS(props->values, UBWC_SWIZZLE, 0) :
DEFAULT_SDE_UBWC_SWIZZLE;
cfg->mdp[0].has_dest_scaler =
PROP_VALUE_ACCESS(props->values, DEST_SCALER, 0);
cfg->mdp[0].smart_panel_align_mode =
PROP_VALUE_ACCESS(props->values, SMART_PANEL_ALIGN_MODE, 0);
cfg->ipcc_protocol_id = PROP_VALUE_ACCESS(props->values, IPCC_PROTOCOL_ID, 0);
if (props->exists[SEC_SID_MASK]) {
cfg->sec_sid_mask_count = props->counts[SEC_SID_MASK];
for (i = 0; i < cfg->sec_sid_mask_count; i++)
cfg->sec_sid_mask[i] = PROP_VALUE_ACCESS(props->values,
SEC_SID_MASK, i);
}
if (PROP_VALUE_ACCESS(props->values, SRC_SPLIT, 0))
set_bit(SDE_FEATURE_SRC_SPLIT, cfg->features);
if (PROP_VALUE_ACCESS(props->values, DIM_LAYER, 0))
set_bit(SDE_FEATURE_DIM_LAYER, cfg->features);
if (PROP_VALUE_ACCESS(props->values, IDLE_PC, 0))
set_bit(SDE_FEATURE_IDLE_PC, cfg->features);
if (PROP_VALUE_ACCESS(props->values, WAKEUP_WITH_TOUCH, 0))
set_bit(SDE_FEATURE_TOUCH_WAKEUP, cfg->features);
cfg->pipe_order_type = PROP_VALUE_ACCESS(props->values,
PIPE_ORDER_VERSION, 0);
if (PROP_VALUE_ACCESS(props->values, BASE_LAYER, 0))
set_bit(SDE_FEATURE_BASE_LAYER, cfg->features);
cfg->qseed_hw_rev = PROP_VALUE_ACCESS(props->values, QSEED_HW_VERSION, 0);
cfg->trusted_vm_env = PROP_VALUE_ACCESS(props->values, TRUSTED_VM_ENV, 0);
cfg->max_trusted_vm_displays = PROP_VALUE_ACCESS(props->values,
MAX_TRUSTED_VM_DISPLAYS, 0);
if (props->exists[TVM_INCLUDE_REG]) {
cfg->tvm_reg_count = props->counts[TVM_INCLUDE_REG] / 2;
for (i = 0; i < cfg->tvm_reg_count; i++) {
cfg->tvm_reg[i].start = PROP_VALUE_ACCESS(props->values,
TVM_INCLUDE_REG, i * 2);
cfg->tvm_reg[i].end = cfg->tvm_reg[i].start +
PROP_VALUE_ACCESS(props->values, TVM_INCLUDE_REG,
i * 2 + 1);
}
}
if (PROP_VALUE_ACCESS(props->values, SDE_EMULATED_ENV, 0))
set_bit(SDE_FEATURE_EMULATED_ENV, cfg->features);
}
static int sde_top_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg)
{
int rc = 0, dma_rc, len;
struct sde_dt_props *props;
const char *type;
u32 major_version;
props = sde_get_dt_props(np, SDE_PROP_MAX, sde_prop,
ARRAY_SIZE(sde_prop), &len);
if (IS_ERR(props))
return PTR_ERR(props);
/* revalidate arrays not bound to off_count elements */
rc = _validate_dt_entry(np, &sde_prop[SEC_SID_MASK], 1,
&props->counts[SEC_SID_MASK], NULL);
if (rc)
goto end;
/* update props with newly validated arrays */
rc = _read_dt_entry(np, sde_prop, ARRAY_SIZE(sde_prop), props->counts,
props->exists, props->values);
if (rc)
goto end;
cfg->mdss_count = 1;
cfg->mdss[0].base = MDSS_BASE_OFFSET;
cfg->mdss[0].id = MDP_TOP;
snprintf(cfg->mdss[0].name, SDE_HW_BLK_NAME_LEN, "mdss_%u",
cfg->mdss[0].id - MDP_TOP);
cfg->mdp_count = 1;
cfg->mdp[0].id = MDP_TOP;
snprintf(cfg->mdp[0].name, SDE_HW_BLK_NAME_LEN, "top_%u",
cfg->mdp[0].id - MDP_TOP);
cfg->mdp[0].base = PROP_VALUE_ACCESS(props->values, SDE_OFF, 0);
cfg->mdp[0].len = props->exists[SDE_LEN] ? PROP_VALUE_ACCESS(
props->values, SDE_LEN, 0) : DEFAULT_SDE_HW_BLOCK_LEN;
_sde_top_parse_dt_helper(cfg, props);
major_version = SDE_HW_MAJOR(cfg->hw_rev);
if (major_version < SDE_HW_MAJOR(SDE_HW_VER_500))
set_bit(SDE_MDP_VSYNC_SEL, &cfg->mdp[0].features);
else if (major_version < SDE_HW_MAJOR(SDE_HW_VER_810))
set_bit(SDE_MDP_WD_TIMER, &cfg->mdp[0].features);
rc = _add_to_irq_offset_list(cfg, SDE_INTR_HWBLK_TOP,
SDE_INTR_TOP_INTR, cfg->mdp[0].base);
if (rc)
goto end;
rc = _add_to_irq_offset_list(cfg, SDE_INTR_HWBLK_TOP,
SDE_INTR_TOP_INTR2, cfg->mdp[0].base);
if (rc)
goto end;
rc = _add_to_irq_offset_list(cfg, SDE_INTR_HWBLK_TOP,
SDE_INTR_TOP_HIST_INTR, cfg->mdp[0].base);
if (rc)
goto end;
rc = of_property_read_string(np, sde_prop[QSEED_SW_LIB_REV].prop_name,
&type);
if (rc) {
SDE_DEBUG("invalid %s node in device tree: %d\n",
sde_prop[QSEED_SW_LIB_REV].prop_name, rc);
rc = 0;
} else if (!strcmp(type, "qseedv3")) {
cfg->qseed_sw_lib_rev = SDE_SSPP_SCALER_QSEED3;
} else if (!strcmp(type, "qseedv3lite")) {
cfg->qseed_sw_lib_rev = SDE_SSPP_SCALER_QSEED3LITE;
} else if (!strcmp(type, "qseedv2")) {
cfg->qseed_sw_lib_rev = SDE_SSPP_SCALER_QSEED2;
} else {
SDE_DEBUG("Unknown type %s for property %s\n", type,
sde_prop[QSEED_SW_LIB_REV].prop_name);
}
rc = of_property_read_string(np, sde_prop[CSC_TYPE].prop_name, &type);
if (rc) {
SDE_DEBUG("invalid %s node in device tree: %d\n",
sde_prop[CSC_TYPE].prop_name, rc);
rc = 0;
} else if (!strcmp(type, "csc")) {
cfg->csc_type = SDE_SSPP_CSC;
} else if (!strcmp(type, "csc-10bit")) {
cfg->csc_type = SDE_SSPP_CSC_10BIT;
} else {
SDE_DEBUG("Unknown type %s for property %s\n", type,
sde_prop[CSC_TYPE].prop_name);
}
/*
* Current SDE support only Smart DMA 2.0-2.5.
* No support for Smart DMA 1.0 yet.
*/
cfg->smart_dma_rev = 0;
dma_rc = of_property_read_string(np, sde_prop[SMART_DMA_REV].prop_name,
&type);
if (dma_rc) {
SDE_DEBUG("invalid %s node in device tree: %d\n",
sde_prop[SMART_DMA_REV].prop_name, dma_rc);
} else if (!strcmp(type, "smart_dma_v2p5")) {
cfg->smart_dma_rev = SDE_SSPP_SMART_DMA_V2p5;
} else if (!strcmp(type, "smart_dma_v2")) {
cfg->smart_dma_rev = SDE_SSPP_SMART_DMA_V2;
} else if (!strcmp(type, "smart_dma_v1")) {
SDE_ERROR("smart dma 1.0 is not supported in SDE\n");
} else {
SDE_DEBUG("unknown smart dma version %s\n", type);
}
end:
sde_put_dt_props(props);
return rc;
}
static int sde_parse_reg_dma_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int rc = 0, i, prop_count[REG_DMA_PROP_MAX];
struct sde_prop_value *prop_value = NULL;
u32 off_count;
bool prop_exists[REG_DMA_PROP_MAX];
bool dma_type_exists[REG_DMA_TYPE_MAX];
enum sde_reg_dma_type dma_type;
prop_value = kcalloc(REG_DMA_PROP_MAX,
sizeof(struct sde_prop_value), GFP_KERNEL);
if (!prop_value) {
rc = -ENOMEM;
goto end;
}
rc = _validate_dt_entry(np, reg_dma_prop, ARRAY_SIZE(reg_dma_prop),
prop_count, &off_count);
if (rc || !off_count)
goto end;
rc = _read_dt_entry(np, reg_dma_prop, ARRAY_SIZE(reg_dma_prop),
prop_count, prop_exists, prop_value);
if (rc)
goto end;
sde_cfg->reg_dma_count = 0;
memset(&dma_type_exists, 0, sizeof(dma_type_exists));
for (i = 0; i < off_count; i++) {
dma_type = PROP_VALUE_ACCESS(prop_value, REG_DMA_ID, i);
if (dma_type >= REG_DMA_TYPE_MAX) {
SDE_ERROR("Invalid DMA type %d\n", dma_type);
goto end;
} else if (dma_type_exists[dma_type]) {
SDE_ERROR("DMA type ID %d exists more than once\n",
dma_type);
goto end;
}
dma_type_exists[dma_type] = true;
sde_cfg->dma_cfg.reg_dma_blks[dma_type].base =
PROP_VALUE_ACCESS(prop_value, REG_DMA_OFF, i);
sde_cfg->dma_cfg.reg_dma_blks[dma_type].valid = true;
sde_cfg->reg_dma_count++;
}
sde_cfg->dma_cfg.version = PROP_VALUE_ACCESS(prop_value,
REG_DMA_VERSION, 0);
sde_cfg->dma_cfg.trigger_sel_off = PROP_VALUE_ACCESS(prop_value,
REG_DMA_TRIGGER_OFF, 0);
sde_cfg->dma_cfg.broadcast_disabled = PROP_VALUE_ACCESS(prop_value,
REG_DMA_BROADCAST_DISABLED, 0);
sde_cfg->dma_cfg.xin_id = PROP_VALUE_ACCESS(prop_value,
REG_DMA_XIN_ID, 0);
sde_cfg->dma_cfg.clk_ctrl = SDE_CLK_CTRL_LUTDMA;
sde_cfg->dma_cfg.vbif_idx = VBIF_RT;
if (test_bit(SDE_FEATURE_VBIF_CLK_SPLIT, sde_cfg->features)) {
sde_cfg->dma_cfg.split_vbif_supported = true;
} else {
for (i = 0; i < sde_cfg->mdp_count; i++) {
sde_cfg->mdp[i].clk_ctrls[sde_cfg->dma_cfg.clk_ctrl].reg_off =
PROP_BITVALUE_ACCESS(prop_value,
REG_DMA_CLK_CTRL, 0, 0);
sde_cfg->mdp[i].clk_ctrls[sde_cfg->dma_cfg.clk_ctrl].bit_off =
PROP_BITVALUE_ACCESS(prop_value,
REG_DMA_CLK_CTRL, 0, 1);
}
}
end:
kfree(prop_value);
/* reg dma is optional feature hence return 0 */
return 0;
}
static int _sde_perf_parse_dt_validate(struct device_node *np, int *prop_count)
{
int rc, len;
rc = _validate_dt_entry(np, sde_perf_prop, ARRAY_SIZE(sde_perf_prop),
prop_count, &len);
if (rc)
return rc;
rc = _validate_dt_entry(np, &sde_perf_prop[PERF_CDP_SETTING], 1,
&prop_count[PERF_CDP_SETTING], NULL);
if (rc)
return rc;
return rc;
}
static int _sde_qos_parse_dt_cfg(struct sde_mdss_cfg *cfg, int *prop_count,
struct sde_prop_value *prop_value, bool *prop_exists)
{
int i, j;
u32 qos_count = 1;
if (prop_exists[QOS_REFRESH_RATES]) {
qos_count = prop_count[QOS_REFRESH_RATES];
cfg->perf.qos_refresh_rate = kcalloc(qos_count,
sizeof(u32), GFP_KERNEL);
if (!cfg->perf.qos_refresh_rate)
goto end;
for (j = 0; j < qos_count; j++) {
cfg->perf.qos_refresh_rate[j] =
PROP_VALUE_ACCESS(prop_value,
QOS_REFRESH_RATES, j);
SDE_DEBUG("qos usage:%d refresh rate:0x%x\n",
j, cfg->perf.qos_refresh_rate[j]);
}
}
cfg->perf.qos_refresh_count = qos_count;
cfg->perf.danger_lut = kcalloc(qos_count,
sizeof(u64) * SDE_QOS_LUT_USAGE_MAX * SDE_DANGER_SAFE_LUT_TYPE_MAX, GFP_KERNEL);
cfg->perf.safe_lut = kcalloc(qos_count,
sizeof(u64) * SDE_QOS_LUT_USAGE_MAX * SDE_DANGER_SAFE_LUT_TYPE_MAX, GFP_KERNEL);
cfg->perf.creq_lut = kcalloc(qos_count,
sizeof(u64) * SDE_QOS_LUT_USAGE_MAX * SDE_CREQ_LUT_TYPE_MAX, GFP_KERNEL);
if (!cfg->perf.creq_lut || !cfg->perf.safe_lut || !cfg->perf.danger_lut)
goto end;
if (prop_exists[QOS_DANGER_LUT] &&
(prop_count[QOS_DANGER_LUT] >=
(SDE_QOS_LUT_USAGE_MAX * qos_count * SDE_DANGER_SAFE_LUT_TYPE_MAX))) {
for (i = 0; i < prop_count[QOS_DANGER_LUT]; i++) {
cfg->perf.danger_lut[i] = PROP_VALUE_ACCESS(prop_value, QOS_DANGER_LUT, i);
SDE_DEBUG("danger usage:%i lut:0x%llx\n", i, cfg->perf.danger_lut[i]);
}
}
if (prop_exists[QOS_SAFE_LUT] &&
(prop_count[QOS_SAFE_LUT] >=
(SDE_QOS_LUT_USAGE_MAX * qos_count * SDE_DANGER_SAFE_LUT_TYPE_MAX))) {
for (i = 0; i < prop_count[QOS_SAFE_LUT]; i++) {
cfg->perf.safe_lut[i] = PROP_VALUE_ACCESS(prop_value, QOS_SAFE_LUT, i);
SDE_DEBUG("safe usage:%d lut:0x%llx\n", i, cfg->perf.safe_lut[i]);
}
}
if (prop_exists[QOS_CREQ_LUT] &&
(prop_count[QOS_CREQ_LUT] >=
(SDE_QOS_LUT_USAGE_MAX * qos_count * SDE_CREQ_LUT_TYPE_MAX))) {
u64 lut_hi, lut_lo;
for (j = 0; j < (qos_count * SDE_QOS_LUT_USAGE_MAX * SDE_CREQ_LUT_TYPE_MAX); j++) {
lut_hi = PROP_VALUE_ACCESS(prop_value, QOS_CREQ_LUT, (j * 2) + 0);
lut_lo = PROP_VALUE_ACCESS(prop_value, QOS_CREQ_LUT, (j * 2) + 1);
cfg->perf.creq_lut[j] = (lut_hi << 32) | lut_lo;
SDE_DEBUG("creq usage:%d lut:0x%llx\n", j, cfg->perf.creq_lut[j]);
}
}
return 0;
end:
kfree(cfg->perf.qos_refresh_rate);
kfree(cfg->perf.creq_lut);
kfree(cfg->perf.danger_lut);
kfree(cfg->perf.safe_lut);
return -ENOMEM;
}
static void _sde_perf_parse_dt_cfg_populate(struct sde_mdss_cfg *cfg,
int *prop_count,
struct sde_prop_value *prop_value,
bool *prop_exists)
{
cfg->perf.max_bw_low =
prop_exists[PERF_MAX_BW_LOW] ?
PROP_VALUE_ACCESS(prop_value, PERF_MAX_BW_LOW, 0) :
DEFAULT_MAX_BW_LOW;
cfg->perf.max_bw_high =
prop_exists[PERF_MAX_BW_HIGH] ?
PROP_VALUE_ACCESS(prop_value, PERF_MAX_BW_HIGH, 0) :
DEFAULT_MAX_BW_HIGH;
cfg->perf.min_core_ib =
prop_exists[PERF_MIN_CORE_IB] ?
PROP_VALUE_ACCESS(prop_value, PERF_MIN_CORE_IB, 0) :
DEFAULT_MAX_BW_LOW;
cfg->perf.min_llcc_ib =
prop_exists[PERF_MIN_LLCC_IB] ?
PROP_VALUE_ACCESS(prop_value, PERF_MIN_LLCC_IB, 0) :
DEFAULT_MAX_BW_LOW;
cfg->perf.min_dram_ib =
prop_exists[PERF_MIN_DRAM_IB] ?
PROP_VALUE_ACCESS(prop_value, PERF_MIN_DRAM_IB, 0) :
DEFAULT_MAX_BW_LOW;
cfg->perf.undersized_prefill_lines =
prop_exists[PERF_UNDERSIZED_PREFILL_LINES] ?
PROP_VALUE_ACCESS(prop_value,
PERF_UNDERSIZED_PREFILL_LINES, 0) :
DEFAULT_UNDERSIZED_PREFILL_LINES;
cfg->perf.xtra_prefill_lines =
prop_exists[PERF_XTRA_PREFILL_LINES] ?
PROP_VALUE_ACCESS(prop_value,
PERF_XTRA_PREFILL_LINES, 0) :
DEFAULT_XTRA_PREFILL_LINES;
cfg->perf.dest_scale_prefill_lines =
prop_exists[PERF_DEST_SCALE_PREFILL_LINES] ?
PROP_VALUE_ACCESS(prop_value,
PERF_DEST_SCALE_PREFILL_LINES, 0) :
DEFAULT_DEST_SCALE_PREFILL_LINES;
cfg->perf.macrotile_prefill_lines =
prop_exists[PERF_MACROTILE_PREFILL_LINES] ?
PROP_VALUE_ACCESS(prop_value,
PERF_MACROTILE_PREFILL_LINES, 0) :
DEFAULT_MACROTILE_PREFILL_LINES;
cfg->perf.yuv_nv12_prefill_lines =
prop_exists[PERF_YUV_NV12_PREFILL_LINES] ?
PROP_VALUE_ACCESS(prop_value,
PERF_YUV_NV12_PREFILL_LINES, 0) :
DEFAULT_YUV_NV12_PREFILL_LINES;
cfg->perf.linear_prefill_lines =
prop_exists[PERF_LINEAR_PREFILL_LINES] ?
PROP_VALUE_ACCESS(prop_value,
PERF_LINEAR_PREFILL_LINES, 0) :
DEFAULT_LINEAR_PREFILL_LINES;
cfg->perf.downscaling_prefill_lines =
prop_exists[PERF_DOWNSCALING_PREFILL_LINES] ?
PROP_VALUE_ACCESS(prop_value,
PERF_DOWNSCALING_PREFILL_LINES, 0) :
DEFAULT_DOWNSCALING_PREFILL_LINES;
cfg->perf.amortizable_threshold =
prop_exists[PERF_AMORTIZABLE_THRESHOLD] ?
PROP_VALUE_ACCESS(prop_value,
PERF_AMORTIZABLE_THRESHOLD, 0) :
DEFAULT_AMORTIZABLE_THRESHOLD;
cfg->perf.num_ddr_channels = prop_exists[PERF_NUM_DDR_CHANNELS] ?
PROP_VALUE_ACCESS(prop_value, PERF_NUM_DDR_CHANNELS, 0) :
DEFAULT_NUM_DDR_CHANNELS;
cfg->perf.dram_efficiency = prop_exists[PERF_DRAM_EFFICIENCY] ?
PROP_VALUE_ACCESS(prop_value, PERF_DRAM_EFFICIENCY, 0) :
DEFAULT_DRAM_EFFICIENCY;
cfg->perf.num_mnoc_ports =
prop_exists[PERF_NUM_MNOC_PORTS] ?
PROP_VALUE_ACCESS(prop_value,
PERF_NUM_MNOC_PORTS, 0) :
DEFAULT_MNOC_PORTS;
cfg->perf.axi_bus_width =
prop_exists[PERF_AXI_BUS_WIDTH] ?
PROP_VALUE_ACCESS(prop_value,
PERF_AXI_BUS_WIDTH, 0) :
DEFAULT_AXI_BUS_WIDTH;
}
static int _sde_perf_parse_dt_cfg(struct device_node *np,
struct sde_mdss_cfg *cfg, int *prop_count,
struct sde_prop_value *prop_value, bool *prop_exists)
{
int rc, j;
const char *str = NULL;
/*
* The following performance parameters (e.g. core_ib_ff) are
* mapped directly as device tree string constants.
*/
rc = of_property_read_string(np,
sde_perf_prop[PERF_CORE_IB_FF].prop_name, &str);
cfg->perf.core_ib_ff = rc ? DEFAULT_CORE_IB_FF : str;
rc = of_property_read_string(np,
sde_perf_prop[PERF_CORE_CLK_FF].prop_name, &str);
cfg->perf.core_clk_ff = rc ? DEFAULT_CORE_CLK_FF : str;
rc = of_property_read_string(np,
sde_perf_prop[PERF_COMP_RATIO_RT].prop_name, &str);
cfg->perf.comp_ratio_rt = rc ? DEFAULT_COMP_RATIO_RT : str;
rc = of_property_read_string(np,
sde_perf_prop[PERF_COMP_RATIO_NRT].prop_name, &str);
cfg->perf.comp_ratio_nrt = rc ? DEFAULT_COMP_RATIO_NRT : str;
rc = 0;
_sde_perf_parse_dt_cfg_populate(cfg, prop_count, prop_value,
prop_exists);
if (prop_exists[PERF_CDP_SETTING]) {
const u32 prop_size = 2;
u32 count = prop_count[PERF_CDP_SETTING] / prop_size;
count = min_t(u32, count, SDE_PERF_CDP_USAGE_MAX);
for (j = 0; j < count; j++) {
cfg->perf.cdp_cfg[j].rd_enable =
PROP_VALUE_ACCESS(prop_value,
PERF_CDP_SETTING, j * prop_size);
cfg->perf.cdp_cfg[j].wr_enable =
PROP_VALUE_ACCESS(prop_value,
PERF_CDP_SETTING, j * prop_size + 1);
SDE_DEBUG("cdp usage:%d rd:%d wr:%d\n",
j, cfg->perf.cdp_cfg[j].rd_enable,
cfg->perf.cdp_cfg[j].wr_enable);
}
set_bit(SDE_FEATURE_CDP, cfg->features);
}
cfg->perf.cpu_mask =
prop_exists[PERF_CPU_MASK] ?
PROP_VALUE_ACCESS(prop_value, PERF_CPU_MASK, 0) :
DEFAULT_CPU_MASK;
cfg->perf.cpu_mask_perf =
prop_exists[CPU_MASK_PERF] ?
PROP_VALUE_ACCESS(prop_value, CPU_MASK_PERF, 0) :
DEFAULT_CPU_MASK;
cfg->perf.cpu_dma_latency =
prop_exists[PERF_CPU_DMA_LATENCY] ?
PROP_VALUE_ACCESS(prop_value, PERF_CPU_DMA_LATENCY, 0) :
DEFAULT_CPU_DMA_LATENCY;
cfg->perf.cpu_irq_latency =
prop_exists[PERF_CPU_IRQ_LATENCY] ?
PROP_VALUE_ACCESS(prop_value, PERF_CPU_IRQ_LATENCY, 0) :
PM_QOS_DEFAULT_VALUE;
return 0;
}
static int sde_perf_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg)
{
int rc, prop_count[PERF_PROP_MAX];
struct sde_prop_value *prop_value = NULL;
bool prop_exists[PERF_PROP_MAX];
if (!cfg) {
SDE_ERROR("invalid argument\n");
rc = -EINVAL;
goto end;
}
prop_value = kzalloc(PERF_PROP_MAX *
sizeof(struct sde_prop_value), GFP_KERNEL);
if (!prop_value) {
rc = -ENOMEM;
goto end;
}
rc = _sde_perf_parse_dt_validate(np, prop_count);
if (rc)
goto freeprop;
rc = _read_dt_entry(np, sde_perf_prop, ARRAY_SIZE(sde_perf_prop),
prop_count, prop_exists, prop_value);
if (rc)
goto freeprop;
rc = _sde_perf_parse_dt_cfg(np, cfg, prop_count, prop_value,
prop_exists);
freeprop:
kfree(prop_value);
end:
return rc;
}
static int sde_qos_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg)
{
int rc, prop_count[QOS_PROP_MAX];
struct sde_prop_value *prop_value = NULL;
bool prop_exists[QOS_PROP_MAX];
if (!cfg) {
SDE_ERROR("invalid argument\n");
rc = -EINVAL;
goto end;
}
prop_value = kzalloc(QOS_PROP_MAX *
sizeof(struct sde_prop_value), GFP_KERNEL);
if (!prop_value) {
rc = -ENOMEM;
goto end;
}
rc = _validate_dt_entry(np, sde_qos_prop, ARRAY_SIZE(sde_qos_prop),
prop_count, NULL);
if (rc)
goto freeprop;
rc = _read_dt_entry(np, sde_qos_prop, ARRAY_SIZE(sde_qos_prop),
prop_count, prop_exists, prop_value);
if (rc)
goto freeprop;
rc = _sde_qos_parse_dt_cfg(cfg, prop_count, prop_value, prop_exists);
freeprop:
kfree(prop_value);
end:
return rc;
}
static int sde_parse_merge_3d_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int rc, prop_count[HW_PROP_MAX], off_count, i;
struct sde_prop_value *prop_value = NULL;
bool prop_exists[HW_PROP_MAX];
struct sde_merge_3d_cfg *merge_3d;
prop_value = kcalloc(HW_PROP_MAX, sizeof(struct sde_prop_value),
GFP_KERNEL);
if (!prop_value)
return -ENOMEM;
rc = _validate_dt_entry(np, merge_3d_prop, ARRAY_SIZE(merge_3d_prop),
prop_count, &off_count);
if (rc)
goto end;
sde_cfg->merge_3d_count = off_count;
rc = _read_dt_entry(np, merge_3d_prop, ARRAY_SIZE(merge_3d_prop),
prop_count,
prop_exists, prop_value);
if (rc) {
sde_cfg->merge_3d_count = 0;
goto end;
}
for (i = 0; i < off_count; i++) {
merge_3d = sde_cfg->merge_3d + i;
merge_3d->base = PROP_VALUE_ACCESS(prop_value, HW_OFF, i);
merge_3d->id = MERGE_3D_0 + i;
snprintf(merge_3d->name, SDE_HW_BLK_NAME_LEN, "merge_3d_%u",
merge_3d->id - MERGE_3D_0);
merge_3d->len = PROP_VALUE_ACCESS(prop_value, HW_LEN, 0);
}
end:
kfree(prop_value);
return rc;
}
static int sde_qdss_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
int rc, prop_count[HW_PROP_MAX], i;
struct sde_prop_value *prop_value = NULL;
bool prop_exists[HW_PROP_MAX];
u32 off_count;
struct sde_qdss_cfg *qdss;
if (!sde_cfg) {
SDE_ERROR("invalid argument\n");
return -EINVAL;
}
prop_value = kzalloc(HW_PROP_MAX *
sizeof(struct sde_prop_value), GFP_KERNEL);
if (!prop_value)
return -ENOMEM;
rc = _validate_dt_entry(np, qdss_prop, ARRAY_SIZE(qdss_prop),
prop_count, &off_count);
if (rc) {
sde_cfg->qdss_count = 0;
goto end;
}
sde_cfg->qdss_count = off_count;
rc = _read_dt_entry(np, qdss_prop, ARRAY_SIZE(qdss_prop), prop_count,
prop_exists, prop_value);
if (rc)
goto end;
for (i = 0; i < off_count; i++) {
qdss = sde_cfg->qdss + i;
qdss->base = PROP_VALUE_ACCESS(prop_value, HW_OFF, i);
qdss->id = QDSS_0 + i;
snprintf(qdss->name, SDE_HW_BLK_NAME_LEN, "qdss_%u",
qdss->id - QDSS_0);
qdss->len = PROP_VALUE_ACCESS(prop_value, HW_LEN, 0);
}
end:
kfree(prop_value);
return rc;
}
static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg,
uint32_t hw_rev)
{
int rc = 0;
uint32_t dma_list_size, vig_list_size, wb2_list_size;
uint32_t virt_vig_list_size, in_rot_list_size = 0;
uint32_t index = 0;
uint32_t in_rot_restricted_list_size = 0;
const struct sde_format_extended *inline_fmt_tbl = NULL;
const struct sde_format_extended *inline_restricted_fmt_tbl = NULL;
/* DMA pipe input formats */
dma_list_size = ARRAY_SIZE(plane_formats);
if (test_bit(SDE_FEATURE_FP16, sde_cfg->features))
dma_list_size += ARRAY_SIZE(fp16_formats);
sde_cfg->dma_formats = kcalloc(dma_list_size,
sizeof(struct sde_format_extended), GFP_KERNEL);
if (!sde_cfg->dma_formats) {
rc = -ENOMEM;
goto out;
}
index = sde_copy_formats(sde_cfg->dma_formats, dma_list_size,
0, plane_formats, ARRAY_SIZE(plane_formats));
if (test_bit(SDE_FEATURE_FP16, sde_cfg->features))
index += sde_copy_formats(sde_cfg->dma_formats, dma_list_size,
index, fp16_formats, ARRAY_SIZE(fp16_formats));
/* ViG pipe input formats */
vig_list_size = ARRAY_SIZE(plane_formats_vig);
if (test_bit(SDE_FEATURE_VIG_P010, sde_cfg->features))
vig_list_size += ARRAY_SIZE(p010_ubwc_formats);
if (test_bit(SDE_FEATURE_FP16, sde_cfg->features))
vig_list_size += ARRAY_SIZE(fp16_formats);
sde_cfg->vig_formats = kcalloc(vig_list_size,
sizeof(struct sde_format_extended), GFP_KERNEL);
if (!sde_cfg->vig_formats) {
rc = -ENOMEM;
goto free_dma;
}
index = sde_copy_formats(sde_cfg->vig_formats, vig_list_size,
0, plane_formats_vig, ARRAY_SIZE(plane_formats_vig));
if (test_bit(SDE_FEATURE_VIG_P010, sde_cfg->features))
index += sde_copy_formats(sde_cfg->vig_formats,
vig_list_size, index, p010_ubwc_formats,
ARRAY_SIZE(p010_ubwc_formats));
if (test_bit(SDE_FEATURE_FP16, sde_cfg->features))
index += sde_copy_formats(sde_cfg->vig_formats, vig_list_size,
index, fp16_formats, ARRAY_SIZE(fp16_formats));
/* Virtual ViG pipe input formats (all virt pipes use DMA formats) */
virt_vig_list_size = ARRAY_SIZE(plane_formats);
if (test_bit(SDE_FEATURE_FP16, sde_cfg->features))
virt_vig_list_size += ARRAY_SIZE(fp16_formats);
sde_cfg->virt_vig_formats = kcalloc(virt_vig_list_size,
sizeof(struct sde_format_extended), GFP_KERNEL);
if (!sde_cfg->virt_vig_formats) {
rc = -ENOMEM;
goto free_vig;
}
index = sde_copy_formats(sde_cfg->virt_vig_formats, virt_vig_list_size,
0, plane_formats, ARRAY_SIZE(plane_formats));
if (test_bit(SDE_FEATURE_FP16, sde_cfg->features))
index += sde_copy_formats(sde_cfg->virt_vig_formats,
virt_vig_list_size, index, fp16_formats,
ARRAY_SIZE(fp16_formats));
/* WB output formats */
wb2_list_size = ARRAY_SIZE(wb2_formats);
sde_cfg->wb_formats = kcalloc(wb2_list_size,
sizeof(struct sde_format_extended), GFP_KERNEL);
if (!sde_cfg->wb_formats) {
SDE_ERROR("failed to allocate wb format list\n");
rc = -ENOMEM;
goto free_virt;
}
index = sde_copy_formats(sde_cfg->wb_formats, wb2_list_size,
0, wb2_formats, ARRAY_SIZE(wb2_formats));
/* Rotation enabled input formats */
if (IS_SDE_INLINE_ROT_REV_100(sde_cfg->true_inline_rot_rev)) {
inline_fmt_tbl = true_inline_rot_v1_fmts;
in_rot_list_size = ARRAY_SIZE(true_inline_rot_v1_fmts);
} else if (IS_SDE_INLINE_ROT_REV_200(sde_cfg->true_inline_rot_rev)) {
inline_fmt_tbl = true_inline_rot_v2_fmts;
in_rot_list_size = ARRAY_SIZE(true_inline_rot_v2_fmts);
} else if (IS_SDE_INLINE_ROT_REV_201(sde_cfg->true_inline_rot_rev)) {
inline_fmt_tbl = true_inline_rot_v201_fmts;
in_rot_list_size = ARRAY_SIZE(true_inline_rot_v201_fmts);
inline_restricted_fmt_tbl = true_inline_rot_v201_restricted_fmts;
in_rot_restricted_list_size = ARRAY_SIZE(true_inline_rot_v201_fmts);
}
if (in_rot_list_size) {
sde_cfg->inline_rot_formats = kcalloc(in_rot_list_size,
sizeof(struct sde_format_extended), GFP_KERNEL);
if (!sde_cfg->inline_rot_formats) {
SDE_ERROR("failed to alloc inline rot format list\n");
rc = -ENOMEM;
goto free_wb;
}
index = sde_copy_formats(sde_cfg->inline_rot_formats,
in_rot_list_size, 0, inline_fmt_tbl, in_rot_list_size);
}
if (in_rot_restricted_list_size) {
sde_cfg->inline_rot_restricted_formats = kcalloc(in_rot_restricted_list_size,
sizeof(struct sde_format_extended), GFP_KERNEL);
if (!sde_cfg->inline_rot_restricted_formats) {
SDE_ERROR("failed to alloc inline rot restricted format list\n");
rc = -ENOMEM;
goto free_in_rot;
}
index = sde_copy_formats(sde_cfg->inline_rot_restricted_formats,
in_rot_restricted_list_size, 0, inline_restricted_fmt_tbl,
in_rot_restricted_list_size);
}
return 0;
free_in_rot:
kfree(sde_cfg->inline_rot_formats);
free_wb:
kfree(sde_cfg->wb_formats);
free_virt:
kfree(sde_cfg->virt_vig_formats);
free_vig:
kfree(sde_cfg->vig_formats);
free_dma:
kfree(sde_cfg->dma_formats);
out:
return rc;
}
static void _sde_hw_setup_uidle(struct sde_uidle_cfg *uidle_cfg)
{
if (!uidle_cfg->uidle_rev)
return;
uidle_cfg->fal10_exit_cnt = SDE_UIDLE_FAL10_EXIT_CNT;
uidle_cfg->fal10_exit_danger = SDE_UIDLE_FAL10_EXIT_DANGER;
uidle_cfg->fal10_danger = SDE_UIDLE_FAL10_DANGER;
uidle_cfg->fal10_target_idle_time = SDE_UIDLE_FAL10_TARGET_IDLE;
uidle_cfg->fal1_target_idle_time = SDE_UIDLE_FAL1_TARGET_IDLE;
uidle_cfg->max_dwnscale = SDE_UIDLE_MAX_DWNSCALE;
uidle_cfg->debugfs_ctrl = true;
uidle_cfg->fal1_max_threshold = SDE_UIDLE_FAL1_MAX_THRESHOLD;
if (IS_SDE_UIDLE_REV_100(uidle_cfg->uidle_rev)) {
uidle_cfg->fal10_threshold =
SDE_UIDLE_FAL10_THRESHOLD_60;
uidle_cfg->max_fps = SDE_UIDLE_MAX_FPS_60;
} else if (IS_SDE_UIDLE_REV_101(uidle_cfg->uidle_rev)) {
set_bit(SDE_UIDLE_QACTIVE_OVERRIDE,
&uidle_cfg->features);
uidle_cfg->fal10_threshold =
SDE_UIDLE_FAL10_THRESHOLD_90;
uidle_cfg->max_fps = SDE_UIDLE_MAX_FPS_90;
} else if (IS_SDE_UIDLE_REV_102(uidle_cfg->uidle_rev)) {
set_bit(SDE_UIDLE_QACTIVE_OVERRIDE,
&uidle_cfg->features);
uidle_cfg->fal10_threshold =
SDE_UIDLE_FAL10_THRESHOLD_90;
uidle_cfg->max_fps = SDE_UIDLE_MAX_FPS_90;
uidle_cfg->max_fal1_fps = SDE_UIDLE_MAX_FPS_240;
uidle_cfg->fal1_max_threshold =
SDE_UIDLE_FAL1_MAX_THRESHOLD_EXT_REV_102;
} else if (IS_SDE_UIDLE_REV_103(uidle_cfg->uidle_rev)) {
set_bit(SDE_UIDLE_QACTIVE_OVERRIDE, &uidle_cfg->features);
uidle_cfg->max_fps = SDE_UIDLE_MAX_FPS_240;
uidle_cfg->max_fal1_fps = SDE_UIDLE_MAX_FPS_240;
uidle_cfg->fal1_max_threshold = SDE_UIDLE_FAL1_MAX_THRESHOLD_EXT_REV_103;
uidle_cfg->fal10_threshold = SDE_UIDLE_FAL10_THRESHOLD_60;
}
}
static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev)
{
int rc = 0, i;
if (!sde_cfg)
return -EINVAL;
/* default settings for *MOST* targets */
set_bit(SDE_FEATURE_COMBINED_ALPHA, sde_cfg->features);
set_bit(SDE_FEATURE_DELAY_PRG_FETCH, sde_cfg->features);
set_bit(SDE_FEATURE_SUI_MISR, sde_cfg->features);
set_bit(SDE_FEATURE_SUI_BLENDSTAGE, sde_cfg->features);
set_bit(SDE_FEATURE_SUI_NS_ALLOWED, sde_cfg->features);
set_bit(SDE_FEATURE_HDR, sde_cfg->features);
sde_cfg->mdss_hw_block_size = DEFAULT_MDSS_HW_BLOCK_SIZE;
for (i = 0; i < SSPP_MAX; i++) {
sde_cfg->demura_supported[i][0] = ~0x0;
sde_cfg->demura_supported[i][1] = ~0x0;
}
/* target specific settings */
if (IS_MSM8996_TARGET(hw_rev)) {
sde_cfg->perf.min_prefill_lines = 21;
set_bit(SDE_FEATURE_DECIMATION, sde_cfg->features);
clear_bit(SDE_FEATURE_COMBINED_ALPHA, sde_cfg->features);
clear_bit(SDE_FEATURE_HDR, sde_cfg->features);
clear_bit(SDE_FEATURE_DELAY_PRG_FETCH, sde_cfg->features);
clear_bit(SDE_FEATURE_SUI_MISR, sde_cfg->features);
clear_bit(SDE_FEATURE_SUI_BLENDSTAGE, sde_cfg->features);
clear_bit(SDE_FEATURE_SUI_NS_ALLOWED, sde_cfg->features);
} else if (IS_MSM8998_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_WB_UBWC, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 25;
sde_cfg->vbif_qos_nlvl = 4;
sde_cfg->ts_prefill_rev = 1;
set_bit(SDE_FEATURE_DECIMATION, sde_cfg->features);
clear_bit(SDE_FEATURE_COMBINED_ALPHA, sde_cfg->features);
clear_bit(SDE_FEATURE_DELAY_PRG_FETCH, sde_cfg->features);
clear_bit(SDE_FEATURE_SUI_MISR, sde_cfg->features);
clear_bit(SDE_FEATURE_SUI_BLENDSTAGE, sde_cfg->features);
clear_bit(SDE_FEATURE_SUI_NS_ALLOWED, sde_cfg->features);
} else if (IS_SDM845_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_WB_UBWC, sde_cfg->features);
set_bit(SDE_FEATURE_CWB, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 24;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
sde_cfg->sui_block_xin_mask = 0x3F71;
set_bit(SDE_FEATURE_DECIMATION, sde_cfg->features);
set_bit(SDE_FEATURE_VIG_P010, sde_cfg->features);
clear_bit(SDE_FEATURE_DELAY_PRG_FETCH, sde_cfg->features);
clear_bit(SDE_FEATURE_SUI_BLENDSTAGE, sde_cfg->features);
clear_bit(SDE_FEATURE_SUI_NS_ALLOWED, sde_cfg->features);
} else if (IS_SDM670_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_WB_UBWC, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 24;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
set_bit(SDE_FEATURE_DECIMATION, sde_cfg->features);
set_bit(SDE_FEATURE_VIG_P010, sde_cfg->features);
clear_bit(SDE_FEATURE_DELAY_PRG_FETCH, sde_cfg->features);
clear_bit(SDE_FEATURE_SUI_MISR, sde_cfg->features);
clear_bit(SDE_FEATURE_SUI_BLENDSTAGE, sde_cfg->features);
clear_bit(SDE_FEATURE_SUI_NS_ALLOWED, sde_cfg->features);
} else if (IS_SM8150_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_CWB, sde_cfg->features);
set_bit(SDE_FEATURE_WB_UBWC, sde_cfg->features);
set_bit(SDE_FEATURE_QSYNC, sde_cfg->features);
set_bit(SDE_FEATURE_HDR_PLUS, sde_cfg->features);
set_bit(SDE_MDP_DHDR_MEMPOOL, &sde_cfg->mdp[0].features);
set_bit(SDE_FEATURE_VIG_P010, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 24;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
sde_cfg->sui_block_xin_mask = 0x3F71;
set_bit(SDE_FEATURE_3D_MERGE_RESET, sde_cfg->features);
set_bit(SDE_FEATURE_DECIMATION, sde_cfg->features);
set_bit(SDE_FEATURE_VBIF_DISABLE_SHAREABLE, sde_cfg->features);
} else if (IS_SDMSHRIKE_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_WB_UBWC, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 24;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
set_bit(SDE_FEATURE_DECIMATION, sde_cfg->features);
set_bit(SDE_FEATURE_VIG_P010, sde_cfg->features);
clear_bit(SDE_FEATURE_SUI_MISR, sde_cfg->features);
clear_bit(SDE_FEATURE_SUI_BLENDSTAGE, sde_cfg->features);
clear_bit(SDE_FEATURE_SUI_NS_ALLOWED, sde_cfg->features);
} else if (IS_SM6150_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_CWB, sde_cfg->features);
set_bit(SDE_FEATURE_QSYNC, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 24;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
set_bit(SDE_FEATURE_DECIMATION, sde_cfg->features);
sde_cfg->sui_block_xin_mask = 0x2EE1;
set_bit(SDE_FEATURE_3D_MERGE_RESET, sde_cfg->features);
set_bit(SDE_FEATURE_VIG_P010, sde_cfg->features);
set_bit(SDE_FEATURE_VBIF_DISABLE_SHAREABLE, sde_cfg->features);
} else if (IS_SDMMAGPIE_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_CWB, sde_cfg->features);
set_bit(SDE_FEATURE_WB_UBWC, sde_cfg->features);
set_bit(SDE_FEATURE_QSYNC, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 24;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
clear_bit(SDE_FEATURE_HDR, sde_cfg->features);
sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
sde_cfg->sui_block_xin_mask = 0xE71;
set_bit(SDE_FEATURE_3D_MERGE_RESET, sde_cfg->features);
set_bit(SDE_FEATURE_VBIF_DISABLE_SHAREABLE, sde_cfg->features);
} else if (IS_KONA_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_CWB, sde_cfg->features);
set_bit(SDE_FEATURE_WB_UBWC, sde_cfg->features);
set_bit(SDE_FEATURE_QSYNC, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 35;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
sde_cfg->sui_block_xin_mask = 0x3F71;
set_bit(SDE_FEATURE_3D_MERGE_RESET, sde_cfg->features);
set_bit(SDE_FEATURE_HDR_PLUS, sde_cfg->features);
set_bit(SDE_MDP_DHDR_MEMPOOL, &sde_cfg->mdp[0].features);
set_bit(SDE_FEATURE_VIG_P010, sde_cfg->features);
sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_1_0_0;
sde_cfg->uidle_cfg.uidle_rev = SDE_UIDLE_VERSION_1_0_0;
set_bit(SDE_FEATURE_INLINE_DISABLE_CONST_CLR, sde_cfg->features);
} else if (IS_SAIPAN_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_CWB, sde_cfg->features);
set_bit(SDE_FEATURE_WB_UBWC, sde_cfg->features);
set_bit(SDE_FEATURE_QSYNC, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 40;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
sde_cfg->sui_block_xin_mask = 0xE71;
set_bit(SDE_FEATURE_3D_MERGE_RESET, sde_cfg->features);
set_bit(SDE_FEATURE_HDR_PLUS, sde_cfg->features);
set_bit(SDE_MDP_DHDR_MEMPOOL, &sde_cfg->mdp[0].features);
set_bit(SDE_FEATURE_VIG_P010, sde_cfg->features);
sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_1_0_0;
set_bit(SDE_FEATURE_INLINE_DISABLE_CONST_CLR, sde_cfg->features);
} else if (IS_SDMTRINKET_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_CWB, sde_cfg->features);
set_bit(SDE_FEATURE_QSYNC, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 24;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
sde_cfg->sui_block_xin_mask = 0xC61;
clear_bit(SDE_FEATURE_HDR, sde_cfg->features);
set_bit(SDE_FEATURE_VBIF_DISABLE_SHAREABLE, sde_cfg->features);
} else if (IS_BENGAL_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_QSYNC, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 24;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
sde_cfg->sui_block_xin_mask = 0xC01;
clear_bit(SDE_FEATURE_HDR, sde_cfg->features);
set_bit(SDE_FEATURE_VBIF_DISABLE_SHAREABLE, sde_cfg->features);
} else if (IS_LAGOON_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_CWB, sde_cfg->features);
set_bit(SDE_FEATURE_QSYNC, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 40;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
sde_cfg->sui_block_xin_mask = 0x261;
set_bit(SDE_FEATURE_VIG_P010, sde_cfg->features);
set_bit(SDE_FEATURE_VBIF_DISABLE_SHAREABLE, sde_cfg->features);
} else if (IS_SCUBA_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_QSYNC, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 24;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
sde_cfg->sui_block_xin_mask = 0x1;
clear_bit(SDE_FEATURE_HDR, sde_cfg->features);
} else if (IS_LAHAINA_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_DEMURA, sde_cfg->features);
sde_cfg->demura_supported[SSPP_DMA1][0] = 0;
sde_cfg->demura_supported[SSPP_DMA1][1] = 1;
sde_cfg->demura_supported[SSPP_DMA3][0] = 0;
sde_cfg->demura_supported[SSPP_DMA3][1] = 1;
set_bit(SDE_FEATURE_CWB, sde_cfg->features);
set_bit(SDE_FEATURE_WB_UBWC, sde_cfg->features);
set_bit(SDE_FEATURE_QSYNC, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 40;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
sde_cfg->sui_block_xin_mask = 0x3F71;
set_bit(SDE_FEATURE_3D_MERGE_RESET, sde_cfg->features);
set_bit(SDE_FEATURE_HDR_PLUS, sde_cfg->features);
set_bit(SDE_MDP_DHDR_MEMPOOL_4K, &sde_cfg->mdp[0].features);
set_bit(SDE_FEATURE_VIG_P010, sde_cfg->features);
sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_2_0_0;
sde_cfg->uidle_cfg.uidle_rev = SDE_UIDLE_VERSION_1_0_1;
set_bit(SDE_FEATURE_VBIF_DISABLE_SHAREABLE, sde_cfg->features);
set_bit(SDE_FEATURE_DITHER_LUMA_MODE, sde_cfg->features);
sde_cfg->mdss_hw_block_size = 0x158;
set_bit(SDE_FEATURE_TRUSTED_VM, sde_cfg->features);
set_bit(SDE_SYS_CACHE_DISP, sde_cfg->sde_sys_cache_type_map);
} else if (IS_HOLI_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_QSYNC, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 24;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
sde_cfg->sui_block_xin_mask = 0xC01;
clear_bit(SDE_FEATURE_HDR, sde_cfg->features);
set_bit(SDE_FEATURE_VBIF_DISABLE_SHAREABLE, sde_cfg->features);
sde_cfg->mdss_hw_block_size = 0x158;
set_bit(SDE_FEATURE_RC_LM_FLUSH_OVERRIDE, sde_cfg->features);
} else if (IS_SHIMA_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_CWB, sde_cfg->features);
set_bit(SDE_FEATURE_WB_UBWC, sde_cfg->features);
set_bit(SDE_FEATURE_QSYNC, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 35;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
sde_cfg->sui_block_xin_mask = 0xE71;
set_bit(SDE_FEATURE_3D_MERGE_RESET, sde_cfg->features);
set_bit(SDE_FEATURE_HDR_PLUS, sde_cfg->features);
set_bit(SDE_MDP_DHDR_MEMPOOL, &sde_cfg->mdp[0].features);
set_bit(SDE_FEATURE_VIG_P010, sde_cfg->features);
sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_1_0_0;
set_bit(SDE_FEATURE_INLINE_DISABLE_CONST_CLR, sde_cfg->features);
set_bit(SDE_FEATURE_VBIF_DISABLE_SHAREABLE, sde_cfg->features);
sde_cfg->mdss_hw_block_size = 0x158;
set_bit(SDE_FEATURE_TRUSTED_VM, sde_cfg->features);
set_bit(SDE_SYS_CACHE_DISP, sde_cfg->sde_sys_cache_type_map);
} else if (IS_WAIPIO_TARGET(hw_rev) || IS_CAPE_TARGET(hw_rev)) {
sde_cfg->allowed_dsc_reservation_switch = SDE_DP_DSC_RESERVATION_SWITCH;
set_bit(SDE_FEATURE_DEDICATED_CWB, sde_cfg->features);
set_bit(SDE_FEATURE_CWB_DITHER, sde_cfg->features);
set_bit(SDE_FEATURE_WB_UBWC, sde_cfg->features);
set_bit(SDE_FEATURE_CWB_CROP, sde_cfg->features);
set_bit(SDE_FEATURE_QSYNC, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 40;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
set_bit(SDE_FEATURE_3D_MERGE_RESET, sde_cfg->features);
set_bit(SDE_FEATURE_HDR_PLUS, sde_cfg->features);
set_bit(SDE_FEATURE_INLINE_SKIP_THRESHOLD, sde_cfg->features);
set_bit(SDE_MDP_DHDR_MEMPOOL_4K, &sde_cfg->mdp[0].features);
set_bit(SDE_FEATURE_VIG_P010, sde_cfg->features);
sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_2_0_1;
sde_cfg->uidle_cfg.uidle_rev = SDE_UIDLE_VERSION_1_0_2;
set_bit(SDE_FEATURE_VBIF_DISABLE_SHAREABLE, sde_cfg->features);
set_bit(SDE_FEATURE_DITHER_LUMA_MODE, sde_cfg->features);
sde_cfg->mdss_hw_block_size = 0x158;
set_bit(SDE_SYS_CACHE_DISP, sde_cfg->sde_sys_cache_type_map);
set_bit(SDE_FEATURE_MULTIRECT_ERROR, sde_cfg->features);
set_bit(SDE_FEATURE_FP16, sde_cfg->features);
set_bit(SDE_MDP_PERIPH_TOP_0_REMOVED, &sde_cfg->mdp[0].features);
set_bit(SDE_FEATURE_DEMURA, sde_cfg->features);
sde_cfg->demura_supported[SSPP_DMA1][0] = 0;
sde_cfg->demura_supported[SSPP_DMA1][1] = 1;
sde_cfg->demura_supported[SSPP_DMA3][0] = 0;
sde_cfg->demura_supported[SSPP_DMA3][1] = 1;
set_bit(SDE_FEATURE_UBWC_STATS, sde_cfg->features);
set_bit(SDE_FEATURE_HW_VSYNC_TS, sde_cfg->features);
set_bit(SDE_FEATURE_AVR_STEP, sde_cfg->features);
set_bit(SDE_FEATURE_TRUSTED_VM, sde_cfg->features);
} else if (IS_YUPIK_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_CWB, sde_cfg->features);
set_bit(SDE_FEATURE_QSYNC, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 40;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
sde_cfg->sui_block_xin_mask = 0x261;
set_bit(SDE_FEATURE_3D_MERGE_RESET, sde_cfg->features);
set_bit(SDE_FEATURE_HDR_PLUS, sde_cfg->features);
set_bit(SDE_MDP_DHDR_MEMPOOL_4K, &sde_cfg->mdp[0].features);
set_bit(SDE_FEATURE_VIG_P010, sde_cfg->features);
sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_2_0_0;
set_bit(SDE_FEATURE_VBIF_DISABLE_SHAREABLE, sde_cfg->features);
set_bit(SDE_FEATURE_DITHER_LUMA_MODE, sde_cfg->features);
sde_cfg->mdss_hw_block_size = 0x158;
set_bit(SDE_FEATURE_RC_LM_FLUSH_OVERRIDE, sde_cfg->features);
} else if (IS_DIWALI_TARGET(hw_rev)) {
sde_cfg->allowed_dsc_reservation_switch = SDE_DP_DSC_RESERVATION_SWITCH;
set_bit(SDE_FEATURE_DEDICATED_CWB, sde_cfg->features);
set_bit(SDE_FEATURE_CWB_DITHER, sde_cfg->features);
set_bit(SDE_FEATURE_WB_UBWC, sde_cfg->features);
set_bit(SDE_FEATURE_CWB_CROP, sde_cfg->features);
set_bit(SDE_FEATURE_QSYNC, sde_cfg->features);
sde_cfg->perf.min_prefill_lines = 40;
sde_cfg->has_reduced_ob_max = true;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
set_bit(SDE_FEATURE_3D_MERGE_RESET, sde_cfg->features);
set_bit(SDE_FEATURE_HDR_PLUS, sde_cfg->features);
set_bit(SDE_FEATURE_INLINE_SKIP_THRESHOLD, sde_cfg->features);
set_bit(SDE_MDP_DHDR_MEMPOOL_4K, &sde_cfg->mdp[0].features);
set_bit(SDE_FEATURE_VIG_P010, sde_cfg->features);
sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_2_0_1;
set_bit(SDE_FEATURE_VBIF_DISABLE_SHAREABLE, sde_cfg->features);
set_bit(SDE_FEATURE_DITHER_LUMA_MODE, sde_cfg->features);
sde_cfg->mdss_hw_block_size = 0x158;
set_bit(SDE_SYS_CACHE_DISP, sde_cfg->sde_sys_cache_type_map);
set_bit(SDE_FEATURE_MULTIRECT_ERROR, sde_cfg->features);
set_bit(SDE_FEATURE_FP16, sde_cfg->features);
set_bit(SDE_MDP_PERIPH_TOP_0_REMOVED, &sde_cfg->mdp[0].features);
set_bit(SDE_FEATURE_HW_VSYNC_TS, sde_cfg->features);
set_bit(SDE_FEATURE_AVR_STEP, sde_cfg->features);
set_bit(SDE_FEATURE_TRUSTED_VM, sde_cfg->features);
set_bit(SDE_FEATURE_UBWC_STATS, sde_cfg->features);
set_bit(SDE_FEATURE_DEMURA, sde_cfg->features);
sde_cfg->demura_supported[SSPP_DMA1][0] = 0;
sde_cfg->demura_supported[SSPP_DMA1][1] = 1;
} else if (IS_KALAMA_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_DEDICATED_CWB, sde_cfg->features);
set_bit(SDE_FEATURE_CWB_DITHER, sde_cfg->features);
set_bit(SDE_FEATURE_WB_UBWC, sde_cfg->features);
set_bit(SDE_FEATURE_CWB_CROP, sde_cfg->features);
set_bit(SDE_FEATURE_QSYNC, sde_cfg->features);
set_bit(SDE_FEATURE_3D_MERGE_RESET, sde_cfg->features);
set_bit(SDE_FEATURE_HDR_PLUS, sde_cfg->features);
set_bit(SDE_FEATURE_INLINE_SKIP_THRESHOLD, sde_cfg->features);
set_bit(SDE_MDP_DHDR_MEMPOOL_4K, &sde_cfg->mdp[0].features);
set_bit(SDE_FEATURE_VIG_P010, sde_cfg->features);
set_bit(SDE_FEATURE_VBIF_DISABLE_SHAREABLE, sde_cfg->features);
set_bit(SDE_FEATURE_DITHER_LUMA_MODE, sde_cfg->features);
set_bit(SDE_FEATURE_MULTIRECT_ERROR, sde_cfg->features);
set_bit(SDE_FEATURE_FP16, sde_cfg->features);
set_bit(SDE_MDP_PERIPH_TOP_0_REMOVED, &sde_cfg->mdp[0].features);
set_bit(SDE_FEATURE_DEMURA, sde_cfg->features);
set_bit(SDE_FEATURE_UBWC_STATS, sde_cfg->features);
set_bit(SDE_FEATURE_HW_VSYNC_TS, sde_cfg->features);
set_bit(SDE_FEATURE_AVR_STEP, sde_cfg->features);
set_bit(SDE_FEATURE_VBIF_CLK_SPLIT, sde_cfg->features);
set_bit(SDE_FEATURE_CTL_DONE, sde_cfg->features);
set_bit(SDE_FEATURE_TRUSTED_VM, sde_cfg->features);
set_bit(SDE_SYS_CACHE_DISP, sde_cfg->sde_sys_cache_type_map);
set_bit(SDE_SYS_CACHE_DISP_1, sde_cfg->sde_sys_cache_type_map);
set_bit(SDE_SYS_CACHE_DISP_WB, sde_cfg->sde_sys_cache_type_map);
set_bit(SDE_FEATURE_SYS_CACHE_NSE, sde_cfg->features);
sde_cfg->allowed_dsc_reservation_switch = SDE_DP_DSC_RESERVATION_SWITCH;
sde_cfg->autorefresh_disable_seq = AUTOREFRESH_DISABLE_SEQ2;
sde_cfg->perf.min_prefill_lines = 40;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->qos_target_time_ns = 11160;
sde_cfg->ts_prefill_rev = 2;
sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_2_0_1;
sde_cfg->uidle_cfg.uidle_rev = SDE_UIDLE_VERSION_1_0_3;
sde_cfg->sid_rev = SDE_SID_VERSION_2_0_0;
sde_cfg->mdss_hw_block_size = 0x158;
sde_cfg->demura_supported[SSPP_DMA1][0] = 0;
sde_cfg->demura_supported[SSPP_DMA1][1] = 1;
sde_cfg->demura_supported[SSPP_DMA3][0] = 0;
sde_cfg->demura_supported[SSPP_DMA3][1] = 1;
sde_cfg->has_line_insertion = true;
} else if (IS_PINEAPPLE_TARGET(hw_rev)) {
set_bit(SDE_FEATURE_DEDICATED_CWB, sde_cfg->features);
set_bit(SDE_FEATURE_CWB_DITHER, sde_cfg->features);
set_bit(SDE_FEATURE_WB_UBWC, sde_cfg->features);
set_bit(SDE_FEATURE_CWB_CROP, sde_cfg->features);
set_bit(SDE_FEATURE_QSYNC, sde_cfg->features);
set_bit(SDE_FEATURE_3D_MERGE_RESET, sde_cfg->features);
set_bit(SDE_FEATURE_HDR_PLUS, sde_cfg->features);
set_bit(SDE_FEATURE_INLINE_SKIP_THRESHOLD, sde_cfg->features);
set_bit(SDE_MDP_DHDR_MEMPOOL_4K, &sde_cfg->mdp[0].features);
set_bit(SDE_FEATURE_VIG_P010, sde_cfg->features);
set_bit(SDE_FEATURE_VBIF_DISABLE_SHAREABLE, sde_cfg->features);
set_bit(SDE_FEATURE_DITHER_LUMA_MODE, sde_cfg->features);
set_bit(SDE_FEATURE_MULTIRECT_ERROR, sde_cfg->features);
set_bit(SDE_FEATURE_FP16, sde_cfg->features);
set_bit(SDE_MDP_PERIPH_TOP_0_REMOVED, &sde_cfg->mdp[0].features);
set_bit(SDE_FEATURE_DEMURA, sde_cfg->features);
set_bit(SDE_FEATURE_UBWC_STATS, sde_cfg->features);
set_bit(SDE_FEATURE_HW_VSYNC_TS, sde_cfg->features);
set_bit(SDE_FEATURE_AVR_STEP, sde_cfg->features);
set_bit(SDE_FEATURE_VBIF_CLK_SPLIT, sde_cfg->features);
set_bit(SDE_FEATURE_CTL_DONE, sde_cfg->features);
set_bit(SDE_FEATURE_TRUSTED_VM, sde_cfg->features);
set_bit(SDE_SYS_CACHE_DISP, sde_cfg->sde_sys_cache_type_map);
set_bit(SDE_SYS_CACHE_DISP_WB, sde_cfg->sde_sys_cache_type_map);
sde_cfg->allowed_dsc_reservation_switch = SDE_DP_DSC_RESERVATION_SWITCH;
sde_cfg->autorefresh_disable_seq = AUTOREFRESH_DISABLE_SEQ2;
sde_cfg->perf.min_prefill_lines = 40;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->qos_target_time_ns = 11160;
sde_cfg->ts_prefill_rev = 2;
sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_2_0_1;
sde_cfg->sid_rev = SDE_SID_VERSION_2_0_0;
sde_cfg->mdss_hw_block_size = 0x158;
sde_cfg->demura_supported[SSPP_DMA1][0] = 0;
sde_cfg->demura_supported[SSPP_DMA1][1] = 1;
sde_cfg->demura_supported[SSPP_DMA3][0] = 0;
sde_cfg->demura_supported[SSPP_DMA3][1] = 1;
sde_cfg->has_line_insertion = true;
} else {
SDE_ERROR("unsupported chipset id:%X\n", hw_rev);
sde_cfg->perf.min_prefill_lines = 0xffff;
rc = -ENODEV;
}
if (!rc)
rc = sde_hardware_format_caps(sde_cfg, hw_rev);
_sde_hw_setup_uidle(&sde_cfg->uidle_cfg);
return rc;
}
static int _sde_hw_dnsc_blur_filter_caps(struct sde_mdss_cfg *sde_cfg)
{
const struct sde_dnsc_blur_filter_info *filters = NULL;
u32 size;
int rc = 0;
if (!sde_cfg->dnsc_blur_count || !sde_cfg->dnsc_blur_rev)
return 0;
if (IS_SDE_DNSC_BLUR_REV_100(sde_cfg->dnsc_blur_rev)) {
filters = dnsc_blur_v100_filters;
size = ARRAY_SIZE(dnsc_blur_v100_filters);
}
if (filters) {
sde_cfg->dnsc_blur_filters = kcalloc(size,
sizeof(struct sde_dnsc_blur_filter_info), GFP_KERNEL);
if (!sde_cfg->dnsc_blur_filters) {
SDE_ERROR("failed to alloc dnsc_blur filter list\n");
rc = -ENOMEM;
goto end;
}
memcpy(sde_cfg->dnsc_blur_filters, filters,
sizeof(struct sde_dnsc_blur_filter_info) * size);
sde_cfg->dnsc_blur_filter_count = size;
}
end:
return rc;
}
static void _sde_hw_fence_caps(struct sde_mdss_cfg *sde_cfg)
{
struct sde_ctl_cfg *ctl;
int i;
if (!sde_cfg->hw_fence_rev)
return;
set_bit(SDE_FEATURE_HW_FENCE_IPCC, sde_cfg->features);
for (i = 0; i < sde_cfg->ctl_count; i++) {
ctl = sde_cfg->ctl + i;
set_bit(SDE_CTL_HW_FENCE, &ctl->features);
}
}
static int _sde_hardware_post_caps(struct sde_mdss_cfg *sde_cfg,
uint32_t hw_rev)
{
int rc = 0, i;
u32 max_horz_deci = 0, max_vert_deci = 0;
if (!sde_cfg)
return -EINVAL;
if (test_bit(SDE_FEATURE_SUI_BLENDSTAGE, sde_cfg->features))
sde_cfg->sui_supported_blendstage = sde_cfg->max_mixer_blendstages - SDE_STAGE_0;
for (i = 0; i < sde_cfg->sspp_count; i++) {
if (sde_cfg->sspp[i].sblk) {
max_horz_deci = max(max_horz_deci,
sde_cfg->sspp[i].sblk->maxhdeciexp);
max_vert_deci = max(max_vert_deci,
sde_cfg->sspp[i].sblk->maxvdeciexp);
}
/*
* set sec-ui blocked SSPP feature flag based on blocked
* xin-mask if sec-ui-misr feature is enabled;
*/
if (test_bit(SDE_FEATURE_SUI_MISR, sde_cfg->features) &&
(sde_cfg->sui_block_xin_mask & BIT(sde_cfg->sspp[i].xin_id)))
set_bit(SDE_SSPP_BLOCK_SEC_UI, &sde_cfg->sspp[i].features);
}
if (max_horz_deci)
sde_cfg->max_display_width = sde_cfg->max_sspp_linewidth *
max_horz_deci;
else
sde_cfg->max_display_width = sde_cfg->max_sspp_linewidth *
MAX_DOWNSCALE_RATIO;
if (max_vert_deci)
sde_cfg->max_display_height =
MAX_DISPLAY_HEIGHT_WITH_DECIMATION * max_vert_deci;
else
sde_cfg->max_display_height = MAX_DISPLAY_HEIGHT_WITH_DECIMATION
* MAX_DOWNSCALE_RATIO;
sde_cfg->min_display_height = MIN_DISPLAY_HEIGHT;
sde_cfg->min_display_width = MIN_DISPLAY_WIDTH;
sde_cfg->max_cwb = min_t(u32, sde_cfg->wb_count, MAX_CWB_SESSIONS);
_sde_hw_fence_caps(sde_cfg);
rc = _sde_hw_dnsc_blur_filter_caps(sde_cfg);
return rc;
}
void sde_hw_catalog_deinit(struct sde_mdss_cfg *sde_cfg)
{
int i, j;
if (!sde_cfg)
return;
sde_hw_catalog_irq_offset_list_delete(&sde_cfg->irq_offset_list);
for (i = 0; i < sde_cfg->sspp_count; i++)
kfree(sde_cfg->sspp[i].sblk);
for (i = 0; i < sde_cfg->mixer_count; i++)
kfree(sde_cfg->mixer[i].sblk);
for (i = 0; i < sde_cfg->wb_count; i++)
kfree(sde_cfg->wb[i].sblk);
for (i = 0; i < sde_cfg->dspp_count; i++)
kfree(sde_cfg->dspp[i].sblk);
if (sde_cfg->ds_count)
kfree(sde_cfg->ds[0].top);
for (i = 0; i < sde_cfg->pingpong_count; i++)
kfree(sde_cfg->pingpong[i].sblk);
for (i = 0; i < sde_cfg->vdc_count; i++)
kfree(sde_cfg->vdc[i].sblk);
for (i = 0; i < sde_cfg->dnsc_blur_count; i++)
kfree(sde_cfg->dnsc_blur[i].sblk);
for (i = 0; i < sde_cfg->vbif_count; i++) {
kfree(sde_cfg->vbif[i].dynamic_ot_rd_tbl.cfg);
kfree(sde_cfg->vbif[i].dynamic_ot_wr_tbl.cfg);
for (j = VBIF_RT_CLIENT; j < VBIF_MAX_CLIENT; j++)
kfree(sde_cfg->vbif[i].qos_tbl[j].priority_lvl);
}
kfree(sde_cfg->perf.qos_refresh_rate);
kfree(sde_cfg->perf.danger_lut);
kfree(sde_cfg->perf.safe_lut);
kfree(sde_cfg->perf.creq_lut);
kfree(sde_cfg->dma_formats);
kfree(sde_cfg->vig_formats);
kfree(sde_cfg->wb_formats);
kfree(sde_cfg->virt_vig_formats);
kfree(sde_cfg->inline_rot_formats);
kfree(sde_cfg->dnsc_blur_filters);
kfree(sde_cfg);
}
static int sde_hw_ver_parse_dt(struct drm_device *dev, struct device_node *np,
struct sde_mdss_cfg *cfg)
{
int rc, len, prop_count[SDE_HW_PROP_MAX];
struct sde_prop_value *prop_value = NULL;
bool prop_exists[SDE_HW_PROP_MAX];
if (!cfg) {
SDE_ERROR("invalid argument\n");
return -EINVAL;
}
prop_value = kzalloc(SDE_HW_PROP_MAX *
sizeof(struct sde_prop_value), GFP_KERNEL);
if (!prop_value)
return -ENOMEM;
rc = _validate_dt_entry(np, sde_hw_prop, ARRAY_SIZE(sde_hw_prop),
prop_count, &len);
if (rc)
goto end;
rc = _read_dt_entry(np, sde_hw_prop, ARRAY_SIZE(sde_hw_prop),
prop_count, prop_exists, prop_value);
if (rc)
goto end;
if (prop_exists[SDE_HW_VERSION])
cfg->hw_rev = PROP_VALUE_ACCESS(prop_value, SDE_HW_VERSION, 0);
else
cfg->hw_rev = sde_kms_get_hw_version(dev);
if (prop_exists[SDE_HW_FENCE_VERSION])
cfg->hw_fence_rev = PROP_VALUE_ACCESS(prop_value, SDE_HW_FENCE_VERSION, 0);
else
cfg->hw_fence_rev = 0; /* disable hw-fences */
end:
kfree(prop_value);
return rc;
}
/*************************************************************
* hardware catalog init
*************************************************************/
struct sde_mdss_cfg *sde_hw_catalog_init(struct drm_device *dev)
{
int rc;
struct sde_mdss_cfg *sde_cfg;
struct device_node *np = dev->dev->of_node;
if (!np)
return ERR_PTR(-EINVAL);
sde_cfg = kzalloc(sizeof(*sde_cfg), GFP_KERNEL);
if (!sde_cfg)
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&sde_cfg->irq_offset_list);
rc = sde_hw_ver_parse_dt(dev, np, sde_cfg);
if (rc)
goto end;
rc = _sde_hardware_pre_caps(sde_cfg, sde_cfg->hw_rev);
if (rc)
goto end;
rc = sde_top_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = sde_perf_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = sde_qos_parse_dt(np, sde_cfg);
if (rc)
goto end;
/* uidle must be done before sspp and ctl,
* so if something goes wrong, we won't
* enable it in ctl and sspp.
*/
rc = sde_uidle_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = sde_cache_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = sde_ctl_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = sde_sspp_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = sde_dspp_top_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = sde_dspp_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = sde_ds_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = sde_dsc_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = sde_vdc_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = sde_pp_parse_dt(np, sde_cfg);
if (rc)
goto end;
/* mixer parsing should be done after dspp,
* ds and pp for mapping setup
*/
rc = sde_mixer_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = sde_intf_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = sde_wb_parse_dt(np, sde_cfg);
if (rc)
goto end;
/* cdm parsing should be done after intf and wb for mapping setup */
rc = sde_cdm_parse_dt(np, sde_cfg);
if (rc)
goto end;
/* dnsc_blur parsing should be done after wb for mapping setup */
rc = sde_dnsc_blur_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = sde_vbif_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = sde_parse_reg_dma_dt(np, sde_cfg);
if (rc)
goto end;
rc = sde_parse_merge_3d_dt(np, sde_cfg);
if (rc)
goto end;
rc = sde_qdss_parse_dt(np, sde_cfg);
if (rc)
goto end;
rc = _sde_hardware_post_caps(sde_cfg, sde_cfg->hw_rev);
if (rc)
goto end;
return sde_cfg;
end:
sde_hw_catalog_deinit(sde_cfg);
return NULL;
}