123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666 |
- /*
- * 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);
- }
- 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);
- }
- 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);
- }
- 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;
- }
- }
- 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;
- }
- 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);
- }
- 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);
- }
- 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;
- }
- 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;
- }
- 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);
- }
- 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);
- }
- 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;
- }
- 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;
- }
- 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);
- }
- 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;
- }
- 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;
- }
- 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);
- }
|