brintos

brintos / linux-shallow public Read only

0
0
Text · 9.0 KiB · cc47c03 Raw
313 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2012 Russell King4 *  Rewritten from the dovefb driver, and Armada510 manuals.5 */6 7#include <drm/drm_atomic.h>8#include <drm/drm_atomic_helper.h>9#include <drm/drm_fourcc.h>10#include <drm/drm_plane_helper.h>11 12#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"19 20static const uint32_t armada_primary_formats[] = {21	DRM_FORMAT_UYVY,22	DRM_FORMAT_YUYV,23	DRM_FORMAT_VYUY,24	DRM_FORMAT_YVYU,25	DRM_FORMAT_ARGB8888,26	DRM_FORMAT_ABGR8888,27	DRM_FORMAT_XRGB8888,28	DRM_FORMAT_XBGR8888,29	DRM_FORMAT_RGB888,30	DRM_FORMAT_BGR888,31	DRM_FORMAT_ARGB1555,32	DRM_FORMAT_ABGR1555,33	DRM_FORMAT_RGB565,34	DRM_FORMAT_BGR565,35};36 37void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],38	u16 pitches[3], bool interlaced)39{40	struct drm_framebuffer *fb = state->fb;41	const struct drm_format_info *format = fb->format;42	unsigned int num_planes = format->num_planes;43	unsigned int x = state->src.x1 >> 16;44	unsigned int y = state->src.y1 >> 16;45	u32 addr = drm_fb_obj(fb)->dev_addr;46	int i;47 48	DRM_DEBUG_KMS("pitch %u x %d y %d bpp %d\n",49		      fb->pitches[0], x, y, format->cpp[0] * 8);50 51	if (num_planes > 3)52		num_planes = 3;53 54	addrs[0][0] = addr + fb->offsets[0] + y * fb->pitches[0] +55		      x * format->cpp[0];56	pitches[0] = fb->pitches[0];57 58	y /= format->vsub;59	x /= format->hsub;60 61	for (i = 1; i < num_planes; i++) {62		addrs[0][i] = addr + fb->offsets[i] + y * fb->pitches[i] +63			      x * format->cpp[i];64		pitches[i] = fb->pitches[i];65	}66	for (; i < 3; i++) {67		addrs[0][i] = 0;68		pitches[i] = 0;69	}70	if (interlaced) {71		for (i = 0; i < 3; i++) {72			addrs[1][i] = addrs[0][i] + pitches[i];73			pitches[i] *= 2;74		}75	} else {76		for (i = 0; i < 3; i++)77			addrs[1][i] = addrs[0][i];78	}79}80 81int armada_drm_plane_atomic_check(struct drm_plane *plane,82	struct drm_atomic_state *state)83{84	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,85										 plane);86	struct armada_plane_state *st = to_armada_plane_state(new_plane_state);87	struct drm_crtc *crtc = new_plane_state->crtc;88	struct drm_crtc_state *crtc_state;89	bool interlace;90	int ret;91 92	if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc)) {93		new_plane_state->visible = false;94		return 0;95	}96 97	if (state)98		crtc_state = drm_atomic_get_existing_crtc_state(state,99								crtc);100	else101		crtc_state = crtc->state;102 103	ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,104						  0,105						  INT_MAX, true, false);106	if (ret)107		return ret;108 109	interlace = crtc_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE;110	if (interlace) {111		if ((new_plane_state->dst.y1 | new_plane_state->dst.y2) & 1)112			return -EINVAL;113		st->src_hw = drm_rect_height(&new_plane_state->src) >> 17;114		st->dst_yx = new_plane_state->dst.y1 >> 1;115		st->dst_hw = drm_rect_height(&new_plane_state->dst) >> 1;116	} else {117		st->src_hw = drm_rect_height(&new_plane_state->src) >> 16;118		st->dst_yx = new_plane_state->dst.y1;119		st->dst_hw = drm_rect_height(&new_plane_state->dst);120	}121 122	st->src_hw <<= 16;123	st->src_hw |= drm_rect_width(&new_plane_state->src) >> 16;124	st->dst_yx <<= 16;125	st->dst_yx |= new_plane_state->dst.x1 & 0x0000ffff;126	st->dst_hw <<= 16;127	st->dst_hw |= drm_rect_width(&new_plane_state->dst) & 0x0000ffff;128 129	armada_drm_plane_calc(new_plane_state, st->addrs, st->pitches,130			      interlace);131	st->interlace = interlace;132 133	return 0;134}135 136static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,137	struct drm_atomic_state *state)138{139	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,140									   plane);141	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,142									   plane);143	struct armada_crtc *dcrtc;144	struct armada_regs *regs;145	u32 cfg, cfg_mask, val;146	unsigned int idx;147 148	DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);149 150	if (!new_state->fb || WARN_ON(!new_state->crtc))151		return;152 153	DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n",154		plane->base.id, plane->name,155		new_state->crtc->base.id, new_state->crtc->name,156		new_state->fb->base.id,157		old_state->visible, new_state->visible);158 159	dcrtc = drm_to_armada_crtc(new_state->crtc);160	regs = dcrtc->regs + dcrtc->regs_idx;161 162	idx = 0;163	if (!old_state->visible && new_state->visible) {164		val = CFG_PDWN64x66;165		if (drm_fb_to_armada_fb(new_state->fb)->fmt > CFG_420)166			val |= CFG_PDWN256x24;167		armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1);168	}169	val = armada_src_hw(new_state);170	if (armada_src_hw(old_state) != val)171		armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN);172	val = armada_dst_yx(new_state);173	if (armada_dst_yx(old_state) != val)174		armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN);175	val = armada_dst_hw(new_state);176	if (armada_dst_hw(old_state) != val)177		armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN);178	if (old_state->src.x1 != new_state->src.x1 ||179	    old_state->src.y1 != new_state->src.y1 ||180	    old_state->fb != new_state->fb ||181	    new_state->crtc->state->mode_changed) {182		armada_reg_queue_set(regs, idx, armada_addr(new_state, 0, 0),183				     LCD_CFG_GRA_START_ADDR0);184		armada_reg_queue_set(regs, idx, armada_addr(new_state, 1, 0),185				     LCD_CFG_GRA_START_ADDR1);186		armada_reg_queue_mod(regs, idx, armada_pitch(new_state, 0),187				     0xffff,188				     LCD_CFG_GRA_PITCH);189	}190	if (old_state->fb != new_state->fb ||191	    new_state->crtc->state->mode_changed) {192		cfg = CFG_GRA_FMT(drm_fb_to_armada_fb(new_state->fb)->fmt) |193		      CFG_GRA_MOD(drm_fb_to_armada_fb(new_state->fb)->mod);194		if (drm_fb_to_armada_fb(new_state->fb)->fmt > CFG_420)195			cfg |= CFG_PALETTE_ENA;196		if (new_state->visible)197			cfg |= CFG_GRA_ENA;198		if (to_armada_plane_state(new_state)->interlace)199			cfg |= CFG_GRA_FTOGGLE;200		cfg_mask = CFG_GRAFORMAT |201			   CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |202				       CFG_SWAPYU | CFG_YUV2RGB) |203			   CFG_PALETTE_ENA | CFG_GRA_FTOGGLE |204			   CFG_GRA_ENA;205	} else if (old_state->visible != new_state->visible) {206		cfg = new_state->visible ? CFG_GRA_ENA : 0;207		cfg_mask = CFG_GRA_ENA;208	} else {209		cfg = cfg_mask = 0;210	}211	if (drm_rect_width(&old_state->src) != drm_rect_width(&new_state->src) ||212	    drm_rect_width(&old_state->dst) != drm_rect_width(&new_state->dst)) {213		cfg_mask |= CFG_GRA_HSMOOTH;214		if (drm_rect_width(&new_state->src) >> 16 !=215		    drm_rect_width(&new_state->dst))216			cfg |= CFG_GRA_HSMOOTH;217	}218 219	if (cfg_mask)220		armada_reg_queue_mod(regs, idx, cfg, cfg_mask,221				     LCD_SPU_DMA_CTRL0);222 223	dcrtc->regs_idx += idx;224}225 226static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane,227	struct drm_atomic_state *state)228{229	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,230									   plane);231	struct armada_crtc *dcrtc;232	struct armada_regs *regs;233	unsigned int idx = 0;234 235	DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);236 237	if (!old_state->crtc)238		return;239 240	DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n",241		plane->base.id, plane->name,242		old_state->crtc->base.id, old_state->crtc->name,243		old_state->fb->base.id);244 245	dcrtc = drm_to_armada_crtc(old_state->crtc);246	regs = dcrtc->regs + dcrtc->regs_idx;247 248	/* Disable plane and power down most RAMs and FIFOs */249	armada_reg_queue_mod(regs, idx, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0);250	armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 |251			     CFG_PDWN32x32 | CFG_PDWN64x66,252			     0, LCD_SPU_SRAM_PARA1);253 254	dcrtc->regs_idx += idx;255}256 257static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = {258	.atomic_check	= armada_drm_plane_atomic_check,259	.atomic_update	= armada_drm_primary_plane_atomic_update,260	.atomic_disable	= armada_drm_primary_plane_atomic_disable,261};262 263void armada_plane_reset(struct drm_plane *plane)264{265	struct armada_plane_state *st;266	if (plane->state)267		__drm_atomic_helper_plane_destroy_state(plane->state);268	kfree(plane->state);269	st = kzalloc(sizeof(*st), GFP_KERNEL);270	if (st)271		__drm_atomic_helper_plane_reset(plane, &st->base);272}273 274struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane)275{276	struct armada_plane_state *st;277 278	if (WARN_ON(!plane->state))279		return NULL;280 281	st = kmemdup(plane->state, sizeof(*st), GFP_KERNEL);282	if (st)283		__drm_atomic_helper_plane_duplicate_state(plane, &st->base);284 285	return &st->base;286}287 288static const struct drm_plane_funcs armada_primary_plane_funcs = {289	.update_plane	= drm_atomic_helper_update_plane,290	.disable_plane	= drm_atomic_helper_disable_plane,291	.destroy	= drm_plane_helper_destroy,292	.reset		= armada_plane_reset,293	.atomic_duplicate_state = armada_plane_duplicate_state,294	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,295};296 297int armada_drm_primary_plane_init(struct drm_device *drm,298	struct drm_plane *primary)299{300	int ret;301 302	drm_plane_helper_add(primary, &armada_primary_plane_helper_funcs);303 304	ret = drm_universal_plane_init(drm, primary, 0,305				       &armada_primary_plane_funcs,306				       armada_primary_formats,307				       ARRAY_SIZE(armada_primary_formats),308				       NULL,309				       DRM_PLANE_TYPE_PRIMARY, NULL);310 311	return ret;312}313