Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
0004  * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
0005  */
0006 
0007 #include "dpu_kms.h"
0008 #include "dpu_hw_catalog.h"
0009 #include "dpu_hwio.h"
0010 #include "dpu_hw_lm.h"
0011 #include "dpu_hw_mdss.h"
0012 
0013 #define LM_OP_MODE                        0x00
0014 #define LM_OUT_SIZE                       0x04
0015 #define LM_BORDER_COLOR_0                 0x08
0016 #define LM_BORDER_COLOR_1                 0x010
0017 
0018 /* These register are offset to mixer base + stage base */
0019 #define LM_BLEND0_OP                     0x00
0020 #define LM_BLEND0_CONST_ALPHA            0x04
0021 #define LM_FG_COLOR_FILL_COLOR_0         0x08
0022 #define LM_FG_COLOR_FILL_COLOR_1         0x0C
0023 #define LM_FG_COLOR_FILL_SIZE            0x10
0024 #define LM_FG_COLOR_FILL_XY              0x14
0025 
0026 #define LM_BLEND0_FG_ALPHA               0x04
0027 #define LM_BLEND0_BG_ALPHA               0x08
0028 
0029 #define LM_MISR_CTRL                     0x310
0030 #define LM_MISR_SIGNATURE                0x314
0031 
0032 
0033 static const struct dpu_lm_cfg *_lm_offset(enum dpu_lm mixer,
0034         const struct dpu_mdss_cfg *m,
0035         void __iomem *addr,
0036         struct dpu_hw_blk_reg_map *b)
0037 {
0038     int i;
0039 
0040     for (i = 0; i < m->mixer_count; i++) {
0041         if (mixer == m->mixer[i].id) {
0042             b->blk_addr = addr + m->mixer[i].base;
0043             b->log_mask = DPU_DBG_MASK_LM;
0044             return &m->mixer[i];
0045         }
0046     }
0047 
0048     return ERR_PTR(-ENOMEM);
0049 }
0050 
0051 /**
0052  * _stage_offset(): returns the relative offset of the blend registers
0053  * for the stage to be setup
0054  * @ctx:     mixer ctx contains the mixer to be programmed
0055  * @stage: stage index to setup
0056  */
0057 static inline int _stage_offset(struct dpu_hw_mixer *ctx, enum dpu_stage stage)
0058 {
0059     const struct dpu_lm_sub_blks *sblk = ctx->cap->sblk;
0060     if (stage != DPU_STAGE_BASE && stage <= sblk->maxblendstages)
0061         return sblk->blendstage_base[stage - DPU_STAGE_0];
0062 
0063     return -EINVAL;
0064 }
0065 
0066 static void dpu_hw_lm_setup_out(struct dpu_hw_mixer *ctx,
0067         struct dpu_hw_mixer_cfg *mixer)
0068 {
0069     struct dpu_hw_blk_reg_map *c = &ctx->hw;
0070     u32 outsize;
0071     u32 op_mode;
0072 
0073     op_mode = DPU_REG_READ(c, LM_OP_MODE);
0074 
0075     outsize = mixer->out_height << 16 | mixer->out_width;
0076     DPU_REG_WRITE(c, LM_OUT_SIZE, outsize);
0077 
0078     /* SPLIT_LEFT_RIGHT */
0079     if (mixer->right_mixer)
0080         op_mode |= BIT(31);
0081     else
0082         op_mode &= ~BIT(31);
0083     DPU_REG_WRITE(c, LM_OP_MODE, op_mode);
0084 }
0085 
0086 static void dpu_hw_lm_setup_border_color(struct dpu_hw_mixer *ctx,
0087         struct dpu_mdss_color *color,
0088         u8 border_en)
0089 {
0090     struct dpu_hw_blk_reg_map *c = &ctx->hw;
0091 
0092     if (border_en) {
0093         DPU_REG_WRITE(c, LM_BORDER_COLOR_0,
0094             (color->color_0 & 0xFFF) |
0095             ((color->color_1 & 0xFFF) << 0x10));
0096         DPU_REG_WRITE(c, LM_BORDER_COLOR_1,
0097             (color->color_2 & 0xFFF) |
0098             ((color->color_3 & 0xFFF) << 0x10));
0099     }
0100 }
0101 
0102 static void dpu_hw_lm_setup_misr(struct dpu_hw_mixer *ctx, bool enable, u32 frame_count)
0103 {
0104     dpu_hw_setup_misr(&ctx->hw, LM_MISR_CTRL, enable, frame_count);
0105 }
0106 
0107 static int dpu_hw_lm_collect_misr(struct dpu_hw_mixer *ctx, u32 *misr_value)
0108 {
0109     return dpu_hw_collect_misr(&ctx->hw, LM_MISR_CTRL, LM_MISR_SIGNATURE, misr_value);
0110 }
0111 
0112 static void dpu_hw_lm_setup_blend_config_combined_alpha(struct dpu_hw_mixer *ctx,
0113     u32 stage, u32 fg_alpha, u32 bg_alpha, u32 blend_op)
0114 {
0115     struct dpu_hw_blk_reg_map *c = &ctx->hw;
0116     int stage_off;
0117     u32 const_alpha;
0118 
0119     if (stage == DPU_STAGE_BASE)
0120         return;
0121 
0122     stage_off = _stage_offset(ctx, stage);
0123     if (WARN_ON(stage_off < 0))
0124         return;
0125 
0126     const_alpha = (bg_alpha & 0xFF) | ((fg_alpha & 0xFF) << 16);
0127     DPU_REG_WRITE(c, LM_BLEND0_CONST_ALPHA + stage_off, const_alpha);
0128     DPU_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op);
0129 }
0130 
0131 static void dpu_hw_lm_setup_blend_config(struct dpu_hw_mixer *ctx,
0132     u32 stage, u32 fg_alpha, u32 bg_alpha, u32 blend_op)
0133 {
0134     struct dpu_hw_blk_reg_map *c = &ctx->hw;
0135     int stage_off;
0136 
0137     if (stage == DPU_STAGE_BASE)
0138         return;
0139 
0140     stage_off = _stage_offset(ctx, stage);
0141     if (WARN_ON(stage_off < 0))
0142         return;
0143 
0144     DPU_REG_WRITE(c, LM_BLEND0_FG_ALPHA + stage_off, fg_alpha);
0145     DPU_REG_WRITE(c, LM_BLEND0_BG_ALPHA + stage_off, bg_alpha);
0146     DPU_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op);
0147 }
0148 
0149 static void dpu_hw_lm_setup_color3(struct dpu_hw_mixer *ctx,
0150     uint32_t mixer_op_mode)
0151 {
0152     struct dpu_hw_blk_reg_map *c = &ctx->hw;
0153     int op_mode;
0154 
0155     /* read the existing op_mode configuration */
0156     op_mode = DPU_REG_READ(c, LM_OP_MODE);
0157 
0158     op_mode = (op_mode & (BIT(31) | BIT(30))) | mixer_op_mode;
0159 
0160     DPU_REG_WRITE(c, LM_OP_MODE, op_mode);
0161 }
0162 
0163 static void _setup_mixer_ops(const struct dpu_mdss_cfg *m,
0164         struct dpu_hw_lm_ops *ops,
0165         unsigned long features)
0166 {
0167     ops->setup_mixer_out = dpu_hw_lm_setup_out;
0168     if (test_bit(DPU_MIXER_COMBINED_ALPHA, &features))
0169         ops->setup_blend_config = dpu_hw_lm_setup_blend_config_combined_alpha;
0170     else
0171         ops->setup_blend_config = dpu_hw_lm_setup_blend_config;
0172     ops->setup_alpha_out = dpu_hw_lm_setup_color3;
0173     ops->setup_border_color = dpu_hw_lm_setup_border_color;
0174     ops->setup_misr = dpu_hw_lm_setup_misr;
0175     ops->collect_misr = dpu_hw_lm_collect_misr;
0176 }
0177 
0178 struct dpu_hw_mixer *dpu_hw_lm_init(enum dpu_lm idx,
0179         void __iomem *addr,
0180         const struct dpu_mdss_cfg *m)
0181 {
0182     struct dpu_hw_mixer *c;
0183     const struct dpu_lm_cfg *cfg;
0184 
0185     c = kzalloc(sizeof(*c), GFP_KERNEL);
0186     if (!c)
0187         return ERR_PTR(-ENOMEM);
0188 
0189     cfg = _lm_offset(idx, m, addr, &c->hw);
0190     if (IS_ERR_OR_NULL(cfg)) {
0191         kfree(c);
0192         return ERR_PTR(-EINVAL);
0193     }
0194 
0195     /* Assign ops */
0196     c->idx = idx;
0197     c->cap = cfg;
0198     _setup_mixer_ops(m, &c->ops, c->cap->features);
0199 
0200     return c;
0201 }
0202 
0203 void dpu_hw_lm_destroy(struct dpu_hw_mixer *lm)
0204 {
0205     kfree(lm);
0206 }