linux/drivers/gpu/ipu-v3/ipu-dmfc.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
   3 * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of the GNU General Public License as published by the
   7 * Free Software Foundation; either version 2 of the License, or (at your
   8 * option) any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  12 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13 * for more details.
  14 */
  15#include <linux/export.h>
  16#include <linux/types.h>
  17#include <linux/errno.h>
  18#include <linux/io.h>
  19
  20#include <video/imx-ipu-v3.h>
  21#include "ipu-prv.h"
  22
  23#define DMFC_RD_CHAN            0x0000
  24#define DMFC_WR_CHAN            0x0004
  25#define DMFC_WR_CHAN_DEF        0x0008
  26#define DMFC_DP_CHAN            0x000c
  27#define DMFC_DP_CHAN_DEF        0x0010
  28#define DMFC_GENERAL1           0x0014
  29#define DMFC_GENERAL2           0x0018
  30#define DMFC_IC_CTRL            0x001c
  31#define DMFC_WR_CHAN_ALT        0x0020
  32#define DMFC_WR_CHAN_DEF_ALT    0x0024
  33#define DMFC_DP_CHAN_ALT        0x0028
  34#define DMFC_DP_CHAN_DEF_ALT    0x002c
  35#define DMFC_GENERAL1_ALT       0x0030
  36#define DMFC_STAT               0x0034
  37
  38#define DMFC_WR_CHAN_1_28               0
  39#define DMFC_WR_CHAN_2_41               8
  40#define DMFC_WR_CHAN_1C_42              16
  41#define DMFC_WR_CHAN_2C_43              24
  42
  43#define DMFC_DP_CHAN_5B_23              0
  44#define DMFC_DP_CHAN_5F_27              8
  45#define DMFC_DP_CHAN_6B_24              16
  46#define DMFC_DP_CHAN_6F_29              24
  47
  48#define DMFC_FIFO_SIZE_64               (3 << 3)
  49#define DMFC_FIFO_SIZE_128              (2 << 3)
  50#define DMFC_FIFO_SIZE_256              (1 << 3)
  51#define DMFC_FIFO_SIZE_512              (0 << 3)
  52
  53#define DMFC_SEGMENT(x)                 ((x & 0x7) << 0)
  54#define DMFC_BURSTSIZE_128              (0 << 6)
  55#define DMFC_BURSTSIZE_64               (1 << 6)
  56#define DMFC_BURSTSIZE_32               (2 << 6)
  57#define DMFC_BURSTSIZE_16               (3 << 6)
  58
  59struct dmfc_channel_data {
  60        int             ipu_channel;
  61        unsigned long   channel_reg;
  62        unsigned long   shift;
  63        unsigned        eot_shift;
  64        unsigned        max_fifo_lines;
  65};
  66
  67static const struct dmfc_channel_data dmfcdata[] = {
  68        {
  69                .ipu_channel    = IPUV3_CHANNEL_MEM_BG_SYNC,
  70                .channel_reg    = DMFC_DP_CHAN,
  71                .shift          = DMFC_DP_CHAN_5B_23,
  72                .eot_shift      = 20,
  73                .max_fifo_lines = 3,
  74        }, {
  75                .ipu_channel    = 24,
  76                .channel_reg    = DMFC_DP_CHAN,
  77                .shift          = DMFC_DP_CHAN_6B_24,
  78                .eot_shift      = 22,
  79                .max_fifo_lines = 1,
  80        }, {
  81                .ipu_channel    = IPUV3_CHANNEL_MEM_FG_SYNC,
  82                .channel_reg    = DMFC_DP_CHAN,
  83                .shift          = DMFC_DP_CHAN_5F_27,
  84                .eot_shift      = 21,
  85                .max_fifo_lines = 2,
  86        }, {
  87                .ipu_channel    = IPUV3_CHANNEL_MEM_DC_SYNC,
  88                .channel_reg    = DMFC_WR_CHAN,
  89                .shift          = DMFC_WR_CHAN_1_28,
  90                .eot_shift      = 16,
  91                .max_fifo_lines = 2,
  92        }, {
  93                .ipu_channel    = 29,
  94                .channel_reg    = DMFC_DP_CHAN,
  95                .shift          = DMFC_DP_CHAN_6F_29,
  96                .eot_shift      = 23,
  97                .max_fifo_lines = 1,
  98        },
  99};
 100
 101#define DMFC_NUM_CHANNELS       ARRAY_SIZE(dmfcdata)
 102
 103struct ipu_dmfc_priv;
 104
 105struct dmfc_channel {
 106        unsigned                        slots;
 107        unsigned                        slotmask;
 108        unsigned                        segment;
 109        int                             burstsize;
 110        struct ipu_soc                  *ipu;
 111        struct ipu_dmfc_priv            *priv;
 112        const struct dmfc_channel_data  *data;
 113};
 114
 115struct ipu_dmfc_priv {
 116        struct ipu_soc *ipu;
 117        struct device *dev;
 118        struct dmfc_channel channels[DMFC_NUM_CHANNELS];
 119        struct mutex mutex;
 120        unsigned long bandwidth_per_slot;
 121        void __iomem *base;
 122        int use_count;
 123};
 124
 125int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
 126{
 127        struct ipu_dmfc_priv *priv = dmfc->priv;
 128        mutex_lock(&priv->mutex);
 129
 130        if (!priv->use_count)
 131                ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
 132
 133        priv->use_count++;
 134
 135        mutex_unlock(&priv->mutex);
 136
 137        return 0;
 138}
 139EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
 140
 141static void ipu_dmfc_wait_fifos(struct ipu_dmfc_priv *priv)
 142{
 143        unsigned long timeout = jiffies + msecs_to_jiffies(1000);
 144
 145        while ((readl(priv->base + DMFC_STAT) & 0x02fff000) != 0x02fff000) {
 146                if (time_after(jiffies, timeout)) {
 147                        dev_warn(priv->dev,
 148                                 "Timeout waiting for DMFC FIFOs to clear\n");
 149                        break;
 150                }
 151                cpu_relax();
 152        }
 153}
 154
 155void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
 156{
 157        struct ipu_dmfc_priv *priv = dmfc->priv;
 158
 159        mutex_lock(&priv->mutex);
 160
 161        priv->use_count--;
 162
 163        if (!priv->use_count) {
 164                ipu_dmfc_wait_fifos(priv);
 165                ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
 166        }
 167
 168        if (priv->use_count < 0)
 169                priv->use_count = 0;
 170
 171        mutex_unlock(&priv->mutex);
 172}
 173EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
 174
 175static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots,
 176                int segment, int burstsize)
 177{
 178        struct ipu_dmfc_priv *priv = dmfc->priv;
 179        u32 val, field;
 180
 181        dev_dbg(priv->dev,
 182                        "dmfc: using %d slots starting from segment %d for IPU channel %d\n",
 183                        slots, segment, dmfc->data->ipu_channel);
 184
 185        switch (slots) {
 186        case 1:
 187                field = DMFC_FIFO_SIZE_64;
 188                break;
 189        case 2:
 190                field = DMFC_FIFO_SIZE_128;
 191                break;
 192        case 4:
 193                field = DMFC_FIFO_SIZE_256;
 194                break;
 195        case 8:
 196                field = DMFC_FIFO_SIZE_512;
 197                break;
 198        default:
 199                return -EINVAL;
 200        }
 201
 202        switch (burstsize) {
 203        case 16:
 204                field |= DMFC_BURSTSIZE_16;
 205                break;
 206        case 32:
 207                field |= DMFC_BURSTSIZE_32;
 208                break;
 209        case 64:
 210                field |= DMFC_BURSTSIZE_64;
 211                break;
 212        case 128:
 213                field |= DMFC_BURSTSIZE_128;
 214                break;
 215        }
 216
 217        field |= DMFC_SEGMENT(segment);
 218
 219        val = readl(priv->base + dmfc->data->channel_reg);
 220
 221        val &= ~(0xff << dmfc->data->shift);
 222        val |= field << dmfc->data->shift;
 223
 224        writel(val, priv->base + dmfc->data->channel_reg);
 225
 226        dmfc->slots = slots;
 227        dmfc->segment = segment;
 228        dmfc->burstsize = burstsize;
 229        dmfc->slotmask = ((1 << slots) - 1) << segment;
 230
 231        return 0;
 232}
 233
 234static int dmfc_bandwidth_to_slots(struct ipu_dmfc_priv *priv,
 235                unsigned long bandwidth)
 236{
 237        int slots = 1;
 238
 239        while (slots * priv->bandwidth_per_slot < bandwidth)
 240                slots *= 2;
 241
 242        return slots;
 243}
 244
 245static int dmfc_find_slots(struct ipu_dmfc_priv *priv, int slots)
 246{
 247        unsigned slotmask_need, slotmask_used = 0;
 248        int i, segment = 0;
 249
 250        slotmask_need = (1 << slots) - 1;
 251
 252        for (i = 0; i < DMFC_NUM_CHANNELS; i++)
 253                slotmask_used |= priv->channels[i].slotmask;
 254
 255        while (slotmask_need <= 0xff) {
 256                if (!(slotmask_used & slotmask_need))
 257                        return segment;
 258
 259                slotmask_need <<= 1;
 260                segment++;
 261        }
 262
 263        return -EBUSY;
 264}
 265
 266void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc)
 267{
 268        struct ipu_dmfc_priv *priv = dmfc->priv;
 269        int i;
 270
 271        dev_dbg(priv->dev, "dmfc: freeing %d slots starting from segment %d\n",
 272                        dmfc->slots, dmfc->segment);
 273
 274        mutex_lock(&priv->mutex);
 275
 276        if (!dmfc->slots)
 277                goto out;
 278
 279        dmfc->slotmask = 0;
 280        dmfc->slots = 0;
 281        dmfc->segment = 0;
 282
 283        for (i = 0; i < DMFC_NUM_CHANNELS; i++)
 284                priv->channels[i].slotmask = 0;
 285
 286        for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
 287                if (priv->channels[i].slots > 0) {
 288                        priv->channels[i].segment =
 289                                dmfc_find_slots(priv, priv->channels[i].slots);
 290                        priv->channels[i].slotmask =
 291                                ((1 << priv->channels[i].slots) - 1) <<
 292                                priv->channels[i].segment;
 293                }
 294        }
 295
 296        for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
 297                if (priv->channels[i].slots > 0)
 298                        ipu_dmfc_setup_channel(&priv->channels[i],
 299                                        priv->channels[i].slots,
 300                                        priv->channels[i].segment,
 301                                        priv->channels[i].burstsize);
 302        }
 303out:
 304        mutex_unlock(&priv->mutex);
 305}
 306EXPORT_SYMBOL_GPL(ipu_dmfc_free_bandwidth);
 307
 308int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc,
 309                unsigned long bandwidth_pixel_per_second, int burstsize)
 310{
 311        struct ipu_dmfc_priv *priv = dmfc->priv;
 312        int slots = dmfc_bandwidth_to_slots(priv, bandwidth_pixel_per_second);
 313        int segment = -1, ret = 0;
 314
 315        dev_dbg(priv->dev, "dmfc: trying to allocate %ldMpixel/s for IPU channel %d\n",
 316                        bandwidth_pixel_per_second / 1000000,
 317                        dmfc->data->ipu_channel);
 318
 319        ipu_dmfc_free_bandwidth(dmfc);
 320
 321        mutex_lock(&priv->mutex);
 322
 323        if (slots > 8) {
 324                ret = -EBUSY;
 325                goto out;
 326        }
 327
 328        /* For the MEM_BG channel, first try to allocate twice the slots */
 329        if (dmfc->data->ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC)
 330                segment = dmfc_find_slots(priv, slots * 2);
 331        else if (slots < 2)
 332                /* Always allocate at least 128*4 bytes (2 slots) */
 333                slots = 2;
 334
 335        if (segment >= 0)
 336                slots *= 2;
 337        else
 338                segment = dmfc_find_slots(priv, slots);
 339        if (segment < 0) {
 340                ret = -EBUSY;
 341                goto out;
 342        }
 343
 344        ipu_dmfc_setup_channel(dmfc, slots, segment, burstsize);
 345
 346out:
 347        mutex_unlock(&priv->mutex);
 348
 349        return ret;
 350}
 351EXPORT_SYMBOL_GPL(ipu_dmfc_alloc_bandwidth);
 352
 353int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width)
 354{
 355        struct ipu_dmfc_priv *priv = dmfc->priv;
 356        u32 dmfc_gen1;
 357
 358        dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
 359
 360        if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
 361                dmfc_gen1 |= 1 << dmfc->data->eot_shift;
 362        else
 363                dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
 364
 365        writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
 366
 367        return 0;
 368}
 369EXPORT_SYMBOL_GPL(ipu_dmfc_init_channel);
 370
 371struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
 372{
 373        struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
 374        int i;
 375
 376        for (i = 0; i < DMFC_NUM_CHANNELS; i++)
 377                if (dmfcdata[i].ipu_channel == ipu_channel)
 378                        return &priv->channels[i];
 379        return ERR_PTR(-ENODEV);
 380}
 381EXPORT_SYMBOL_GPL(ipu_dmfc_get);
 382
 383void ipu_dmfc_put(struct dmfc_channel *dmfc)
 384{
 385        ipu_dmfc_free_bandwidth(dmfc);
 386}
 387EXPORT_SYMBOL_GPL(ipu_dmfc_put);
 388
 389int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
 390                struct clk *ipu_clk)
 391{
 392        struct ipu_dmfc_priv *priv;
 393        int i;
 394
 395        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 396        if (!priv)
 397                return -ENOMEM;
 398
 399        priv->base = devm_ioremap(dev, base, PAGE_SIZE);
 400        if (!priv->base)
 401                return -ENOMEM;
 402
 403        priv->dev = dev;
 404        priv->ipu = ipu;
 405        mutex_init(&priv->mutex);
 406
 407        ipu->dmfc_priv = priv;
 408
 409        for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
 410                priv->channels[i].priv = priv;
 411                priv->channels[i].ipu = ipu;
 412                priv->channels[i].data = &dmfcdata[i];
 413        }
 414
 415        writel(0x0, priv->base + DMFC_WR_CHAN);
 416        writel(0x0, priv->base + DMFC_DP_CHAN);
 417
 418        /*
 419         * We have a total bandwidth of clkrate * 4pixel divided
 420         * into 8 slots.
 421         */
 422        priv->bandwidth_per_slot = clk_get_rate(ipu_clk) * 4 / 8;
 423
 424        dev_dbg(dev, "dmfc: 8 slots with %ldMpixel/s bandwidth each\n",
 425                        priv->bandwidth_per_slot / 1000000);
 426
 427        writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
 428        writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
 429        writel(0x00000003, priv->base + DMFC_GENERAL1);
 430
 431        return 0;
 432}
 433
 434void ipu_dmfc_exit(struct ipu_soc *ipu)
 435{
 436}
 437