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