root/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _pingpong_offset
  2. dpu_hw_pp_setup_te_config
  3. dpu_hw_pp_poll_timeout_wr_ptr
  4. dpu_hw_pp_enable_te
  5. dpu_hw_pp_connect_external_te
  6. dpu_hw_pp_get_vsync_info
  7. dpu_hw_pp_get_line_count
  8. _setup_pingpong_ops
  9. dpu_hw_pingpong_init
  10. dpu_hw_pingpong_destroy

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
   3  */
   4 
   5 #include <linux/iopoll.h>
   6 
   7 #include "dpu_hw_mdss.h"
   8 #include "dpu_hwio.h"
   9 #include "dpu_hw_catalog.h"
  10 #include "dpu_hw_pingpong.h"
  11 #include "dpu_kms.h"
  12 #include "dpu_trace.h"
  13 
  14 #define PP_TEAR_CHECK_EN                0x000
  15 #define PP_SYNC_CONFIG_VSYNC            0x004
  16 #define PP_SYNC_CONFIG_HEIGHT           0x008
  17 #define PP_SYNC_WRCOUNT                 0x00C
  18 #define PP_VSYNC_INIT_VAL               0x010
  19 #define PP_INT_COUNT_VAL                0x014
  20 #define PP_SYNC_THRESH                  0x018
  21 #define PP_START_POS                    0x01C
  22 #define PP_RD_PTR_IRQ                   0x020
  23 #define PP_WR_PTR_IRQ                   0x024
  24 #define PP_OUT_LINE_COUNT               0x028
  25 #define PP_LINE_COUNT                   0x02C
  26 
  27 #define PP_FBC_MODE                     0x034
  28 #define PP_FBC_BUDGET_CTL               0x038
  29 #define PP_FBC_LOSSY_MODE               0x03C
  30 
  31 static struct dpu_pingpong_cfg *_pingpong_offset(enum dpu_pingpong pp,
  32                 struct dpu_mdss_cfg *m,
  33                 void __iomem *addr,
  34                 struct dpu_hw_blk_reg_map *b)
  35 {
  36         int i;
  37 
  38         for (i = 0; i < m->pingpong_count; i++) {
  39                 if (pp == m->pingpong[i].id) {
  40                         b->base_off = addr;
  41                         b->blk_off = m->pingpong[i].base;
  42                         b->length = m->pingpong[i].len;
  43                         b->hwversion = m->hwversion;
  44                         b->log_mask = DPU_DBG_MASK_PINGPONG;
  45                         return &m->pingpong[i];
  46                 }
  47         }
  48 
  49         return ERR_PTR(-EINVAL);
  50 }
  51 
  52 static int dpu_hw_pp_setup_te_config(struct dpu_hw_pingpong *pp,
  53                 struct dpu_hw_tear_check *te)
  54 {
  55         struct dpu_hw_blk_reg_map *c;
  56         int cfg;
  57 
  58         if (!pp || !te)
  59                 return -EINVAL;
  60         c = &pp->hw;
  61 
  62         cfg = BIT(19); /*VSYNC_COUNTER_EN */
  63         if (te->hw_vsync_mode)
  64                 cfg |= BIT(20);
  65 
  66         cfg |= te->vsync_count;
  67 
  68         DPU_REG_WRITE(c, PP_SYNC_CONFIG_VSYNC, cfg);
  69         DPU_REG_WRITE(c, PP_SYNC_CONFIG_HEIGHT, te->sync_cfg_height);
  70         DPU_REG_WRITE(c, PP_VSYNC_INIT_VAL, te->vsync_init_val);
  71         DPU_REG_WRITE(c, PP_RD_PTR_IRQ, te->rd_ptr_irq);
  72         DPU_REG_WRITE(c, PP_START_POS, te->start_pos);
  73         DPU_REG_WRITE(c, PP_SYNC_THRESH,
  74                         ((te->sync_threshold_continue << 16) |
  75                          te->sync_threshold_start));
  76         DPU_REG_WRITE(c, PP_SYNC_WRCOUNT,
  77                         (te->start_pos + te->sync_threshold_start + 1));
  78 
  79         return 0;
  80 }
  81 
  82 static int dpu_hw_pp_poll_timeout_wr_ptr(struct dpu_hw_pingpong *pp,
  83                 u32 timeout_us)
  84 {
  85         struct dpu_hw_blk_reg_map *c;
  86         u32 val;
  87         int rc;
  88 
  89         if (!pp)
  90                 return -EINVAL;
  91 
  92         c = &pp->hw;
  93         rc = readl_poll_timeout(c->base_off + c->blk_off + PP_LINE_COUNT,
  94                         val, (val & 0xffff) >= 1, 10, timeout_us);
  95 
  96         return rc;
  97 }
  98 
  99 static int dpu_hw_pp_enable_te(struct dpu_hw_pingpong *pp, bool enable)
 100 {
 101         struct dpu_hw_blk_reg_map *c;
 102 
 103         if (!pp)
 104                 return -EINVAL;
 105         c = &pp->hw;
 106 
 107         DPU_REG_WRITE(c, PP_TEAR_CHECK_EN, enable);
 108         return 0;
 109 }
 110 
 111 static int dpu_hw_pp_connect_external_te(struct dpu_hw_pingpong *pp,
 112                 bool enable_external_te)
 113 {
 114         struct dpu_hw_blk_reg_map *c = &pp->hw;
 115         u32 cfg;
 116         int orig;
 117 
 118         if (!pp)
 119                 return -EINVAL;
 120 
 121         c = &pp->hw;
 122         cfg = DPU_REG_READ(c, PP_SYNC_CONFIG_VSYNC);
 123         orig = (bool)(cfg & BIT(20));
 124         if (enable_external_te)
 125                 cfg |= BIT(20);
 126         else
 127                 cfg &= ~BIT(20);
 128         DPU_REG_WRITE(c, PP_SYNC_CONFIG_VSYNC, cfg);
 129         trace_dpu_pp_connect_ext_te(pp->idx - PINGPONG_0, cfg);
 130 
 131         return orig;
 132 }
 133 
 134 static int dpu_hw_pp_get_vsync_info(struct dpu_hw_pingpong *pp,
 135                 struct dpu_hw_pp_vsync_info *info)
 136 {
 137         struct dpu_hw_blk_reg_map *c;
 138         u32 val;
 139 
 140         if (!pp || !info)
 141                 return -EINVAL;
 142         c = &pp->hw;
 143 
 144         val = DPU_REG_READ(c, PP_VSYNC_INIT_VAL);
 145         info->rd_ptr_init_val = val & 0xffff;
 146 
 147         val = DPU_REG_READ(c, PP_INT_COUNT_VAL);
 148         info->rd_ptr_frame_count = (val & 0xffff0000) >> 16;
 149         info->rd_ptr_line_count = val & 0xffff;
 150 
 151         val = DPU_REG_READ(c, PP_LINE_COUNT);
 152         info->wr_ptr_line_count = val & 0xffff;
 153 
 154         return 0;
 155 }
 156 
 157 static u32 dpu_hw_pp_get_line_count(struct dpu_hw_pingpong *pp)
 158 {
 159         struct dpu_hw_blk_reg_map *c = &pp->hw;
 160         u32 height, init;
 161         u32 line = 0xFFFF;
 162 
 163         if (!pp)
 164                 return 0;
 165         c = &pp->hw;
 166 
 167         init = DPU_REG_READ(c, PP_VSYNC_INIT_VAL) & 0xFFFF;
 168         height = DPU_REG_READ(c, PP_SYNC_CONFIG_HEIGHT) & 0xFFFF;
 169 
 170         if (height < init)
 171                 return line;
 172 
 173         line = DPU_REG_READ(c, PP_INT_COUNT_VAL) & 0xFFFF;
 174 
 175         if (line < init)
 176                 line += (0xFFFF - init);
 177         else
 178                 line -= init;
 179 
 180         return line;
 181 }
 182 
 183 static void _setup_pingpong_ops(struct dpu_hw_pingpong_ops *ops,
 184         const struct dpu_pingpong_cfg *hw_cap)
 185 {
 186         ops->setup_tearcheck = dpu_hw_pp_setup_te_config;
 187         ops->enable_tearcheck = dpu_hw_pp_enable_te;
 188         ops->connect_external_te = dpu_hw_pp_connect_external_te;
 189         ops->get_vsync_info = dpu_hw_pp_get_vsync_info;
 190         ops->poll_timeout_wr_ptr = dpu_hw_pp_poll_timeout_wr_ptr;
 191         ops->get_line_count = dpu_hw_pp_get_line_count;
 192 };
 193 
 194 static struct dpu_hw_blk_ops dpu_hw_ops;
 195 
 196 struct dpu_hw_pingpong *dpu_hw_pingpong_init(enum dpu_pingpong idx,
 197                 void __iomem *addr,
 198                 struct dpu_mdss_cfg *m)
 199 {
 200         struct dpu_hw_pingpong *c;
 201         struct dpu_pingpong_cfg *cfg;
 202 
 203         c = kzalloc(sizeof(*c), GFP_KERNEL);
 204         if (!c)
 205                 return ERR_PTR(-ENOMEM);
 206 
 207         cfg = _pingpong_offset(idx, m, addr, &c->hw);
 208         if (IS_ERR_OR_NULL(cfg)) {
 209                 kfree(c);
 210                 return ERR_PTR(-EINVAL);
 211         }
 212 
 213         c->idx = idx;
 214         c->caps = cfg;
 215         _setup_pingpong_ops(&c->ops, c->caps);
 216 
 217         dpu_hw_blk_init(&c->base, DPU_HW_BLK_PINGPONG, idx, &dpu_hw_ops);
 218 
 219         return c;
 220 }
 221 
 222 void dpu_hw_pingpong_destroy(struct dpu_hw_pingpong *pp)
 223 {
 224         if (pp)
 225                 dpu_hw_blk_destroy(&pp->base);
 226         kfree(pp);
 227 }

/* [<][>][^][v][top][bottom][index][help] */