123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856 |
- /*
- * 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 "atmel_hlcdc_dc.h"
- #define SUBPIXEL_MASK 0xffff
- static uint32_t rgb_formats[] = {
- 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_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_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 bool atmel_hlcdc_format_embedds_alpha(u32 format)
- {
- int i;
- for (i = 0; i < sizeof(format); i++) {
- char tmp = (format >> (8 * i)) & 0xff;
- if (tmp == 'A')
- return true;
- }
- return false;
- }
- 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,
- };
- static void
- atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_plane_update_req *req)
- {
- const struct atmel_hlcdc_layer_cfg_layout *layout =
- &plane->layer.desc->layout;
- if (layout->size)
- atmel_hlcdc_layer_update_cfg(&plane->layer,
- layout->size,
- 0xffffffff,
- (req->crtc_w - 1) |
- ((req->crtc_h - 1) << 16));
- if (layout->memsize)
- atmel_hlcdc_layer_update_cfg(&plane->layer,
- layout->memsize,
- 0xffffffff,
- (req->src_w - 1) |
- ((req->src_h - 1) << 16));
- if (layout->pos)
- atmel_hlcdc_layer_update_cfg(&plane->layer,
- layout->pos,
- 0xffffffff,
- req->crtc_x |
- (req->crtc_y << 16));
- /* TODO: rework the rescaling part */
- if (req->crtc_w != req->src_w || req->crtc_h != req->src_h) {
- u32 factor_reg = 0;
- if (req->crtc_w != req->src_w) {
- int i;
- u32 factor;
- u32 *coeff_tab = heo_upscaling_xcoef;
- u32 max_memsize;
- if (req->crtc_w < req->src_w)
- coeff_tab = heo_downscaling_xcoef;
- for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++)
- atmel_hlcdc_layer_update_cfg(&plane->layer,
- 17 + i,
- 0xffffffff,
- coeff_tab[i]);
- factor = ((8 * 256 * req->src_w) - (256 * 4)) /
- req->crtc_w;
- factor++;
- max_memsize = ((factor * req->crtc_w) + (256 * 4)) /
- 2048;
- if (max_memsize > req->src_w)
- factor--;
- factor_reg |= factor | 0x80000000;
- }
- if (req->crtc_h != req->src_h) {
- int i;
- u32 factor;
- u32 *coeff_tab = heo_upscaling_ycoef;
- u32 max_memsize;
- if (req->crtc_w < req->src_w)
- coeff_tab = heo_downscaling_ycoef;
- for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
- atmel_hlcdc_layer_update_cfg(&plane->layer,
- 33 + i,
- 0xffffffff,
- coeff_tab[i]);
- factor = ((8 * 256 * req->src_w) - (256 * 4)) /
- req->crtc_w;
- factor++;
- max_memsize = ((factor * req->crtc_w) + (256 * 4)) /
- 2048;
- if (max_memsize > req->src_w)
- factor--;
- factor_reg |= (factor << 16) | 0x80000000;
- }
- atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff,
- factor_reg);
- }
- }
- static void
- atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_plane_update_req *req)
- {
- const struct atmel_hlcdc_layer_cfg_layout *layout =
- &plane->layer.desc->layout;
- unsigned int cfg = ATMEL_HLCDC_LAYER_DMA;
- if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
- cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
- ATMEL_HLCDC_LAYER_ITER;
- if (atmel_hlcdc_format_embedds_alpha(req->fb->pixel_format))
- cfg |= ATMEL_HLCDC_LAYER_LAEN;
- else
- cfg |= ATMEL_HLCDC_LAYER_GAEN;
- }
- atmel_hlcdc_layer_update_cfg(&plane->layer,
- ATMEL_HLCDC_LAYER_DMA_CFG_ID,
- ATMEL_HLCDC_LAYER_DMA_BLEN_MASK,
- ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16);
- atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
- ATMEL_HLCDC_LAYER_ITER2BL |
- ATMEL_HLCDC_LAYER_ITER |
- ATMEL_HLCDC_LAYER_GAEN |
- ATMEL_HLCDC_LAYER_LAEN |
- ATMEL_HLCDC_LAYER_OVR |
- ATMEL_HLCDC_LAYER_DMA, cfg);
- }
- static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_plane_update_req *req)
- {
- u32 cfg;
- int ret;
- ret = atmel_hlcdc_format_to_plane_mode(req->fb->pixel_format, &cfg);
- if (ret)
- return;
- if ((req->fb->pixel_format == DRM_FORMAT_YUV422 ||
- req->fb->pixel_format == DRM_FORMAT_NV61) &&
- (plane->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))))
- cfg |= ATMEL_HLCDC_YUV422ROT;
- atmel_hlcdc_layer_update_cfg(&plane->layer,
- ATMEL_HLCDC_LAYER_FORMAT_CFG_ID,
- 0xffffffff,
- cfg);
- /*
- * Rotation optimization is not working on RGB888 (rotation is still
- * working but without any optimization).
- */
- if (req->fb->pixel_format == DRM_FORMAT_RGB888)
- cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS;
- else
- cfg = 0;
- atmel_hlcdc_layer_update_cfg(&plane->layer,
- ATMEL_HLCDC_LAYER_DMA_CFG_ID,
- ATMEL_HLCDC_LAYER_DMA_ROTDIS, cfg);
- }
- static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_plane_update_req *req)
- {
- struct atmel_hlcdc_layer *layer = &plane->layer;
- const struct atmel_hlcdc_layer_cfg_layout *layout =
- &layer->desc->layout;
- int i;
- atmel_hlcdc_layer_update_set_fb(&plane->layer, req->fb, req->offsets);
- for (i = 0; i < req->nplanes; i++) {
- if (layout->xstride[i]) {
- atmel_hlcdc_layer_update_cfg(&plane->layer,
- layout->xstride[i],
- 0xffffffff,
- req->xstride[i]);
- }
- if (layout->pstride[i]) {
- atmel_hlcdc_layer_update_cfg(&plane->layer,
- layout->pstride[i],
- 0xffffffff,
- req->pstride[i]);
- }
- }
- }
- static int atmel_hlcdc_plane_check_update_req(struct drm_plane *p,
- struct atmel_hlcdc_plane_update_req *req,
- const struct drm_display_mode *mode)
- {
- struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
- const struct atmel_hlcdc_layer_cfg_layout *layout =
- &plane->layer.desc->layout;
- if (!layout->size &&
- (mode->hdisplay != req->crtc_w ||
- mode->vdisplay != req->crtc_h))
- return -EINVAL;
- if (plane->layer.desc->max_height &&
- req->crtc_h > plane->layer.desc->max_height)
- return -EINVAL;
- if (plane->layer.desc->max_width &&
- req->crtc_w > plane->layer.desc->max_width)
- return -EINVAL;
- if ((req->crtc_h != req->src_h || req->crtc_w != req->src_w) &&
- (!layout->memsize ||
- atmel_hlcdc_format_embedds_alpha(req->fb->pixel_format)))
- return -EINVAL;
- if (req->crtc_x < 0 || req->crtc_y < 0)
- return -EINVAL;
- if (req->crtc_w + req->crtc_x > mode->hdisplay ||
- req->crtc_h + req->crtc_y > mode->vdisplay)
- return -EINVAL;
- return 0;
- }
- int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p,
- struct atmel_hlcdc_plane_update_req *req,
- const struct drm_display_mode *mode)
- {
- struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
- unsigned int patched_crtc_w;
- unsigned int patched_crtc_h;
- unsigned int patched_src_w;
- unsigned int patched_src_h;
- unsigned int tmp;
- int x_offset = 0;
- int y_offset = 0;
- int hsub = 1;
- int vsub = 1;
- int i;
- if ((req->src_x | req->src_y | req->src_w | req->src_h) &
- SUBPIXEL_MASK)
- return -EINVAL;
- req->src_x >>= 16;
- req->src_y >>= 16;
- req->src_w >>= 16;
- req->src_h >>= 16;
- req->nplanes = drm_format_num_planes(req->fb->pixel_format);
- if (req->nplanes > ATMEL_HLCDC_MAX_PLANES)
- return -EINVAL;
- /*
- * Swap width and size in case of 90 or 270 degrees rotation
- */
- if (plane->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
- tmp = req->crtc_w;
- req->crtc_w = req->crtc_h;
- req->crtc_h = tmp;
- tmp = req->src_w;
- req->src_w = req->src_h;
- req->src_h = tmp;
- }
- if (req->crtc_x + req->crtc_w > mode->hdisplay)
- patched_crtc_w = mode->hdisplay - req->crtc_x;
- else
- patched_crtc_w = req->crtc_w;
- if (req->crtc_x < 0) {
- patched_crtc_w += req->crtc_x;
- x_offset = -req->crtc_x;
- req->crtc_x = 0;
- }
- if (req->crtc_y + req->crtc_h > mode->vdisplay)
- patched_crtc_h = mode->vdisplay - req->crtc_y;
- else
- patched_crtc_h = req->crtc_h;
- if (req->crtc_y < 0) {
- patched_crtc_h += req->crtc_y;
- y_offset = -req->crtc_y;
- req->crtc_y = 0;
- }
- patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * req->src_w,
- req->crtc_w);
- patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * req->src_h,
- req->crtc_h);
- hsub = drm_format_horz_chroma_subsampling(req->fb->pixel_format);
- vsub = drm_format_vert_chroma_subsampling(req->fb->pixel_format);
- for (i = 0; i < req->nplanes; i++) {
- unsigned int offset = 0;
- int xdiv = i ? hsub : 1;
- int ydiv = i ? vsub : 1;
- req->bpp[i] = drm_format_plane_cpp(req->fb->pixel_format, i);
- if (!req->bpp[i])
- return -EINVAL;
- switch (plane->rotation & 0xf) {
- case BIT(DRM_ROTATE_90):
- offset = ((y_offset + req->src_y + patched_src_w - 1) /
- ydiv) * req->fb->pitches[i];
- offset += ((x_offset + req->src_x) / xdiv) *
- req->bpp[i];
- req->xstride[i] = ((patched_src_w - 1) / ydiv) *
- req->fb->pitches[i];
- req->pstride[i] = -req->fb->pitches[i] - req->bpp[i];
- break;
- case BIT(DRM_ROTATE_180):
- offset = ((y_offset + req->src_y + patched_src_h - 1) /
- ydiv) * req->fb->pitches[i];
- offset += ((x_offset + req->src_x + patched_src_w - 1) /
- xdiv) * req->bpp[i];
- req->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
- req->bpp[i]) - req->fb->pitches[i];
- req->pstride[i] = -2 * req->bpp[i];
- break;
- case BIT(DRM_ROTATE_270):
- offset = ((y_offset + req->src_y) / ydiv) *
- req->fb->pitches[i];
- offset += ((x_offset + req->src_x + patched_src_h - 1) /
- xdiv) * req->bpp[i];
- req->xstride[i] = -(((patched_src_w - 1) / ydiv) *
- req->fb->pitches[i]) -
- (2 * req->bpp[i]);
- req->pstride[i] = req->fb->pitches[i] - req->bpp[i];
- break;
- case BIT(DRM_ROTATE_0):
- default:
- offset = ((y_offset + req->src_y) / ydiv) *
- req->fb->pitches[i];
- offset += ((x_offset + req->src_x) / xdiv) *
- req->bpp[i];
- req->xstride[i] = req->fb->pitches[i] -
- ((patched_src_w / xdiv) *
- req->bpp[i]);
- req->pstride[i] = 0;
- break;
- }
- req->offsets[i] = offset + req->fb->offsets[i];
- }
- req->src_w = patched_src_w;
- req->src_h = patched_src_h;
- req->crtc_w = patched_crtc_w;
- req->crtc_h = patched_crtc_h;
- return atmel_hlcdc_plane_check_update_req(p, req, mode);
- }
- int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p,
- struct atmel_hlcdc_plane_update_req *req)
- {
- struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
- int ret;
- ret = atmel_hlcdc_layer_update_start(&plane->layer);
- if (ret)
- return ret;
- atmel_hlcdc_plane_update_pos_and_size(plane, req);
- atmel_hlcdc_plane_update_general_settings(plane, req);
- atmel_hlcdc_plane_update_format(plane, req);
- atmel_hlcdc_plane_update_buffers(plane, req);
- atmel_hlcdc_layer_update_commit(&plane->layer);
- return 0;
- }
- int atmel_hlcdc_plane_update_with_mode(struct drm_plane *p,
- struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- 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,
- const struct drm_display_mode *mode)
- {
- struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
- struct atmel_hlcdc_plane_update_req req;
- int ret = 0;
- memset(&req, 0, sizeof(req));
- req.crtc_x = crtc_x;
- req.crtc_y = crtc_y;
- req.crtc_w = crtc_w;
- req.crtc_h = crtc_h;
- req.src_x = src_x;
- req.src_y = src_y;
- req.src_w = src_w;
- req.src_h = src_h;
- req.fb = fb;
- ret = atmel_hlcdc_plane_prepare_update_req(&plane->base, &req, mode);
- if (ret)
- return ret;
- if (!req.crtc_h || !req.crtc_w)
- return atmel_hlcdc_layer_disable(&plane->layer);
- return atmel_hlcdc_plane_apply_update_req(&plane->base, &req);
- }
- static int atmel_hlcdc_plane_update(struct drm_plane *p,
- struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- 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)
- {
- return atmel_hlcdc_plane_update_with_mode(p, crtc, fb, crtc_x, crtc_y,
- crtc_w, crtc_h, src_x, src_y,
- src_w, src_h, &crtc->hwmode);
- }
- static int atmel_hlcdc_plane_disable(struct drm_plane *p)
- {
- struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
- return atmel_hlcdc_layer_disable(&plane->layer);
- }
- static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
- {
- struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
- if (plane->base.fb)
- drm_framebuffer_unreference(plane->base.fb);
- atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
- drm_plane_cleanup(p);
- devm_kfree(p->dev->dev, plane);
- }
- static int atmel_hlcdc_plane_set_alpha(struct atmel_hlcdc_plane *plane,
- u8 alpha)
- {
- atmel_hlcdc_layer_update_start(&plane->layer);
- atmel_hlcdc_layer_update_cfg(&plane->layer,
- plane->layer.desc->layout.general_config,
- ATMEL_HLCDC_LAYER_GA_MASK,
- alpha << ATMEL_HLCDC_LAYER_GA_SHIFT);
- atmel_hlcdc_layer_update_commit(&plane->layer);
- return 0;
- }
- static int atmel_hlcdc_plane_set_rotation(struct atmel_hlcdc_plane *plane,
- unsigned int rotation)
- {
- plane->rotation = rotation;
- return 0;
- }
- static int atmel_hlcdc_plane_set_property(struct drm_plane *p,
- struct drm_property *property,
- uint64_t value)
- {
- struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
- struct atmel_hlcdc_plane_properties *props = plane->properties;
- if (property == props->alpha)
- atmel_hlcdc_plane_set_alpha(plane, value);
- else if (property == props->rotation)
- atmel_hlcdc_plane_set_rotation(plane, value);
- else
- return -EINVAL;
- return 0;
- }
- static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
- const struct atmel_hlcdc_layer_desc *desc,
- struct atmel_hlcdc_plane_properties *props)
- {
- struct regmap *regmap = plane->layer.hlcdc->regmap;
- if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
- desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
- drm_object_attach_property(&plane->base.base,
- props->alpha, 255);
- /* Set default alpha value */
- regmap_update_bits(regmap,
- desc->regs_offset +
- ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
- ATMEL_HLCDC_LAYER_GA_MASK,
- ATMEL_HLCDC_LAYER_GA_MASK);
- }
- if (desc->layout.xstride && desc->layout.pstride)
- drm_object_attach_property(&plane->base.base,
- props->rotation,
- BIT(DRM_ROTATE_0));
- if (desc->layout.csc) {
- /*
- * TODO: decare a "yuv-to-rgb-conv-factors" property to let
- * userspace modify these factors (using a BLOB property ?).
- */
- regmap_write(regmap,
- desc->regs_offset +
- ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
- 0x4c900091);
- regmap_write(regmap,
- desc->regs_offset +
- ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
- 0x7a5f5090);
- regmap_write(regmap,
- desc->regs_offset +
- ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
- 0x40040890);
- }
- }
- static struct drm_plane_funcs layer_plane_funcs = {
- .update_plane = atmel_hlcdc_plane_update,
- .disable_plane = atmel_hlcdc_plane_disable,
- .set_property = atmel_hlcdc_plane_set_property,
- .destroy = atmel_hlcdc_plane_destroy,
- };
- static struct atmel_hlcdc_plane *
- atmel_hlcdc_plane_create(struct drm_device *dev,
- const struct atmel_hlcdc_layer_desc *desc,
- struct atmel_hlcdc_plane_properties *props)
- {
- struct atmel_hlcdc_plane *plane;
- enum drm_plane_type type;
- int ret;
- plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
- if (!plane)
- return ERR_PTR(-ENOMEM);
- ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
- if (ret)
- return ERR_PTR(ret);
- 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, type);
- if (ret)
- return ERR_PTR(ret);
- /* Set default property values*/
- atmel_hlcdc_plane_init_properties(plane, desc, props);
- return plane;
- }
- static struct atmel_hlcdc_plane_properties *
- atmel_hlcdc_plane_create_properties(struct drm_device *dev)
- {
- struct atmel_hlcdc_plane_properties *props;
- props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
- if (!props)
- return ERR_PTR(-ENOMEM);
- props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
- if (!props->alpha)
- return ERR_PTR(-ENOMEM);
- props->rotation = drm_mode_create_rotation_property(dev,
- BIT(DRM_ROTATE_0) |
- BIT(DRM_ROTATE_90) |
- BIT(DRM_ROTATE_180) |
- BIT(DRM_ROTATE_270));
- if (!props->rotation)
- return ERR_PTR(-ENOMEM);
- return props;
- }
- struct atmel_hlcdc_planes *
- atmel_hlcdc_create_planes(struct drm_device *dev)
- {
- struct atmel_hlcdc_dc *dc = dev->dev_private;
- struct atmel_hlcdc_plane_properties *props;
- struct atmel_hlcdc_planes *planes;
- const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
- int nlayers = dc->desc->nlayers;
- int i;
- planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
- if (!planes)
- return ERR_PTR(-ENOMEM);
- for (i = 0; i < nlayers; i++) {
- if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
- planes->noverlays++;
- }
- if (planes->noverlays) {
- planes->overlays = devm_kzalloc(dev->dev,
- planes->noverlays *
- sizeof(*planes->overlays),
- GFP_KERNEL);
- if (!planes->overlays)
- return ERR_PTR(-ENOMEM);
- }
- props = atmel_hlcdc_plane_create_properties(dev);
- if (IS_ERR(props))
- return ERR_CAST(props);
- planes->noverlays = 0;
- for (i = 0; i < nlayers; i++) {
- struct atmel_hlcdc_plane *plane;
- if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
- continue;
- plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
- if (IS_ERR(plane))
- return ERR_CAST(plane);
- plane->properties = props;
- switch (descs[i].type) {
- case ATMEL_HLCDC_BASE_LAYER:
- if (planes->primary)
- return ERR_PTR(-EINVAL);
- planes->primary = plane;
- break;
- case ATMEL_HLCDC_OVERLAY_LAYER:
- planes->overlays[planes->noverlays++] = plane;
- break;
- case ATMEL_HLCDC_CURSOR_LAYER:
- if (planes->cursor)
- return ERR_PTR(-EINVAL);
- planes->cursor = plane;
- break;
- default:
- break;
- }
- }
- return planes;
- }
|