root/drivers/gpu/ipu-v3/ipu-dp.c

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

DEFINITIONS

This source file includes following definitions.
  1. to_flow
  2. ipu_dp_set_global_alpha
  3. ipu_dp_set_window_pos
  4. ipu_dp_csc_init
  5. ipu_dp_setup_channel
  6. ipu_dp_enable
  7. ipu_dp_enable_channel
  8. ipu_dp_disable_channel
  9. ipu_dp_disable
  10. ipu_dp_get
  11. ipu_dp_put
  12. ipu_dp_init
  13. ipu_dp_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
   4  * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
   5  */
   6 #include <linux/export.h>
   7 #include <linux/kernel.h>
   8 #include <linux/types.h>
   9 #include <linux/errno.h>
  10 #include <linux/io.h>
  11 #include <linux/err.h>
  12 
  13 #include <video/imx-ipu-v3.h>
  14 #include "ipu-prv.h"
  15 
  16 #define DP_SYNC 0
  17 #define DP_ASYNC0 0x60
  18 #define DP_ASYNC1 0xBC
  19 
  20 #define DP_COM_CONF             0x0
  21 #define DP_GRAPH_WIND_CTRL      0x0004
  22 #define DP_FG_POS               0x0008
  23 #define DP_CSC_A_0              0x0044
  24 #define DP_CSC_A_1              0x0048
  25 #define DP_CSC_A_2              0x004C
  26 #define DP_CSC_A_3              0x0050
  27 #define DP_CSC_0                0x0054
  28 #define DP_CSC_1                0x0058
  29 
  30 #define DP_COM_CONF_FG_EN               (1 << 0)
  31 #define DP_COM_CONF_GWSEL               (1 << 1)
  32 #define DP_COM_CONF_GWAM                (1 << 2)
  33 #define DP_COM_CONF_GWCKE               (1 << 3)
  34 #define DP_COM_CONF_CSC_DEF_MASK        (3 << 8)
  35 #define DP_COM_CONF_CSC_DEF_OFFSET      8
  36 #define DP_COM_CONF_CSC_DEF_FG          (3 << 8)
  37 #define DP_COM_CONF_CSC_DEF_BG          (2 << 8)
  38 #define DP_COM_CONF_CSC_DEF_BOTH        (1 << 8)
  39 
  40 #define IPUV3_NUM_FLOWS         3
  41 
  42 struct ipu_dp_priv;
  43 
  44 struct ipu_dp {
  45         u32 flow;
  46         bool in_use;
  47         bool foreground;
  48         enum ipu_color_space in_cs;
  49 };
  50 
  51 struct ipu_flow {
  52         struct ipu_dp foreground;
  53         struct ipu_dp background;
  54         enum ipu_color_space out_cs;
  55         void __iomem *base;
  56         struct ipu_dp_priv *priv;
  57 };
  58 
  59 struct ipu_dp_priv {
  60         struct ipu_soc *ipu;
  61         struct device *dev;
  62         void __iomem *base;
  63         struct ipu_flow flow[IPUV3_NUM_FLOWS];
  64         struct mutex mutex;
  65         int use_count;
  66 };
  67 
  68 static u32 ipu_dp_flow_base[] = {DP_SYNC, DP_ASYNC0, DP_ASYNC1};
  69 
  70 static inline struct ipu_flow *to_flow(struct ipu_dp *dp)
  71 {
  72         if (dp->foreground)
  73                 return container_of(dp, struct ipu_flow, foreground);
  74         else
  75                 return container_of(dp, struct ipu_flow, background);
  76 }
  77 
  78 int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable,
  79                 u8 alpha, bool bg_chan)
  80 {
  81         struct ipu_flow *flow = to_flow(dp);
  82         struct ipu_dp_priv *priv = flow->priv;
  83         u32 reg;
  84 
  85         mutex_lock(&priv->mutex);
  86 
  87         reg = readl(flow->base + DP_COM_CONF);
  88         if (bg_chan)
  89                 reg &= ~DP_COM_CONF_GWSEL;
  90         else
  91                 reg |= DP_COM_CONF_GWSEL;
  92         writel(reg, flow->base + DP_COM_CONF);
  93 
  94         if (enable) {
  95                 reg = readl(flow->base + DP_GRAPH_WIND_CTRL) & 0x00FFFFFFL;
  96                 writel(reg | ((u32) alpha << 24),
  97                              flow->base + DP_GRAPH_WIND_CTRL);
  98 
  99                 reg = readl(flow->base + DP_COM_CONF);
 100                 writel(reg | DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
 101         } else {
 102                 reg = readl(flow->base + DP_COM_CONF);
 103                 writel(reg & ~DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
 104         }
 105 
 106         ipu_srm_dp_update(priv->ipu, true);
 107 
 108         mutex_unlock(&priv->mutex);
 109 
 110         return 0;
 111 }
 112 EXPORT_SYMBOL_GPL(ipu_dp_set_global_alpha);
 113 
 114 int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos)
 115 {
 116         struct ipu_flow *flow = to_flow(dp);
 117         struct ipu_dp_priv *priv = flow->priv;
 118 
 119         writel((x_pos << 16) | y_pos, flow->base + DP_FG_POS);
 120 
 121         ipu_srm_dp_update(priv->ipu, true);
 122 
 123         return 0;
 124 }
 125 EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos);
 126 
 127 static void ipu_dp_csc_init(struct ipu_flow *flow,
 128                 enum ipu_color_space in,
 129                 enum ipu_color_space out,
 130                 u32 place)
 131 {
 132         u32 reg;
 133 
 134         reg = readl(flow->base + DP_COM_CONF);
 135         reg &= ~DP_COM_CONF_CSC_DEF_MASK;
 136 
 137         if (in == out) {
 138                 writel(reg, flow->base + DP_COM_CONF);
 139                 return;
 140         }
 141 
 142         if (in == IPUV3_COLORSPACE_RGB && out == IPUV3_COLORSPACE_YUV) {
 143                 writel(0x099 | (0x12d << 16), flow->base + DP_CSC_A_0);
 144                 writel(0x03a | (0x3a9 << 16), flow->base + DP_CSC_A_1);
 145                 writel(0x356 | (0x100 << 16), flow->base + DP_CSC_A_2);
 146                 writel(0x100 | (0x329 << 16), flow->base + DP_CSC_A_3);
 147                 writel(0x3d6 | (0x0000 << 16) | (2 << 30),
 148                                 flow->base + DP_CSC_0);
 149                 writel(0x200 | (2 << 14) | (0x200 << 16) | (2 << 30),
 150                                 flow->base + DP_CSC_1);
 151         } else {
 152                 writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0);
 153                 writel(0x0cc | (0x095 << 16), flow->base + DP_CSC_A_1);
 154                 writel(0x3ce | (0x398 << 16), flow->base + DP_CSC_A_2);
 155                 writel(0x095 | (0x0ff << 16), flow->base + DP_CSC_A_3);
 156                 writel(0x000 | (0x3e42 << 16) | (1 << 30),
 157                                 flow->base + DP_CSC_0);
 158                 writel(0x10a | (1 << 14) | (0x3dd6 << 16) | (1 << 30),
 159                                 flow->base + DP_CSC_1);
 160         }
 161 
 162         reg |= place;
 163 
 164         writel(reg, flow->base + DP_COM_CONF);
 165 }
 166 
 167 int ipu_dp_setup_channel(struct ipu_dp *dp,
 168                 enum ipu_color_space in,
 169                 enum ipu_color_space out)
 170 {
 171         struct ipu_flow *flow = to_flow(dp);
 172         struct ipu_dp_priv *priv = flow->priv;
 173 
 174         mutex_lock(&priv->mutex);
 175 
 176         dp->in_cs = in;
 177 
 178         if (!dp->foreground)
 179                 flow->out_cs = out;
 180 
 181         if (flow->foreground.in_cs == flow->background.in_cs) {
 182                 /*
 183                  * foreground and background are of same colorspace, put
 184                  * colorspace converter after combining unit.
 185                  */
 186                 ipu_dp_csc_init(flow, flow->foreground.in_cs, flow->out_cs,
 187                                 DP_COM_CONF_CSC_DEF_BOTH);
 188         } else {
 189                 if (flow->foreground.in_cs == IPUV3_COLORSPACE_UNKNOWN ||
 190                     flow->foreground.in_cs == flow->out_cs)
 191                         /*
 192                          * foreground identical to output, apply color
 193                          * conversion on background
 194                          */
 195                         ipu_dp_csc_init(flow, flow->background.in_cs,
 196                                         flow->out_cs, DP_COM_CONF_CSC_DEF_BG);
 197                 else
 198                         ipu_dp_csc_init(flow, flow->foreground.in_cs,
 199                                         flow->out_cs, DP_COM_CONF_CSC_DEF_FG);
 200         }
 201 
 202         ipu_srm_dp_update(priv->ipu, true);
 203 
 204         mutex_unlock(&priv->mutex);
 205 
 206         return 0;
 207 }
 208 EXPORT_SYMBOL_GPL(ipu_dp_setup_channel);
 209 
 210 int ipu_dp_enable(struct ipu_soc *ipu)
 211 {
 212         struct ipu_dp_priv *priv = ipu->dp_priv;
 213 
 214         mutex_lock(&priv->mutex);
 215 
 216         if (!priv->use_count)
 217                 ipu_module_enable(priv->ipu, IPU_CONF_DP_EN);
 218 
 219         priv->use_count++;
 220 
 221         mutex_unlock(&priv->mutex);
 222 
 223         return 0;
 224 }
 225 EXPORT_SYMBOL_GPL(ipu_dp_enable);
 226 
 227 int ipu_dp_enable_channel(struct ipu_dp *dp)
 228 {
 229         struct ipu_flow *flow = to_flow(dp);
 230         struct ipu_dp_priv *priv = flow->priv;
 231         u32 reg;
 232 
 233         if (!dp->foreground)
 234                 return 0;
 235 
 236         mutex_lock(&priv->mutex);
 237 
 238         reg = readl(flow->base + DP_COM_CONF);
 239         reg |= DP_COM_CONF_FG_EN;
 240         writel(reg, flow->base + DP_COM_CONF);
 241 
 242         ipu_srm_dp_update(priv->ipu, true);
 243 
 244         mutex_unlock(&priv->mutex);
 245 
 246         return 0;
 247 }
 248 EXPORT_SYMBOL_GPL(ipu_dp_enable_channel);
 249 
 250 void ipu_dp_disable_channel(struct ipu_dp *dp, bool sync)
 251 {
 252         struct ipu_flow *flow = to_flow(dp);
 253         struct ipu_dp_priv *priv = flow->priv;
 254         u32 reg, csc;
 255 
 256         dp->in_cs = IPUV3_COLORSPACE_UNKNOWN;
 257 
 258         if (!dp->foreground)
 259                 return;
 260 
 261         mutex_lock(&priv->mutex);
 262 
 263         reg = readl(flow->base + DP_COM_CONF);
 264         csc = reg & DP_COM_CONF_CSC_DEF_MASK;
 265         reg &= ~DP_COM_CONF_CSC_DEF_MASK;
 266         if (csc == DP_COM_CONF_CSC_DEF_BOTH || csc == DP_COM_CONF_CSC_DEF_BG)
 267                 reg |= DP_COM_CONF_CSC_DEF_BG;
 268 
 269         reg &= ~DP_COM_CONF_FG_EN;
 270         writel(reg, flow->base + DP_COM_CONF);
 271 
 272         writel(0, flow->base + DP_FG_POS);
 273         ipu_srm_dp_update(priv->ipu, sync);
 274 
 275         mutex_unlock(&priv->mutex);
 276 }
 277 EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
 278 
 279 void ipu_dp_disable(struct ipu_soc *ipu)
 280 {
 281         struct ipu_dp_priv *priv = ipu->dp_priv;
 282 
 283         mutex_lock(&priv->mutex);
 284 
 285         priv->use_count--;
 286 
 287         if (!priv->use_count)
 288                 ipu_module_disable(priv->ipu, IPU_CONF_DP_EN);
 289 
 290         if (priv->use_count < 0)
 291                 priv->use_count = 0;
 292 
 293         mutex_unlock(&priv->mutex);
 294 }
 295 EXPORT_SYMBOL_GPL(ipu_dp_disable);
 296 
 297 struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow)
 298 {
 299         struct ipu_dp_priv *priv = ipu->dp_priv;
 300         struct ipu_dp *dp;
 301 
 302         if ((flow >> 1) >= IPUV3_NUM_FLOWS)
 303                 return ERR_PTR(-EINVAL);
 304 
 305         if (flow & 1)
 306                 dp = &priv->flow[flow >> 1].foreground;
 307         else
 308                 dp = &priv->flow[flow >> 1].background;
 309 
 310         if (dp->in_use)
 311                 return ERR_PTR(-EBUSY);
 312 
 313         dp->in_use = true;
 314 
 315         return dp;
 316 }
 317 EXPORT_SYMBOL_GPL(ipu_dp_get);
 318 
 319 void ipu_dp_put(struct ipu_dp *dp)
 320 {
 321         dp->in_use = false;
 322 }
 323 EXPORT_SYMBOL_GPL(ipu_dp_put);
 324 
 325 int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
 326 {
 327         struct ipu_dp_priv *priv;
 328         int i;
 329 
 330         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 331         if (!priv)
 332                 return -ENOMEM;
 333         priv->dev = dev;
 334         priv->ipu = ipu;
 335 
 336         ipu->dp_priv = priv;
 337 
 338         priv->base = devm_ioremap(dev, base, PAGE_SIZE);
 339         if (!priv->base)
 340                 return -ENOMEM;
 341 
 342         mutex_init(&priv->mutex);
 343 
 344         for (i = 0; i < IPUV3_NUM_FLOWS; i++) {
 345                 priv->flow[i].background.in_cs = IPUV3_COLORSPACE_UNKNOWN;
 346                 priv->flow[i].foreground.in_cs = IPUV3_COLORSPACE_UNKNOWN;
 347                 priv->flow[i].foreground.foreground = true;
 348                 priv->flow[i].base = priv->base + ipu_dp_flow_base[i];
 349                 priv->flow[i].priv = priv;
 350         }
 351 
 352         return 0;
 353 }
 354 
 355 void ipu_dp_exit(struct ipu_soc *ipu)
 356 {
 357 }

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