Commit d7868cb7 authored by Liu Ying's avatar Liu Ying Committed by Philipp Zabel

gpu: ipu-v3: ipu-dmfc: Use static DMFC FIFO allocation mechanism

For all video modes we support currently, we always get 2 slots for
a plane by using the current existing dynamic DMFC FIFO allocation
mechanism.  So, let's change to use the static one to simplify the
code.  This also makes it easier to implement the atomic mode setting
as we don't need to handle allocation failure cases then.
Signed-off-by: default avatarLiu Ying <gnuiyl@gmail.com>
Acked-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: default avatarPhilipp Zabel <p.zabel@pengutronix.de>
parent 08a89018
......@@ -53,24 +53,6 @@ int ipu_plane_irq(struct ipu_plane *ipu_plane)
IPU_IRQ_EOF);
}
static int calc_vref(struct drm_display_mode *mode)
{
unsigned long htotal, vtotal;
htotal = mode->htotal;
vtotal = mode->vtotal;
if (!htotal || !vtotal)
return 60;
return DIV_ROUND_UP(mode->clock * 1000, vtotal * htotal);
}
static inline int calc_bandwidth(int width, int height, unsigned int vref)
{
return width * height * vref;
}
int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
int x, int y)
{
......@@ -291,14 +273,6 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
}
}
ret = ipu_dmfc_alloc_bandwidth(ipu_plane->dmfc,
calc_bandwidth(crtc_w, crtc_h,
calc_vref(mode)), 64);
if (ret) {
dev_err(dev, "allocating dmfc bandwidth failed with %d\n", ret);
return ret;
}
ipu_dmfc_config_wait4eot(ipu_plane->dmfc, crtc_w);
ipu_cpmem_zero(ipu_plane->ipu_ch);
......
......@@ -45,17 +45,6 @@
#define DMFC_DP_CHAN_6B_24 16
#define DMFC_DP_CHAN_6F_29 24
#define DMFC_FIFO_SIZE_64 (3 << 3)
#define DMFC_FIFO_SIZE_128 (2 << 3)
#define DMFC_FIFO_SIZE_256 (1 << 3)
#define DMFC_FIFO_SIZE_512 (0 << 3)
#define DMFC_SEGMENT(x) ((x & 0x7) << 0)
#define DMFC_BURSTSIZE_128 (0 << 6)
#define DMFC_BURSTSIZE_64 (1 << 6)
#define DMFC_BURSTSIZE_32 (2 << 6)
#define DMFC_BURSTSIZE_16 (3 << 6)
struct dmfc_channel_data {
int ipu_channel;
unsigned long channel_reg;
......@@ -104,9 +93,6 @@ struct ipu_dmfc_priv;
struct dmfc_channel {
unsigned slots;
unsigned slotmask;
unsigned segment;
int burstsize;
struct ipu_soc *ipu;
struct ipu_dmfc_priv *priv;
const struct dmfc_channel_data *data;
......@@ -117,7 +103,6 @@ struct ipu_dmfc_priv {
struct device *dev;
struct dmfc_channel channels[DMFC_NUM_CHANNELS];
struct mutex mutex;
unsigned long bandwidth_per_slot;
void __iomem *base;
int use_count;
};
......@@ -172,184 +157,6 @@ void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
}
EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots,
int segment, int burstsize)
{
struct ipu_dmfc_priv *priv = dmfc->priv;
u32 val, field;
dev_dbg(priv->dev,
"dmfc: using %d slots starting from segment %d for IPU channel %d\n",
slots, segment, dmfc->data->ipu_channel);
switch (slots) {
case 1:
field = DMFC_FIFO_SIZE_64;
break;
case 2:
field = DMFC_FIFO_SIZE_128;
break;
case 4:
field = DMFC_FIFO_SIZE_256;
break;
case 8:
field = DMFC_FIFO_SIZE_512;
break;
default:
return -EINVAL;
}
switch (burstsize) {
case 16:
field |= DMFC_BURSTSIZE_16;
break;
case 32:
field |= DMFC_BURSTSIZE_32;
break;
case 64:
field |= DMFC_BURSTSIZE_64;
break;
case 128:
field |= DMFC_BURSTSIZE_128;
break;
}
field |= DMFC_SEGMENT(segment);
val = readl(priv->base + dmfc->data->channel_reg);
val &= ~(0xff << dmfc->data->shift);
val |= field << dmfc->data->shift;
writel(val, priv->base + dmfc->data->channel_reg);
dmfc->slots = slots;
dmfc->segment = segment;
dmfc->burstsize = burstsize;
dmfc->slotmask = ((1 << slots) - 1) << segment;
return 0;
}
static int dmfc_bandwidth_to_slots(struct ipu_dmfc_priv *priv,
unsigned long bandwidth)
{
int slots = 1;
while (slots * priv->bandwidth_per_slot < bandwidth)
slots *= 2;
return slots;
}
static int dmfc_find_slots(struct ipu_dmfc_priv *priv, int slots)
{
unsigned slotmask_need, slotmask_used = 0;
int i, segment = 0;
slotmask_need = (1 << slots) - 1;
for (i = 0; i < DMFC_NUM_CHANNELS; i++)
slotmask_used |= priv->channels[i].slotmask;
while (slotmask_need <= 0xff) {
if (!(slotmask_used & slotmask_need))
return segment;
slotmask_need <<= 1;
segment++;
}
return -EBUSY;
}
void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc)
{
struct ipu_dmfc_priv *priv = dmfc->priv;
int i;
dev_dbg(priv->dev, "dmfc: freeing %d slots starting from segment %d\n",
dmfc->slots, dmfc->segment);
mutex_lock(&priv->mutex);
if (!dmfc->slots)
goto out;
dmfc->slotmask = 0;
dmfc->slots = 0;
dmfc->segment = 0;
for (i = 0; i < DMFC_NUM_CHANNELS; i++)
priv->channels[i].slotmask = 0;
for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
if (priv->channels[i].slots > 0) {
priv->channels[i].segment =
dmfc_find_slots(priv, priv->channels[i].slots);
priv->channels[i].slotmask =
((1 << priv->channels[i].slots) - 1) <<
priv->channels[i].segment;
}
}
for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
if (priv->channels[i].slots > 0)
ipu_dmfc_setup_channel(&priv->channels[i],
priv->channels[i].slots,
priv->channels[i].segment,
priv->channels[i].burstsize);
}
out:
mutex_unlock(&priv->mutex);
}
EXPORT_SYMBOL_GPL(ipu_dmfc_free_bandwidth);
int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc,
unsigned long bandwidth_pixel_per_second, int burstsize)
{
struct ipu_dmfc_priv *priv = dmfc->priv;
int slots = dmfc_bandwidth_to_slots(priv, bandwidth_pixel_per_second);
int segment = -1, ret = 0;
dev_dbg(priv->dev, "dmfc: trying to allocate %ldMpixel/s for IPU channel %d\n",
bandwidth_pixel_per_second / 1000000,
dmfc->data->ipu_channel);
ipu_dmfc_free_bandwidth(dmfc);
mutex_lock(&priv->mutex);
if (slots > 8) {
ret = -EBUSY;
goto out;
}
/* For the MEM_BG channel, first try to allocate twice the slots */
if (dmfc->data->ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC)
segment = dmfc_find_slots(priv, slots * 2);
else if (slots < 2)
/* Always allocate at least 128*4 bytes (2 slots) */
slots = 2;
if (segment >= 0)
slots *= 2;
else
segment = dmfc_find_slots(priv, slots);
if (segment < 0) {
ret = -EBUSY;
goto out;
}
ipu_dmfc_setup_channel(dmfc, slots, segment, burstsize);
out:
mutex_unlock(&priv->mutex);
return ret;
}
EXPORT_SYMBOL_GPL(ipu_dmfc_alloc_bandwidth);
void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width)
{
struct ipu_dmfc_priv *priv = dmfc->priv;
......@@ -384,7 +191,6 @@ EXPORT_SYMBOL_GPL(ipu_dmfc_get);
void ipu_dmfc_put(struct dmfc_channel *dmfc)
{
ipu_dmfc_free_bandwidth(dmfc);
}
EXPORT_SYMBOL_GPL(ipu_dmfc_put);
......@@ -412,20 +218,15 @@ int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
priv->channels[i].priv = priv;
priv->channels[i].ipu = ipu;
priv->channels[i].data = &dmfcdata[i];
}
writel(0x0, priv->base + DMFC_WR_CHAN);
writel(0x0, priv->base + DMFC_DP_CHAN);
/*
* We have a total bandwidth of clkrate * 4pixel divided
* into 8 slots.
*/
priv->bandwidth_per_slot = clk_get_rate(ipu_clk) * 4 / 8;
dev_dbg(dev, "dmfc: 8 slots with %ldMpixel/s bandwidth each\n",
priv->bandwidth_per_slot / 1000000);
if (dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC ||
dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_FG_SYNC ||
dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_DC_SYNC)
priv->channels[i].slots = 2;
}
writel(0x00000050, priv->base + DMFC_WR_CHAN);
writel(0x00005654, priv->base + DMFC_DP_CHAN);
writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
writel(0x00000003, priv->base + DMFC_GENERAL1);
......
......@@ -235,9 +235,6 @@ int ipu_di_init_sync_panel(struct ipu_di *, struct ipu_di_signal_cfg *sig);
struct dmfc_channel;
int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc);
void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc);
int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc,
unsigned long bandwidth_mbs, int burstsize);
void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc);
void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width);
struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipuv3_channel);
void ipu_dmfc_put(struct dmfc_channel *dmfc);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment