Release 4.7 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
  
  
/*
 * Copyright (C) 2014 Free Electrons
 * Copyright (C) 2014 Atmel
 *
 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include "atmel_hlcdc_dc.h"
static void
atmel_hlcdc_layer_fb_flip_release(struct drm_flip_work *work, void *val)
{
	struct atmel_hlcdc_layer_fb_flip *flip = val;
	if (flip->fb)
		drm_framebuffer_unreference(flip->fb);
	kfree(flip);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| boris brezillon | boris brezillon | 40 | 100.00% | 1 | 100.00% | 
 | Total | 40 | 100.00% | 1 | 100.00% | 
static void
atmel_hlcdc_layer_fb_flip_destroy(struct atmel_hlcdc_layer_fb_flip *flip)
{
	if (flip->fb)
		drm_framebuffer_unreference(flip->fb);
	kfree(flip->task);
	kfree(flip);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| boris brezillon | boris brezillon | 36 | 100.00% | 1 | 100.00% | 
 | Total | 36 | 100.00% | 1 | 100.00% | 
static void
atmel_hlcdc_layer_fb_flip_release_queue(struct atmel_hlcdc_layer *layer,
					struct atmel_hlcdc_layer_fb_flip *flip)
{
	int i;
	if (!flip)
		return;
	for (i = 0; i < layer->max_planes; i++) {
		if (!flip->dscrs[i])
			break;
		flip->dscrs[i]->status = 0;
		flip->dscrs[i] = NULL;
	}
	drm_flip_work_queue_task(&layer->gc, flip->task);
	drm_flip_work_commit(&layer->gc, layer->wq);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| boris brezillon | boris brezillon | 97 | 100.00% | 1 | 100.00% | 
 | Total | 97 | 100.00% | 1 | 100.00% | 
static void atmel_hlcdc_layer_update_reset(struct atmel_hlcdc_layer *layer,
					   int id)
{
	struct atmel_hlcdc_layer_update *upd = &layer->update;
	struct atmel_hlcdc_layer_update_slot *slot;
	if (id < 0 || id > 1)
		return;
	slot = &upd->slots[id];
	bitmap_clear(slot->updated_configs, 0, layer->desc->nconfigs);
	memset(slot->configs, 0,
	       sizeof(*slot->configs) * layer->desc->nconfigs);
	if (slot->fb_flip) {
		atmel_hlcdc_layer_fb_flip_release_queue(layer, slot->fb_flip);
		slot->fb_flip = NULL;
	}
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| boris brezillon | boris brezillon | 111 | 100.00% | 1 | 100.00% | 
 | Total | 111 | 100.00% | 1 | 100.00% | 
static void atmel_hlcdc_layer_update_apply(struct atmel_hlcdc_layer *layer)
{
	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
	const struct atmel_hlcdc_layer_desc *desc = layer->desc;
	struct atmel_hlcdc_layer_update *upd = &layer->update;
	struct regmap *regmap = layer->hlcdc->regmap;
	struct atmel_hlcdc_layer_update_slot *slot;
	struct atmel_hlcdc_layer_fb_flip *fb_flip;
	struct atmel_hlcdc_dma_channel_dscr *dscr;
	unsigned int cfg;
	u32 action = 0;
	int i = 0;
	if (upd->pending < 0 || upd->pending > 1)
		return;
	slot = &upd->slots[upd->pending];
	for_each_set_bit(cfg, slot->updated_configs, layer->desc->nconfigs) {
		regmap_write(regmap,
			     desc->regs_offset +
			     ATMEL_HLCDC_LAYER_CFG(layer, cfg),
			     slot->configs[cfg]);
		action |= ATMEL_HLCDC_LAYER_UPDATE;
	}
	fb_flip = slot->fb_flip;
	if (!fb_flip->fb)
		goto apply;
	if (dma->status == ATMEL_HLCDC_LAYER_DISABLED) {
		for (i = 0; i < fb_flip->ngems; i++) {
			dscr = fb_flip->dscrs[i];
			dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH |
				     ATMEL_HLCDC_LAYER_DMA_IRQ |
				     ATMEL_HLCDC_LAYER_ADD_IRQ |
				     ATMEL_HLCDC_LAYER_DONE_IRQ;
			regmap_write(regmap,
				     desc->regs_offset +
				     ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
				     dscr->addr);
			regmap_write(regmap,
				     desc->regs_offset +
				     ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
				     dscr->ctrl);
			regmap_write(regmap,
				     desc->regs_offset +
				     ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
				     dscr->next);
		}
		action |= ATMEL_HLCDC_LAYER_DMA_CHAN;
		dma->status = ATMEL_HLCDC_LAYER_ENABLED;
	} else {
		for (i = 0; i < fb_flip->ngems; i++) {
			dscr =  fb_flip->dscrs[i];
			dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH |
				     ATMEL_HLCDC_LAYER_DMA_IRQ |
				     ATMEL_HLCDC_LAYER_DSCR_IRQ |
				     ATMEL_HLCDC_LAYER_DONE_IRQ;
			regmap_write(regmap,
				     desc->regs_offset +
				     ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
				     dscr->next);
		}
		action |= ATMEL_HLCDC_LAYER_A2Q;
	}
	/* Release unneeded descriptors */
	for (i = fb_flip->ngems; i < layer->max_planes; i++) {
		fb_flip->dscrs[i]->status = 0;
		fb_flip->dscrs[i] = NULL;
	}
	dma->queue = fb_flip;
	slot->fb_flip = NULL;
apply:
	if (action)
		regmap_write(regmap,
			     desc->regs_offset + ATMEL_HLCDC_LAYER_CHER,
			     action);
	atmel_hlcdc_layer_update_reset(layer, upd->pending);
	upd->pending = -1;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| boris brezillon | boris brezillon | 423 | 100.00% | 1 | 100.00% | 
 | Total | 423 | 100.00% | 1 | 100.00% | 
void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer)
{
	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
	const struct atmel_hlcdc_layer_desc *desc = layer->desc;
	struct regmap *regmap = layer->hlcdc->regmap;
	struct atmel_hlcdc_layer_fb_flip *flip;
	unsigned long flags;
	unsigned int isr, imr;
	unsigned int status;
	unsigned int plane_status;
	u32 flip_status;
	int i;
	regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IMR, &imr);
	regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR, &isr);
	status = imr & isr;
	if (!status)
		return;
	spin_lock_irqsave(&layer->lock, flags);
	flip = dma->queue ? dma->queue : dma->cur;
	if (!flip) {
		spin_unlock_irqrestore(&layer->lock, flags);
		return;
	}
	/*
         * Set LOADED and DONE flags: they'll be cleared if at least one
         * memory plane is not LOADED or DONE.
         */
	flip_status = ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED |
		      ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE;
	for (i = 0; i < flip->ngems; i++) {
		plane_status = (status >> (8 * i));
		if (plane_status &
		    (ATMEL_HLCDC_LAYER_ADD_IRQ |
		     ATMEL_HLCDC_LAYER_DSCR_IRQ) &
		    ~flip->dscrs[i]->ctrl) {
			flip->dscrs[i]->status |=
					ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED;
			flip->dscrs[i]->ctrl |=
					ATMEL_HLCDC_LAYER_ADD_IRQ |
					ATMEL_HLCDC_LAYER_DSCR_IRQ;
		}
		if (plane_status &
		    ATMEL_HLCDC_LAYER_DONE_IRQ &
		    ~flip->dscrs[i]->ctrl) {
			flip->dscrs[i]->status |=
					ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE;
			flip->dscrs[i]->ctrl |=
					ATMEL_HLCDC_LAYER_DONE_IRQ;
		}
		if (plane_status & ATMEL_HLCDC_LAYER_OVR_IRQ)
			flip->dscrs[i]->status |=
					ATMEL_HLCDC_DMA_CHANNEL_DSCR_OVERRUN;
		/*
                 * Clear LOADED and DONE flags if the memory plane is either
                 * not LOADED or not DONE.
                 */
		if (!(flip->dscrs[i]->status &
		      ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED))
			flip_status &= ~ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED;
		if (!(flip->dscrs[i]->status &
		      ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE))
			flip_status &= ~ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE;
		/*
                 * An overrun on one memory plane impact the whole framebuffer
                 * transfer, hence we set the OVERRUN flag as soon as there's
                 * one memory plane reporting such an overrun.
                 */
		flip_status |= flip->dscrs[i]->status &
			       ATMEL_HLCDC_DMA_CHANNEL_DSCR_OVERRUN;
	}
	/* Get changed bits */
	flip_status ^= flip->status;
	flip->status |= flip_status;
	if (flip_status & ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED) {
		atmel_hlcdc_layer_fb_flip_release_queue(layer, dma->cur);
		dma->cur = dma->queue;
		dma->queue = NULL;
	}
	if (flip_status & ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE) {
		atmel_hlcdc_layer_fb_flip_release_queue(layer, dma->cur);
		dma->cur = NULL;
	}
	if (flip_status & ATMEL_HLCDC_DMA_CHANNEL_DSCR_OVERRUN) {
		regmap_write(regmap,
			     desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
			     ATMEL_HLCDC_LAYER_RST);
		if (dma->queue)
			atmel_hlcdc_layer_fb_flip_release_queue(layer,
								dma->queue);
		if (dma->cur)
			atmel_hlcdc_layer_fb_flip_release_queue(layer,
								dma->cur);
		dma->cur = NULL;
		dma->queue = NULL;
	}
	if (!dma->queue) {
		atmel_hlcdc_layer_update_apply(layer);
		if (!dma->cur)
			dma->status = ATMEL_HLCDC_LAYER_DISABLED;
	}
	spin_unlock_irqrestore(&layer->lock, flags);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| boris brezillon | boris brezillon | 515 | 100.00% | 1 | 100.00% | 
 | Total | 515 | 100.00% | 1 | 100.00% | 
void atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
{
	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
	struct atmel_hlcdc_layer_update *upd = &layer->update;
	struct regmap *regmap = layer->hlcdc->regmap;
	const struct atmel_hlcdc_layer_desc *desc = layer->desc;
	unsigned long flags;
	unsigned int isr;
	spin_lock_irqsave(&layer->lock, flags);
	/* Disable the layer */
	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
		     ATMEL_HLCDC_LAYER_RST | ATMEL_HLCDC_LAYER_A2Q |
		     ATMEL_HLCDC_LAYER_UPDATE);
	/* Clear all pending interrupts */
	regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR, &isr);
	/* Discard current and queued framebuffer transfers. */
	if (dma->cur) {
		atmel_hlcdc_layer_fb_flip_release_queue(layer, dma->cur);
		dma->cur = NULL;
	}
	if (dma->queue) {
		atmel_hlcdc_layer_fb_flip_release_queue(layer, dma->queue);
		dma->queue = NULL;
	}
	/*
         * Then discard the pending update request (if any) to prevent
         * DMA irq handler from restarting the DMA channel after it has
         * been disabled.
         */
	if (upd->pending >= 0) {
		atmel_hlcdc_layer_update_reset(layer, upd->pending);
		upd->pending = -1;
	}
	dma->status = ATMEL_HLCDC_LAYER_DISABLED;
	spin_unlock_irqrestore(&layer->lock, flags);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| boris brezillon | boris brezillon | 192 | 100.00% | 3 | 100.00% | 
 | Total | 192 | 100.00% | 3 | 100.00% | 
int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer)
{
	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
	struct atmel_hlcdc_layer_update *upd = &layer->update;
	struct regmap *regmap = layer->hlcdc->regmap;
	struct atmel_hlcdc_layer_fb_flip *fb_flip;
	struct atmel_hlcdc_layer_update_slot *slot;
	unsigned long flags;
	int i, j = 0;
	fb_flip = kzalloc(sizeof(*fb_flip), GFP_KERNEL);
	if (!fb_flip)
		return -ENOMEM;
	fb_flip->task = drm_flip_work_allocate_task(fb_flip, GFP_KERNEL);
	if (!fb_flip->task) {
		kfree(fb_flip);
		return -ENOMEM;
	}
	spin_lock_irqsave(&layer->lock, flags);
	upd->next = upd->pending ? 0 : 1;
	slot = &upd->slots[upd->next];
	for (i = 0; i < layer->max_planes * 4; i++) {
		if (!dma->dscrs[i].status) {
			fb_flip->dscrs[j++] = &dma->dscrs[i];
			dma->dscrs[i].status =
				ATMEL_HLCDC_DMA_CHANNEL_DSCR_RESERVED;
			if (j == layer->max_planes)
				break;
		}
	}
	if (j < layer->max_planes) {
		for (i = 0; i < j; i++)
			fb_flip->dscrs[i]->status = 0;
	}
	if (j < layer->max_planes) {
		spin_unlock_irqrestore(&layer->lock, flags);
		atmel_hlcdc_layer_fb_flip_destroy(fb_flip);
		return -EBUSY;
	}
	slot->fb_flip = fb_flip;
	if (upd->pending >= 0) {
		memcpy(slot->configs,
		       upd->slots[upd->pending].configs,
		       layer->desc->nconfigs * sizeof(u32));
		memcpy(slot->updated_configs,
		       upd->slots[upd->pending].updated_configs,
		       DIV_ROUND_UP(layer->desc->nconfigs,
				    BITS_PER_BYTE * sizeof(unsigned long)) *
		       sizeof(unsigned long));
		slot->fb_flip->fb = upd->slots[upd->pending].fb_flip->fb;
		if (upd->slots[upd->pending].fb_flip->fb) {
			slot->fb_flip->fb =
				upd->slots[upd->pending].fb_flip->fb;
			slot->fb_flip->ngems =
				upd->slots[upd->pending].fb_flip->ngems;
			drm_framebuffer_reference(slot->fb_flip->fb);
		}
	} else {
		regmap_bulk_read(regmap,
				 layer->desc->regs_offset +
				 ATMEL_HLCDC_LAYER_CFG(layer, 0),
				 upd->slots[upd->next].configs,
				 layer->desc->nconfigs);
	}
	spin_unlock_irqrestore(&layer->lock, flags);
	return 0;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| boris brezillon | boris brezillon | 499 | 100.00% | 1 | 100.00% | 
 | Total | 499 | 100.00% | 1 | 100.00% | 
void atmel_hlcdc_layer_update_rollback(struct atmel_hlcdc_layer *layer)
{
	struct atmel_hlcdc_layer_update *upd = &layer->update;
	atmel_hlcdc_layer_update_reset(layer, upd->next);
	upd->next = -1;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| boris brezillon | boris brezillon | 36 | 100.00% | 1 | 100.00% | 
 | Total | 36 | 100.00% | 1 | 100.00% | 
void atmel_hlcdc_layer_update_set_fb(struct atmel_hlcdc_layer *layer,
				     struct drm_framebuffer *fb,
				     unsigned int *offsets)
{
	struct atmel_hlcdc_layer_update *upd = &layer->update;
	struct atmel_hlcdc_layer_fb_flip *fb_flip;
	struct atmel_hlcdc_layer_update_slot *slot;
	struct atmel_hlcdc_dma_channel_dscr *dscr;
	struct drm_framebuffer *old_fb;
	int nplanes = 0;
	int i;
	if (upd->next < 0 || upd->next > 1)
		return;
	if (fb)
		nplanes = drm_format_num_planes(fb->pixel_format);
	if (nplanes > layer->max_planes)
		return;
	slot = &upd->slots[upd->next];
	fb_flip = slot->fb_flip;
	old_fb = slot->fb_flip->fb;
	for (i = 0; i < nplanes; i++) {
		struct drm_gem_cma_object *gem;
		dscr = slot->fb_flip->dscrs[i];
		gem = drm_fb_cma_get_gem_obj(fb, i);
		dscr->addr = gem->paddr + offsets[i];
	}
	fb_flip->ngems = nplanes;
	fb_flip->fb = fb;
	if (fb)
		drm_framebuffer_reference(fb);
	if (old_fb)
		drm_framebuffer_unreference(old_fb);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| boris brezillon | boris brezillon | 204 | 100.00% | 1 | 100.00% | 
 | Total | 204 | 100.00% | 1 | 100.00% | 
void atmel_hlcdc_layer_update_cfg(struct atmel_hlcdc_layer *layer, int cfg,
				  u32 mask, u32 val)
{
	struct atmel_hlcdc_layer_update *upd = &layer->update;
	struct atmel_hlcdc_layer_update_slot *slot;
	if (upd->next < 0 || upd->next > 1)
		return;
	if (cfg >= layer->desc->nconfigs)
		return;
	slot = &upd->slots[upd->next];
	slot->configs[cfg] &= ~mask;
	slot->configs[cfg] |= (val & mask);
	set_bit(cfg, slot->updated_configs);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| boris brezillon | boris brezillon | 104 | 100.00% | 1 | 100.00% | 
 | Total | 104 | 100.00% | 1 | 100.00% | 
void atmel_hlcdc_layer_update_commit(struct atmel_hlcdc_layer *layer)
{
	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
	struct atmel_hlcdc_layer_update *upd = &layer->update;
	struct atmel_hlcdc_layer_update_slot *slot;
	unsigned long flags;
	if (upd->next < 0  || upd->next > 1)
		return;
	slot = &upd->slots[upd->next];
	spin_lock_irqsave(&layer->lock, flags);
	/*
         * Release pending update request and replace it by the new one.
         */
	if (upd->pending >= 0)
		atmel_hlcdc_layer_update_reset(layer, upd->pending);
	upd->pending = upd->next;
	upd->next = -1;
	if (!dma->queue)
		atmel_hlcdc_layer_update_apply(layer);
	spin_unlock_irqrestore(&layer->lock, flags);
	upd->next = -1;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| boris brezillon | boris brezillon | 138 | 100.00% | 1 | 100.00% | 
 | Total | 138 | 100.00% | 1 | 100.00% | 
static int atmel_hlcdc_layer_dma_init(struct drm_device *dev,
				      struct atmel_hlcdc_layer *layer)
{
	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
	dma_addr_t dma_addr;
	int i;
	dma->dscrs = dma_alloc_coherent(dev->dev,
					layer->max_planes * 4 *
					sizeof(*dma->dscrs),
					&dma_addr, GFP_KERNEL);
	if (!dma->dscrs)
		return -ENOMEM;
	for (i = 0; i < layer->max_planes * 4; i++) {
		struct atmel_hlcdc_dma_channel_dscr *dscr = &dma->dscrs[i];
		dscr->next = dma_addr + (i * sizeof(*dscr));
	}
	return 0;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| boris brezillon | boris brezillon | 124 | 100.00% | 1 | 100.00% | 
 | Total | 124 | 100.00% | 1 | 100.00% | 
static void atmel_hlcdc_layer_dma_cleanup(struct drm_device *dev,
					  struct atmel_hlcdc_layer *layer)
{
	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
	int i;
	for (i = 0; i < layer->max_planes * 4; i++) {
		struct atmel_hlcdc_dma_channel_dscr *dscr = &dma->dscrs[i];
		dscr->status = 0;
	}
	dma_free_coherent(dev->dev, layer->max_planes * 4 *
			  sizeof(*dma->dscrs), dma->dscrs,
			  dma->dscrs[0].next);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| boris brezillon | boris brezillon | 101 | 100.00% | 1 | 100.00% | 
 | Total | 101 | 100.00% | 1 | 100.00% | 
static int atmel_hlcdc_layer_update_init(struct drm_device *dev,
				struct atmel_hlcdc_layer *layer,
				const struct atmel_hlcdc_layer_desc *desc)
{
	struct atmel_hlcdc_layer_update *upd = &layer->update;
	int updated_size;
	void *buffer;
	int i;
	updated_size = DIV_ROUND_UP(desc->nconfigs,
				    BITS_PER_BYTE *
				    sizeof(unsigned long));
	buffer = devm_kzalloc(dev->dev,
			      ((desc->nconfigs * sizeof(u32)) +
				(updated_size * sizeof(unsigned long))) * 2,
			      GFP_KERNEL);
	if (!buffer)
		return -ENOMEM;
	for (i = 0; i < 2; i++) {
		upd->slots[i].updated_configs = buffer;
		buffer += updated_size * sizeof(unsigned long);
		upd->slots[i].configs = buffer;
		buffer += desc->nconfigs * sizeof(u32);
	}
	upd->pending = -1;
	upd->next = -1;
	return 0;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| boris brezillon | boris brezillon | 179 | 100.00% | 1 | 100.00% | 
 | Total | 179 | 100.00% | 1 | 100.00% | 
int atmel_hlcdc_layer_init(struct drm_device *dev,
			   struct atmel_hlcdc_layer *layer,
			   const struct atmel_hlcdc_layer_desc *desc)
{
	struct atmel_hlcdc_dc *dc = dev->dev_private;
	struct regmap *regmap = dc->hlcdc->regmap;
	unsigned int tmp;
	int ret;
	int i;
	layer->hlcdc = dc->hlcdc;
	layer->wq = dc->wq;
	layer->desc = desc;
	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
		     ATMEL_HLCDC_LAYER_RST);
	for (i = 0; i < desc->formats->nformats; i++) {
		int nplanes = drm_format_num_planes(desc->formats->formats[i]);
		if (nplanes > layer->max_planes)
			layer->max_planes = nplanes;
	}
	spin_lock_init(&layer->lock);
	drm_flip_work_init(&layer->gc, desc->name,
			   atmel_hlcdc_layer_fb_flip_release);
	ret = atmel_hlcdc_layer_dma_init(dev, layer);
	if (ret)
		return ret;
	ret = atmel_hlcdc_layer_update_init(dev, layer, desc);
	if (ret)
		return ret;
	/* Flush Status Register */
	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IDR,
		     0xffffffff);
	regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR,
		    &tmp);
	tmp = 0;
	for (i = 0; i < layer->max_planes; i++)
		tmp |= (ATMEL_HLCDC_LAYER_DMA_IRQ |
			ATMEL_HLCDC_LAYER_DSCR_IRQ |
			ATMEL_HLCDC_LAYER_ADD_IRQ |
			ATMEL_HLCDC_LAYER_DONE_IRQ |
			ATMEL_HLCDC_LAYER_OVR_IRQ) << (8 * i);
	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IER, tmp);
	return 0;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| boris brezillon | boris brezillon | 273 | 100.00% | 1 | 100.00% | 
 | Total | 273 | 100.00% | 1 | 100.00% | 
void atmel_hlcdc_layer_cleanup(struct drm_device *dev,
			       struct atmel_hlcdc_layer *layer)
{
	const struct atmel_hlcdc_layer_desc *desc = layer->desc;
	struct regmap *regmap = layer->hlcdc->regmap;
	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IDR,
		     0xffffffff);
	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
		     ATMEL_HLCDC_LAYER_RST);
	atmel_hlcdc_layer_dma_cleanup(dev, layer);
	drm_flip_work_cleanup(&layer->gc);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| boris brezillon | boris brezillon | 77 | 100.00% | 1 | 100.00% | 
 | Total | 77 | 100.00% | 1 | 100.00% | 
Overall Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| boris brezillon | boris brezillon | 3159 | 100.00% | 3 | 100.00% | 
 | Total | 3159 | 100.00% | 3 | 100.00% | 
  
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.