brintos

brintos / linux-shallow public Read only

0
0
Text · 9.1 KiB · 07ad17d Raw
317 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * shmob_drm_plane.c  --  SH Mobile DRM Planes4 *5 * Copyright (C) 2012 Renesas Electronics Corporation6 *7 * Laurent Pinchart (laurent.pinchart@ideasonboard.com)8 */9 10#include <drm/drm_atomic.h>11#include <drm/drm_atomic_helper.h>12#include <drm/drm_crtc.h>13#include <drm/drm_fb_dma_helper.h>14#include <drm/drm_fourcc.h>15#include <drm/drm_framebuffer.h>16#include <drm/drm_gem_dma_helper.h>17 18#include "shmob_drm_drv.h"19#include "shmob_drm_kms.h"20#include "shmob_drm_plane.h"21#include "shmob_drm_regs.h"22 23struct shmob_drm_plane {24	struct drm_plane base;25	unsigned int index;26};27 28struct shmob_drm_plane_state {29	struct drm_plane_state base;30 31	const struct shmob_drm_format_info *format;32	u32 dma[2];33};34 35static inline struct shmob_drm_plane *to_shmob_plane(struct drm_plane *plane)36{37	return container_of(plane, struct shmob_drm_plane, base);38}39 40static inline struct shmob_drm_plane_state *to_shmob_plane_state(struct drm_plane_state *state)41{42	return container_of(state, struct shmob_drm_plane_state, base);43}44 45static void shmob_drm_plane_compute_base(struct shmob_drm_plane_state *sstate)46{47	struct drm_framebuffer *fb = sstate->base.fb;48	unsigned int x = sstate->base.src_x >> 16;49	unsigned int y = sstate->base.src_y >> 16;50	struct drm_gem_dma_object *gem;51	unsigned int bpp;52 53	bpp = shmob_drm_format_is_yuv(sstate->format) ? 8 : sstate->format->bpp;54	gem = drm_fb_dma_get_gem_obj(fb, 0);55	sstate->dma[0] = gem->dma_addr + fb->offsets[0]56		       + y * fb->pitches[0] + x * bpp / 8;57 58	if (shmob_drm_format_is_yuv(sstate->format)) {59		bpp = sstate->format->bpp - 8;60		gem = drm_fb_dma_get_gem_obj(fb, 1);61		sstate->dma[1] = gem->dma_addr + fb->offsets[1]62			       + y / (bpp == 4 ? 2 : 1) * fb->pitches[1]63			       + x * (bpp == 16 ? 2 : 1);64	}65}66 67static void shmob_drm_primary_plane_setup(struct shmob_drm_plane *splane,68					  struct drm_plane_state *state)69{70	struct shmob_drm_plane_state *sstate = to_shmob_plane_state(state);71	struct shmob_drm_device *sdev = to_shmob_device(splane->base.dev);72	struct drm_framebuffer *fb = state->fb;73 74	/* TODO: Handle YUV colorspaces. Hardcode REC709 for now. */75	lcdc_write(sdev, LDDFR, sstate->format->lddfr | LDDFR_CF1);76	lcdc_write(sdev, LDMLSR, fb->pitches[0]);77 78	/* Word and long word swap. */79	lcdc_write(sdev, LDDDSR, sstate->format->ldddsr);80 81	lcdc_write_mirror(sdev, LDSA1R, sstate->dma[0]);82	if (shmob_drm_format_is_yuv(sstate->format))83		lcdc_write_mirror(sdev, LDSA2R, sstate->dma[1]);84 85	lcdc_write(sdev, LDRCNTR, lcdc_read(sdev, LDRCNTR) ^ LDRCNTR_MRS);86}87 88static void shmob_drm_overlay_plane_setup(struct shmob_drm_plane *splane,89					  struct drm_plane_state *state)90{91	struct shmob_drm_plane_state *sstate = to_shmob_plane_state(state);92	struct shmob_drm_device *sdev = to_shmob_device(splane->base.dev);93	struct drm_framebuffer *fb = state->fb;94	u32 format;95 96	/* TODO: Support ROP3 mode */97	format = LDBBSIFR_EN | ((state->alpha >> 8) << LDBBSIFR_LAY_SHIFT) |98		 sstate->format->ldbbsifr;99 100#define plane_reg_dump(sdev, splane, reg) \101	dev_dbg(sdev->ddev.dev, "%s(%u): %s 0x%08x 0x%08x\n", __func__, \102		splane->index, #reg, \103		lcdc_read(sdev, reg(splane->index)), \104		lcdc_read(sdev, reg(splane->index) + LCDC_SIDE_B_OFFSET))105 106	plane_reg_dump(sdev, splane, LDBnBSIFR);107	plane_reg_dump(sdev, splane, LDBnBSSZR);108	plane_reg_dump(sdev, splane, LDBnBLOCR);109	plane_reg_dump(sdev, splane, LDBnBSMWR);110	plane_reg_dump(sdev, splane, LDBnBSAYR);111	plane_reg_dump(sdev, splane, LDBnBSACR);112 113	lcdc_write(sdev, LDBCR, LDBCR_UPC(splane->index));114	dev_dbg(sdev->ddev.dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,115		"LDBCR", lcdc_read(sdev, LDBCR));116 117	lcdc_write(sdev, LDBnBSIFR(splane->index), format);118 119	lcdc_write(sdev, LDBnBSSZR(splane->index),120		   (state->crtc_h << LDBBSSZR_BVSS_SHIFT) |121		   (state->crtc_w << LDBBSSZR_BHSS_SHIFT));122	lcdc_write(sdev, LDBnBLOCR(splane->index),123		   (state->crtc_y << LDBBLOCR_CVLC_SHIFT) |124		   (state->crtc_x << LDBBLOCR_CHLC_SHIFT));125	lcdc_write(sdev, LDBnBSMWR(splane->index),126		   fb->pitches[0] << LDBBSMWR_BSMW_SHIFT);127 128	lcdc_write(sdev, LDBnBSAYR(splane->index), sstate->dma[0]);129	if (shmob_drm_format_is_yuv(sstate->format))130		lcdc_write(sdev, LDBnBSACR(splane->index), sstate->dma[1]);131 132	lcdc_write(sdev, LDBCR,133		   LDBCR_UPF(splane->index) | LDBCR_UPD(splane->index));134	dev_dbg(sdev->ddev.dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,135		"LDBCR", lcdc_read(sdev, LDBCR));136 137	plane_reg_dump(sdev, splane, LDBnBSIFR);138	plane_reg_dump(sdev, splane, LDBnBSSZR);139	plane_reg_dump(sdev, splane, LDBnBLOCR);140	plane_reg_dump(sdev, splane, LDBnBSMWR);141	plane_reg_dump(sdev, splane, LDBnBSAYR);142	plane_reg_dump(sdev, splane, LDBnBSACR);143}144 145static int shmob_drm_plane_atomic_check(struct drm_plane *plane,146					struct drm_atomic_state *state)147{148	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);149	struct shmob_drm_plane_state *sstate = to_shmob_plane_state(new_plane_state);150	struct drm_crtc_state *crtc_state;151	bool is_primary = plane->type == DRM_PLANE_TYPE_PRIMARY;152	int ret;153 154	if (!new_plane_state->crtc) {155		/*156		 * The visible field is not reset by the DRM core but only157		 * updated by drm_atomic_helper_check_plane_state(), set it158		 * manually.159		 */160		new_plane_state->visible = false;161		sstate->format = NULL;162		return 0;163	}164 165	crtc_state = drm_atomic_get_crtc_state(state, new_plane_state->crtc);166	if (IS_ERR(crtc_state))167		return PTR_ERR(crtc_state);168 169	ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,170						  DRM_PLANE_NO_SCALING,171						  DRM_PLANE_NO_SCALING,172						  !is_primary, true);173	if (ret < 0)174		return ret;175 176	if (!new_plane_state->visible) {177		sstate->format = NULL;178		return 0;179	}180 181	sstate->format = shmob_drm_format_info(new_plane_state->fb->format->format);182	if (!sstate->format) {183		dev_dbg(plane->dev->dev,184			"plane_atomic_check: unsupported format %p4cc\n",185			&new_plane_state->fb->format->format);186		return -EINVAL;187	}188 189	shmob_drm_plane_compute_base(sstate);190 191	return 0;192}193 194static void shmob_drm_plane_atomic_update(struct drm_plane *plane,195					  struct drm_atomic_state *state)196{197	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);198	struct shmob_drm_plane *splane = to_shmob_plane(plane);199 200	if (!new_plane_state->visible)201		return;202 203	if (plane->type == DRM_PLANE_TYPE_PRIMARY)204		shmob_drm_primary_plane_setup(splane, new_plane_state);205	else206		shmob_drm_overlay_plane_setup(splane, new_plane_state);207}208 209static void shmob_drm_plane_atomic_disable(struct drm_plane *plane,210					   struct drm_atomic_state *state)211{212	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);213	struct shmob_drm_device *sdev = to_shmob_device(plane->dev);214	struct shmob_drm_plane *splane = to_shmob_plane(plane);215 216	if (!old_state->crtc)217		return;218 219	if (plane->type != DRM_PLANE_TYPE_OVERLAY)220		return;221 222	lcdc_write(sdev, LDBCR, LDBCR_UPC(splane->index));223	lcdc_write(sdev, LDBnBSIFR(splane->index), 0);224	lcdc_write(sdev, LDBCR,225			 LDBCR_UPF(splane->index) | LDBCR_UPD(splane->index));226}227 228static struct drm_plane_state *229shmob_drm_plane_atomic_duplicate_state(struct drm_plane *plane)230{231	struct shmob_drm_plane_state *state;232	struct shmob_drm_plane_state *copy;233 234	if (WARN_ON(!plane->state))235		return NULL;236 237	state = to_shmob_plane_state(plane->state);238	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);239	if (copy == NULL)240		return NULL;241 242	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base);243 244	return &copy->base;245}246 247static void shmob_drm_plane_atomic_destroy_state(struct drm_plane *plane,248						 struct drm_plane_state *state)249{250	__drm_atomic_helper_plane_destroy_state(state);251	kfree(to_shmob_plane_state(state));252}253 254static void shmob_drm_plane_reset(struct drm_plane *plane)255{256	struct shmob_drm_plane_state *state;257 258	if (plane->state) {259		shmob_drm_plane_atomic_destroy_state(plane, plane->state);260		plane->state = NULL;261	}262 263	state = kzalloc(sizeof(*state), GFP_KERNEL);264	if (state == NULL)265		return;266 267	__drm_atomic_helper_plane_reset(plane, &state->base);268}269 270static const struct drm_plane_helper_funcs shmob_drm_plane_helper_funcs = {271	.atomic_check = shmob_drm_plane_atomic_check,272	.atomic_update = shmob_drm_plane_atomic_update,273	.atomic_disable = shmob_drm_plane_atomic_disable,274};275 276static const struct drm_plane_funcs shmob_drm_plane_funcs = {277	.update_plane = drm_atomic_helper_update_plane,278	.disable_plane = drm_atomic_helper_disable_plane,279	.reset = shmob_drm_plane_reset,280	.atomic_duplicate_state = shmob_drm_plane_atomic_duplicate_state,281	.atomic_destroy_state = shmob_drm_plane_atomic_destroy_state,282};283 284static const uint32_t formats[] = {285	DRM_FORMAT_RGB565,286	DRM_FORMAT_RGB888,287	DRM_FORMAT_ARGB8888,288	DRM_FORMAT_XRGB8888,289	DRM_FORMAT_NV12,290	DRM_FORMAT_NV21,291	DRM_FORMAT_NV16,292	DRM_FORMAT_NV61,293	DRM_FORMAT_NV24,294	DRM_FORMAT_NV42,295};296 297struct drm_plane *shmob_drm_plane_create(struct shmob_drm_device *sdev,298					 enum drm_plane_type type,299					 unsigned int index)300{301	struct shmob_drm_plane *splane;302 303	splane = drmm_universal_plane_alloc(&sdev->ddev,304					    struct shmob_drm_plane, base, 1,305					    &shmob_drm_plane_funcs, formats,306					    ARRAY_SIZE(formats),  NULL, type,307					    NULL);308	if (IS_ERR(splane))309		return ERR_CAST(splane);310 311	splane->index = index;312 313	drm_plane_helper_add(&splane->base, &shmob_drm_plane_helper_funcs);314 315	return &splane->base;316}317