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