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 "komeda_dev.h"
8 #include "komeda_pipeline.h"
9 
10 /** komeda_pipeline_add - Add a pipeline to &komeda_dev */
11 struct komeda_pipeline *
12 komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
13 		    struct komeda_pipeline_funcs *funcs)
14 {
15 	struct komeda_pipeline *pipe;
16 
17 	if (mdev->n_pipelines + 1 > KOMEDA_MAX_PIPELINES) {
18 		DRM_ERROR("Exceed max support %d pipelines.\n",
19 			  KOMEDA_MAX_PIPELINES);
20 		return NULL;
21 	}
22 
23 	if (size < sizeof(*pipe)) {
24 		DRM_ERROR("Request pipeline size too small.\n");
25 		return NULL;
26 	}
27 
28 	pipe = devm_kzalloc(mdev->dev, size, GFP_KERNEL);
29 	if (!pipe)
30 		return NULL;
31 
32 	pipe->mdev = mdev;
33 	pipe->id   = mdev->n_pipelines;
34 	pipe->funcs = funcs;
35 
36 	mdev->pipelines[mdev->n_pipelines] = pipe;
37 	mdev->n_pipelines++;
38 
39 	return pipe;
40 }
41 
42 void komeda_pipeline_destroy(struct komeda_dev *mdev,
43 			     struct komeda_pipeline *pipe)
44 {
45 	struct komeda_component *c;
46 	int i;
47 
48 	dp_for_each_set_bit(i, pipe->avail_comps) {
49 		c = komeda_pipeline_get_component(pipe, i);
50 		komeda_component_destroy(mdev, c);
51 	}
52 
53 	clk_put(pipe->pxlclk);
54 	clk_put(pipe->aclk);
55 
56 	of_node_put(pipe->of_output_dev);
57 	of_node_put(pipe->of_output_port);
58 	of_node_put(pipe->of_node);
59 
60 	devm_kfree(mdev->dev, pipe);
61 }
62 
63 struct komeda_component **
64 komeda_pipeline_get_component_pos(struct komeda_pipeline *pipe, int id)
65 {
66 	struct komeda_dev *mdev = pipe->mdev;
67 	struct komeda_pipeline *temp = NULL;
68 	struct komeda_component **pos = NULL;
69 
70 	switch (id) {
71 	case KOMEDA_COMPONENT_LAYER0:
72 	case KOMEDA_COMPONENT_LAYER1:
73 	case KOMEDA_COMPONENT_LAYER2:
74 	case KOMEDA_COMPONENT_LAYER3:
75 		pos = to_cpos(pipe->layers[id - KOMEDA_COMPONENT_LAYER0]);
76 		break;
77 	case KOMEDA_COMPONENT_WB_LAYER:
78 		pos = to_cpos(pipe->wb_layer);
79 		break;
80 	case KOMEDA_COMPONENT_COMPIZ0:
81 	case KOMEDA_COMPONENT_COMPIZ1:
82 		temp = mdev->pipelines[id - KOMEDA_COMPONENT_COMPIZ0];
83 		if (!temp) {
84 			DRM_ERROR("compiz-%d doesn't exist.\n", id);
85 			return NULL;
86 		}
87 		pos = to_cpos(temp->compiz);
88 		break;
89 	case KOMEDA_COMPONENT_SCALER0:
90 	case KOMEDA_COMPONENT_SCALER1:
91 		pos = to_cpos(pipe->scalers[id - KOMEDA_COMPONENT_SCALER0]);
92 		break;
93 	case KOMEDA_COMPONENT_IPS0:
94 	case KOMEDA_COMPONENT_IPS1:
95 		temp = mdev->pipelines[id - KOMEDA_COMPONENT_IPS0];
96 		if (!temp) {
97 			DRM_ERROR("ips-%d doesn't exist.\n", id);
98 			return NULL;
99 		}
100 		pos = to_cpos(temp->improc);
101 		break;
102 	case KOMEDA_COMPONENT_TIMING_CTRLR:
103 		pos = to_cpos(pipe->ctrlr);
104 		break;
105 	default:
106 		pos = NULL;
107 		DRM_ERROR("Unknown pipeline resource ID: %d.\n", id);
108 		break;
109 	}
110 
111 	return pos;
112 }
113 
114 struct komeda_component *
115 komeda_pipeline_get_component(struct komeda_pipeline *pipe, int id)
116 {
117 	struct komeda_component **pos = NULL;
118 	struct komeda_component *c = NULL;
119 
120 	pos = komeda_pipeline_get_component_pos(pipe, id);
121 	if (pos)
122 		c = *pos;
123 
124 	return c;
125 }
126 
127 /** komeda_component_add - Add a component to &komeda_pipeline */
128 struct komeda_component *
129 komeda_component_add(struct komeda_pipeline *pipe,
130 		     size_t comp_sz, u32 id, u32 hw_id,
131 		     struct komeda_component_funcs *funcs,
132 		     u8 max_active_inputs, u32 supported_inputs,
133 		     u8 max_active_outputs, u32 __iomem *reg,
134 		     const char *name_fmt, ...)
135 {
136 	struct komeda_component **pos;
137 	struct komeda_component *c;
138 	int idx, *num = NULL;
139 
140 	if (max_active_inputs > KOMEDA_COMPONENT_N_INPUTS) {
141 		WARN(1, "please large KOMEDA_COMPONENT_N_INPUTS to %d.\n",
142 		     max_active_inputs);
143 		return NULL;
144 	}
145 
146 	pos = komeda_pipeline_get_component_pos(pipe, id);
147 	if (!pos || (*pos))
148 		return NULL;
149 
150 	if (has_bit(id, KOMEDA_PIPELINE_LAYERS)) {
151 		idx = id - KOMEDA_COMPONENT_LAYER0;
152 		num = &pipe->n_layers;
153 		if (idx != pipe->n_layers) {
154 			DRM_ERROR("please add Layer by id sequence.\n");
155 			return NULL;
156 		}
157 	} else if (has_bit(id,  KOMEDA_PIPELINE_SCALERS)) {
158 		idx = id - KOMEDA_COMPONENT_SCALER0;
159 		num = &pipe->n_scalers;
160 		if (idx != pipe->n_scalers) {
161 			DRM_ERROR("please add Scaler by id sequence.\n");
162 			return NULL;
163 		}
164 	}
165 
166 	c = devm_kzalloc(pipe->mdev->dev, comp_sz, GFP_KERNEL);
167 	if (!c)
168 		return NULL;
169 
170 	c->id = id;
171 	c->hw_id = hw_id;
172 	c->reg = reg;
173 	c->pipeline = pipe;
174 	c->max_active_inputs = max_active_inputs;
175 	c->max_active_outputs = max_active_outputs;
176 	c->supported_inputs = supported_inputs;
177 	c->funcs = funcs;
178 
179 	if (name_fmt) {
180 		va_list args;
181 
182 		va_start(args, name_fmt);
183 		vsnprintf(c->name, sizeof(c->name), name_fmt, args);
184 		va_end(args);
185 	}
186 
187 	if (num)
188 		*num = *num + 1;
189 
190 	pipe->avail_comps |= BIT(c->id);
191 	*pos = c;
192 
193 	return c;
194 }
195 
196 void komeda_component_destroy(struct komeda_dev *mdev,
197 			      struct komeda_component *c)
198 {
199 	devm_kfree(mdev->dev, c);
200 }
201