brintos

brintos / linux-shallow public Read only

0
0
Text · 21.6 KiB · d227a2c Raw
793 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Copyright (C) 2023 Loongson Technology Corporation Limited4 */5 6#include <linux/delay.h>7 8#include <drm/drm_atomic.h>9#include <drm/drm_atomic_helper.h>10#include <drm/drm_framebuffer.h>11#include <drm/drm_gem_atomic_helper.h>12 13#include "lsdc_drv.h"14#include "lsdc_regs.h"15#include "lsdc_ttm.h"16 17static const u32 lsdc_primary_formats[] = {18	DRM_FORMAT_XRGB8888,19};20 21static const u32 lsdc_cursor_formats[] = {22	DRM_FORMAT_ARGB8888,23};24 25static const u64 lsdc_fb_format_modifiers[] = {26	DRM_FORMAT_MOD_LINEAR,27	DRM_FORMAT_MOD_INVALID28};29 30static unsigned int lsdc_get_fb_offset(struct drm_framebuffer *fb,31				       struct drm_plane_state *state)32{33	unsigned int offset = fb->offsets[0];34 35	offset += fb->format->cpp[0] * (state->src_x >> 16);36	offset += fb->pitches[0] * (state->src_y >> 16);37 38	return offset;39}40 41static u64 lsdc_fb_base_addr(struct drm_framebuffer *fb)42{43	struct lsdc_device *ldev = to_lsdc(fb->dev);44	struct lsdc_bo *lbo = gem_to_lsdc_bo(fb->obj[0]);45 46	return lsdc_bo_gpu_offset(lbo) + ldev->vram_base;47}48 49static int lsdc_primary_atomic_check(struct drm_plane *plane,50				     struct drm_atomic_state *state)51{52	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);53	struct drm_crtc *crtc = new_plane_state->crtc;54	struct drm_crtc_state *new_crtc_state;55 56	if (!crtc)57		return 0;58 59	new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);60 61	return drm_atomic_helper_check_plane_state(new_plane_state,62						   new_crtc_state,63						   DRM_PLANE_NO_SCALING,64						   DRM_PLANE_NO_SCALING,65						   false, true);66}67 68static void lsdc_primary_atomic_update(struct drm_plane *plane,69				       struct drm_atomic_state *state)70{71	struct lsdc_primary *primary = to_lsdc_primary(plane);72	const struct lsdc_primary_plane_ops *ops = primary->ops;73	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);74	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);75	struct drm_framebuffer *new_fb = new_plane_state->fb;76	struct drm_framebuffer *old_fb = old_plane_state->fb;77	u64 fb_addr = lsdc_fb_base_addr(new_fb);78 79	fb_addr += lsdc_get_fb_offset(new_fb, new_plane_state);80 81	ops->update_fb_addr(primary, fb_addr);82	ops->update_fb_stride(primary, new_fb->pitches[0]);83 84	if (!old_fb || old_fb->format != new_fb->format)85		ops->update_fb_format(primary, new_fb->format);86}87 88static void lsdc_primary_atomic_disable(struct drm_plane *plane,89					struct drm_atomic_state *state)90{91	/*92	 * Do nothing, just prevent call into atomic_update().93	 * Writing the format as LSDC_PF_NONE can disable the primary,94	 * But it seems not necessary...95	 */96	drm_dbg(plane->dev, "%s disabled\n", plane->name);97}98 99static int lsdc_plane_prepare_fb(struct drm_plane *plane,100				 struct drm_plane_state *new_state)101{102	struct drm_framebuffer *fb = new_state->fb;103	struct lsdc_bo *lbo;104	u64 gpu_vaddr;105	int ret;106 107	if (!fb)108		return 0;109 110	lbo = gem_to_lsdc_bo(fb->obj[0]);111 112	ret = lsdc_bo_reserve(lbo);113	if (unlikely(ret)) {114		drm_err(plane->dev, "bo %p reserve failed\n", lbo);115		return ret;116	}117 118	ret = lsdc_bo_pin(lbo, LSDC_GEM_DOMAIN_VRAM, &gpu_vaddr);119 120	lsdc_bo_unreserve(lbo);121 122	if (unlikely(ret)) {123		drm_err(plane->dev, "bo %p pin failed\n", lbo);124		return ret;125	}126 127	lsdc_bo_ref(lbo);128 129	if (plane->type != DRM_PLANE_TYPE_CURSOR)130		drm_dbg(plane->dev,131			"%s[%p] pin at 0x%llx, bo size: %zu\n",132			plane->name, lbo, gpu_vaddr, lsdc_bo_size(lbo));133 134	return drm_gem_plane_helper_prepare_fb(plane, new_state);135}136 137static void lsdc_plane_cleanup_fb(struct drm_plane *plane,138				  struct drm_plane_state *old_state)139{140	struct drm_framebuffer *fb = old_state->fb;141	struct lsdc_bo *lbo;142	int ret;143 144	if (!fb)145		return;146 147	lbo = gem_to_lsdc_bo(fb->obj[0]);148 149	ret = lsdc_bo_reserve(lbo);150	if (unlikely(ret)) {151		drm_err(plane->dev, "%p reserve failed\n", lbo);152		return;153	}154 155	lsdc_bo_unpin(lbo);156 157	lsdc_bo_unreserve(lbo);158 159	lsdc_bo_unref(lbo);160 161	if (plane->type != DRM_PLANE_TYPE_CURSOR)162		drm_dbg(plane->dev, "%s unpin\n", plane->name);163}164 165static const struct drm_plane_helper_funcs lsdc_primary_helper_funcs = {166	.prepare_fb = lsdc_plane_prepare_fb,167	.cleanup_fb = lsdc_plane_cleanup_fb,168	.atomic_check = lsdc_primary_atomic_check,169	.atomic_update = lsdc_primary_atomic_update,170	.atomic_disable = lsdc_primary_atomic_disable,171};172 173static int lsdc_cursor_plane_atomic_async_check(struct drm_plane *plane,174						struct drm_atomic_state *state)175{176	struct drm_plane_state *new_state;177	struct drm_crtc_state *crtc_state;178 179	new_state = drm_atomic_get_new_plane_state(state, plane);180 181	if (!plane->state || !plane->state->fb) {182		drm_dbg(plane->dev, "%s: state is NULL\n", plane->name);183		return -EINVAL;184	}185 186	if (new_state->crtc_w != new_state->crtc_h) {187		drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",188			new_state->crtc_w, new_state->crtc_h);189		return -EINVAL;190	}191 192	if (new_state->crtc_w != 64 && new_state->crtc_w != 32) {193		drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",194			new_state->crtc_w, new_state->crtc_h);195		return -EINVAL;196	}197 198	crtc_state = drm_atomic_get_existing_crtc_state(state, new_state->crtc);199	if (!crtc_state->active)200		return -EINVAL;201 202	if (plane->state->crtc != new_state->crtc ||203	    plane->state->src_w != new_state->src_w ||204	    plane->state->src_h != new_state->src_h ||205	    plane->state->crtc_w != new_state->crtc_w ||206	    plane->state->crtc_h != new_state->crtc_h)207		return -EINVAL;208 209	if (new_state->visible != plane->state->visible)210		return -EINVAL;211 212	return drm_atomic_helper_check_plane_state(plane->state,213						   crtc_state,214						   DRM_PLANE_NO_SCALING,215						   DRM_PLANE_NO_SCALING,216						   true, true);217}218 219static void lsdc_cursor_plane_atomic_async_update(struct drm_plane *plane,220						  struct drm_atomic_state *state)221{222	struct lsdc_cursor *cursor = to_lsdc_cursor(plane);223	const struct lsdc_cursor_plane_ops *ops = cursor->ops;224	struct drm_framebuffer *old_fb = plane->state->fb;225	struct drm_framebuffer *new_fb;226	struct drm_plane_state *new_state;227 228	new_state = drm_atomic_get_new_plane_state(state, plane);229 230	new_fb = plane->state->fb;231 232	plane->state->crtc_x = new_state->crtc_x;233	plane->state->crtc_y = new_state->crtc_y;234	plane->state->crtc_h = new_state->crtc_h;235	plane->state->crtc_w = new_state->crtc_w;236	plane->state->src_x = new_state->src_x;237	plane->state->src_y = new_state->src_y;238	plane->state->src_h = new_state->src_h;239	plane->state->src_w = new_state->src_w;240	swap(plane->state->fb, new_state->fb);241 242	if (new_state->visible) {243		enum lsdc_cursor_size cursor_size;244 245		switch (new_state->crtc_w) {246		case 64:247			cursor_size = CURSOR_SIZE_64X64;248			break;249		case 32:250			cursor_size = CURSOR_SIZE_32X32;251			break;252		default:253			cursor_size = CURSOR_SIZE_32X32;254			break;255		}256 257		ops->update_position(cursor, new_state->crtc_x, new_state->crtc_y);258 259		ops->update_cfg(cursor, cursor_size, CURSOR_FORMAT_ARGB8888);260 261		if (!old_fb || old_fb != new_fb)262			ops->update_bo_addr(cursor, lsdc_fb_base_addr(new_fb));263	}264}265 266/* ls7a1000 cursor plane helpers */267 268static int ls7a1000_cursor_plane_atomic_check(struct drm_plane *plane,269					      struct drm_atomic_state *state)270{271	struct drm_plane_state *new_plane_state;272	struct drm_crtc_state *new_crtc_state;273	struct drm_crtc *crtc;274 275	new_plane_state = drm_atomic_get_new_plane_state(state, plane);276 277	crtc = new_plane_state->crtc;278	if (!crtc) {279		drm_dbg(plane->dev, "%s is not bind to a crtc\n", plane->name);280		return 0;281	}282 283	if (new_plane_state->crtc_w != 32 || new_plane_state->crtc_h != 32) {284		drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",285			new_plane_state->crtc_w, new_plane_state->crtc_h);286		return -EINVAL;287	}288 289	new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);290 291	return drm_atomic_helper_check_plane_state(new_plane_state,292						   new_crtc_state,293						   DRM_PLANE_NO_SCALING,294						   DRM_PLANE_NO_SCALING,295						   true, true);296}297 298static void ls7a1000_cursor_plane_atomic_update(struct drm_plane *plane,299						struct drm_atomic_state *state)300{301	struct lsdc_cursor *cursor = to_lsdc_cursor(plane);302	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);303	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);304	struct drm_framebuffer *new_fb = new_plane_state->fb;305	struct drm_framebuffer *old_fb = old_plane_state->fb;306	const struct lsdc_cursor_plane_ops *ops = cursor->ops;307	u64 addr = lsdc_fb_base_addr(new_fb);308 309	if (!new_plane_state->visible)310		return;311 312	ops->update_position(cursor, new_plane_state->crtc_x, new_plane_state->crtc_y);313 314	if (!old_fb || old_fb != new_fb)315		ops->update_bo_addr(cursor, addr);316 317	ops->update_cfg(cursor, CURSOR_SIZE_32X32, CURSOR_FORMAT_ARGB8888);318}319 320static void ls7a1000_cursor_plane_atomic_disable(struct drm_plane *plane,321						 struct drm_atomic_state *state)322{323	struct lsdc_cursor *cursor = to_lsdc_cursor(plane);324	const struct lsdc_cursor_plane_ops *ops = cursor->ops;325 326	ops->update_cfg(cursor, CURSOR_SIZE_32X32, CURSOR_FORMAT_DISABLE);327}328 329static const struct drm_plane_helper_funcs ls7a1000_cursor_plane_helper_funcs = {330	.prepare_fb = lsdc_plane_prepare_fb,331	.cleanup_fb = lsdc_plane_cleanup_fb,332	.atomic_check = ls7a1000_cursor_plane_atomic_check,333	.atomic_update = ls7a1000_cursor_plane_atomic_update,334	.atomic_disable = ls7a1000_cursor_plane_atomic_disable,335	.atomic_async_check = lsdc_cursor_plane_atomic_async_check,336	.atomic_async_update = lsdc_cursor_plane_atomic_async_update,337};338 339/* ls7a2000 cursor plane helpers */340 341static int ls7a2000_cursor_plane_atomic_check(struct drm_plane *plane,342					      struct drm_atomic_state *state)343{344	struct drm_plane_state *new_plane_state;345	struct drm_crtc_state *new_crtc_state;346	struct drm_crtc *crtc;347 348	new_plane_state = drm_atomic_get_new_plane_state(state, plane);349 350	crtc = new_plane_state->crtc;351	if (!crtc) {352		drm_dbg(plane->dev, "%s is not bind to a crtc\n", plane->name);353		return 0;354	}355 356	if (new_plane_state->crtc_w != new_plane_state->crtc_h) {357		drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",358			new_plane_state->crtc_w, new_plane_state->crtc_h);359		return -EINVAL;360	}361 362	if (new_plane_state->crtc_w != 64 && new_plane_state->crtc_w != 32) {363		drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",364			new_plane_state->crtc_w, new_plane_state->crtc_h);365		return -EINVAL;366	}367 368	new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);369 370	return drm_atomic_helper_check_plane_state(new_plane_state,371						   new_crtc_state,372						   DRM_PLANE_NO_SCALING,373						   DRM_PLANE_NO_SCALING,374						   true, true);375}376 377/* Update the format, size and location of the cursor */378 379static void ls7a2000_cursor_plane_atomic_update(struct drm_plane *plane,380						struct drm_atomic_state *state)381{382	struct lsdc_cursor *cursor = to_lsdc_cursor(plane);383	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);384	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);385	struct drm_framebuffer *new_fb = new_plane_state->fb;386	struct drm_framebuffer *old_fb = old_plane_state->fb;387	const struct lsdc_cursor_plane_ops *ops = cursor->ops;388	enum lsdc_cursor_size cursor_size;389 390	if (!new_plane_state->visible)391		return;392 393	ops->update_position(cursor, new_plane_state->crtc_x, new_plane_state->crtc_y);394 395	if (!old_fb || new_fb != old_fb) {396		u64 addr = lsdc_fb_base_addr(new_fb);397 398		ops->update_bo_addr(cursor, addr);399	}400 401	switch (new_plane_state->crtc_w) {402	case 64:403		cursor_size = CURSOR_SIZE_64X64;404		break;405	case 32:406		cursor_size = CURSOR_SIZE_32X32;407		break;408	default:409		cursor_size = CURSOR_SIZE_64X64;410		break;411	}412 413	ops->update_cfg(cursor, cursor_size, CURSOR_FORMAT_ARGB8888);414}415 416static void ls7a2000_cursor_plane_atomic_disable(struct drm_plane *plane,417						 struct drm_atomic_state *state)418{419	struct lsdc_cursor *cursor = to_lsdc_cursor(plane);420	const struct lsdc_cursor_plane_ops *hw_ops = cursor->ops;421 422	hw_ops->update_cfg(cursor, CURSOR_SIZE_64X64, CURSOR_FORMAT_DISABLE);423}424 425static const struct drm_plane_helper_funcs ls7a2000_cursor_plane_helper_funcs = {426	.prepare_fb = lsdc_plane_prepare_fb,427	.cleanup_fb = lsdc_plane_cleanup_fb,428	.atomic_check = ls7a2000_cursor_plane_atomic_check,429	.atomic_update = ls7a2000_cursor_plane_atomic_update,430	.atomic_disable = ls7a2000_cursor_plane_atomic_disable,431	.atomic_async_check = lsdc_cursor_plane_atomic_async_check,432	.atomic_async_update = lsdc_cursor_plane_atomic_async_update,433};434 435static void lsdc_plane_atomic_print_state(struct drm_printer *p,436					  const struct drm_plane_state *state)437{438	struct drm_framebuffer *fb = state->fb;439	u64 addr;440 441	if (!fb)442		return;443 444	addr = lsdc_fb_base_addr(fb);445 446	drm_printf(p, "\tdma addr=%llx\n", addr);447}448 449static const struct drm_plane_funcs lsdc_plane_funcs = {450	.update_plane = drm_atomic_helper_update_plane,451	.disable_plane = drm_atomic_helper_disable_plane,452	.destroy = drm_plane_cleanup,453	.reset = drm_atomic_helper_plane_reset,454	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,455	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,456	.atomic_print_state = lsdc_plane_atomic_print_state,457};458 459/* Primary plane 0 hardware related ops  */460 461static void lsdc_primary0_update_fb_addr(struct lsdc_primary *primary, u64 addr)462{463	struct lsdc_device *ldev = primary->ldev;464	u32 status;465	u32 lo, hi;466 467	/* 40-bit width physical address bus */468	lo = addr & 0xFFFFFFFF;469	hi = (addr >> 32) & 0xFF;470 471	status = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG);472	if (status & FB_REG_IN_USING) {473		lsdc_wreg32(ldev, LSDC_CRTC0_FB1_ADDR_LO_REG, lo);474		lsdc_wreg32(ldev, LSDC_CRTC0_FB1_ADDR_HI_REG, hi);475	} else {476		lsdc_wreg32(ldev, LSDC_CRTC0_FB0_ADDR_LO_REG, lo);477		lsdc_wreg32(ldev, LSDC_CRTC0_FB0_ADDR_HI_REG, hi);478	}479}480 481static void lsdc_primary0_update_fb_stride(struct lsdc_primary *primary, u32 stride)482{483	struct lsdc_device *ldev = primary->ldev;484 485	lsdc_wreg32(ldev, LSDC_CRTC0_STRIDE_REG, stride);486}487 488static void lsdc_primary0_update_fb_format(struct lsdc_primary *primary,489					   const struct drm_format_info *format)490{491	struct lsdc_device *ldev = primary->ldev;492	u32 status;493 494	status = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG);495 496	/*497	 * TODO: add RGB565 support, only support XRBG8888 at present498	 */499	status &= ~CFG_PIX_FMT_MASK;500	status |= LSDC_PF_XRGB8888;501 502	lsdc_wreg32(ldev, LSDC_CRTC0_CFG_REG, status);503}504 505/* Primary plane 1 hardware related ops */506 507static void lsdc_primary1_update_fb_addr(struct lsdc_primary *primary, u64 addr)508{509	struct lsdc_device *ldev = primary->ldev;510	u32 status;511	u32 lo, hi;512 513	/* 40-bit width physical address bus */514	lo = addr & 0xFFFFFFFF;515	hi = (addr >> 32) & 0xFF;516 517	status = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG);518	if (status & FB_REG_IN_USING) {519		lsdc_wreg32(ldev, LSDC_CRTC1_FB1_ADDR_LO_REG, lo);520		lsdc_wreg32(ldev, LSDC_CRTC1_FB1_ADDR_HI_REG, hi);521	} else {522		lsdc_wreg32(ldev, LSDC_CRTC1_FB0_ADDR_LO_REG, lo);523		lsdc_wreg32(ldev, LSDC_CRTC1_FB0_ADDR_HI_REG, hi);524	}525}526 527static void lsdc_primary1_update_fb_stride(struct lsdc_primary *primary, u32 stride)528{529	struct lsdc_device *ldev = primary->ldev;530 531	lsdc_wreg32(ldev, LSDC_CRTC1_STRIDE_REG, stride);532}533 534static void lsdc_primary1_update_fb_format(struct lsdc_primary *primary,535					   const struct drm_format_info *format)536{537	struct lsdc_device *ldev = primary->ldev;538	u32 status;539 540	status = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG);541 542	/*543	 * TODO: add RGB565 support, only support XRBG8888 at present544	 */545	status &= ~CFG_PIX_FMT_MASK;546	status |= LSDC_PF_XRGB8888;547 548	lsdc_wreg32(ldev, LSDC_CRTC1_CFG_REG, status);549}550 551static const struct lsdc_primary_plane_ops lsdc_primary_plane_hw_ops[2] = {552	{553		.update_fb_addr = lsdc_primary0_update_fb_addr,554		.update_fb_stride = lsdc_primary0_update_fb_stride,555		.update_fb_format = lsdc_primary0_update_fb_format,556	},557	{558		.update_fb_addr = lsdc_primary1_update_fb_addr,559		.update_fb_stride = lsdc_primary1_update_fb_stride,560		.update_fb_format = lsdc_primary1_update_fb_format,561	},562};563 564/*565 * Update location, format, enable and disable state of the cursor,566 * For those who have two hardware cursor, let cursor 0 is attach to CRTC-0,567 * cursor 1 is attach to CRTC-1. Compositing the primary plane and cursor568 * plane is automatically done by hardware, the cursor is alway on the top of569 * the primary plane. In other word, z-order is fixed in hardware and cannot570 * be changed. For those old DC who has only one hardware cursor, we made it571 * shared by the two screen, this works on extend screen mode.572 */573 574/* cursor plane 0 (for pipe 0) related hardware ops */575 576static void lsdc_cursor0_update_bo_addr(struct lsdc_cursor *cursor, u64 addr)577{578	struct lsdc_device *ldev = cursor->ldev;579 580	/* 40-bit width physical address bus */581	lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_HI_REG, (addr >> 32) & 0xFF);582	lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_LO_REG, addr);583}584 585static void lsdc_cursor0_update_position(struct lsdc_cursor *cursor, int x, int y)586{587	struct lsdc_device *ldev = cursor->ldev;588 589	if (x < 0)590		x = 0;591 592	if (y < 0)593		y = 0;594 595	lsdc_wreg32(ldev, LSDC_CURSOR0_POSITION_REG, (y << 16) | x);596}597 598static void lsdc_cursor0_update_cfg(struct lsdc_cursor *cursor,599				    enum lsdc_cursor_size cursor_size,600				    enum lsdc_cursor_format fmt)601{602	struct lsdc_device *ldev = cursor->ldev;603	u32 cfg;604 605	cfg = CURSOR_ON_CRTC0 << CURSOR_LOCATION_SHIFT |606	      cursor_size << CURSOR_SIZE_SHIFT |607	      fmt << CURSOR_FORMAT_SHIFT;608 609	lsdc_wreg32(ldev, LSDC_CURSOR0_CFG_REG, cfg);610}611 612/* cursor plane 1 (for pipe 1) related hardware ops */613 614static void lsdc_cursor1_update_bo_addr(struct lsdc_cursor *cursor, u64 addr)615{616	struct lsdc_device *ldev = cursor->ldev;617 618	/* 40-bit width physical address bus */619	lsdc_wreg32(ldev, LSDC_CURSOR1_ADDR_HI_REG, (addr >> 32) & 0xFF);620	lsdc_wreg32(ldev, LSDC_CURSOR1_ADDR_LO_REG, addr);621}622 623static void lsdc_cursor1_update_position(struct lsdc_cursor *cursor, int x, int y)624{625	struct lsdc_device *ldev = cursor->ldev;626 627	if (x < 0)628		x = 0;629 630	if (y < 0)631		y = 0;632 633	lsdc_wreg32(ldev, LSDC_CURSOR1_POSITION_REG, (y << 16) | x);634}635 636static void lsdc_cursor1_update_cfg(struct lsdc_cursor *cursor,637				    enum lsdc_cursor_size cursor_size,638				    enum lsdc_cursor_format fmt)639{640	struct lsdc_device *ldev = cursor->ldev;641	u32 cfg;642 643	cfg = CURSOR_ON_CRTC1 << CURSOR_LOCATION_SHIFT |644	      cursor_size << CURSOR_SIZE_SHIFT |645	      fmt << CURSOR_FORMAT_SHIFT;646 647	lsdc_wreg32(ldev, LSDC_CURSOR1_CFG_REG, cfg);648}649 650/* The hardware cursors become normal since ls7a2000/ls2k2000 */651 652static const struct lsdc_cursor_plane_ops ls7a2000_cursor_hw_ops[2] = {653	{654		.update_bo_addr = lsdc_cursor0_update_bo_addr,655		.update_cfg = lsdc_cursor0_update_cfg,656		.update_position = lsdc_cursor0_update_position,657	},658	{659		.update_bo_addr = lsdc_cursor1_update_bo_addr,660		.update_cfg = lsdc_cursor1_update_cfg,661		.update_position = lsdc_cursor1_update_position,662	},663};664 665/* Quirks for cursor 1, only for old loongson display controller */666 667static void lsdc_cursor1_update_bo_addr_quirk(struct lsdc_cursor *cursor, u64 addr)668{669	struct lsdc_device *ldev = cursor->ldev;670 671	/* 40-bit width physical address bus */672	lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_HI_REG, (addr >> 32) & 0xFF);673	lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_LO_REG, addr);674}675 676static void lsdc_cursor1_update_position_quirk(struct lsdc_cursor *cursor, int x, int y)677{678	struct lsdc_device *ldev = cursor->ldev;679 680	if (x < 0)681		x = 0;682 683	if (y < 0)684		y = 0;685 686	lsdc_wreg32(ldev, LSDC_CURSOR0_POSITION_REG, (y << 16) | x);687}688 689static void lsdc_cursor1_update_cfg_quirk(struct lsdc_cursor *cursor,690					  enum lsdc_cursor_size cursor_size,691					  enum lsdc_cursor_format fmt)692{693	struct lsdc_device *ldev = cursor->ldev;694	u32 cfg;695 696	cfg = CURSOR_ON_CRTC1 << CURSOR_LOCATION_SHIFT |697	      cursor_size << CURSOR_SIZE_SHIFT |698	      fmt << CURSOR_FORMAT_SHIFT;699 700	lsdc_wreg32(ldev, LSDC_CURSOR0_CFG_REG, cfg);701}702 703/*704 * The unforgiving LS7A1000/LS2K1000 has only one hardware cursors plane705 */706static const struct lsdc_cursor_plane_ops ls7a1000_cursor_hw_ops[2] = {707	{708		.update_bo_addr = lsdc_cursor0_update_bo_addr,709		.update_cfg = lsdc_cursor0_update_cfg,710		.update_position = lsdc_cursor0_update_position,711	},712	{713		.update_bo_addr = lsdc_cursor1_update_bo_addr_quirk,714		.update_cfg = lsdc_cursor1_update_cfg_quirk,715		.update_position = lsdc_cursor1_update_position_quirk,716	},717};718 719int lsdc_primary_plane_init(struct drm_device *ddev,720			    struct drm_plane *plane,721			    unsigned int index)722{723	struct lsdc_primary *primary = to_lsdc_primary(plane);724	int ret;725 726	ret = drm_universal_plane_init(ddev, plane, 1 << index,727				       &lsdc_plane_funcs,728				       lsdc_primary_formats,729				       ARRAY_SIZE(lsdc_primary_formats),730				       lsdc_fb_format_modifiers,731				       DRM_PLANE_TYPE_PRIMARY,732				       "ls-primary-plane-%u", index);733	if (ret)734		return ret;735 736	drm_plane_helper_add(plane, &lsdc_primary_helper_funcs);737 738	primary->ldev = to_lsdc(ddev);739	primary->ops = &lsdc_primary_plane_hw_ops[index];740 741	return 0;742}743 744int ls7a1000_cursor_plane_init(struct drm_device *ddev,745			       struct drm_plane *plane,746			       unsigned int index)747{748	struct lsdc_cursor *cursor = to_lsdc_cursor(plane);749	int ret;750 751	ret = drm_universal_plane_init(ddev, plane, 1 << index,752				       &lsdc_plane_funcs,753				       lsdc_cursor_formats,754				       ARRAY_SIZE(lsdc_cursor_formats),755				       lsdc_fb_format_modifiers,756				       DRM_PLANE_TYPE_CURSOR,757				       "ls-cursor-plane-%u", index);758	if (ret)759		return ret;760 761	cursor->ldev = to_lsdc(ddev);762	cursor->ops = &ls7a1000_cursor_hw_ops[index];763 764	drm_plane_helper_add(plane, &ls7a1000_cursor_plane_helper_funcs);765 766	return 0;767}768 769int ls7a2000_cursor_plane_init(struct drm_device *ddev,770			       struct drm_plane *plane,771			       unsigned int index)772{773	struct lsdc_cursor *cursor = to_lsdc_cursor(plane);774	int ret;775 776	ret = drm_universal_plane_init(ddev, plane, 1 << index,777				       &lsdc_plane_funcs,778				       lsdc_cursor_formats,779				       ARRAY_SIZE(lsdc_cursor_formats),780				       lsdc_fb_format_modifiers,781				       DRM_PLANE_TYPE_CURSOR,782				       "ls-cursor-plane-%u", index);783	if (ret)784		return ret;785 786	cursor->ldev = to_lsdc(ddev);787	cursor->ops = &ls7a2000_cursor_hw_ops[index];788 789	drm_plane_helper_add(plane, &ls7a2000_cursor_plane_helper_funcs);790 791	return 0;792}793