/* 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 */