Path: blob/master/drivers/gpu/drm/armada/armada_plane.c
26481 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>1011#include "armada_crtc.h"12#include "armada_drm.h"13#include "armada_fb.h"14#include "armada_gem.h"15#include "armada_hw.h"16#include "armada_plane.h"17#include "armada_trace.h"1819static const uint32_t armada_primary_formats[] = {20DRM_FORMAT_UYVY,21DRM_FORMAT_YUYV,22DRM_FORMAT_VYUY,23DRM_FORMAT_YVYU,24DRM_FORMAT_ARGB8888,25DRM_FORMAT_ABGR8888,26DRM_FORMAT_XRGB8888,27DRM_FORMAT_XBGR8888,28DRM_FORMAT_RGB888,29DRM_FORMAT_BGR888,30DRM_FORMAT_ARGB1555,31DRM_FORMAT_ABGR1555,32DRM_FORMAT_RGB565,33DRM_FORMAT_BGR565,34};3536void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],37u16 pitches[3], bool interlaced)38{39struct drm_framebuffer *fb = state->fb;40const struct drm_format_info *format = fb->format;41unsigned int num_planes = format->num_planes;42unsigned int x = state->src.x1 >> 16;43unsigned int y = state->src.y1 >> 16;44u32 addr = drm_fb_obj(fb)->dev_addr;45int i;4647DRM_DEBUG_KMS("pitch %u x %d y %d bpp %d\n",48fb->pitches[0], x, y, format->cpp[0] * 8);4950if (num_planes > 3)51num_planes = 3;5253addrs[0][0] = addr + fb->offsets[0] + y * fb->pitches[0] +54x * format->cpp[0];55pitches[0] = fb->pitches[0];5657y /= format->vsub;58x /= format->hsub;5960for (i = 1; i < num_planes; i++) {61addrs[0][i] = addr + fb->offsets[i] + y * fb->pitches[i] +62x * format->cpp[i];63pitches[i] = fb->pitches[i];64}65for (; i < 3; i++) {66addrs[0][i] = 0;67pitches[i] = 0;68}69if (interlaced) {70for (i = 0; i < 3; i++) {71addrs[1][i] = addrs[0][i] + pitches[i];72pitches[i] *= 2;73}74} else {75for (i = 0; i < 3; i++)76addrs[1][i] = addrs[0][i];77}78}7980int armada_drm_plane_atomic_check(struct drm_plane *plane,81struct drm_atomic_state *state)82{83struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,84plane);85struct armada_plane_state *st = to_armada_plane_state(new_plane_state);86struct drm_crtc *crtc = new_plane_state->crtc;87struct drm_crtc_state *crtc_state;88bool interlace;89int ret;9091if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc)) {92new_plane_state->visible = false;93return 0;94}9596if (state)97crtc_state = drm_atomic_get_existing_crtc_state(state,98crtc);99else100crtc_state = crtc->state;101102ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,1030,104INT_MAX, true, false);105if (ret)106return ret;107108interlace = crtc_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE;109if (interlace) {110if ((new_plane_state->dst.y1 | new_plane_state->dst.y2) & 1)111return -EINVAL;112st->src_hw = drm_rect_height(&new_plane_state->src) >> 17;113st->dst_yx = new_plane_state->dst.y1 >> 1;114st->dst_hw = drm_rect_height(&new_plane_state->dst) >> 1;115} else {116st->src_hw = drm_rect_height(&new_plane_state->src) >> 16;117st->dst_yx = new_plane_state->dst.y1;118st->dst_hw = drm_rect_height(&new_plane_state->dst);119}120121st->src_hw <<= 16;122st->src_hw |= drm_rect_width(&new_plane_state->src) >> 16;123st->dst_yx <<= 16;124st->dst_yx |= new_plane_state->dst.x1 & 0x0000ffff;125st->dst_hw <<= 16;126st->dst_hw |= drm_rect_width(&new_plane_state->dst) & 0x0000ffff;127128armada_drm_plane_calc(new_plane_state, st->addrs, st->pitches,129interlace);130st->interlace = interlace;131132return 0;133}134135static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,136struct drm_atomic_state *state)137{138struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,139plane);140struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,141plane);142struct armada_crtc *dcrtc;143struct armada_regs *regs;144u32 cfg, cfg_mask, val;145unsigned int idx;146147DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);148149if (!new_state->fb || WARN_ON(!new_state->crtc))150return;151152DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n",153plane->base.id, plane->name,154new_state->crtc->base.id, new_state->crtc->name,155new_state->fb->base.id,156old_state->visible, new_state->visible);157158dcrtc = drm_to_armada_crtc(new_state->crtc);159regs = dcrtc->regs + dcrtc->regs_idx;160161idx = 0;162if (!old_state->visible && new_state->visible) {163val = CFG_PDWN64x66;164if (drm_fb_to_armada_fb(new_state->fb)->fmt > CFG_420)165val |= CFG_PDWN256x24;166armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1);167}168val = armada_src_hw(new_state);169if (armada_src_hw(old_state) != val)170armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN);171val = armada_dst_yx(new_state);172if (armada_dst_yx(old_state) != val)173armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN);174val = armada_dst_hw(new_state);175if (armada_dst_hw(old_state) != val)176armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN);177if (old_state->src.x1 != new_state->src.x1 ||178old_state->src.y1 != new_state->src.y1 ||179old_state->fb != new_state->fb ||180new_state->crtc->state->mode_changed) {181armada_reg_queue_set(regs, idx, armada_addr(new_state, 0, 0),182LCD_CFG_GRA_START_ADDR0);183armada_reg_queue_set(regs, idx, armada_addr(new_state, 1, 0),184LCD_CFG_GRA_START_ADDR1);185armada_reg_queue_mod(regs, idx, armada_pitch(new_state, 0),1860xffff,187LCD_CFG_GRA_PITCH);188}189if (old_state->fb != new_state->fb ||190new_state->crtc->state->mode_changed) {191cfg = CFG_GRA_FMT(drm_fb_to_armada_fb(new_state->fb)->fmt) |192CFG_GRA_MOD(drm_fb_to_armada_fb(new_state->fb)->mod);193if (drm_fb_to_armada_fb(new_state->fb)->fmt > CFG_420)194cfg |= CFG_PALETTE_ENA;195if (new_state->visible)196cfg |= CFG_GRA_ENA;197if (to_armada_plane_state(new_state)->interlace)198cfg |= CFG_GRA_FTOGGLE;199cfg_mask = CFG_GRAFORMAT |200CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |201CFG_SWAPYU | CFG_YUV2RGB) |202CFG_PALETTE_ENA | CFG_GRA_FTOGGLE |203CFG_GRA_ENA;204} else if (old_state->visible != new_state->visible) {205cfg = new_state->visible ? CFG_GRA_ENA : 0;206cfg_mask = CFG_GRA_ENA;207} else {208cfg = cfg_mask = 0;209}210if (drm_rect_width(&old_state->src) != drm_rect_width(&new_state->src) ||211drm_rect_width(&old_state->dst) != drm_rect_width(&new_state->dst)) {212cfg_mask |= CFG_GRA_HSMOOTH;213if (drm_rect_width(&new_state->src) >> 16 !=214drm_rect_width(&new_state->dst))215cfg |= CFG_GRA_HSMOOTH;216}217218if (cfg_mask)219armada_reg_queue_mod(regs, idx, cfg, cfg_mask,220LCD_SPU_DMA_CTRL0);221222dcrtc->regs_idx += idx;223}224225static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane,226struct drm_atomic_state *state)227{228struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,229plane);230struct armada_crtc *dcrtc;231struct armada_regs *regs;232unsigned int idx = 0;233234DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);235236if (!old_state->crtc)237return;238239DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n",240plane->base.id, plane->name,241old_state->crtc->base.id, old_state->crtc->name,242old_state->fb->base.id);243244dcrtc = drm_to_armada_crtc(old_state->crtc);245regs = dcrtc->regs + dcrtc->regs_idx;246247/* Disable plane and power down most RAMs and FIFOs */248armada_reg_queue_mod(regs, idx, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0);249armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 |250CFG_PDWN32x32 | CFG_PDWN64x66,2510, LCD_SPU_SRAM_PARA1);252253dcrtc->regs_idx += idx;254}255256static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = {257.atomic_check = armada_drm_plane_atomic_check,258.atomic_update = armada_drm_primary_plane_atomic_update,259.atomic_disable = armada_drm_primary_plane_atomic_disable,260};261262void armada_plane_reset(struct drm_plane *plane)263{264struct armada_plane_state *st;265if (plane->state)266__drm_atomic_helper_plane_destroy_state(plane->state);267kfree(plane->state);268st = kzalloc(sizeof(*st), GFP_KERNEL);269if (st)270__drm_atomic_helper_plane_reset(plane, &st->base);271}272273struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane)274{275struct armada_plane_state *st;276277if (WARN_ON(!plane->state))278return NULL;279280st = kmemdup(plane->state, sizeof(*st), GFP_KERNEL);281if (st)282__drm_atomic_helper_plane_duplicate_state(plane, &st->base);283284return &st->base;285}286287static const struct drm_plane_funcs armada_primary_plane_funcs = {288.update_plane = drm_atomic_helper_update_plane,289.disable_plane = drm_atomic_helper_disable_plane,290.destroy = drm_plane_helper_destroy,291.reset = armada_plane_reset,292.atomic_duplicate_state = armada_plane_duplicate_state,293.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,294};295296int armada_drm_primary_plane_init(struct drm_device *drm,297struct drm_plane *primary)298{299int ret;300301drm_plane_helper_add(primary, &armada_primary_plane_helper_funcs);302303ret = drm_universal_plane_init(drm, primary, 0,304&armada_primary_plane_funcs,305armada_primary_formats,306ARRAY_SIZE(armada_primary_formats),307NULL,308DRM_PLANE_TYPE_PRIMARY, NULL);309310return ret;311}312313314