Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (C) STMicroelectronics SA 2014
  4 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
  5 *          Fabien Dessenne <fabien.dessenne@st.com>
  6 *          for STMicroelectronics.
  7 */
  8#include <linux/seq_file.h>
  9
 10#include "sti_compositor.h"
 11#include "sti_mixer.h"
 12#include "sti_vtg.h"
 13
 14/* Module parameter to set the background color of the mixer */
 15static unsigned int bkg_color = 0x000000;
 16MODULE_PARM_DESC(bkgcolor, "Value of the background color 0xRRGGBB");
 17module_param_named(bkgcolor, bkg_color, int, 0644);
 18
 19/* regs offset */
 20#define GAM_MIXER_CTL      0x00
 21#define GAM_MIXER_BKC      0x04
 22#define GAM_MIXER_BCO      0x0C
 23#define GAM_MIXER_BCS      0x10
 24#define GAM_MIXER_AVO      0x28
 25#define GAM_MIXER_AVS      0x2C
 26#define GAM_MIXER_CRB      0x34
 27#define GAM_MIXER_ACT      0x38
 28#define GAM_MIXER_MBP      0x3C
 29#define GAM_MIXER_MX0      0x80
 30
 31/* id for depth of CRB reg */
 32#define GAM_DEPTH_VID0_ID  1
 33#define GAM_DEPTH_VID1_ID  2
 34#define GAM_DEPTH_GDP0_ID  3
 35#define GAM_DEPTH_GDP1_ID  4
 36#define GAM_DEPTH_GDP2_ID  5
 37#define GAM_DEPTH_GDP3_ID  6
 38#define GAM_DEPTH_MASK_ID  7
 39
 40/* mask in CTL reg */
 41#define GAM_CTL_BACK_MASK  BIT(0)
 42#define GAM_CTL_VID0_MASK  BIT(1)
 43#define GAM_CTL_VID1_MASK  BIT(2)
 44#define GAM_CTL_GDP0_MASK  BIT(3)
 45#define GAM_CTL_GDP1_MASK  BIT(4)
 46#define GAM_CTL_GDP2_MASK  BIT(5)
 47#define GAM_CTL_GDP3_MASK  BIT(6)
 48#define GAM_CTL_CURSOR_MASK BIT(9)
 49
 50const char *sti_mixer_to_str(struct sti_mixer *mixer)
 51{
 52	switch (mixer->id) {
 53	case STI_MIXER_MAIN:
 54		return "MAIN_MIXER";
 55	case STI_MIXER_AUX:
 56		return "AUX_MIXER";
 57	default:
 58		return "<UNKNOWN MIXER>";
 59	}
 60}
 61
 62static inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id)
 63{
 64	return readl(mixer->regs + reg_id);
 65}
 66
 67static inline void sti_mixer_reg_write(struct sti_mixer *mixer,
 68				       u32 reg_id, u32 val)
 69{
 70	writel(val, mixer->regs + reg_id);
 71}
 72
 73#define DBGFS_DUMP(reg) seq_printf(s, "\n  %-25s 0x%08X", #reg, \
 74				   sti_mixer_reg_read(mixer, reg))
 75
 76static void mixer_dbg_ctl(struct seq_file *s, int val)
 77{
 78	unsigned int i;
 79	int count = 0;
 80	char *const disp_layer[] = {"BKG", "VID0", "VID1", "GDP0",
 81				    "GDP1", "GDP2", "GDP3"};
 82
 83	seq_puts(s, "\tEnabled: ");
 84	for (i = 0; i < 7; i++) {
 85		if (val & 1) {
 86			seq_printf(s, "%s ", disp_layer[i]);
 87			count++;
 88		}
 89		val = val >> 1;
 90	}
 91
 92	val = val >> 2;
 93	if (val & 1) {
 94		seq_puts(s, "CURS ");
 95		count++;
 96	}
 97	if (!count)
 98		seq_puts(s, "Nothing");
 99}
