blob: 7d99fd9ed43befd796ae3e59149e8e70307b0fe4 [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
*/
#ifndef _SDE_ROTATOR_R3_INTERNAL_H
#define _SDE_ROTATOR_R3_INTERNAL_H
#include "sde_rotator_core.h"
struct sde_hw_rotator;
struct sde_hw_rotator_context;
/**
* Flags
*/
#define SDE_ROT_FLAG_SECURE_OVERLAY_SESSION 0x1
#define SDE_ROT_FLAG_FLIP_LR 0x2
#define SDE_ROT_FLAG_FLIP_UD 0x4
#define SDE_ROT_FLAG_SOURCE_ROTATED_90 0x8
#define SDE_ROT_FLAG_ROT_90 0x10
#define SDE_ROT_FLAG_DEINTERLACE 0x20
#define SDE_ROT_FLAG_SECURE_CAMERA_SESSION 0x40
/**
* General defines
*/
#define SDE_HW_ROT_REGDMA_RAM_SIZE 1024
#define SDE_HW_ROT_REGDMA_TOTAL_CTX 8
#define SDE_HW_ROT_REGDMA_SEG_MASK (SDE_HW_ROT_REGDMA_TOTAL_CTX - 1)
#define SDE_HW_ROT_REGDMA_SEG_SIZE \
(SDE_HW_ROT_REGDMA_RAM_SIZE / SDE_HW_ROT_REGDMA_TOTAL_CTX)
#define SDE_REGDMA_SWTS_MASK 0x00000FFF
#define SDE_REGDMA_SWTS_SHIFT 12
enum sde_rot_queue_prio {
ROT_QUEUE_HIGH_PRIORITY,
ROT_QUEUE_LOW_PRIORITY,
ROT_QUEUE_MAX
};
enum sde_rot_angle {
ROT_ANGLE_0,
ROT_ANGLE_90,
ROT_ANGEL_MAX
};
enum sde_rotator_regdma_mode {
ROT_REGDMA_OFF,
ROT_REGDMA_ON,
ROT_REGDMA_MAX
};
/**
* struct sde_hw_rot_sspp_cfg: Rotator SSPP Configration description
* @src: source surface information
* @src_rect: src ROI, caller takes into account the different operations
* such as decimation, flip etc to program this field
* @addr: source surface address
*/
struct sde_hw_rot_sspp_cfg {
struct sde_mdp_format_params *fmt;
struct sde_mdp_plane_sizes src_plane;
struct sde_rect *src_rect;
struct sde_mdp_data *data;
u32 img_width;
u32 img_height;
u32 fps;
u64 bw;
};
/**
* struct sde_hw_rot_wb_cfg: Rotator WB Configration description
* @dest: destination surface information
* @dest_rect: dest ROI, caller takes into account the different operations
* such as decimation, flip etc to program this field
* @addr: destination surface address
* @prefill_bw: prefill bandwidth in Bps
*/
struct sde_hw_rot_wb_cfg {
struct sde_mdp_format_params *fmt;
struct sde_mdp_plane_sizes dst_plane;
struct sde_rect *dst_rect;
struct sde_mdp_data *data;
u32 img_width;
u32 img_height;
u32 v_downscale_factor;
u32 h_downscale_factor;
u32 fps;
u64 bw;
u64 prefill_bw;
};
/**
*
* struct sde_hw_rotator_ops: Interface to the Rotator Hw driver functions
*
* Pre-requsises:
* - Caller must call the init function to get the rotator context
* - These functions will be called after clocks are enabled
*/
struct sde_hw_rotator_ops {
/**
* setup_rotator_fetchengine():
* Setup Source format
* Setup Source dimension/cropping rectangle (ROI)
* Setup Source surface base address and stride
* Setup fetch engine op mode (linear/tiled/compression/...)
* @ctx: Rotator context created in sde_hw_rotator_config
* @queue_id: Select either low / high priority queue
* @cfg: Rotator Fetch engine configuration parameters
* @danger_lut: Danger LUT setting
* @safe_lut: Safe LUT setting
* @dnsc_factor_w: Downscale factor for width
* @dnsc_factor_h: Downscale factor for height
* @flags: Specific config flag, see SDE_ROT_FLAG_ for details
*/
void (*setup_rotator_fetchengine)(
struct sde_hw_rotator_context *ctx,
enum sde_rot_queue_prio queue_id,
struct sde_hw_rot_sspp_cfg *cfg,
u32 danger_lut,
u32 safe_lut,
u32 dnsc_factor_w,
u32 dnsc_factor_h,
u32 flags);
/**
* setup_rotator_wbengine():
* Setup destination formats
* Setup destination dimension/cropping rectangle (ROI)
* Setup destination surface base address and strides
* Setup writeback engine op mode (linear/tiled/compression)
* @ctx: Rotator context created in sde_hw_rotator_config
* @queue_id: Select either low / high priority queue
* @cfg: Rotator WriteBack engine configuration parameters
* @flags: Specific config flag, see SDE_ROT_FLAG_ for details
*/
void (*setup_rotator_wbengine)(
struct sde_hw_rotator_context *ctx,
enum sde_rot_queue_prio queue_id,
struct sde_hw_rot_wb_cfg *cfg,
u32 flags);
/**
* start_rotator():
* Kick start rotator operation based on cached setup parameters
* REGDMA commands will get generated at this points
* @ctx: Rotator context
* @queue_id: Select either low / high priority queue
* Returns: unique job timestamp per submit. Used for tracking
* rotator finished job.
*/
u32 (*start_rotator)(
struct sde_hw_rotator_context *ctx,
enum sde_rot_queue_prio queue_id);
/**
* wait_rotator_done():
* Notify Rotator HAL layer previously submitted job finished.
* A job timestamp will return to caller.
* @ctx: Rotator context
* @flags: Reserved
* Returns: job timestamp for tracking purpose
*
*/
u32 (*wait_rotator_done)(
struct sde_hw_rotator_context *ctx,
enum sde_rot_queue_prio queue_id,
u32 flags);
/**
* get_pending_ts():
* Obtain current active timestamp from rotator hw
* @rot: HW Rotator structure
* @ctx: Rotator context
* @ts: current timestamp return from rot hw
* Returns: true if context has pending requests
*/
int (*get_pending_ts)(
struct sde_hw_rotator *rot,
struct sde_hw_rotator_context *ctx,
u32 *ts);
/**
* update_ts():
* Update rotator timestmap with given value
* @rot: HW Rotator structure
* @q_id: rotator queue id
* @ts: new timestamp for rotator
*/
void (*update_ts)(
struct sde_hw_rotator *rot,
u32 q_id,
u32 ts);
};
/**
* struct sde_dbg_buf : Debug buffer used by debugfs
* @vaddr: VA address mapped from dma buffer
* @dmabuf: DMA buffer
* @buflen: Length of DMA buffer
* @width: pixel width of buffer
* @height: pixel height of buffer
*/
struct sde_dbg_buf {
void *vaddr;
struct dma_buf *dmabuf;
unsigned long buflen;
u32 width;
u32 height;
};
/**
* struct sde_hw_rotator_context : Each rotator context ties to each priority
* queue. Max number of concurrent contexts in regdma is limited to regdma
* ram segment size allocation. Each rotator context can be any priority. A
* incremental timestamp is used to identify and assigned to each context.
* @list: list of pending context
* @sequence_id: unique sequence identifier for rotation request
* @sbuf_mode: true if stream buffer is requested
* @start_ctrl: start control register update value
* @sys_cache_mode: sys cache mode register update value
* @op_mode: rot top op mode selection
* @last_entry: pointer to last configured entry (for debugging purposes)
*/
struct sde_hw_rotator_context {
struct list_head list;
struct sde_hw_rotator *rot;
struct sde_rot_hw_resource *hwres;
enum sde_rot_queue_prio q_id;
u32 session_id;
u32 sequence_id;
char __iomem *regdma_base;
char __iomem *regdma_wrptr;
u32 timestamp;
struct completion rot_comp;
wait_queue_head_t regdma_waitq;
struct sde_dbg_buf src_dbgbuf;
struct sde_dbg_buf dst_dbgbuf;
u32 last_regdma_isr_status;
u32 last_regdma_timestamp;
dma_addr_t ts_addr;
bool is_secure;
bool is_traffic_shaping;
bool sbuf_mode;
bool abort;
u32 start_ctrl;
u32 sys_cache_mode;
u32 op_mode;
struct sde_rot_entry *last_entry;
};
/**
* struct sde_hw_rotator_resource_info : Each rotator resource ties to each
* priority queue
*/
struct sde_hw_rotator_resource_info {
struct sde_hw_rotator *rot;
struct sde_rot_hw_resource hw;
};
/**
* struct sde_hw_rotator : Rotator description
* @hw: mdp register mapped offset
* @ops: pointer to operations possible for the rotator HW
* @highest_bank: highest bank size of memory
* @ubwc_malsize: ubwc minimum allowable length
* @ubwc_swizzle: ubwc swizzle enable
* @sbuf_headroom: stream buffer headroom in lines
* @solid_fill: true if solid fill is requested
* @constant_color: solid fill constant color
* @sbuf_ctx: list of active sbuf context in FIFO order
* @vid_trigger: video mode trigger select
* @cmd_trigger: command mode trigger select
* @inpixfmts: array of supported input pixel formats fourcc per mode
* @num_inpixfmt: size of the supported input pixel format array per mode
* @outpixfmts: array of supported output pixel formats in fourcc per mode
* @num_outpixfmt: size of the supported output pixel formats array per mode
* @downscale_caps: capability string of scaling
* @maxlinewidth: maximum line width supported
*/
struct sde_hw_rotator {
/* base */
char __iomem *mdss_base;
/* Platform device from upper manager */
struct platform_device *pdev;
/* Ops */
struct sde_hw_rotator_ops ops;
/* Cmd Queue */
u32 cmd_queue[SDE_HW_ROT_REGDMA_RAM_SIZE];
/* Cmd Queue Write Ptr */
char __iomem *cmd_wr_ptr[ROT_QUEUE_MAX][SDE_HW_ROT_REGDMA_TOTAL_CTX];
/* Rotator Context */
struct sde_hw_rotator_context
*rotCtx[ROT_QUEUE_MAX][SDE_HW_ROT_REGDMA_TOTAL_CTX];
/* Cmd timestamp sequence for different priority*/
atomic_t timestamp[ROT_QUEUE_MAX];
/* regdma mode */
enum sde_rotator_regdma_mode mode;
/* logical interrupt number */
int irq_num;
atomic_t irq_enabled;
/* internal ION memory for SW timestamp */
struct ion_client *iclient;
struct sde_mdp_img_data swts_buf;
void *swts_buffer;
u32 highest_bank;
u32 ubwc_malsize;
u32 ubwc_swizzle;
u32 sbuf_headroom;
u32 solid_fill;
u32 constant_color;
spinlock_t rotctx_lock;
spinlock_t rotisr_lock;
bool dbgmem;
bool reset_hw_ts;
u32 last_hwts[ROT_QUEUE_MAX];
u32 koff_timeout;
u32 vid_trigger;
u32 cmd_trigger;
struct list_head sbuf_ctx[ROT_QUEUE_MAX];
const u32 *inpixfmts[SDE_ROTATOR_MODE_MAX];
u32 num_inpixfmt[SDE_ROTATOR_MODE_MAX];
const u32 *outpixfmts[SDE_ROTATOR_MODE_MAX];
u32 num_outpixfmt[SDE_ROTATOR_MODE_MAX];
const char *downscale_caps;
u32 maxlinewidth;
};
/**
* sde_hw_rotator_get_regdma_ctxidx(): regdma segment index is based on
* timestamp. For non-regdma, just return 0 (i.e. first index)
* @ctx: Rotator Context
* return: regdma segment index
*/
static inline u32 sde_hw_rotator_get_regdma_ctxidx(
struct sde_hw_rotator_context *ctx)
{
if (ctx->rot->mode == ROT_REGDMA_OFF)
return 0;
else
return ctx->timestamp & SDE_HW_ROT_REGDMA_SEG_MASK;
}
/**
* sde_hw_rotator_get_regdma_segment_base: return the base pointe of current
* regdma command buffer
* @ctx: Rotator Context
* return: base segment address
*/
static inline char __iomem *sde_hw_rotator_get_regdma_segment_base(
struct sde_hw_rotator_context *ctx)
{
SDEROT_DBG("regdma base @slot[%d]: %pK\n",
sde_hw_rotator_get_regdma_ctxidx(ctx),
ctx->regdma_base);
return ctx->regdma_base;
}
/**
* sde_hw_rotator_get_regdma_segment(): return current regdma command buffer
* pointer for current regdma segment.
* @ctx: Rotator Context
* return: segment address
*/
static inline char __iomem *sde_hw_rotator_get_regdma_segment(
struct sde_hw_rotator_context *ctx)
{
u32 idx = sde_hw_rotator_get_regdma_ctxidx(ctx);
char __iomem *addr = ctx->regdma_wrptr;
SDEROT_DBG("regdma slot[%d] ==> %pK\n", idx, addr);
return addr;
}
/**
* sde_hw_rotator_put_regdma_segment(): update current regdma command buffer
* pointer for current regdma segment
* @ctx: Rotator Context
* @wrptr: current regdma segment location
*/
static inline void sde_hw_rotator_put_regdma_segment(
struct sde_hw_rotator_context *ctx,
char __iomem *wrptr)
{
u32 idx = sde_hw_rotator_get_regdma_ctxidx(ctx);
ctx->regdma_wrptr = wrptr;
SDEROT_DBG("regdma slot[%d] <== %pK\n", idx, wrptr);
}
/**
* sde_hw_rotator_put_ctx(): Storing rotator context according to its
* timestamp.
*/
static inline void sde_hw_rotator_put_ctx(struct sde_hw_rotator_context *ctx)
{
struct sde_hw_rotator *rot = ctx->rot;
u32 idx = sde_hw_rotator_get_regdma_ctxidx(ctx);
unsigned long flags;
spin_lock_irqsave(&rot->rotisr_lock, flags);
rot->rotCtx[ctx->q_id][idx] = ctx;
if (ctx->sbuf_mode)
list_add_tail(&ctx->list, &rot->sbuf_ctx[ctx->q_id]);
spin_unlock_irqrestore(&rot->rotisr_lock, flags);
SDEROT_DBG("rotCtx[%d][%d] <== ctx:%pK | session-id:%d\n",
ctx->q_id, idx, ctx, ctx->session_id);
}
/**
* sde_hw_rotator_clr_ctx(): Clearing rotator context according to its
* timestamp.
*/
static inline void sde_hw_rotator_clr_ctx(struct sde_hw_rotator_context *ctx)
{
struct sde_hw_rotator *rot = ctx->rot;
u32 idx = sde_hw_rotator_get_regdma_ctxidx(ctx);
unsigned long flags;
spin_lock_irqsave(&rot->rotisr_lock, flags);
rot->rotCtx[ctx->q_id][idx] = NULL;
if (ctx->sbuf_mode)
list_del_init(&ctx->list);
spin_unlock_irqrestore(&rot->rotisr_lock, flags);
SDEROT_DBG("rotCtx[%d][%d] <== null | session-id:%d\n",
ctx->q_id, idx, ctx->session_id);
}
#endif /*_SDE_ROTATOR_R3_INTERNAL_H */