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