100
101static void mixer_dbg_crb(struct seq_file *s, int val)
102{
103	int i;
104
105	seq_puts(s, "\tDepth: ");
106	for (i = 0; i < GAM_MIXER_NB_DEPTH_LEVEL; i++) {
107		switch (val & GAM_DEPTH_MASK_ID) {
108		case GAM_DEPTH_VID0_ID:
109			seq_puts(s, "VID0");
110			break;
111		case GAM_DEPTH_VID1_ID:
112			seq_puts(s, "VID1");
113			break;
114		case GAM_DEPTH_GDP0_ID:
115			seq_puts(s, "GDP0");
116			break;
117		case GAM_DEPTH_GDP1_ID:
118			seq_puts(s, "GDP1");
119			break;
120		case GAM_DEPTH_GDP2_ID:
121			seq_puts(s, "GDP2");
122			break;
123		case GAM_DEPTH_GDP3_ID:
124			seq_puts(s, "GDP3");
125			break;
126		default:
127			seq_puts(s, "---");
128		}
129
130		if (i < GAM_MIXER_NB_DEPTH_LEVEL - 1)
131			seq_puts(s, " < ");
132		val = val >> 3;
133	}
134}
135
136static void mixer_dbg_mxn(struct seq_file *s, void *addr)
137{
138	int i;
139
140	for (i = 1; i < 8; i++)
141		seq_printf(s, "-0x%08X", (int)readl(addr + i * 4));
142}
143
144static int mixer_dbg_show(struct seq_file *s, void *arg)
145{
146	struct drm_info_node *node = s->private;
147	struct sti_mixer *mixer = (struct sti_mixer *)node->info_ent->data;
148
149	seq_printf(s, "%s: (vaddr = 0x%p)",
150		   sti_mixer_to_str(mixer), mixer->regs);
151
152	DBGFS_DUMP(GAM_MIXER_CTL);
153	mixer_dbg_ctl(s, sti_mixer_reg_read(mixer, GAM_MIXER_CTL));
154	DBGFS_DUMP(GAM_MIXER_BKC);
155	DBGFS_DUMP(GAM_MIXER_BCO);
156	DBGFS_DUMP(GAM_MIXER_BCS);
157	DBGFS_DUMP(GAM_MIXER_AVO);
158	DBGFS_DUMP(GAM_MIXER_AVS);
159	DBGFS_DUMP(GAM_MIXER_CRB);
160	mixer_dbg_crb(s, sti_mixer_reg_read(mixer, GAM_MIXER_CRB));
161	DBGFS_DUMP(GAM_MIXER_ACT);
162	DBGFS_DUMP(GAM_MIXER_MBP);
163	DBGFS_DUMP(GAM_MIXER_MX0);
164	mixer_dbg_mxn(s, mixer->regs + GAM_MIXER_MX0);
165	seq_putc(s, '\n');
166	return 0;
167}
168
169static struct drm_info_list mixer0_debugfs_files[] = {
170	{ "mixer_main", mixer_dbg_show, 0, NULL },
171};
172
173static struct drm_info_list mixer1_debugfs_files[] = {
174	{ "mixer_aux", mixer_dbg_show, 0, NULL },
175};
176
177int sti_mixer_debugfs_init(struct sti_mixer *mixer, struct drm_minor *minor)
178{
179	unsigned int i;
180	struct drm_info_list *mixer_debugfs_files;
181	int nb_files;
182
183	switch (mixer->id) {
184	case STI_MIXER_MAIN:
185		mixer_debugfs_files = mixer0_debugfs_files;
186		nb_files = ARRAY_SIZE(mixer0_debugfs_files);
187		break;
188	case STI_MIXER_AUX:
189		mixer_debugfs_files = mixer1_debugfs_files;
190		nb_files = ARRAY_SIZE(mixer1_debugfs_files);
191		break;
192	default:
193		return -EINVAL;
194	}
195
196	for (i = 0; i < nb_files; i++)
197		mixer_debugfs_files[i].data = mixer;
198
199	return drm_debugfs_create_files(mixer_debugfs_files,
200					nb_files,
201					minor->debugfs_root, minor);
202}
203
204void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable)
205{
206	u32 val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL);
207
208	val &= ~GAM_CTL_BACK_MASK;
209	val |= enable;
210	sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val);
211}
212
213static void sti_mixer_set_background_color(struct sti_mixer *mixer,
214					   unsigned int rgb)
215{
216	sti_mixer_reg_write(mixer, GAM_MIXER_BKC, rgb);
217}
218
219static void sti_mixer_set_background_area(struct sti_mixer *mixer,
220					  struct drm_display_mode *mode)
221{
222	u32 ydo, xdo, yds, xds;
223
224	ydo = sti_vtg_get_line_number(*mode, 0);
225	yds = sti_vtg_get_line_number(*mode, mode->vdisplay - 1);
226	xdo = sti_vtg_get_pixel_number(*mode, 0);
227	xds = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1);
228
229	sti_mixer_reg_write(mixer, GAM_MIXER_BCO, ydo << 16 | xdo);
230	sti_mixer_reg_write(mixer, GAM_MIXER_BCS, yds << 16 | xds);
231}
232
233int sti_mixer_set_plane_depth(struct sti_mixer *mixer, struct sti_plane *plane)
234{
235	int plane_id, depth = plane->drm_plane.state->normalized_zpos;
236	unsigned int i;
237	u32 mask, val;
238
239	switch (plane->desc) {
240	case STI_GDP_0:
241		plane_id = GAM_DEPTH_GDP0_ID;
242		break;
243	case STI_GDP_1:
244		plane_id = GAM_DEPTH_GDP1_ID;
245		break;
246	case STI_GDP_2:
247		plane_id = GAM_DEPTH_GDP2_ID;
248		break;
249	case STI_GDP_3:
250		plane_id = GAM_DEPTH_GDP3_ID;
251		break;
252	case STI_HQVDP_0:
253		plane_id = GAM_DEPTH_VID0_ID;
254		break;
255	case STI_CURSOR:
256		/* no need to set depth for cursor */
257		return 0;
258	default:
259		DRM_ERROR("Unknown plane %d\n", plane->desc);
260		return 1;
261	}
262
263	/* Search if a previous depth was already assigned to the plane */
264	val = sti_mixer_reg_read(mixer, GAM_MIXER_CRB);
265	for (i = 0; i < GAM_MIXER_NB_DEPTH_LEVEL; i++) {
266		mask = GAM_DEPTH_MASK_ID << (3 * i);
267		if ((val & mask) == plane_id << (3 * i))
268			break;
269	}
270
271	mask |= GAM_DEPTH_MASK_ID << (3 * depth);
272	plane_id = plane_id << (3 * depth);
273
274	DRM_DEBUG_DRIVER("%s %s depth=%d\n", sti_mixer_to_str(mixer),
275			 sti_plane_to_str(plane), depth);
276	dev_dbg(mixer->dev, "GAM_MIXER_CRB val 0x%x mask 0x%x\n",
277		plane_id, mask);
278
279	val &= ~mask;
280	val |= plane_id;
281	sti_mixer_reg_write(mixer, GAM_MIXER_CRB, val);
282
283	dev_dbg(mixer->dev, "Read GAM_MIXER_CRB 0x%x\n",
284		sti_mixer_reg_read(mixer, GAM_MIXER_CRB));
285	return 0;
286}
287
288int sti_mixer_active_video_area(struct sti_mixer *mixer,
289				struct drm_display_mode *mode)
290{
291	u32 ydo, xdo, yds, xds;
292
293	ydo = sti_vtg_get_line_number(*mode, 0);
294	yds = sti_vtg_get_line_number(*mode, mode->vdisplay - 1);
295	xdo = sti_vtg_get_pixel_number(*mode, 0);
296	xds = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1);
297
298	DRM_DEBUG_DRIVER("%s active video area xdo:%d ydo:%d xds:%d yds:%d\n",
299			 sti_mixer_to_str(mixer), xdo, ydo, xds, yds);
300	sti_mixer_reg_write(mixer, GAM_MIXER_AVO, ydo << 16 | xdo);
301	sti_mixer_reg_write(mixer, GAM_MIXER_AVS, yds << 16 | xds);
302
303	sti_mixer_set_background_color(mixer, bkg_color);
304
305	sti_mixer_set_background_area(mixer, mode);
306	sti_mixer_set_background_status(mixer, true);
307	return 0;
308}
309
310static u32 sti_mixer_get_plane_mask(struct sti_plane *plane)
311{
312	switch (plane->desc) {
313	case STI_BACK:
314		return GAM_CTL_BACK_MASK;
315	case STI_GDP_0:
316		return GAM_CTL_GDP0_MASK;
317	case STI_GDP_1:
318		return GAM_CTL_GDP1_MASK;
319	case STI_GDP_2:
320		return GAM_CTL_GDP2_MASK;
321	case STI_GDP_3:
322		return GAM_CTL_GDP3_MASK;
323	case STI_HQVDP_0:
324		return GAM_CTL_VID0_MASK;
325	case STI_CURSOR:
326		return GAM_CTL_CURSOR_MASK;
327	default:
328		return 0;
329	}
330}
331
332int sti_mixer_set_plane_status(struct sti_mixer *mixer,
333			       struct sti_plane *plane, bool status)
334{
335	u32 mask, val;
336
337	DRM_DEBUG_DRIVER("%s %s %s\n", status ? "enable" : "disable",
338			 sti_mixer_to_str(mixer), sti_plane_to_str(plane));
339
340	mask = sti_mixer_get_plane_mask(plane);
341	if (!mask) {
342		DRM_ERROR("Can't find layer mask\n");
343		return -EINVAL;
344	}
345
346	val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL);
347	val &= ~mask;
348	val |= status ? mask : 0;
349	sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val);
350
351	return 0;
352}
353
354struct sti_mixer *sti_mixer_create(struct device *dev,
355				   struct drm_device *drm_dev,
356				   int id,
357				   void __iomem *baseaddr)
358{
359	struct sti_mixer *mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
360
361	dev_dbg(dev, "%s\n", __func__);
362	if (!mixer) {
363		DRM_ERROR("Failed to allocated memory for mixer\n");
364		return NULL;
365	}
366	mixer->regs = baseaddr;
367	mixer->dev = dev;
368	mixer->id = id;
369
370	DRM_DEBUG_DRIVER("%s created. Regs=%p\n",
371			 sti_mixer_to_str(mixer), mixer->regs);
372
373	return mixer;
374}