| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (C) 2014 Free Electrons
- * Copyright (C) 2014 Atmel
- *
- * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
- */
- #include <linux/dmapool.h>
- #include <linux/mfd/atmel-hlcdc.h>
- #include <drm/drm_atomic.h>
- #include <drm/drm_atomic_helper.h>
- #include <drm/drm_blend.h>
- #include <drm/drm_fb_dma_helper.h>
- #include <drm/drm_fourcc.h>
- #include <drm/drm_framebuffer.h>
- #include <drm/drm_gem_dma_helper.h>
- #include "atmel_hlcdc_dc.h"
- /**
- * struct atmel_hlcdc_plane_state - Atmel HLCDC Plane state structure.
- *
- * @base: DRM plane state
- * @crtc_x: x position of the plane relative to the CRTC
- * @crtc_y: y position of the plane relative to the CRTC
- * @crtc_w: visible width of the plane
- * @crtc_h: visible height of the plane
- * @src_x: x buffer position
- * @src_y: y buffer position
- * @src_w: buffer width
- * @src_h: buffer height
- * @disc_x: x discard position
- * @disc_y: y discard position
- * @disc_w: discard width
- * @disc_h: discard height
- * @ahb_id: AHB identification number
- * @bpp: bytes per pixel deduced from pixel_format
- * @offsets: offsets to apply to the GEM buffers
- * @xstride: value to add to the pixel pointer between each line
- * @pstride: value to add to the pixel pointer between each pixel
- * @nplanes: number of planes (deduced from pixel_format)
- * @dscrs: DMA descriptors
- */
- struct atmel_hlcdc_plane_state {
- struct drm_plane_state base;
- int crtc_x;
- int crtc_y;
- unsigned int crtc_w;
- unsigned int crtc_h;
- uint32_t src_x;
- uint32_t src_y;
- uint32_t src_w;
- uint32_t src_h;
- int disc_x;
- int disc_y;
- int disc_w;
- int disc_h;
- int ahb_id;
- /* These fields are private and should not be touched */
- int bpp[ATMEL_HLCDC_LAYER_MAX_PLANES];
- unsigned int offsets[ATMEL_HLCDC_LAYER_MAX_PLANES];
- int xstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
- int pstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
- int nplanes;
- /* DMA descriptors. */
- struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_LAYER_MAX_PLANES];
- };
- static inline struct atmel_hlcdc_plane_state *
- drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
- {
- return container_of(s, struct atmel_hlcdc_plane_state, base);
- }
- #define SUBPIXEL_MASK 0xffff
- static uint32_t rgb_formats[] = {
- DRM_FORMAT_C8,
- DRM_FORMAT_XRGB4444,
- DRM_FORMAT_ARGB4444,
- DRM_FORMAT_RGBA4444,
- DRM_FORMAT_ARGB1555,
- DRM_FORMAT_RGB565,
- DRM_FORMAT_RGB888,
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_ARGB8888,
- DRM_FORMAT_RGBA8888,
- };
- struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
- .formats = rgb_formats,
- .nformats = ARRAY_SIZE(rgb_formats),
- };
- static uint32_t rgb_and_yuv_formats[] = {
- DRM_FORMAT_C8,
- DRM_FORMAT_XRGB4444,
- DRM_FORMAT_ARGB4444,
- DRM_FORMAT_RGBA4444,
- DRM_FORMAT_ARGB1555,
- DRM_FORMAT_RGB565,
- DRM_FORMAT_RGB888,
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_ARGB8888,
- DRM_FORMAT_RGBA8888,
- DRM_FORMAT_AYUV,
- DRM_FORMAT_YUYV,
- DRM_FORMAT_UYVY,
- DRM_FORMAT_YVYU,
- DRM_FORMAT_VYUY,
- DRM_FORMAT_NV21,
- DRM_FORMAT_NV61,
- DRM_FORMAT_YUV422,
- DRM_FORMAT_YUV420,
- };
- struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
- .formats = rgb_and_yuv_formats,
- .nformats = ARRAY_SIZE(rgb_and_yuv_formats),
- };
- static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
- {
- switch (format) {
- case DRM_FORMAT_C8:
- *mode = ATMEL_HLCDC_C8_MODE;
- break;
- case DRM_FORMAT_XRGB4444:
- *mode = ATMEL_HLCDC_XRGB4444_MODE;
- break;
- case DRM_FORMAT_ARGB4444:
- *mode = ATMEL_HLCDC_ARGB4444_MODE;
- break;
- case DRM_FORMAT_RGBA4444:
- *mode = ATMEL_HLCDC_RGBA4444_MODE;
- break;
- case DRM_FORMAT_RGB565:
- *mode = ATMEL_HLCDC_RGB565_MODE;
- break;
- case DRM_FORMAT_RGB888:
- *mode = ATMEL_HLCDC_RGB888_MODE;
- break;
- case DRM_FORMAT_ARGB1555:
- *mode = ATMEL_HLCDC_ARGB1555_MODE;
- break;
- case DRM_FORMAT_XRGB8888:
- *mode = ATMEL_HLCDC_XRGB8888_MODE;
- break;
- case DRM_FORMAT_ARGB8888:
- *mode = ATMEL_HLCDC_ARGB8888_MODE;
- break;
- case DRM_FORMAT_RGBA8888:
- *mode = ATMEL_HLCDC_RGBA8888_MODE;
- break;
- case DRM_FORMAT_AYUV:
- *mode = ATMEL_HLCDC_AYUV_MODE;
- break;
- case DRM_FORMAT_YUYV:
- *mode = ATMEL_HLCDC_YUYV_MODE;
- break;
- case DRM_FORMAT_UYVY:
- *mode = ATMEL_HLCDC_UYVY_MODE;
- break;
- case DRM_FORMAT_YVYU:
- *mode = ATMEL_HLCDC_YVYU_MODE;
- break;
- case DRM_FORMAT_VYUY:
- *mode = ATMEL_HLCDC_VYUY_MODE;
- break;
- case DRM_FORMAT_NV21:
- *mode = ATMEL_HLCDC_NV21_MODE;
- break;
- case DRM_FORMAT_NV61:
- *mode = ATMEL_HLCDC_NV61_MODE;
- break;
- case DRM_FORMAT_YUV420:
- *mode = ATMEL_HLCDC_YUV420_MODE;
- break;
- case DRM_FORMAT_YUV422:
- *mode = ATMEL_HLCDC_YUV422_MODE;
- break;
- default:
- return -ENOTSUPP;
- }
- return 0;
- }
- static u32 heo_downscaling_xcoef[] = {
- 0x11343311,
- 0x000000f7,
- 0x1635300c,
- 0x000000f9,
- 0x1b362c08,
- 0x000000fb,
- 0x1f372804,
- 0x000000fe,
- 0x24382400,
- 0x00000000,
- 0x28371ffe,
- 0x00000004,
- 0x2c361bfb,
- 0x00000008,
- 0x303516f9,
- 0x0000000c,
- };
- static u32 heo_downscaling_ycoef[] = {
- 0x00123737,
- 0x00173732,
- 0x001b382d,
- 0x001f3928,
- 0x00243824,
- 0x0028391f,
- 0x002d381b,
- 0x00323717,
- };
- static u32 heo_upscaling_xcoef[] = {
- 0xf74949f7,
- 0x00000000,
- 0xf55f33fb,
- 0x000000fe,
- 0xf5701efe,
- 0x000000ff,
- 0xf87c0dff,
- 0x00000000,
- 0x00800000,
- 0x00000000,
- 0x0d7cf800,
- 0x000000ff,
- 0x1e70f5ff,
- 0x000000fe,
- 0x335ff5fe,
- 0x000000fb,
- };
- static u32 heo_upscaling_ycoef[] = {
- 0x00004040,
- 0x00075920,
- 0x00056f0c,
- 0x00027b03,
- 0x00008000,
- 0x00037b02,
- 0x000c6f05,
- 0x00205907,
- };
- #define ATMEL_HLCDC_XPHIDEF 4
- #define ATMEL_HLCDC_YPHIDEF 4
- static u32 atmel_hlcdc_plane_phiscaler_get_factor(u32 srcsize,
- u32 dstsize,
- u32 phidef)
- {
- u32 factor, max_memsize;
- factor = (256 * ((8 * (srcsize - 1)) - phidef)) / (dstsize - 1);
- max_memsize = ((factor * (dstsize - 1)) + (256 * phidef)) / 2048;
- if (max_memsize > srcsize - 1)
- factor--;
- return factor;
- }
- static void
- atmel_hlcdc_plane_scaler_set_phicoeff(struct atmel_hlcdc_plane *plane,
- const u32 *coeff_tab, int size,
- unsigned int cfg_offs)
- {
- int i;
- for (i = 0; i < size; i++)
- atmel_hlcdc_layer_write_cfg(&plane->layer, cfg_offs + i,
- coeff_tab[i]);
- }
- static
- void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_plane_state *state)
- {
- const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
- u32 xfactor, yfactor;
- if (!desc->layout.scaler_config)
- return;
- if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
- atmel_hlcdc_layer_write_cfg(&plane->layer,
- desc->layout.scaler_config, 0);
- return;
- }
- if (desc->layout.phicoeffs.x) {
- xfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_w,
- state->crtc_w,
- ATMEL_HLCDC_XPHIDEF);
- yfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_h,
- state->crtc_h,
- ATMEL_HLCDC_YPHIDEF);
- atmel_hlcdc_plane_scaler_set_phicoeff(plane,
- state->crtc_w < state->src_w ?
- heo_downscaling_xcoef :
- heo_upscaling_xcoef,
- ARRAY_SIZE(heo_upscaling_xcoef),
- desc->layout.phicoeffs.x);
- atmel_hlcdc_plane_scaler_set_phicoeff(plane,
- state->crtc_h < state->src_h ?
- heo_downscaling_ycoef :
- heo_upscaling_ycoef,
- ARRAY_SIZE(heo_upscaling_ycoef),
- desc->layout.phicoeffs.y);
- } else {
- xfactor = (1024 * state->src_w) / state->crtc_w;
- yfactor = (1024 * state->src_h) / state->crtc_h;
- }
- atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
- ATMEL_HLCDC_LAYER_SCALER_ENABLE |
- ATMEL_HLCDC_LAYER_SCALER_FACTORS(xfactor,
- yfactor));
- }
- static
- void atmel_xlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_plane_state *state)
- {
- const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
- u32 xfactor, yfactor;
- if (!desc->layout.scaler_config)
- return;
- if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
- atmel_hlcdc_layer_write_cfg(&plane->layer,
- desc->layout.scaler_config, 0);
- return;
- }
- /* xfactor = round[(2^20 * XMEMSIZE)/XSIZE)] */
- xfactor = (u32)(((1 << 20) * state->src_w) / state->crtc_w);
- /* yfactor = round[(2^20 * YMEMSIZE)/YSIZE)] */
- yfactor = (u32)(((1 << 20) * state->src_h) / state->crtc_h);
- atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
- ATMEL_XLCDC_LAYER_VSCALER_LUMA_ENABLE |
- ATMEL_XLCDC_LAYER_VSCALER_CHROMA_ENABLE |
- ATMEL_XLCDC_LAYER_HSCALER_LUMA_ENABLE |
- ATMEL_XLCDC_LAYER_HSCALER_CHROMA_ENABLE);
- atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 1,
- yfactor);
- atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 3,
- xfactor);
- /*
- * With YCbCr 4:2:2 and YCbYcr 4:2:0 window resampling, configuration
- * register LCDC_HEOCFG25.VXSCFACT and LCDC_HEOCFG27.HXSCFACT is half
- * the value of yfactor and xfactor.
- */
- if (state->base.fb->format->format == DRM_FORMAT_YUV420) {
- yfactor /= 2;
- xfactor /= 2;
- }
- atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 2,
- yfactor);
- atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 4,
- xfactor);
- }
- static void
- atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_plane_state *state)
- {
- const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
- struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
- if (desc->layout.size)
- atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.size,
- ATMEL_HLCDC_LAYER_SIZE(state->crtc_w,
- state->crtc_h));
- if (desc->layout.memsize)
- atmel_hlcdc_layer_write_cfg(&plane->layer,
- desc->layout.memsize,
- ATMEL_HLCDC_LAYER_SIZE(state->src_w,
- state->src_h));
- if (desc->layout.pos)
- atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.pos,
- ATMEL_HLCDC_LAYER_POS(state->crtc_x,
- state->crtc_y));
- dc->desc->ops->plane_setup_scaler(plane, state);
- }
- static
- void atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_plane_state *state)
- {
- unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id;
- const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
- const struct drm_format_info *format = state->base.fb->format;
- /*
- * Rotation optimization is not working on RGB888 (rotation is still
- * working but without any optimization).
- */
- if (format->format == DRM_FORMAT_RGB888)
- cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS;
- atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG,
- cfg);
- cfg = ATMEL_HLCDC_LAYER_DMA | ATMEL_HLCDC_LAYER_REP;
- if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
- cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
- ATMEL_HLCDC_LAYER_ITER;
- if (format->has_alpha)
- cfg |= ATMEL_HLCDC_LAYER_LAEN;
- else
- cfg |= ATMEL_HLCDC_LAYER_GAEN |
- ATMEL_HLCDC_LAYER_GA(state->base.alpha);
- }
- if (state->disc_h && state->disc_w)
- cfg |= ATMEL_HLCDC_LAYER_DISCEN;
- atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
- cfg);
- }
- static
- void atmel_xlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_plane_state *state)
- {
- const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
- const struct drm_format_info *format = state->base.fb->format;
- unsigned int cfg;
- atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_XLCDC_LAYER_DMA_CFG,
- ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id);
- cfg = ATMEL_XLCDC_LAYER_DMA | ATMEL_XLCDC_LAYER_REP;
- if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
- /*
- * Alpha Blending bits specific to SAM9X7 SoC
- */
- cfg |= ATMEL_XLCDC_LAYER_SFACTC_A0_MULT_AS |
- ATMEL_XLCDC_LAYER_SFACTA_ONE |
- ATMEL_XLCDC_LAYER_DFACTC_M_A0_MULT_AS |
- ATMEL_XLCDC_LAYER_DFACTA_ONE;
- if (format->has_alpha)
- cfg |= ATMEL_XLCDC_LAYER_A0(0xff);
- else
- cfg |= ATMEL_XLCDC_LAYER_A0(state->base.alpha);
- }
- if (state->disc_h && state->disc_w)
- cfg |= ATMEL_XLCDC_LAYER_DISCEN;
- atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
- cfg);
- }
- static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_plane_state *state)
- {
- u32 cfg;
- int ret;
- ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->format->format,
- &cfg);
- if (ret)
- return;
- if ((state->base.fb->format->format == DRM_FORMAT_YUV422 ||
- state->base.fb->format->format == DRM_FORMAT_NV61) &&
- drm_rotation_90_or_270(state->base.rotation))
- cfg |= ATMEL_HLCDC_YUV422ROT;
- atmel_hlcdc_layer_write_cfg(&plane->layer,
- ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg);
- }
- static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_plane_state *state)
- {
- struct drm_crtc *crtc = state->base.crtc;
- struct drm_color_lut *lut;
- int idx;
- if (!crtc || !crtc->state)
- return;
- if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
- return;
- lut = (struct drm_color_lut *)crtc->state->gamma_lut->data;
- for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++, lut++) {
- u32 val = ((lut->red << 8) & 0xff0000) |
- (lut->green & 0xff00) |
- (lut->blue >> 8);
- atmel_hlcdc_layer_write_clut(&plane->layer, idx, val);
- }
- }
- static void atmel_hlcdc_update_buffers(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_plane_state *state,
- u32 sr, int i)
- {
- atmel_hlcdc_layer_write_reg(&plane->layer,
- ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
- state->dscrs[i]->self);
- if (sr & ATMEL_HLCDC_LAYER_EN)
- return;
- atmel_hlcdc_layer_write_reg(&plane->layer,
- ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
- state->dscrs[i]->addr);
- atmel_hlcdc_layer_write_reg(&plane->layer,
- ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
- state->dscrs[i]->ctrl);
- atmel_hlcdc_layer_write_reg(&plane->layer,
- ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
- state->dscrs[i]->self);
- }
- static void atmel_xlcdc_update_buffers(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_plane_state *state,
- u32 sr, int i)
- {
- atmel_hlcdc_layer_write_reg(&plane->layer,
- ATMEL_XLCDC_LAYER_PLANE_ADDR(i),
- state->dscrs[i]->addr);
- }
- static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_plane_state *state)
- {
- const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
- struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
- struct drm_framebuffer *fb = state->base.fb;
- u32 sr;
- int i;
- if (!dc->desc->is_xlcdc)
- sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
- for (i = 0; i < state->nplanes; i++) {
- struct drm_gem_dma_object *gem = drm_fb_dma_get_gem_obj(fb, i);
- state->dscrs[i]->addr = gem->dma_addr + state->offsets[i];
- dc->desc->ops->lcdc_update_buffers(plane, state, sr, i);
- if (desc->layout.xstride[i])
- atmel_hlcdc_layer_write_cfg(&plane->layer,
- desc->layout.xstride[i],
- state->xstride[i]);
- if (desc->layout.pstride[i])
- atmel_hlcdc_layer_write_cfg(&plane->layer,
- desc->layout.pstride[i],
- state->pstride[i]);
- }
- }
- int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
- {
- unsigned int ahb_load[2] = { };
- struct drm_plane *plane;
- drm_atomic_crtc_state_for_each_plane(plane, c_state) {
- struct atmel_hlcdc_plane_state *plane_state;
- struct drm_plane_state *plane_s;
- unsigned int pixels, load = 0;
- int i;
- plane_s = drm_atomic_get_plane_state(c_state->state, plane);
- if (IS_ERR(plane_s))
- return PTR_ERR(plane_s);
- plane_state =
- drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
- pixels = (plane_state->src_w * plane_state->src_h) -
- (plane_state->disc_w * plane_state->disc_h);
- for (i = 0; i < plane_state->nplanes; i++)
- load += pixels * plane_state->bpp[i];
- if (ahb_load[0] <= ahb_load[1])
- plane_state->ahb_id = 0;
- else
- plane_state->ahb_id = 1;
- ahb_load[plane_state->ahb_id] += load;
- }
- return 0;
- }
- int
- atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
- {
- int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
- const struct atmel_hlcdc_layer_cfg_layout *layout;
- struct atmel_hlcdc_plane_state *primary_state;
- struct drm_plane_state *primary_s;
- struct atmel_hlcdc_plane *primary;
- struct drm_plane *ovl;
- primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
- layout = &primary->layer.desc->layout;
- if (!layout->disc_pos || !layout->disc_size)
- return 0;
- primary_s = drm_atomic_get_plane_state(c_state->state,
- &primary->base);
- if (IS_ERR(primary_s))
- return PTR_ERR(primary_s);
- primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
- drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
- struct atmel_hlcdc_plane_state *ovl_state;
- struct drm_plane_state *ovl_s;
- if (ovl == c_state->crtc->primary)
- continue;
- ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
- if (IS_ERR(ovl_s))
- return PTR_ERR(ovl_s);
- ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
- if (!ovl_s->visible ||
- !ovl_s->fb ||
- ovl_s->fb->format->has_alpha ||
- ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE)
- continue;
- /* TODO: implement a smarter hidden area detection */
- if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
- continue;
- disc_x = ovl_state->crtc_x;
- disc_y = ovl_state->crtc_y;
- disc_h = ovl_state->crtc_h;
- disc_w = ovl_state->crtc_w;
- }
- primary_state->disc_x = disc_x;
- primary_state->disc_y = disc_y;
- primary_state->disc_w = disc_w;
- primary_state->disc_h = disc_h;
- return 0;
- }
- static void
- atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_plane_state *state)
- {
- const struct atmel_hlcdc_layer_cfg_layout *layout;
- layout = &plane->layer.desc->layout;
- if (!layout->disc_pos || !layout->disc_size)
- return;
- atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
- ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
- state->disc_y));
- atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
- ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
- state->disc_h));
- }
- static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
- struct drm_atomic_state *state)
- {
- struct drm_plane_state *s = drm_atomic_get_new_plane_state(state, p);
- struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
- struct atmel_hlcdc_plane_state *hstate =
- drm_plane_state_to_atmel_hlcdc_plane_state(s);
- const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
- struct drm_framebuffer *fb = hstate->base.fb;
- const struct drm_display_mode *mode;
- struct drm_crtc_state *crtc_state;
- int ret;
- int i;
- if (!hstate->base.crtc || WARN_ON(!fb))
- return 0;
- crtc_state = drm_atomic_get_existing_crtc_state(state, s->crtc);
- mode = &crtc_state->adjusted_mode;
- ret = drm_atomic_helper_check_plane_state(s, crtc_state,
- (1 << 16) / 2048,
- INT_MAX, true, true);
- if (ret || !s->visible)
- return ret;
- hstate->src_x = s->src.x1;
- hstate->src_y = s->src.y1;
- hstate->src_w = drm_rect_width(&s->src);
- hstate->src_h = drm_rect_height(&s->src);
- hstate->crtc_x = s->dst.x1;
- hstate->crtc_y = s->dst.y1;
- hstate->crtc_w = drm_rect_width(&s->dst);
- hstate->crtc_h = drm_rect_height(&s->dst);
- if ((hstate->src_x | hstate->src_y | hstate->src_w | hstate->src_h) &
- SUBPIXEL_MASK)
- return -EINVAL;
- hstate->src_x >>= 16;
- hstate->src_y >>= 16;
- hstate->src_w >>= 16;
- hstate->src_h >>= 16;
- hstate->nplanes = fb->format->num_planes;
- if (hstate->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
- return -EINVAL;
- for (i = 0; i < hstate->nplanes; i++) {
- unsigned int offset = 0;
- int xdiv = i ? fb->format->hsub : 1;
- int ydiv = i ? fb->format->vsub : 1;
- hstate->bpp[i] = fb->format->cpp[i];
- if (!hstate->bpp[i])
- return -EINVAL;
- switch (hstate->base.rotation & DRM_MODE_ROTATE_MASK) {
- case DRM_MODE_ROTATE_90:
- offset = (hstate->src_y / ydiv) *
- fb->pitches[i];
- offset += ((hstate->src_x + hstate->src_w - 1) /
- xdiv) * hstate->bpp[i];
- hstate->xstride[i] = -(((hstate->src_h - 1) / ydiv) *
- fb->pitches[i]) -
- (2 * hstate->bpp[i]);
- hstate->pstride[i] = fb->pitches[i] - hstate->bpp[i];
- break;
- case DRM_MODE_ROTATE_180:
- offset = ((hstate->src_y + hstate->src_h - 1) /
- ydiv) * fb->pitches[i];
- offset += ((hstate->src_x + hstate->src_w - 1) /
- xdiv) * hstate->bpp[i];
- hstate->xstride[i] = ((((hstate->src_w - 1) / xdiv) - 1) *
- hstate->bpp[i]) - fb->pitches[i];
- hstate->pstride[i] = -2 * hstate->bpp[i];
- break;
- case DRM_MODE_ROTATE_270:
- offset = ((hstate->src_y + hstate->src_h - 1) /
- ydiv) * fb->pitches[i];
- offset += (hstate->src_x / xdiv) * hstate->bpp[i];
- hstate->xstride[i] = ((hstate->src_h - 1) / ydiv) *
- fb->pitches[i];
- hstate->pstride[i] = -fb->pitches[i] - hstate->bpp[i];
- break;
- case DRM_MODE_ROTATE_0:
- default:
- offset = (hstate->src_y / ydiv) * fb->pitches[i];
- offset += (hstate->src_x / xdiv) * hstate->bpp[i];
- hstate->xstride[i] = fb->pitches[i] -
- ((hstate->src_w / xdiv) *
- hstate->bpp[i]);
- hstate->pstride[i] = 0;
- break;
- }
- hstate->offsets[i] = offset + fb->offsets[i];
- }
- /*
- * Swap width and size in case of 90 or 270 degrees rotation
- */
- if (drm_rotation_90_or_270(hstate->base.rotation)) {
- swap(hstate->src_w, hstate->src_h);
- }
- if (!desc->layout.size &&
- (mode->hdisplay != hstate->crtc_w ||
- mode->vdisplay != hstate->crtc_h))
- return -EINVAL;
- if ((hstate->crtc_h != hstate->src_h || hstate->crtc_w != hstate->src_w) &&
- (!desc->layout.memsize ||
- hstate->base.fb->format->has_alpha))
- return -EINVAL;
- return 0;
- }
- static void atmel_hlcdc_atomic_disable(struct atmel_hlcdc_plane *plane)
- {
- /* Disable interrupts */
- atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
- 0xffffffff);
- /* Disable the layer */
- atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
- ATMEL_HLCDC_LAYER_RST |
- ATMEL_HLCDC_LAYER_A2Q |
- ATMEL_HLCDC_LAYER_UPDATE);
- /* Clear all pending interrupts */
- atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
- }
- static void atmel_xlcdc_atomic_disable(struct atmel_hlcdc_plane *plane)
- {
- /* Disable interrupts */
- atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_XLCDC_LAYER_IDR,
- 0xffffffff);
- /* Disable the layer */
- atmel_hlcdc_layer_write_reg(&plane->layer,
- ATMEL_XLCDC_LAYER_ENR, 0);
- /* Clear all pending interrupts */
- atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_XLCDC_LAYER_ISR);
- }
- static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
- struct drm_atomic_state *state)
- {
- struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
- struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
- dc->desc->ops->lcdc_atomic_disable(plane);
- }
- static void atmel_hlcdc_atomic_update(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_dc *dc)
- {
- u32 sr;
- /* Enable the overrun interrupts. */
- atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
- ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
- ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
- ATMEL_HLCDC_LAYER_OVR_IRQ(2));
- /* Apply the new config at the next SOF event. */
- sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
- atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
- ATMEL_HLCDC_LAYER_UPDATE |
- (sr & ATMEL_HLCDC_LAYER_EN ?
- ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
- }
- static void atmel_xlcdc_atomic_update(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_dc *dc)
- {
- /* Enable the overrun interrupts. */
- atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_XLCDC_LAYER_IER,
- ATMEL_XLCDC_LAYER_OVR_IRQ(0) |
- ATMEL_XLCDC_LAYER_OVR_IRQ(1) |
- ATMEL_XLCDC_LAYER_OVR_IRQ(2));
- atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_XLCDC_LAYER_ENR,
- ATMEL_XLCDC_LAYER_EN);
- /*
- * Updating XLCDC_xxxCFGx, XLCDC_xxxFBA and XLCDC_xxxEN,
- * (where xxx indicates each layer) requires writing one to the
- * Update Attribute field for each layer in LCDC_ATTRE register for SAM9X7.
- */
- regmap_write(dc->hlcdc->regmap, ATMEL_XLCDC_ATTRE, ATMEL_XLCDC_BASE_UPDATE |
- ATMEL_XLCDC_OVR1_UPDATE | ATMEL_XLCDC_OVR3_UPDATE |
- ATMEL_XLCDC_HEO_UPDATE);
- }
- static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
- struct drm_atomic_state *state)
- {
- struct drm_plane_state *new_s = drm_atomic_get_new_plane_state(state,
- p);
- struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
- struct atmel_hlcdc_plane_state *hstate =
- drm_plane_state_to_atmel_hlcdc_plane_state(new_s);
- struct atmel_hlcdc_dc *dc = p->dev->dev_private;
- if (!new_s->crtc || !new_s->fb)
- return;
- if (!hstate->base.visible) {
- atmel_hlcdc_plane_atomic_disable(p, state);
- return;
- }
- atmel_hlcdc_plane_update_pos_and_size(plane, hstate);
- dc->desc->ops->lcdc_update_general_settings(plane, hstate);
- atmel_hlcdc_plane_update_format(plane, hstate);
- atmel_hlcdc_plane_update_clut(plane, hstate);
- atmel_hlcdc_plane_update_buffers(plane, hstate);
- atmel_hlcdc_plane_update_disc_area(plane, hstate);
- dc->desc->ops->lcdc_atomic_update(plane, dc);
- }
- static void atmel_hlcdc_csc_init(struct atmel_hlcdc_plane *plane,
- const struct atmel_hlcdc_layer_desc *desc)
- {
- /*
- * TODO: declare a "yuv-to-rgb-conv-factors" property to let
- * userspace modify these factors (using a BLOB property ?).
- */
- static const u32 hlcdc_csc_coeffs[] = {
- 0x4c900091,
- 0x7a5f5090,
- 0x40040890
- };
- for (int i = 0; i < ARRAY_SIZE(hlcdc_csc_coeffs); i++) {
- atmel_hlcdc_layer_write_cfg(&plane->layer,
- desc->layout.csc + i,
- hlcdc_csc_coeffs[i]);
- }
- }
- static void atmel_xlcdc_csc_init(struct atmel_hlcdc_plane *plane,
- const struct atmel_hlcdc_layer_desc *desc)
- {
- /*
- * yuv-to-rgb-conv-factors are now defined from LCDC_HEOCFG16 to
- * LCDC_HEOCFG21 registers in SAM9X7.
- */
- static const u32 xlcdc_csc_coeffs[] = {
- 0x00000488,
- 0x00000648,
- 0x1EA00480,
- 0x00001D28,
- 0x08100480,
- 0x00000000,
- 0x00000007
- };
- for (int i = 0; i < ARRAY_SIZE(xlcdc_csc_coeffs); i++) {
- atmel_hlcdc_layer_write_cfg(&plane->layer,
- desc->layout.csc + i,
- xlcdc_csc_coeffs[i]);
- }
- if (desc->layout.vxs_config && desc->layout.hxs_config) {
- /*
- * Updating vxs.config and hxs.config fixes the
- * Green Color Issue in SAM9X7 EGT Video Player App
- */
- atmel_hlcdc_layer_write_cfg(&plane->layer,
- desc->layout.vxs_config,
- ATMEL_XLCDC_LAYER_VXSYCFG_ONE |
- ATMEL_XLCDC_LAYER_VXSYTAP2_ENABLE |
- ATMEL_XLCDC_LAYER_VXSCCFG_ONE |
- ATMEL_XLCDC_LAYER_VXSCTAP2_ENABLE);
- atmel_hlcdc_layer_write_cfg(&plane->layer,
- desc->layout.hxs_config,
- ATMEL_XLCDC_LAYER_HXSYCFG_ONE |
- ATMEL_XLCDC_LAYER_HXSYTAP2_ENABLE |
- ATMEL_XLCDC_LAYER_HXSCCFG_ONE |
- ATMEL_XLCDC_LAYER_HXSCTAP2_ENABLE);
- }
- }
- static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
- {
- const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
- struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
- if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
- desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
- int ret;
- ret = drm_plane_create_alpha_property(&plane->base);
- if (ret)
- return ret;
- }
- if (desc->layout.xstride[0] && desc->layout.pstride[0]) {
- int ret;
- ret = drm_plane_create_rotation_property(&plane->base,
- DRM_MODE_ROTATE_0,
- DRM_MODE_ROTATE_0 |
- DRM_MODE_ROTATE_90 |
- DRM_MODE_ROTATE_180 |
- DRM_MODE_ROTATE_270);
- if (ret)
- return ret;
- }
- if (desc->layout.csc)
- dc->desc->ops->lcdc_csc_init(plane, desc);
- return 0;
- }
- static void atmel_hlcdc_irq_dbg(struct atmel_hlcdc_plane *plane,
- const struct atmel_hlcdc_layer_desc *desc)
- {
- u32 isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
- /*
- * There's not much we can do in case of overrun except informing
- * the user. However, we are in interrupt context here, hence the
- * use of dev_dbg().
- */
- if (isr &
- (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
- ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
- dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
- desc->name);
- }
- static void atmel_xlcdc_irq_dbg(struct atmel_hlcdc_plane *plane,
- const struct atmel_hlcdc_layer_desc *desc)
- {
- u32 isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_XLCDC_LAYER_ISR);
- /*
- * There's not much we can do in case of overrun except informing
- * the user. However, we are in interrupt context here, hence the
- * use of dev_dbg().
- */
- if (isr &
- (ATMEL_XLCDC_LAYER_OVR_IRQ(0) | ATMEL_XLCDC_LAYER_OVR_IRQ(1) |
- ATMEL_XLCDC_LAYER_OVR_IRQ(2)))
- dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
- desc->name);
- }
- void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
- {
- const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
- struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
- dc->desc->ops->lcdc_irq_dbg(plane, desc);
- }
- const struct atmel_lcdc_dc_ops atmel_hlcdc_ops = {
- .plane_setup_scaler = atmel_hlcdc_plane_setup_scaler,
- .lcdc_update_buffers = atmel_hlcdc_update_buffers,
- .lcdc_atomic_disable = atmel_hlcdc_atomic_disable,
- .lcdc_update_general_settings = atmel_hlcdc_plane_update_general_settings,
- .lcdc_atomic_update = atmel_hlcdc_atomic_update,
- .lcdc_csc_init = atmel_hlcdc_csc_init,
- .lcdc_irq_dbg = atmel_hlcdc_irq_dbg,
- };
- const struct atmel_lcdc_dc_ops atmel_xlcdc_ops = {
- .plane_setup_scaler = atmel_xlcdc_plane_setup_scaler,
- .lcdc_update_buffers = atmel_xlcdc_update_buffers,
- .lcdc_atomic_disable = atmel_xlcdc_atomic_disable,
- .lcdc_update_general_settings = atmel_xlcdc_plane_update_general_settings,
- .lcdc_atomic_update = atmel_xlcdc_atomic_update,
- .lcdc_csc_init = atmel_xlcdc_csc_init,
- .lcdc_irq_dbg = atmel_xlcdc_irq_dbg,
- };
- static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
- .atomic_check = atmel_hlcdc_plane_atomic_check,
- .atomic_update = atmel_hlcdc_plane_atomic_update,
- .atomic_disable = atmel_hlcdc_plane_atomic_disable,
- };
- static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
- struct atmel_hlcdc_plane_state *state)
- {
- struct atmel_hlcdc_dc *dc = p->dev->dev_private;
- int i;
- for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
- struct atmel_hlcdc_dma_channel_dscr *dscr;
- dma_addr_t dscr_dma;
- dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
- if (!dscr)
- goto err;
- dscr->addr = 0;
- dscr->next = dscr_dma;
- dscr->self = dscr_dma;
- dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
- state->dscrs[i] = dscr;
- }
- return 0;
- err:
- for (i--; i >= 0; i--) {
- dma_pool_free(dc->dscrpool, state->dscrs[i],
- state->dscrs[i]->self);
- }
- return -ENOMEM;
- }
- static void atmel_hlcdc_plane_reset(struct drm_plane *p)
- {
- struct atmel_hlcdc_plane_state *state;
- if (p->state) {
- state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
- if (state->base.fb)
- drm_framebuffer_put(state->base.fb);
- kfree(state);
- p->state = NULL;
- }
- state = kzalloc(sizeof(*state), GFP_KERNEL);
- if (state) {
- if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
- kfree(state);
- dev_err(p->dev->dev,
- "Failed to allocate initial plane state\n");
- return;
- }
- __drm_atomic_helper_plane_reset(p, &state->base);
- }
- }
- static struct drm_plane_state *
- atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
- {
- struct atmel_hlcdc_plane_state *state =
- drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
- struct atmel_hlcdc_plane_state *copy;
- copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
- if (!copy)
- return NULL;
- if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
- kfree(copy);
- return NULL;
- }
- if (copy->base.fb)
- drm_framebuffer_get(copy->base.fb);
- return ©->base;
- }
- static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
- struct drm_plane_state *s)
- {
- struct atmel_hlcdc_plane_state *state =
- drm_plane_state_to_atmel_hlcdc_plane_state(s);
- struct atmel_hlcdc_dc *dc = p->dev->dev_private;
- int i;
- for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
- dma_pool_free(dc->dscrpool, state->dscrs[i],
- state->dscrs[i]->self);
- }
- if (s->fb)
- drm_framebuffer_put(s->fb);
- kfree(state);
- }
- static const struct drm_plane_funcs layer_plane_funcs = {
- .update_plane = drm_atomic_helper_update_plane,
- .disable_plane = drm_atomic_helper_disable_plane,
- .destroy = drm_plane_cleanup,
- .reset = atmel_hlcdc_plane_reset,
- .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
- .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
- };
- static int atmel_hlcdc_plane_create(struct drm_device *dev,
- const struct atmel_hlcdc_layer_desc *desc)
- {
- struct atmel_hlcdc_dc *dc = dev->dev_private;
- struct atmel_hlcdc_plane *plane;
- enum drm_plane_type type;
- int ret;
- plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
- if (!plane)
- return -ENOMEM;
- atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
- if (desc->type == ATMEL_HLCDC_BASE_LAYER)
- type = DRM_PLANE_TYPE_PRIMARY;
- else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
- type = DRM_PLANE_TYPE_CURSOR;
- else
- type = DRM_PLANE_TYPE_OVERLAY;
- ret = drm_universal_plane_init(dev, &plane->base, 0,
- &layer_plane_funcs,
- desc->formats->formats,
- desc->formats->nformats,
- NULL, type, NULL);
- if (ret)
- return ret;
- drm_plane_helper_add(&plane->base,
- &atmel_hlcdc_layer_plane_helper_funcs);
- /* Set default property values*/
- ret = atmel_hlcdc_plane_init_properties(plane);
- if (ret)
- return ret;
- dc->layers[desc->id] = &plane->layer;
- return 0;
- }
- int atmel_hlcdc_create_planes(struct drm_device *dev)
- {
- struct atmel_hlcdc_dc *dc = dev->dev_private;
- const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
- int nlayers = dc->desc->nlayers;
- int i, ret;
- dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
- sizeof(struct atmel_hlcdc_dma_channel_dscr),
- sizeof(u64), 0);
- if (!dc->dscrpool)
- return -ENOMEM;
- for (i = 0; i < nlayers; i++) {
- if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
- descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
- descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
- continue;
- ret = atmel_hlcdc_plane_create(dev, &descs[i]);
- if (ret)
- return ret;
- }
- return 0;
- }
|