Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1/*
  2 * Copyright (c) 2015 MediaTek Inc.
  3 * Author: CK Hu <ck.hu@mediatek.com>
  4 *
  5 * This program is free software; you can redistribute it and/or modify
  6 * it under the terms of the GNU General Public License version 2 as
  7 * published by the Free Software Foundation.
  8 *
  9 * This program is distributed in the hope that it will be useful,
 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 * GNU General Public License for more details.
 13 */
 14
 15#include <drm/drmP.h>
 16#include <drm/drm_atomic.h>
 17#include <drm/drm_atomic_helper.h>
 18#include <drm/drm_plane_helper.h>
 19
 20#include "mtk_drm_crtc.h"
 21#include "mtk_drm_ddp_comp.h"
 22#include "mtk_drm_drv.h"
 23#include "mtk_drm_fb.h"
 24#include "mtk_drm_gem.h"
 25#include "mtk_drm_plane.h"
 26
 27static const u32 formats[] = {
 28	DRM_FORMAT_XRGB8888,
 29	DRM_FORMAT_ARGB8888,
 30	DRM_FORMAT_RGB565,
 31	DRM_FORMAT_UYVY,
 32	DRM_FORMAT_YUYV,
 33};
 34
 35static void mtk_plane_reset(struct drm_plane *plane)
 36{
 37	struct mtk_plane_state *state;
 38
 39	if (plane->state) {
 40		__drm_atomic_helper_plane_destroy_state(plane->state);
 41
 42		state = to_mtk_plane_state(plane->state);
 43		memset(state, 0, sizeof(*state));
 44	} else {
 45		state = kzalloc(sizeof(*state), GFP_KERNEL);
 46		if (!state)
 47			return;
 48		plane->state = &state->base;
 49	}
 50
 51	state->base.plane = plane;
 52	state->pending.format = DRM_FORMAT_RGB565;
 53}
 54
 55static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane)
 56{
 57	struct mtk_plane_state *old_state = to_mtk_plane_state(plane->state);
 58	struct mtk_plane_state *state;
 59
 60	state = kzalloc(sizeof(*state), GFP_KERNEL);
 61	if (!state)
 62		return NULL;
 63
 64	__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
 65
 66	WARN_ON(state->base.plane != plane);
 67
 68	state->pending = old_state->pending;
 69
 70	return &state->base;
 71}
 72
 73static void mtk_drm_plane_destroy_state(struct drm_plane *plane,
 74					struct drm_plane_state *state)
 75{
 76	__drm_atomic_helper_plane_destroy_state(state);
 77	kfree(to_mtk_plane_state(state));
 78}
 79
 80static const struct drm_plane_funcs mtk_plane_funcs = {
 81	.update_plane = drm_atomic_helper_update_plane,
 82	.disable_plane = drm_atomic_helper_disable_plane,
 83	.destroy = drm_plane_cleanup,
 84	.reset = mtk_plane_reset,
 85	.atomic_duplicate_state = mtk_plane_duplicate_state,
 86	.atomic_destroy_state = mtk_drm_plane_destroy_state,
 87};
 88
 89static int mtk_plane_atomic_check(struct drm_plane *plane,
 90				  struct drm_plane_state *state)
 91{
 92	struct drm_framebuffer *fb = state->fb;
 93	struct drm_crtc_state *crtc_state;
 94
 95	if (!fb)
 96		return 0;
 97
 98	if (!mtk_fb_get_gem_obj(fb)) {
 99		DRM_DEBUG_KMS("buffer is null\n");
100		return -EFAULT;
101	}
102
103	if (!state->crtc)
104		return 0;
105
106	crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
107	if (IS_ERR(crtc_state))
108		return PTR_ERR(crtc_state);
109
110	return drm_atomic_helper_check_plane_state(state, crtc_state,
111						   DRM_PLANE_HELPER_NO_SCALING,
112						   DRM_PLANE_HELPER_NO_SCALING,
113						   true, true);
114}
115
116static void mtk_plane_atomic_update(struct drm_plane *plane,
117				    struct drm_plane_state *old_state)
118{
119	struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
120	struct drm_crtc *crtc = plane->state->crtc;
121	struct drm_framebuffer *fb = plane->state->fb;
122	struct drm_gem_object *gem;
123	struct mtk_drm_gem_obj *mtk_gem;
124	unsigned int pitch, format;
125	dma_addr_t addr;
126
127	if (!crtc || WARN_ON(!fb))
128		return;
129
130	gem = mtk_fb_get_gem_obj(fb);
131	mtk_gem = to_mtk_gem_obj(gem);
132	addr = mtk_gem->dma_addr;
133	pitch = fb->pitches[0];
134	format = fb->format->format;
135
136	addr += (plane->state->src.x1 >> 16) * fb->format->cpp[0];
137	addr += (plane->state->src.y1 >> 16) * pitch;
138
139	state->pending.enable = true;
140	state->pending.pitch = pitch;
141	state->pending.format = format;
142	state->pending.addr = addr;
143	state->pending.x = plane->state->dst.x1;
144	state->pending.y = plane->state->dst.y1;
145	state->pending.width = drm_rect_width(&plane->state->dst);
146	state->pending.height = drm_rect_height(&plane->state->dst);
147	wmb(); /* Make sure the above parameters are set before update */
148	state->pending.dirty = true;
149}
150
151static void mtk_plane_atomic_disable(struct drm_plane *plane,
152				     struct drm_plane_state *old_state)
153{
154	struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
155
156	state->pending.enable = false;
157	wmb(); /* Make sure the above parameter is set before update */
158	state->pending.dirty = true;
159}
160
161static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = {
162	.atomic_check = mtk_plane_atomic_check,
163	.atomic_update = mtk_plane_atomic_update,
164	.atomic_disable = mtk_plane_atomic_disable,
165};
166
167int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,
168		   unsigned long possible_crtcs, enum drm_plane_type type)
169{
170	int err;
171
172	err = drm_universal_plane_init(dev, plane, possible_crtcs,
173				       &mtk_plane_funcs, formats,
174				       ARRAY_SIZE(formats), NULL, type, NULL);
175	if (err) {
176		DRM_ERROR("failed to initialize plane\n");
177		return err;
178	}
179
180	drm_plane_helper_add(plane, &mtk_plane_helper_funcs);
181
182	return 0;
183}