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

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

DEFINITIONS

This source file includes following definitions.
  1. ipu_pre_get_available_count
  2. ipu_pre_lookup_by_phandle
  3. ipu_pre_get
  4. ipu_pre_put
  5. ipu_pre_configure
  6. ipu_pre_update
  7. ipu_pre_update_pending
  8. ipu_pre_get_baddr
  9. ipu_pre_probe
  10. ipu_pre_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2017 Lucas Stach, Pengutronix
   4  */
   5 
   6 #include <drm/drm_fourcc.h>
   7 #include <linux/clk.h>
   8 #include <linux/err.h>
   9 #include <linux/genalloc.h>
  10 #include <linux/module.h>
  11 #include <linux/of.h>
  12 #include <linux/platform_device.h>
  13 #include <video/imx-ipu-v3.h>
  14 
  15 #include "ipu-prv.h"
  16 
  17 #define IPU_PRE_MAX_WIDTH       2048
  18 #define IPU_PRE_NUM_SCANLINES   8
  19 
  20 #define IPU_PRE_CTRL                                    0x000
  21 #define IPU_PRE_CTRL_SET                                0x004
  22 #define  IPU_PRE_CTRL_ENABLE                            (1 << 0)
  23 #define  IPU_PRE_CTRL_BLOCK_EN                          (1 << 1)
  24 #define  IPU_PRE_CTRL_BLOCK_16                          (1 << 2)
  25 #define  IPU_PRE_CTRL_SDW_UPDATE                        (1 << 4)
  26 #define  IPU_PRE_CTRL_VFLIP                             (1 << 5)
  27 #define  IPU_PRE_CTRL_SO                                (1 << 6)
  28 #define  IPU_PRE_CTRL_INTERLACED_FIELD                  (1 << 7)
  29 #define  IPU_PRE_CTRL_HANDSHAKE_EN                      (1 << 8)
  30 #define  IPU_PRE_CTRL_HANDSHAKE_LINE_NUM(v)             ((v & 0x3) << 9)
  31 #define  IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN           (1 << 11)
  32 #define  IPU_PRE_CTRL_EN_REPEAT                         (1 << 28)
  33 #define  IPU_PRE_CTRL_TPR_REST_SEL                      (1 << 29)
  34 #define  IPU_PRE_CTRL_CLKGATE                           (1 << 30)
  35 #define  IPU_PRE_CTRL_SFTRST                            (1 << 31)
  36 
  37 #define IPU_PRE_CUR_BUF                                 0x030
  38 
  39 #define IPU_PRE_NEXT_BUF                                0x040
  40 
  41 #define IPU_PRE_TPR_CTRL                                0x070
  42 #define  IPU_PRE_TPR_CTRL_TILE_FORMAT(v)                ((v & 0xff) << 0)
  43 #define  IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK              0xff
  44 #define  IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT            (1 << 0)
  45 #define  IPU_PRE_TPR_CTRL_TILE_FORMAT_SPLIT_BUF         (1 << 4)
  46 #define  IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF        (1 << 5)
  47 #define  IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED       (1 << 6)
  48 
  49 #define IPU_PRE_PREFETCH_ENG_CTRL                       0x080
  50 #define  IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN              (1 << 0)
  51 #define  IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(v)          ((v & 0x7) << 1)
  52 #define  IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(v)      ((v & 0x3) << 4)
  53 #define  IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(v)    ((v & 0x7) << 8)
  54 #define  IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS             (1 << 11)
  55 #define  IPU_PRE_PREF_ENG_CTRL_FIELD_INVERSE            (1 << 12)
  56 #define  IPU_PRE_PREF_ENG_CTRL_PARTIAL_UV_SWAP          (1 << 14)
  57 #define  IPU_PRE_PREF_ENG_CTRL_TPR_COOR_OFFSET_EN       (1 << 15)
  58 
  59 #define IPU_PRE_PREFETCH_ENG_INPUT_SIZE                 0x0a0
  60 #define  IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(v)       ((v & 0xffff) << 0)
  61 #define  IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(v)      ((v & 0xffff) << 16)
  62 
  63 #define IPU_PRE_PREFETCH_ENG_PITCH                      0x0d0
  64 #define  IPU_PRE_PREFETCH_ENG_PITCH_Y(v)                ((v & 0xffff) << 0)
  65 #define  IPU_PRE_PREFETCH_ENG_PITCH_UV(v)               ((v & 0xffff) << 16)
  66 
  67 #define IPU_PRE_STORE_ENG_CTRL                          0x110
  68 #define  IPU_PRE_STORE_ENG_CTRL_STORE_EN                (1 << 0)
  69 #define  IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(v)         ((v & 0x7) << 1)
  70 #define  IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(v)    ((v & 0x3) << 4)
  71 
  72 #define IPU_PRE_STORE_ENG_STATUS                        0x120
  73 #define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_MASK    0xffff
  74 #define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_SHIFT   0
  75 #define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK    0x3fff
  76 #define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT   16
  77 #define  IPU_PRE_STORE_ENG_STATUS_STORE_FIFO_FULL       (1 << 30)
  78 #define  IPU_PRE_STORE_ENG_STATUS_STORE_FIELD           (1 << 31)
  79 
  80 #define IPU_PRE_STORE_ENG_SIZE                          0x130
  81 #define  IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(v)          ((v & 0xffff) << 0)
  82 #define  IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(v)         ((v & 0xffff) << 16)
  83 
  84 #define IPU_PRE_STORE_ENG_PITCH                         0x140
  85 #define  IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(v)           ((v & 0xffff) << 0)
  86 
  87 #define IPU_PRE_STORE_ENG_ADDR                          0x150
  88 
  89 struct ipu_pre {
  90         struct list_head        list;
  91         struct device           *dev;
  92 
  93         void __iomem            *regs;
  94         struct clk              *clk_axi;
  95         struct gen_pool         *iram;
  96 
  97         dma_addr_t              buffer_paddr;
  98         void                    *buffer_virt;
  99         bool                    in_use;
 100         unsigned int            safe_window_end;
 101         unsigned int            last_bufaddr;
 102 };
 103 
 104 static DEFINE_MUTEX(ipu_pre_list_mutex);
 105 static LIST_HEAD(ipu_pre_list);
 106 static int available_pres;
 107 
 108 int ipu_pre_get_available_count(void)
 109 {
 110         return available_pres;
 111 }
 112 
 113 struct ipu_pre *
 114 ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index)
 115 {
 116         struct device_node *pre_node = of_parse_phandle(dev->of_node,
 117                                                         name, index);
 118         struct ipu_pre *pre;
 119 
 120         mutex_lock(&ipu_pre_list_mutex);
 121         list_for_each_entry(pre, &ipu_pre_list, list) {
 122                 if (pre_node == pre->dev->of_node) {
 123                         mutex_unlock(&ipu_pre_list_mutex);
 124                         device_link_add(dev, pre->dev,
 125                                         DL_FLAG_AUTOREMOVE_CONSUMER);
 126                         of_node_put(pre_node);
 127                         return pre;
 128                 }
 129         }
 130         mutex_unlock(&ipu_pre_list_mutex);
 131 
 132         of_node_put(pre_node);
 133 
 134         return NULL;
 135 }
 136 
 137 int ipu_pre_get(struct ipu_pre *pre)
 138 {
 139         u32 val;
 140 
 141         if (pre->in_use)
 142                 return -EBUSY;
 143 
 144         /* first get the engine out of reset and remove clock gating */
 145         writel(0, pre->regs + IPU_PRE_CTRL);
 146 
 147         /* init defaults that should be applied to all streams */
 148         val = IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN |
 149               IPU_PRE_CTRL_HANDSHAKE_EN |
 150               IPU_PRE_CTRL_TPR_REST_SEL |
 151               IPU_PRE_CTRL_SDW_UPDATE;
 152         writel(val, pre->regs + IPU_PRE_CTRL);
 153 
 154         pre->in_use = true;
 155         return 0;
 156 }
 157 
 158 void ipu_pre_put(struct ipu_pre *pre)
 159 {
 160         writel(IPU_PRE_CTRL_SFTRST, pre->regs + IPU_PRE_CTRL);
 161 
 162         pre->in_use = false;
 163 }
 164 
 165 void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
 166                        unsigned int height, unsigned int stride, u32 format,
 167                        uint64_t modifier, unsigned int bufaddr)
 168 {
 169         const struct drm_format_info *info = drm_format_info(format);
 170         u32 active_bpp = info->cpp[0] >> 1;
 171         u32 val;
 172 
 173         /* calculate safe window for ctrl register updates */
 174         if (modifier == DRM_FORMAT_MOD_LINEAR)
 175                 pre->safe_window_end = height - 2;
 176         else
 177                 pre->safe_window_end = DIV_ROUND_UP(height, 4) - 1;
 178 
 179         writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF);
 180         writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
 181         pre->last_bufaddr = bufaddr;
 182 
 183         val = IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(0) |
 184               IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(active_bpp) |
 185               IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(4) |
 186               IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS |
 187               IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN;
 188         writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_CTRL);
 189 
 190         val = IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(width) |
 191               IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(height);
 192         writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_INPUT_SIZE);
 193 
 194         val = IPU_PRE_PREFETCH_ENG_PITCH_Y(stride);
 195         writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_PITCH);
 196 
 197         val = IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(active_bpp) |
 198               IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(4) |
 199               IPU_PRE_STORE_ENG_CTRL_STORE_EN;
 200         writel(val, pre->regs + IPU_PRE_STORE_ENG_CTRL);
 201 
 202         val = IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(width) |
 203               IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(height);
 204         writel(val, pre->regs + IPU_PRE_STORE_ENG_SIZE);
 205 
 206         val = IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(stride);
 207         writel(val, pre->regs + IPU_PRE_STORE_ENG_PITCH);
 208 
 209         writel(pre->buffer_paddr, pre->regs + IPU_PRE_STORE_ENG_ADDR);
 210 
 211         val = readl(pre->regs + IPU_PRE_TPR_CTRL);
 212         val &= ~IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK;
 213         if (modifier != DRM_FORMAT_MOD_LINEAR) {
 214                 /* only support single buffer formats for now */
 215                 val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF;
 216                 if (modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED)
 217                         val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED;
 218                 if (info->cpp[0] == 2)
 219                         val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT;
 220         }
 221         writel(val, pre->regs + IPU_PRE_TPR_CTRL);
 222 
 223         val = readl(pre->regs + IPU_PRE_CTRL);
 224         val |= IPU_PRE_CTRL_EN_REPEAT | IPU_PRE_CTRL_ENABLE |
 225                IPU_PRE_CTRL_SDW_UPDATE;
 226         if (modifier == DRM_FORMAT_MOD_LINEAR)
 227                 val &= ~IPU_PRE_CTRL_BLOCK_EN;
 228         else
 229                 val |= IPU_PRE_CTRL_BLOCK_EN;
 230         writel(val, pre->regs + IPU_PRE_CTRL);
 231 }
 232 
 233 void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr)
 234 {
 235         unsigned long timeout = jiffies + msecs_to_jiffies(5);
 236         unsigned short current_yblock;
 237         u32 val;
 238 
 239         if (bufaddr == pre->last_bufaddr)
 240                 return;
 241 
 242         writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
 243         pre->last_bufaddr = bufaddr;
 244 
 245         do {
 246                 if (time_after(jiffies, timeout)) {
 247                         dev_warn(pre->dev, "timeout waiting for PRE safe window\n");
 248                         return;
 249                 }
 250 
 251                 val = readl(pre->regs + IPU_PRE_STORE_ENG_STATUS);
 252                 current_yblock =
 253                         (val >> IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT) &
 254                         IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK;
 255         } while (current_yblock == 0 || current_yblock >= pre->safe_window_end);
 256 
 257         writel(IPU_PRE_CTRL_SDW_UPDATE, pre->regs + IPU_PRE_CTRL_SET);
 258 }
 259 
 260 bool ipu_pre_update_pending(struct ipu_pre *pre)
 261 {
 262         return !!(readl_relaxed(pre->regs + IPU_PRE_CTRL) &
 263                   IPU_PRE_CTRL_SDW_UPDATE);
 264 }
 265 
 266 u32 ipu_pre_get_baddr(struct ipu_pre *pre)
 267 {
 268         return (u32)pre->buffer_paddr;
 269 }
 270 
 271 static int ipu_pre_probe(struct platform_device *pdev)
 272 {
 273         struct device *dev = &pdev->dev;
 274         struct resource *res;
 275         struct ipu_pre *pre;
 276 
 277         pre = devm_kzalloc(dev, sizeof(*pre), GFP_KERNEL);
 278         if (!pre)
 279                 return -ENOMEM;
 280 
 281         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 282         pre->regs = devm_ioremap_resource(&pdev->dev, res);
 283         if (IS_ERR(pre->regs))
 284                 return PTR_ERR(pre->regs);
 285 
 286         pre->clk_axi = devm_clk_get(dev, "axi");
 287         if (IS_ERR(pre->clk_axi))
 288                 return PTR_ERR(pre->clk_axi);
 289 
 290         pre->iram = of_gen_pool_get(dev->of_node, "fsl,iram", 0);
 291         if (!pre->iram)
 292                 return -EPROBE_DEFER;
 293 
 294         /*
 295          * Allocate IRAM buffer with maximum size. This could be made dynamic,
 296          * but as there is no other user of this IRAM region and we can fit all
 297          * max sized buffers into it, there is no need yet.
 298          */
 299         pre->buffer_virt = gen_pool_dma_alloc(pre->iram, IPU_PRE_MAX_WIDTH *
 300                                               IPU_PRE_NUM_SCANLINES * 4,
 301                                               &pre->buffer_paddr);
 302         if (!pre->buffer_virt)
 303                 return -ENOMEM;
 304 
 305         clk_prepare_enable(pre->clk_axi);
 306 
 307         pre->dev = dev;
 308         platform_set_drvdata(pdev, pre);
 309         mutex_lock(&ipu_pre_list_mutex);
 310         list_add(&pre->list, &ipu_pre_list);
 311         available_pres++;
 312         mutex_unlock(&ipu_pre_list_mutex);
 313 
 314         return 0;
 315 }
 316 
 317 static int ipu_pre_remove(struct platform_device *pdev)
 318 {
 319         struct ipu_pre *pre = platform_get_drvdata(pdev);
 320 
 321         mutex_lock(&ipu_pre_list_mutex);
 322         list_del(&pre->list);
 323         available_pres--;
 324         mutex_unlock(&ipu_pre_list_mutex);
 325 
 326         clk_disable_unprepare(pre->clk_axi);
 327 
 328         if (pre->buffer_virt)
 329                 gen_pool_free(pre->iram, (unsigned long)pre->buffer_virt,
 330                               IPU_PRE_MAX_WIDTH * IPU_PRE_NUM_SCANLINES * 4);
 331         return 0;
 332 }
 333 
 334 static const struct of_device_id ipu_pre_dt_ids[] = {
 335         { .compatible = "fsl,imx6qp-pre", },
 336         { /* sentinel */ },
 337 };
 338 
 339 struct platform_driver ipu_pre_drv = {
 340         .probe          = ipu_pre_probe,
 341         .remove         = ipu_pre_remove,
 342         .driver         = {
 343                 .name   = "imx-ipu-pre",
 344                 .of_match_table = ipu_pre_dt_ids,
 345         },
 346 };

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