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