Path: blob/master/drivers/gpu/drm/armada/armada_plane.c
50376 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Copyright (C) 2012 Russell King3* Rewritten from the dovefb driver, and Armada510 manuals.4*/56#include <drm/drm_atomic.h>7#include <drm/drm_atomic_helper.h>8#include <drm/drm_fourcc.h>9#include <drm/drm_plane_helper.h>10#include <drm/drm_print.h>1112#include "armada_crtc.h"13#include "armada_drm.h"14#include "armada_fb.h"15#include "armada_gem.h"16#include "armada_hw.h"17#include "armada_plane.h"18#include "armada_trace.h"1920static const uint32_t armada_primary_formats[] = {21DRM_FORMAT_UYVY,22DRM_FORMAT_YUYV,23DRM_FORMAT_VYUY,24DRM_FORMAT_YVYU,25DRM_FORMAT_ARGB8888,26DRM_FORMAT_ABGR8888,27DRM_FORMAT_XRGB8888,28DRM_FORMAT_XBGR8888,29DRM_FORMAT_RGB888,30DRM_FORMAT_BGR888,31DRM_FORMAT_ARGB1555,32DRM_FORMAT_ABGR1555,33DRM_FORMAT_RGB565,34DRM_FORMAT_BGR565,35};3637void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],38u16 pitches[3], bool interlaced)39{40struct drm_framebuffer *fb = state->fb;41const struct drm_format_info *format = fb->format;42unsigned int num_planes = format->num_planes;43unsigned int x = state->src.x1 >> 16;44unsigned int y = state->src.y1 >> 16;45u32 addr = drm_fb_obj(fb)->dev_addr;46int i;4748DRM_DEBUG_KMS("pitch %u x %d y %d bpp %d\n",49fb->pitches[0], x, y, format->cpp[0] * 8);5051if (num_planes > 3)52num_planes = 3;5354addrs[0][0] = addr + fb->offsets[0] + y * fb->pitches[0] +55x * format->cpp[0];56pitches[0] = fb->pitches[0];5758y /= format->vsub;59x /= format->hsub;6061for (i = 1; i < num_planes; i++) {62addrs[0][i] = addr + fb->offsets[i] + y * fb->pitches[i] +63x * format->cpp[i];64pitches[i] = fb->pitches[i];65}66for (; i < 3; i++) {67addrs[0][i] = 0;68pitches[i] = 0;69}70if (interlaced) {71for (i = 0; i < 3; i++) {72addrs[1][i] = addrs[0][i] + pitches[i];73pitches[i] *= 2;74}75} else {76for (i = 0; i < 3; i++)77addrs[1][i] = addrs[0][i];78}79}8081int armada_drm_plane_atomic_check(struct drm_plane *plane,82struct drm_atomic_state *state)83{84struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,85plane);86struct armada_plane_state *st = to_armada_plane_state(new_plane_state);87struct drm_crtc *crtc = new_plane_state->crtc;88struct drm_crtc_state *crtc_state;89bool interlace;90int ret;9192if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc)) {93new_plane_state->visible = false;94return 0;95}9697crtc_state = drm_atomic_get_new_crtc_state(state, crtc);98ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,990,100INT_MAX, true, false);101if (ret)102return ret;103104interlace = crtc_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE;105if (interlace) {106if ((new_plane_state->dst.y1 | new_plane_state->dst.y2) & 1)107return -EINVAL;108st->src_hw = drm_rect_height(&new_plane_state->src) >> 17;109st->dst_yx = new_plane_state->dst.y1 >> 1;110st->dst_hw = drm_rect_height(&new_plane_state->dst) >> 1;111} else {112st->src_hw = drm_rect_height(&new_plane_state->src) >> 16;113st->dst_yx = new_plane_state->dst.y1;114st->dst_hw = drm_rect_height(&new_plane_state->dst);115}116117st->src_hw <<= 16;118st->src_hw |= drm_rect_width(&new_plane_state->src) >> 16;119st->dst_yx <<= 16;120st->dst_yx |= new_plane_state->dst.x1 & 0x0000ffff;121st->dst_hw <<= 16;122st->dst_hw |= drm_rect_width(&new_plane_state->dst) & 0x0000ffff;123124armada_drm_plane_calc(new_plane_state, st->addrs, st->pitches,125interlace);126st->interlace = interlace;127128return 0;129}130131static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,132struct drm_atomic_state *state)133{134struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,135plane);136struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,137plane);138struct armada_crtc *dcrtc;139struct armada_regs *regs;140u32 cfg, cfg_mask, val;141unsigned int idx;142143DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);144145if (!new_state->fb || WARN_ON(!new_state->crtc))146return;147148DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n",149plane->base.id, plane->name,150new_state->crtc->base.id, new_state->crtc->name,151new_state->fb->base.id,152old_state->visible, new_state->visible);153154dcrtc = drm_to_armada_crtc(new_state->crtc);155regs = dcrtc->regs + dcrtc->regs_idx;156157idx = 0;158if (!old_state->visible && new_state->visible) {159val = CFG_PDWN64x66;160if (drm_fb_to_armada_fb(new_state->fb)->fmt > CFG_420)161val |= CFG_PDWN256x24;162armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1);163}164val = armada_src_hw(new_state);165if (armada_src_hw(old_state) != val)166armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN);167val = armada_dst_yx(new_state);168if (armada_dst_yx(old_state) != val)169armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN);170val = armada_dst_hw(new_state);171if (armada_dst_hw(old_state) != val)172armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN);173if (old_state->src.x1 != new_state->src.x1 ||174old_state->src.y1 != new_state->src.y1 ||175old_state->fb != new_state->fb ||176new_state->crtc->state->mode_changed) {177armada_reg_queue_set(regs, idx, armada_addr(new_state, 0, 0),178LCD_CFG_GRA_START_ADDR0);179armada_reg_queue_set(regs, idx, armada_addr(new_state, 1, 0),180LCD_CFG_GRA_START_ADDR1);181armada_reg_queue_mod(regs, idx, armada_pitch(new_state, 0),1820xffff,183LCD_CFG_GRA_PITCH);184}185if (old_state->fb != new_state->fb ||186new_state->crtc->state->mode_changed) {187cfg = CFG_GRA_FMT(drm_fb_to_armada_fb(new_state->fb)->fmt) |188CFG_GRA_MOD(drm_fb_to_armada_fb(new_state->fb)->mod);189if (drm_fb_to_armada_fb(new_state->fb)->fmt > CFG_420)190cfg |= CFG_PALETTE_ENA;191if (new_state->visible)192cfg |= CFG_GRA_ENA;193if (to_armada_plane_state(new_state)->interlace)194cfg |= CFG_GRA_FTOGGLE;195cfg_mask = CFG_GRAFORMAT |196CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |197CFG_SWAPYU | CFG_YUV2RGB) |198CFG_PALETTE_ENA | CFG_GRA_FTOGGLE |199CFG_GRA_ENA;200} else if (old_state->visible != new_state->visible) {201cfg = new_state->visible ? CFG_GRA_ENA : 0;202cfg_mask = CFG_GRA_ENA;203} else {204cfg = cfg_mask = 0;205}206if (drm_rect_width(&old_state->src) != drm_rect_width(&new_state->src) ||207drm_rect_width(&old_state->dst) != drm_rect_width(&new_state->dst)) {208cfg_mask |= CFG_GRA_HSMOOTH;209if (drm_rect_width(&new_state->src) >> 16 !=210drm_rect_width(&new_state->dst))211cfg |= CFG_GRA_HSMOOTH;212}213214if (cfg_mask)215armada_reg_queue_mod(regs, idx, cfg, cfg_mask,216LCD_SPU_DMA_CTRL0);217218dcrtc->regs_idx += idx;219}220221static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane,222struct drm_atomic_state *state)223{224struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,225plane);226struct armada_crtc *dcrtc;227struct armada_regs *regs;228unsigned int idx = 0;229230DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);231232if (!old_state->crtc)233return;234235DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n",236plane->base.id, plane->name,237old_state->crtc->base.id, old_state->crtc->name,238old_state->fb->base.id);239240dcrtc = drm_to_armada_crtc(old_state->crtc);241regs = dcrtc->regs + dcrtc->regs_idx;242243/* Disable plane and power down most RAMs and FIFOs */244armada_reg_queue_mod(regs, idx, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0);245armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 |246CFG_PDWN32x32 | CFG_PDWN64x66,2470, LCD_SPU_SRAM_PARA1);248249dcrtc->regs_idx += idx;250}251252static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = {253.atomic_check = armada_drm_plane_atomic_check,254.atomic_update = armada_drm_primary_plane_atomic_update,255.atomic_disable = armada_drm_primary_plane_atomic_disable,256};257258void armada_plane_reset(struct drm_plane *plane)259{260struct armada_plane_state *st;261if (plane->state)262__drm_atomic_helper_plane_destroy_state(plane->state);263kfree(plane->state);264st = kzalloc(sizeof(*st), GFP_KERNEL);265if (st)266__drm_atomic_helper_plane_reset(plane, &st->base);267}268269struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane)270{271struct armada_plane_state *st;272273if (WARN_ON(!plane->state))274return NULL;275276st = kmemdup(plane->state, sizeof(*st), GFP_KERNEL);277if (st)278__drm_atomic_helper_plane_duplicate_state(plane, &st->base);279280return &st->base;281}282283static const struct drm_plane_funcs armada_primary_plane_funcs = {284.update_plane = drm_atomic_helper_update_plane,285.disable_plane = drm_atomic_helper_disable_plane,286.destroy = drm_plane_helper_destroy,287.reset = armada_plane_reset,288.atomic_duplicate_state = armada_plane_duplicate_state,289.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,290};291292int armada_drm_primary_plane_init(struct drm_device *drm,293struct drm_plane *primary)294{295int ret;296297drm_plane_helper_add(primary, &armada_primary_plane_helper_funcs);298299ret = drm_universal_plane_init(drm, primary, 0,300&armada_primary_plane_funcs,301armada_primary_formats,302ARRAY_SIZE(armada_primary_formats),303NULL,304DRM_PLANE_TYPE_PRIMARY, NULL);305306return ret;307}308309310