1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include <linux/of.h>
8
9#include <drm/drm_print.h>
10
11#include "komeda_dev.h"
12#include "komeda_pipeline.h"
13
14/** komeda_pipeline_add - Add a pipeline to &komeda_dev */
15struct komeda_pipeline *
16komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
17		    const struct komeda_pipeline_funcs *funcs)
18{
19	struct komeda_pipeline *pipe;
20
21	if (mdev->n_pipelines + 1 > KOMEDA_MAX_PIPELINES) {
22		DRM_ERROR("Exceed max support %d pipelines.\n",
23			  KOMEDA_MAX_PIPELINES);
24		return ERR_PTR(-ENOSPC);
25	}
26
27	if (size < sizeof(*pipe)) {
28		DRM_ERROR("Request pipeline size too small.\n");
29		return ERR_PTR(-EINVAL);
30	}
31
32	pipe = devm_kzalloc(mdev->dev, size, GFP_KERNEL);
33	if (!pipe)
34		return ERR_PTR(-ENOMEM);
35
36	pipe->mdev = mdev;
37	pipe->id   = mdev->n_pipelines;
38	pipe->funcs = funcs;
39
40	mdev->pipelines[mdev->n_pipelines] = pipe;
41	mdev->n_pipelines++;
42
43	return pipe;
44}
45
46void komeda_pipeline_destroy(struct komeda_dev *mdev,
47			     struct komeda_pipeline *pipe)
48{
49	struct komeda_component *c;
50	int i;
51	unsigned long avail_comps = pipe->avail_comps;
52
53	for_each_set_bit(i, &avail_comps, 32) {
54		c = komeda_pipeline_get_component(pipe, i);
55		komeda_component_destroy(mdev, c);
56	}
57
58	clk_put(pipe->pxlclk);
59
60	of_node_put(pipe->of_output_links[0]);
61	of_node_put(pipe->of_output_links[1]);
62	of_node_put(pipe->of_output_port);
63	of_node_put(pipe->of_node);
64
65	devm_kfree(mdev->dev, pipe);
66}
67
68static struct komeda_component **
69komeda_pipeline_get_component_pos(struct komeda_pipeline *pipe, int id)
70{
71	struct komeda_dev *mdev = pipe->mdev;
72	struct komeda_pipeline *temp = NULL;
73	struct komeda_component **pos = NULL;
74
75	switch (id) {
76	case KOMEDA_COMPONENT_LAYER0:
77	case KOMEDA_COMPONENT_LAYER1:
78	case KOMEDA_COMPONENT_LAYER2:
79	case KOMEDA_COMPONENT_LAYER3:
80		pos = to_cpos(pipe->layers[id - KOMEDA_COMPONENT_LAYER0]);
81		break;
82	case KOMEDA_COMPONENT_WB_LAYER:
83		pos = to_cpos(pipe->wb_layer);
84		break;
85	case KOMEDA_COMPONENT_COMPIZ0:
86	case KOMEDA_COMPONENT_COMPIZ1:
87		temp = mdev->pipelines[id - KOMEDA_COMPONENT_COMPIZ0];
88		if (!temp) {
89			DRM_ERROR("compiz-%d doesn't exist.\n", id);
90			return NULL;
91		}
92		pos = to_cpos(temp->compiz);
93		break;
94	case KOMEDA_COMPONENT_SCALER0:
95	case KOMEDA_COMPONENT_SCALER1:
96		pos = to_cpos(pipe->scalers[id - KOMEDA_COMPONENT_SCALER0]);
97		break;
98	case KOMEDA_COMPONENT_SPLITTER:
99		pos = to_cpos(pipe->splitter);
100		break;
101	case KOMEDA_COMPONENT_MERGER:
102		pos = to_cpos(pipe->merger);
103		break;
104	case KOMEDA_COMPONENT_IPS0:
105	case KOMEDA_COMPONENT_IPS1:
106		temp = mdev->pipelines[id - KOMEDA_COMPONENT_IPS0];
107		if (!temp) {
108			DRM_ERROR("ips-%d doesn't exist.\n", id);
109			return NULL;
110		}
111		pos = to_cpos(temp->improc);
112		break;
113	case KOMEDA_COMPONENT_TIMING_CTRLR:
114		pos = to_cpos(pipe->ctrlr);
115		break;
116	default:
117		pos = NULL;
118		DRM_ERROR("Unknown pipeline resource ID: %d.\n", id);
119		break;
120	}
121
122	return pos;
123}
124
125struct komeda_component *
126komeda_pipeline_get_component(struct komeda_pipeline *pipe, int id)
127{
128	struct komeda_component **pos = NULL;
129	struct komeda_component *c = NULL;
130
131	pos = komeda_pipeline_get_component_pos(pipe, id);
132	if (pos)
133		c = *pos;
134
135	return c;
136}
137
138struct komeda_component *
139komeda_pipeline_get_first_component(struct komeda_pipeline *pipe,
140				    u32 comp_mask)
141{
142	struct komeda_component *c = NULL;
143	unsigned long comp_mask_local = (unsigned long)comp_mask;
144	int id;
145
146	id = find_first_bit(&comp_mask_local, 32);
147	if (id < 32)
148		c = komeda_pipeline_get_component(pipe, id);
149
150	return c;
151}
152
153static struct komeda_component *
154komeda_component_pickup_input(struct komeda_component *c, u32 avail_comps)
155{
156	u32 avail_inputs = c->supported_inputs & (avail_comps);
157
158	return komeda_pipeline_get_first_component(c->pipeline, avail_inputs);
159}
160
161/** komeda_component_add - Add a component to &komeda_pipeline */
162struct komeda_component *
163komeda_component_add(struct komeda_pipeline *pipe,
164		     size_t comp_sz, u32 id, u32 hw_id,
165		     const struct komeda_component_funcs *funcs,
166		     u8 max_active_inputs, u32 supported_inputs,
167		     u8 max_active_outputs, u32 __iomem *reg,
168		     const char *name_fmt, ...)
169{
170	struct komeda_component **pos;
171	struct komeda_component *c;
172	int idx, *num = NULL;
173
174	if (max_active_inputs > KOMEDA_COMPONENT_N_INPUTS) {
175		WARN(1, "please large KOMEDA_COMPONENT_N_INPUTS to %d.\n",
176		     max_active_inputs);
177		return ERR_PTR(-ENOSPC);
178	}
179
180	pos = komeda_pipeline_get_component_pos(pipe, id);
181	if (!pos || (*pos))
182		return ERR_PTR(-EINVAL);
183
184	if (has_bit(id, KOMEDA_PIPELINE_LAYERS)) {
185		idx = id - KOMEDA_COMPONENT_LAYER0;
186		num = &pipe->n_layers;
187		if (idx != pipe->n_layers) {
188			DRM_ERROR("please add Layer by id sequence.\n");
189			return ERR_PTR(-EINVAL);
190		}
191	} else if (has_bit(id,  KOMEDA_PIPELINE_SCALERS)) {
192		idx = id - KOMEDA_COMPONENT_SCALER0;
193		num = &pipe->n_scalers;
194		if (idx != pipe->n_scalers) {
195			DRM_ERROR("please add Scaler by id sequence.\n");
196			return ERR_PTR(-EINVAL);
197		}
198	}
199
200	c = devm_kzalloc(pipe->mdev->dev, comp_sz, GFP_KERNEL);
201	if (!c)
202		return ERR_PTR(-ENOMEM);
203
204	c->id = id;
205	c->hw_id = hw_id;
206	c->reg = reg;
207	c->pipeline = pipe;
208	c->max_active_inputs = max_active_inputs;
209	c->max_active_outputs = max_active_outputs;
210	c->supported_inputs = supported_inputs;
211	c->funcs = funcs;
212
213	if (name_fmt) {
214		va_list args;
215
216		va_start(args, name_fmt);
217		vsnprintf(c->name, sizeof(c->name), name_fmt, args);
218		va_end(args);
219	}
220
221	if (num)
222		*num = *num + 1;
223
224	pipe->avail_comps |= BIT(c->id);
225	*pos = c;
226
227	return c;
228}
229
230void komeda_component_destroy(struct komeda_dev *mdev,
231			      struct komeda_component *c)
232{
233	devm_kfree(mdev->dev, c);
234}
235
236static void komeda_component_dump(struct komeda_component *c)
237{
238	if (!c)
239		return;
240
241	DRM_DEBUG("	%s: ID %d-0x%08lx.\n",
242		  c->name, c->id, BIT(c->id));
243	DRM_DEBUG("		max_active_inputs:%d, supported_inputs: 0x%08x.\n",
244		  c->max_active_inputs, c->supported_inputs);
245	DRM_DEBUG("		max_active_outputs:%d, supported_outputs: 0x%08x.\n",
246		  c->max_active_outputs, c->supported_outputs);
247}
248
249static void komeda_pipeline_dump(struct komeda_pipeline *pipe)
250{
251	struct komeda_component *c;
252	int id;
253	unsigned long avail_comps = pipe->avail_comps;
254
255	DRM_INFO("Pipeline-%d: n_layers: %d, n_scalers: %d, output: %s.\n",
256		 pipe->id, pipe->n_layers, pipe->n_scalers,
257		 pipe->dual_link ? "dual-link" : "single-link");
258	DRM_INFO("	output_link[0]: %s.\n",
259		 pipe->of_output_links[0] ?
260		 pipe->of_output_links[0]->full_name : "none");
261	DRM_INFO("	output_link[1]: %s.\n",
262		 pipe->of_output_links[1] ?
263		 pipe->of_output_links[1]->full_name : "none");
264
265	for_each_set_bit(id, &avail_comps, 32) {
266		c = komeda_pipeline_get_component(pipe, id);
267
268		komeda_component_dump(c);
269	}
270}
271
272static void komeda_component_verify_inputs(struct komeda_component *c)
273{
274	struct komeda_pipeline *pipe = c->pipeline;
275	struct komeda_component *input;
276	int id;
277	unsigned long supported_inputs = c->supported_inputs;
278
279	for_each_set_bit(id, &supported_inputs, 32) {
280		input = komeda_pipeline_get_component(pipe, id);
281		if (!input) {
282			c->supported_inputs &= ~(BIT(id));
283			DRM_WARN("Can not find input(ID-%d) for component: %s.\n",
284				 id, c->name);
285			continue;
286		}
287
288		input->supported_outputs |= BIT(c->id);
289	}
290}
291
292static struct komeda_layer *
293komeda_get_layer_split_right_layer(struct komeda_pipeline *pipe,
294				   struct komeda_layer *left)
295{
296	int index = left->base.id - KOMEDA_COMPONENT_LAYER0;
297	int i;
298
299	for (i = index + 1; i < pipe->n_layers; i++)
300		if (left->layer_type == pipe->layers[i]->layer_type)
301			return pipe->layers[i];
302	return NULL;
303}
304
305static void komeda_pipeline_assemble(struct komeda_pipeline *pipe)
306{
307	struct komeda_component *c;
308	struct komeda_layer *layer;
309	int i, id;
310	unsigned long avail_comps = pipe->avail_comps;
311
312	for_each_set_bit(id, &avail_comps, 32) {
313		c = komeda_pipeline_get_component(pipe, id);
314		komeda_component_verify_inputs(c);
315	}
316	/* calculate right layer for the layer split */
317	for (i = 0; i < pipe->n_layers; i++) {
318		layer = pipe->layers[i];
319
320		layer->right = komeda_get_layer_split_right_layer(pipe, layer);
321	}
322
323	if (pipe->dual_link && !pipe->ctrlr->supports_dual_link) {
324		pipe->dual_link = false;
325		DRM_WARN("PIPE-%d doesn't support dual-link, ignore DT dual-link configuration.\n",
326			 pipe->id);
327	}
328}
329
330/* if pipeline_A accept another pipeline_B's component as input, treat
331 * pipeline_B as slave of pipeline_A.
332 */
333struct komeda_pipeline *
334komeda_pipeline_get_slave(struct komeda_pipeline *master)
335{
336	struct komeda_component *slave;
337
338	slave = komeda_component_pickup_input(&master->compiz->base,
339					      KOMEDA_PIPELINE_COMPIZS);
340
341	return slave ? slave->pipeline : NULL;
342}
343
344int komeda_assemble_pipelines(struct komeda_dev *mdev)
345{
346	struct komeda_pipeline *pipe;
347	int i;
348
349	for (i = 0; i < mdev->n_pipelines; i++) {
350		pipe = mdev->pipelines[i];
351
352		komeda_pipeline_assemble(pipe);
353		komeda_pipeline_dump(pipe);
354	}
355
356	return 0;
357}
358
359void komeda_pipeline_dump_register(struct komeda_pipeline *pipe,
360				   struct seq_file *sf)
361{
362	struct komeda_component *c;
363	u32 id;
364	unsigned long avail_comps;
365
366	seq_printf(sf, "\n======== Pipeline-%d ==========\n", pipe->id);
367
368	if (pipe->funcs && pipe->funcs->dump_register)
369		pipe->funcs->dump_register(pipe, sf);
370
371	avail_comps = pipe->avail_comps;
372	for_each_set_bit(id, &avail_comps, 32) {
373		c = komeda_pipeline_get_component(pipe, id);
374
375		seq_printf(sf, "\n------%s------\n", c->name);
376		if (c->funcs->dump_register)
377			c->funcs->dump_register(c, sf);
378	}
379}
380