139b9004dSPhilipp Zabel /* 239b9004dSPhilipp Zabel * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de> 339b9004dSPhilipp Zabel * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. 439b9004dSPhilipp Zabel * 539b9004dSPhilipp Zabel * This program is free software; you can redistribute it and/or modify it 639b9004dSPhilipp Zabel * under the terms of the GNU General Public License as published by the 739b9004dSPhilipp Zabel * Free Software Foundation; either version 2 of the License, or (at your 839b9004dSPhilipp Zabel * option) any later version. 939b9004dSPhilipp Zabel * 1039b9004dSPhilipp Zabel * This program is distributed in the hope that it will be useful, but 1139b9004dSPhilipp Zabel * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 1239b9004dSPhilipp Zabel * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1339b9004dSPhilipp Zabel * for more details. 1439b9004dSPhilipp Zabel */ 1539b9004dSPhilipp Zabel #include <linux/export.h> 1639b9004dSPhilipp Zabel #include <linux/types.h> 1739b9004dSPhilipp Zabel #include <linux/errno.h> 1839b9004dSPhilipp Zabel #include <linux/io.h> 1939b9004dSPhilipp Zabel 2039b9004dSPhilipp Zabel #include <video/imx-ipu-v3.h> 2139b9004dSPhilipp Zabel #include "ipu-prv.h" 2239b9004dSPhilipp Zabel 2339b9004dSPhilipp Zabel #define DMFC_RD_CHAN 0x0000 2439b9004dSPhilipp Zabel #define DMFC_WR_CHAN 0x0004 2539b9004dSPhilipp Zabel #define DMFC_WR_CHAN_DEF 0x0008 2639b9004dSPhilipp Zabel #define DMFC_DP_CHAN 0x000c 2739b9004dSPhilipp Zabel #define DMFC_DP_CHAN_DEF 0x0010 2839b9004dSPhilipp Zabel #define DMFC_GENERAL1 0x0014 2939b9004dSPhilipp Zabel #define DMFC_GENERAL2 0x0018 3039b9004dSPhilipp Zabel #define DMFC_IC_CTRL 0x001c 31682b7c1cSLinus Torvalds #define DMFC_WR_CHAN_ALT 0x0020 32682b7c1cSLinus Torvalds #define DMFC_WR_CHAN_DEF_ALT 0x0024 33682b7c1cSLinus Torvalds #define DMFC_DP_CHAN_ALT 0x0028 34682b7c1cSLinus Torvalds #define DMFC_DP_CHAN_DEF_ALT 0x002c 35682b7c1cSLinus Torvalds #define DMFC_GENERAL1_ALT 0x0030 36682b7c1cSLinus Torvalds #define DMFC_STAT 0x0034 3739b9004dSPhilipp Zabel 3839b9004dSPhilipp Zabel #define DMFC_WR_CHAN_1_28 0 3939b9004dSPhilipp Zabel #define DMFC_WR_CHAN_2_41 8 4039b9004dSPhilipp Zabel #define DMFC_WR_CHAN_1C_42 16 4139b9004dSPhilipp Zabel #define DMFC_WR_CHAN_2C_43 24 4239b9004dSPhilipp Zabel 4339b9004dSPhilipp Zabel #define DMFC_DP_CHAN_5B_23 0 4439b9004dSPhilipp Zabel #define DMFC_DP_CHAN_5F_27 8 4539b9004dSPhilipp Zabel #define DMFC_DP_CHAN_6B_24 16 4639b9004dSPhilipp Zabel #define DMFC_DP_CHAN_6F_29 24 4739b9004dSPhilipp Zabel 4839b9004dSPhilipp Zabel #define DMFC_FIFO_SIZE_64 (3 << 3) 4939b9004dSPhilipp Zabel #define DMFC_FIFO_SIZE_128 (2 << 3) 5039b9004dSPhilipp Zabel #define DMFC_FIFO_SIZE_256 (1 << 3) 5139b9004dSPhilipp Zabel #define DMFC_FIFO_SIZE_512 (0 << 3) 5239b9004dSPhilipp Zabel 5339b9004dSPhilipp Zabel #define DMFC_SEGMENT(x) ((x & 0x7) << 0) 5439b9004dSPhilipp Zabel #define DMFC_BURSTSIZE_128 (0 << 6) 5539b9004dSPhilipp Zabel #define DMFC_BURSTSIZE_64 (1 << 6) 5639b9004dSPhilipp Zabel #define DMFC_BURSTSIZE_32 (2 << 6) 5739b9004dSPhilipp Zabel #define DMFC_BURSTSIZE_16 (3 << 6) 5839b9004dSPhilipp Zabel 5939b9004dSPhilipp Zabel struct dmfc_channel_data { 6039b9004dSPhilipp Zabel int ipu_channel; 6139b9004dSPhilipp Zabel unsigned long channel_reg; 6239b9004dSPhilipp Zabel unsigned long shift; 6339b9004dSPhilipp Zabel unsigned eot_shift; 6439b9004dSPhilipp Zabel unsigned max_fifo_lines; 6539b9004dSPhilipp Zabel }; 6639b9004dSPhilipp Zabel 6739b9004dSPhilipp Zabel static const struct dmfc_channel_data dmfcdata[] = { 6839b9004dSPhilipp Zabel { 6939b9004dSPhilipp Zabel .ipu_channel = IPUV3_CHANNEL_MEM_BG_SYNC, 7039b9004dSPhilipp Zabel .channel_reg = DMFC_DP_CHAN, 7139b9004dSPhilipp Zabel .shift = DMFC_DP_CHAN_5B_23, 7239b9004dSPhilipp Zabel .eot_shift = 20, 7339b9004dSPhilipp Zabel .max_fifo_lines = 3, 7439b9004dSPhilipp Zabel }, { 7539b9004dSPhilipp Zabel .ipu_channel = 24, 7639b9004dSPhilipp Zabel .channel_reg = DMFC_DP_CHAN, 7739b9004dSPhilipp Zabel .shift = DMFC_DP_CHAN_6B_24, 7839b9004dSPhilipp Zabel .eot_shift = 22, 7939b9004dSPhilipp Zabel .max_fifo_lines = 1, 8039b9004dSPhilipp Zabel }, { 8139b9004dSPhilipp Zabel .ipu_channel = IPUV3_CHANNEL_MEM_FG_SYNC, 8239b9004dSPhilipp Zabel .channel_reg = DMFC_DP_CHAN, 8339b9004dSPhilipp Zabel .shift = DMFC_DP_CHAN_5F_27, 8439b9004dSPhilipp Zabel .eot_shift = 21, 8539b9004dSPhilipp Zabel .max_fifo_lines = 2, 8639b9004dSPhilipp Zabel }, { 8739b9004dSPhilipp Zabel .ipu_channel = IPUV3_CHANNEL_MEM_DC_SYNC, 8839b9004dSPhilipp Zabel .channel_reg = DMFC_WR_CHAN, 8939b9004dSPhilipp Zabel .shift = DMFC_WR_CHAN_1_28, 9039b9004dSPhilipp Zabel .eot_shift = 16, 9139b9004dSPhilipp Zabel .max_fifo_lines = 2, 9239b9004dSPhilipp Zabel }, { 9339b9004dSPhilipp Zabel .ipu_channel = 29, 9439b9004dSPhilipp Zabel .channel_reg = DMFC_DP_CHAN, 9539b9004dSPhilipp Zabel .shift = DMFC_DP_CHAN_6F_29, 9639b9004dSPhilipp Zabel .eot_shift = 23, 9739b9004dSPhilipp Zabel .max_fifo_lines = 1, 9839b9004dSPhilipp Zabel }, 9939b9004dSPhilipp Zabel }; 10039b9004dSPhilipp Zabel 10139b9004dSPhilipp Zabel #define DMFC_NUM_CHANNELS ARRAY_SIZE(dmfcdata) 10239b9004dSPhilipp Zabel 10339b9004dSPhilipp Zabel struct ipu_dmfc_priv; 10439b9004dSPhilipp Zabel 10539b9004dSPhilipp Zabel struct dmfc_channel { 10639b9004dSPhilipp Zabel unsigned slots; 10739b9004dSPhilipp Zabel unsigned slotmask; 10839b9004dSPhilipp Zabel unsigned segment; 10939b9004dSPhilipp Zabel int burstsize; 11039b9004dSPhilipp Zabel struct ipu_soc *ipu; 11139b9004dSPhilipp Zabel struct ipu_dmfc_priv *priv; 11239b9004dSPhilipp Zabel const struct dmfc_channel_data *data; 11339b9004dSPhilipp Zabel }; 11439b9004dSPhilipp Zabel 11539b9004dSPhilipp Zabel struct ipu_dmfc_priv { 11639b9004dSPhilipp Zabel struct ipu_soc *ipu; 11739b9004dSPhilipp Zabel struct device *dev; 11839b9004dSPhilipp Zabel struct dmfc_channel channels[DMFC_NUM_CHANNELS]; 11939b9004dSPhilipp Zabel struct mutex mutex; 12039b9004dSPhilipp Zabel unsigned long bandwidth_per_slot; 12139b9004dSPhilipp Zabel void __iomem *base; 12239b9004dSPhilipp Zabel int use_count; 12339b9004dSPhilipp Zabel }; 12439b9004dSPhilipp Zabel 12539b9004dSPhilipp Zabel int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc) 12639b9004dSPhilipp Zabel { 12739b9004dSPhilipp Zabel struct ipu_dmfc_priv *priv = dmfc->priv; 12839b9004dSPhilipp Zabel mutex_lock(&priv->mutex); 12939b9004dSPhilipp Zabel 13039b9004dSPhilipp Zabel if (!priv->use_count) 13139b9004dSPhilipp Zabel ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN); 13239b9004dSPhilipp Zabel 13339b9004dSPhilipp Zabel priv->use_count++; 13439b9004dSPhilipp Zabel 13539b9004dSPhilipp Zabel mutex_unlock(&priv->mutex); 13639b9004dSPhilipp Zabel 13739b9004dSPhilipp Zabel return 0; 13839b9004dSPhilipp Zabel } 13939b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel); 14039b9004dSPhilipp Zabel 141682b7c1cSLinus Torvalds static void ipu_dmfc_wait_fifos(struct ipu_dmfc_priv *priv) 142682b7c1cSLinus Torvalds { 143682b7c1cSLinus Torvalds unsigned long timeout = jiffies + msecs_to_jiffies(1000); 144682b7c1cSLinus Torvalds 145682b7c1cSLinus Torvalds while ((readl(priv->base + DMFC_STAT) & 0x02fff000) != 0x02fff000) { 146682b7c1cSLinus Torvalds if (time_after(jiffies, timeout)) { 147682b7c1cSLinus Torvalds dev_warn(priv->dev, 148682b7c1cSLinus Torvalds "Timeout waiting for DMFC FIFOs to clear\n"); 149682b7c1cSLinus Torvalds break; 150682b7c1cSLinus Torvalds } 151682b7c1cSLinus Torvalds cpu_relax(); 152682b7c1cSLinus Torvalds } 153682b7c1cSLinus Torvalds } 154682b7c1cSLinus Torvalds 15539b9004dSPhilipp Zabel void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc) 15639b9004dSPhilipp Zabel { 15739b9004dSPhilipp Zabel struct ipu_dmfc_priv *priv = dmfc->priv; 15839b9004dSPhilipp Zabel 15939b9004dSPhilipp Zabel mutex_lock(&priv->mutex); 16039b9004dSPhilipp Zabel 16139b9004dSPhilipp Zabel priv->use_count--; 16239b9004dSPhilipp Zabel 163682b7c1cSLinus Torvalds if (!priv->use_count) { 164682b7c1cSLinus Torvalds ipu_dmfc_wait_fifos(priv); 16539b9004dSPhilipp Zabel ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN); 166682b7c1cSLinus Torvalds } 16739b9004dSPhilipp Zabel 16839b9004dSPhilipp Zabel if (priv->use_count < 0) 16939b9004dSPhilipp Zabel priv->use_count = 0; 17039b9004dSPhilipp Zabel 17139b9004dSPhilipp Zabel mutex_unlock(&priv->mutex); 17239b9004dSPhilipp Zabel } 17339b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel); 17439b9004dSPhilipp Zabel 17539b9004dSPhilipp Zabel static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots, 17639b9004dSPhilipp Zabel int segment, int burstsize) 17739b9004dSPhilipp Zabel { 17839b9004dSPhilipp Zabel struct ipu_dmfc_priv *priv = dmfc->priv; 17939b9004dSPhilipp Zabel u32 val, field; 18039b9004dSPhilipp Zabel 18139b9004dSPhilipp Zabel dev_dbg(priv->dev, 18239b9004dSPhilipp Zabel "dmfc: using %d slots starting from segment %d for IPU channel %d\n", 18339b9004dSPhilipp Zabel slots, segment, dmfc->data->ipu_channel); 18439b9004dSPhilipp Zabel 18539b9004dSPhilipp Zabel switch (slots) { 18639b9004dSPhilipp Zabel case 1: 18739b9004dSPhilipp Zabel field = DMFC_FIFO_SIZE_64; 18839b9004dSPhilipp Zabel break; 18939b9004dSPhilipp Zabel case 2: 19039b9004dSPhilipp Zabel field = DMFC_FIFO_SIZE_128; 19139b9004dSPhilipp Zabel break; 19239b9004dSPhilipp Zabel case 4: 19339b9004dSPhilipp Zabel field = DMFC_FIFO_SIZE_256; 19439b9004dSPhilipp Zabel break; 19539b9004dSPhilipp Zabel case 8: 19639b9004dSPhilipp Zabel field = DMFC_FIFO_SIZE_512; 19739b9004dSPhilipp Zabel break; 19839b9004dSPhilipp Zabel default: 19939b9004dSPhilipp Zabel return -EINVAL; 20039b9004dSPhilipp Zabel } 20139b9004dSPhilipp Zabel 20239b9004dSPhilipp Zabel switch (burstsize) { 20339b9004dSPhilipp Zabel case 16: 20439b9004dSPhilipp Zabel field |= DMFC_BURSTSIZE_16; 20539b9004dSPhilipp Zabel break; 20639b9004dSPhilipp Zabel case 32: 20739b9004dSPhilipp Zabel field |= DMFC_BURSTSIZE_32; 20839b9004dSPhilipp Zabel break; 20939b9004dSPhilipp Zabel case 64: 21039b9004dSPhilipp Zabel field |= DMFC_BURSTSIZE_64; 21139b9004dSPhilipp Zabel break; 21239b9004dSPhilipp Zabel case 128: 21339b9004dSPhilipp Zabel field |= DMFC_BURSTSIZE_128; 21439b9004dSPhilipp Zabel break; 21539b9004dSPhilipp Zabel } 21639b9004dSPhilipp Zabel 21739b9004dSPhilipp Zabel field |= DMFC_SEGMENT(segment); 21839b9004dSPhilipp Zabel 21939b9004dSPhilipp Zabel val = readl(priv->base + dmfc->data->channel_reg); 22039b9004dSPhilipp Zabel 22139b9004dSPhilipp Zabel val &= ~(0xff << dmfc->data->shift); 22239b9004dSPhilipp Zabel val |= field << dmfc->data->shift; 22339b9004dSPhilipp Zabel 22439b9004dSPhilipp Zabel writel(val, priv->base + dmfc->data->channel_reg); 22539b9004dSPhilipp Zabel 22639b9004dSPhilipp Zabel dmfc->slots = slots; 22739b9004dSPhilipp Zabel dmfc->segment = segment; 22839b9004dSPhilipp Zabel dmfc->burstsize = burstsize; 22939b9004dSPhilipp Zabel dmfc->slotmask = ((1 << slots) - 1) << segment; 23039b9004dSPhilipp Zabel 23139b9004dSPhilipp Zabel return 0; 23239b9004dSPhilipp Zabel } 23339b9004dSPhilipp Zabel 23439b9004dSPhilipp Zabel static int dmfc_bandwidth_to_slots(struct ipu_dmfc_priv *priv, 23539b9004dSPhilipp Zabel unsigned long bandwidth) 23639b9004dSPhilipp Zabel { 23739b9004dSPhilipp Zabel int slots = 1; 23839b9004dSPhilipp Zabel 23939b9004dSPhilipp Zabel while (slots * priv->bandwidth_per_slot < bandwidth) 24039b9004dSPhilipp Zabel slots *= 2; 24139b9004dSPhilipp Zabel 24239b9004dSPhilipp Zabel return slots; 24339b9004dSPhilipp Zabel } 24439b9004dSPhilipp Zabel 24539b9004dSPhilipp Zabel static int dmfc_find_slots(struct ipu_dmfc_priv *priv, int slots) 24639b9004dSPhilipp Zabel { 24739b9004dSPhilipp Zabel unsigned slotmask_need, slotmask_used = 0; 24839b9004dSPhilipp Zabel int i, segment = 0; 24939b9004dSPhilipp Zabel 25039b9004dSPhilipp Zabel slotmask_need = (1 << slots) - 1; 25139b9004dSPhilipp Zabel 25239b9004dSPhilipp Zabel for (i = 0; i < DMFC_NUM_CHANNELS; i++) 25339b9004dSPhilipp Zabel slotmask_used |= priv->channels[i].slotmask; 25439b9004dSPhilipp Zabel 25539b9004dSPhilipp Zabel while (slotmask_need <= 0xff) { 25639b9004dSPhilipp Zabel if (!(slotmask_used & slotmask_need)) 25739b9004dSPhilipp Zabel return segment; 25839b9004dSPhilipp Zabel 25939b9004dSPhilipp Zabel slotmask_need <<= 1; 26039b9004dSPhilipp Zabel segment++; 26139b9004dSPhilipp Zabel } 26239b9004dSPhilipp Zabel 26339b9004dSPhilipp Zabel return -EBUSY; 26439b9004dSPhilipp Zabel } 26539b9004dSPhilipp Zabel 26639b9004dSPhilipp Zabel void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc) 26739b9004dSPhilipp Zabel { 26839b9004dSPhilipp Zabel struct ipu_dmfc_priv *priv = dmfc->priv; 26939b9004dSPhilipp Zabel int i; 27039b9004dSPhilipp Zabel 27139b9004dSPhilipp Zabel dev_dbg(priv->dev, "dmfc: freeing %d slots starting from segment %d\n", 27239b9004dSPhilipp Zabel dmfc->slots, dmfc->segment); 27339b9004dSPhilipp Zabel 27439b9004dSPhilipp Zabel mutex_lock(&priv->mutex); 27539b9004dSPhilipp Zabel 27639b9004dSPhilipp Zabel if (!dmfc->slots) 27739b9004dSPhilipp Zabel goto out; 27839b9004dSPhilipp Zabel 27939b9004dSPhilipp Zabel dmfc->slotmask = 0; 28039b9004dSPhilipp Zabel dmfc->slots = 0; 28139b9004dSPhilipp Zabel dmfc->segment = 0; 28239b9004dSPhilipp Zabel 28339b9004dSPhilipp Zabel for (i = 0; i < DMFC_NUM_CHANNELS; i++) 28439b9004dSPhilipp Zabel priv->channels[i].slotmask = 0; 28539b9004dSPhilipp Zabel 28639b9004dSPhilipp Zabel for (i = 0; i < DMFC_NUM_CHANNELS; i++) { 28739b9004dSPhilipp Zabel if (priv->channels[i].slots > 0) { 28839b9004dSPhilipp Zabel priv->channels[i].segment = 28939b9004dSPhilipp Zabel dmfc_find_slots(priv, priv->channels[i].slots); 29039b9004dSPhilipp Zabel priv->channels[i].slotmask = 29139b9004dSPhilipp Zabel ((1 << priv->channels[i].slots) - 1) << 29239b9004dSPhilipp Zabel priv->channels[i].segment; 29339b9004dSPhilipp Zabel } 29439b9004dSPhilipp Zabel } 29539b9004dSPhilipp Zabel 29639b9004dSPhilipp Zabel for (i = 0; i < DMFC_NUM_CHANNELS; i++) { 29739b9004dSPhilipp Zabel if (priv->channels[i].slots > 0) 29839b9004dSPhilipp Zabel ipu_dmfc_setup_channel(&priv->channels[i], 29939b9004dSPhilipp Zabel priv->channels[i].slots, 30039b9004dSPhilipp Zabel priv->channels[i].segment, 30139b9004dSPhilipp Zabel priv->channels[i].burstsize); 30239b9004dSPhilipp Zabel } 30339b9004dSPhilipp Zabel out: 30439b9004dSPhilipp Zabel mutex_unlock(&priv->mutex); 30539b9004dSPhilipp Zabel } 30639b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_free_bandwidth); 30739b9004dSPhilipp Zabel 30839b9004dSPhilipp Zabel int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc, 30939b9004dSPhilipp Zabel unsigned long bandwidth_pixel_per_second, int burstsize) 31039b9004dSPhilipp Zabel { 31139b9004dSPhilipp Zabel struct ipu_dmfc_priv *priv = dmfc->priv; 31239b9004dSPhilipp Zabel int slots = dmfc_bandwidth_to_slots(priv, bandwidth_pixel_per_second); 31339b9004dSPhilipp Zabel int segment = -1, ret = 0; 31439b9004dSPhilipp Zabel 31539b9004dSPhilipp Zabel dev_dbg(priv->dev, "dmfc: trying to allocate %ldMpixel/s for IPU channel %d\n", 31639b9004dSPhilipp Zabel bandwidth_pixel_per_second / 1000000, 31739b9004dSPhilipp Zabel dmfc->data->ipu_channel); 31839b9004dSPhilipp Zabel 31939b9004dSPhilipp Zabel ipu_dmfc_free_bandwidth(dmfc); 32039b9004dSPhilipp Zabel 32139b9004dSPhilipp Zabel mutex_lock(&priv->mutex); 32239b9004dSPhilipp Zabel 32339b9004dSPhilipp Zabel if (slots > 8) { 32439b9004dSPhilipp Zabel ret = -EBUSY; 32539b9004dSPhilipp Zabel goto out; 32639b9004dSPhilipp Zabel } 32739b9004dSPhilipp Zabel 32839b9004dSPhilipp Zabel /* For the MEM_BG channel, first try to allocate twice the slots */ 32939b9004dSPhilipp Zabel if (dmfc->data->ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC) 33039b9004dSPhilipp Zabel segment = dmfc_find_slots(priv, slots * 2); 33139b9004dSPhilipp Zabel else if (slots < 2) 33239b9004dSPhilipp Zabel /* Always allocate at least 128*4 bytes (2 slots) */ 33339b9004dSPhilipp Zabel slots = 2; 33439b9004dSPhilipp Zabel 33539b9004dSPhilipp Zabel if (segment >= 0) 33639b9004dSPhilipp Zabel slots *= 2; 33739b9004dSPhilipp Zabel else 33839b9004dSPhilipp Zabel segment = dmfc_find_slots(priv, slots); 33939b9004dSPhilipp Zabel if (segment < 0) { 34039b9004dSPhilipp Zabel ret = -EBUSY; 34139b9004dSPhilipp Zabel goto out; 34239b9004dSPhilipp Zabel } 34339b9004dSPhilipp Zabel 34439b9004dSPhilipp Zabel ipu_dmfc_setup_channel(dmfc, slots, segment, burstsize); 34539b9004dSPhilipp Zabel 34639b9004dSPhilipp Zabel out: 34739b9004dSPhilipp Zabel mutex_unlock(&priv->mutex); 34839b9004dSPhilipp Zabel 34939b9004dSPhilipp Zabel return ret; 35039b9004dSPhilipp Zabel } 35139b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_alloc_bandwidth); 35239b9004dSPhilipp Zabel 35339b9004dSPhilipp Zabel int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width) 35439b9004dSPhilipp Zabel { 35539b9004dSPhilipp Zabel struct ipu_dmfc_priv *priv = dmfc->priv; 35639b9004dSPhilipp Zabel u32 dmfc_gen1; 35739b9004dSPhilipp Zabel 358*32c26a56SLiu Ying mutex_lock(&priv->mutex); 359*32c26a56SLiu Ying 36039b9004dSPhilipp Zabel dmfc_gen1 = readl(priv->base + DMFC_GENERAL1); 36139b9004dSPhilipp Zabel 36239b9004dSPhilipp Zabel if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines) 36339b9004dSPhilipp Zabel dmfc_gen1 |= 1 << dmfc->data->eot_shift; 36439b9004dSPhilipp Zabel else 36539b9004dSPhilipp Zabel dmfc_gen1 &= ~(1 << dmfc->data->eot_shift); 36639b9004dSPhilipp Zabel 36739b9004dSPhilipp Zabel writel(dmfc_gen1, priv->base + DMFC_GENERAL1); 36839b9004dSPhilipp Zabel 369*32c26a56SLiu Ying mutex_unlock(&priv->mutex); 370*32c26a56SLiu Ying 37139b9004dSPhilipp Zabel return 0; 37239b9004dSPhilipp Zabel } 37339b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_init_channel); 37439b9004dSPhilipp Zabel 37539b9004dSPhilipp Zabel struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel) 37639b9004dSPhilipp Zabel { 37739b9004dSPhilipp Zabel struct ipu_dmfc_priv *priv = ipu->dmfc_priv; 37839b9004dSPhilipp Zabel int i; 37939b9004dSPhilipp Zabel 38039b9004dSPhilipp Zabel for (i = 0; i < DMFC_NUM_CHANNELS; i++) 38139b9004dSPhilipp Zabel if (dmfcdata[i].ipu_channel == ipu_channel) 38239b9004dSPhilipp Zabel return &priv->channels[i]; 38339b9004dSPhilipp Zabel return ERR_PTR(-ENODEV); 38439b9004dSPhilipp Zabel } 38539b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_get); 38639b9004dSPhilipp Zabel 38739b9004dSPhilipp Zabel void ipu_dmfc_put(struct dmfc_channel *dmfc) 38839b9004dSPhilipp Zabel { 38939b9004dSPhilipp Zabel ipu_dmfc_free_bandwidth(dmfc); 39039b9004dSPhilipp Zabel } 39139b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_put); 39239b9004dSPhilipp Zabel 39339b9004dSPhilipp Zabel int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base, 39439b9004dSPhilipp Zabel struct clk *ipu_clk) 39539b9004dSPhilipp Zabel { 39639b9004dSPhilipp Zabel struct ipu_dmfc_priv *priv; 39739b9004dSPhilipp Zabel int i; 39839b9004dSPhilipp Zabel 39939b9004dSPhilipp Zabel priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 40039b9004dSPhilipp Zabel if (!priv) 40139b9004dSPhilipp Zabel return -ENOMEM; 40239b9004dSPhilipp Zabel 40339b9004dSPhilipp Zabel priv->base = devm_ioremap(dev, base, PAGE_SIZE); 40439b9004dSPhilipp Zabel if (!priv->base) 40539b9004dSPhilipp Zabel return -ENOMEM; 40639b9004dSPhilipp Zabel 40739b9004dSPhilipp Zabel priv->dev = dev; 40839b9004dSPhilipp Zabel priv->ipu = ipu; 40939b9004dSPhilipp Zabel mutex_init(&priv->mutex); 41039b9004dSPhilipp Zabel 41139b9004dSPhilipp Zabel ipu->dmfc_priv = priv; 41239b9004dSPhilipp Zabel 41339b9004dSPhilipp Zabel for (i = 0; i < DMFC_NUM_CHANNELS; i++) { 41439b9004dSPhilipp Zabel priv->channels[i].priv = priv; 41539b9004dSPhilipp Zabel priv->channels[i].ipu = ipu; 41639b9004dSPhilipp Zabel priv->channels[i].data = &dmfcdata[i]; 41739b9004dSPhilipp Zabel } 41839b9004dSPhilipp Zabel 41939b9004dSPhilipp Zabel writel(0x0, priv->base + DMFC_WR_CHAN); 42039b9004dSPhilipp Zabel writel(0x0, priv->base + DMFC_DP_CHAN); 42139b9004dSPhilipp Zabel 42239b9004dSPhilipp Zabel /* 42339b9004dSPhilipp Zabel * We have a total bandwidth of clkrate * 4pixel divided 42439b9004dSPhilipp Zabel * into 8 slots. 42539b9004dSPhilipp Zabel */ 42639b9004dSPhilipp Zabel priv->bandwidth_per_slot = clk_get_rate(ipu_clk) * 4 / 8; 42739b9004dSPhilipp Zabel 42839b9004dSPhilipp Zabel dev_dbg(dev, "dmfc: 8 slots with %ldMpixel/s bandwidth each\n", 42939b9004dSPhilipp Zabel priv->bandwidth_per_slot / 1000000); 43039b9004dSPhilipp Zabel 43139b9004dSPhilipp Zabel writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF); 43239b9004dSPhilipp Zabel writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF); 43339b9004dSPhilipp Zabel writel(0x00000003, priv->base + DMFC_GENERAL1); 43439b9004dSPhilipp Zabel 43539b9004dSPhilipp Zabel return 0; 43639b9004dSPhilipp Zabel } 43739b9004dSPhilipp Zabel 43839b9004dSPhilipp Zabel void ipu_dmfc_exit(struct ipu_soc *ipu) 43939b9004dSPhilipp Zabel { 44039b9004dSPhilipp Zabel } 441