blob: 8e85c8197cef9e5fb7f7044b5986c174af6e00c8 [file] [log] [blame]
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
Clarence Ip7aa390f2016-05-26 21:06:54 -04002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include "msm_prop.h"
14
15void msm_property_init(struct msm_property_info *info,
16 struct drm_mode_object *base,
17 struct drm_device *dev,
18 struct drm_property **property_array,
19 struct msm_property_data *property_data,
20 uint32_t property_count,
21 uint32_t blob_count,
22 uint32_t state_size)
23{
24 /* prevent access if any of these are NULL */
25 if (!base || !dev || !property_array || !property_data) {
26 property_count = 0;
27 blob_count = 0;
28
29 DRM_ERROR("invalid arguments, forcing zero properties\n");
30 return;
31 }
32
33 /* can't have more blob properties than total properties */
34 if (blob_count > property_count) {
35 blob_count = property_count;
36
37 DBG("Capping number of blob properties to %d", blob_count);
38 }
39
40 if (!info) {
41 DRM_ERROR("info pointer is NULL\n");
42 } else {
43 info->base = base;
44 info->dev = dev;
45 info->property_array = property_array;
46 info->property_data = property_data;
47 info->property_count = property_count;
48 info->blob_count = blob_count;
49 info->install_request = 0;
50 info->install_count = 0;
51 info->recent_idx = 0;
Clarence Ip913624e2016-06-23 14:56:32 -040052 info->is_active = false;
Clarence Ip7aa390f2016-05-26 21:06:54 -040053 info->state_size = state_size;
54 info->state_cache_size = 0;
55 mutex_init(&info->property_lock);
56
57 memset(property_data,
58 0,
59 sizeof(struct msm_property_data) *
60 property_count);
61 }
62}
63
64void msm_property_destroy(struct msm_property_info *info)
65{
66 if (!info)
67 return;
68
69 /* free state cache */
70 while (info->state_cache_size > 0)
71 kfree(info->state_cache[--(info->state_cache_size)]);
72
73 mutex_destroy(&info->property_lock);
74}
75
Clarence Ip4a2955d2017-07-04 18:04:33 -040076int msm_property_pop_dirty(struct msm_property_info *info,
77 struct msm_property_state *property_state)
Clarence Ip913624e2016-06-23 14:56:32 -040078{
79 struct list_head *item;
80 int rc = 0;
81
Clarence Ip4a2955d2017-07-04 18:04:33 -040082 if (!info || !property_state || !property_state->values) {
83 DRM_ERROR("invalid argument(s)\n");
Clarence Ip913624e2016-06-23 14:56:32 -040084 return -EINVAL;
85 }
86
87 mutex_lock(&info->property_lock);
Clarence Ip4a2955d2017-07-04 18:04:33 -040088 if (list_empty(&property_state->dirty_list)) {
Clarence Ip913624e2016-06-23 14:56:32 -040089 rc = -EAGAIN;
90 } else {
Clarence Ip4a2955d2017-07-04 18:04:33 -040091 item = property_state->dirty_list.next;
Clarence Ip913624e2016-06-23 14:56:32 -040092 list_del_init(item);
Clarence Ip4a2955d2017-07-04 18:04:33 -040093 rc = container_of(item, struct msm_property_value, dirty_node)
94 - property_state->values;
Clarence Ip913624e2016-06-23 14:56:32 -040095 DRM_DEBUG_KMS("property %d dirty\n", rc);
96 }
97 mutex_unlock(&info->property_lock);
98
99 return rc;
100}
101
102/**
103 * _msm_property_set_dirty_no_lock - flag given property as being dirty
104 * This function doesn't mutex protect the
105 * dirty linked list.
106 * @info: Pointer to property info container struct
Clarence Ip4a2955d2017-07-04 18:04:33 -0400107 * @property_state: Pointer to property state container struct
Clarence Ip913624e2016-06-23 14:56:32 -0400108 * @property_idx: Property index
109 */
110static void _msm_property_set_dirty_no_lock(
111 struct msm_property_info *info,
Clarence Ip4a2955d2017-07-04 18:04:33 -0400112 struct msm_property_state *property_state,
Clarence Ip913624e2016-06-23 14:56:32 -0400113 uint32_t property_idx)
114{
Clarence Ip4a2955d2017-07-04 18:04:33 -0400115 if (!info || !property_state || !property_state->values ||
116 property_idx >= info->property_count) {
117 DRM_ERROR("invalid argument(s), idx %u\n", property_idx);
Clarence Ip913624e2016-06-23 14:56:32 -0400118 return;
119 }
120
121 /* avoid re-inserting if already dirty */
Clarence Ip4a2955d2017-07-04 18:04:33 -0400122 if (!list_empty(&property_state->values[property_idx].dirty_node)) {
Clarence Ip913624e2016-06-23 14:56:32 -0400123 DRM_DEBUG_KMS("property %u already dirty\n", property_idx);
124 return;
125 }
126
Clarence Ip4a2955d2017-07-04 18:04:33 -0400127 list_add_tail(&property_state->values[property_idx].dirty_node,
128 &property_state->dirty_list);
Clarence Ip913624e2016-06-23 14:56:32 -0400129}
130
Lloyd Atkinson440728e2017-11-22 10:07:08 -0500131bool msm_property_is_dirty(
132 struct msm_property_info *info,
133 struct msm_property_state *property_state,
134 uint32_t property_idx)
135{
136 if (!info || !property_state || !property_state->values ||
137 property_idx >= info->property_count) {
138 DRM_ERROR("invalid argument(s), idx %u\n", property_idx);
139 return false;
140 }
141
142 return !list_empty(&property_state->values[property_idx].dirty_node);
143}
144
Clarence Ip5fc00c52016-09-23 15:03:34 -0400145/**
146 * _msm_property_install_integer - install standard drm range property
147 * @info: Pointer to property info container struct
148 * @name: Property name
149 * @flags: Other property type flags, e.g. DRM_MODE_PROP_IMMUTABLE
150 * @min: Min property value
151 * @max: Max property value
152 * @init: Default Property value
153 * @property_idx: Property index
154 * @force_dirty: Whether or not to filter 'dirty' status on unchanged values
155 */
156static void _msm_property_install_integer(struct msm_property_info *info,
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -0400157 const char *name, int flags, uint64_t min, uint64_t max,
Clarence Ip5fc00c52016-09-23 15:03:34 -0400158 uint64_t init, uint32_t property_idx, bool force_dirty)
Clarence Ip7aa390f2016-05-26 21:06:54 -0400159{
160 struct drm_property **prop;
161
162 if (!info)
163 return;
164
165 ++info->install_request;
166
167 if (!name || (property_idx >= info->property_count)) {
168 DRM_ERROR("invalid argument(s), %s\n", name ? name : "null");
169 } else {
170 prop = &info->property_array[property_idx];
171 /*
172 * Properties need to be attached to each drm object that
173 * uses them, but only need to be created once
174 */
175 if (*prop == 0) {
176 *prop = drm_property_create_range(info->dev,
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -0400177 flags, name, min, max);
Clarence Ip7aa390f2016-05-26 21:06:54 -0400178 if (*prop == 0)
179 DRM_ERROR("create %s property failed\n", name);
180 }
181
182 /* save init value for later */
183 info->property_data[property_idx].default_value = init;
Clarence Ip5fc00c52016-09-23 15:03:34 -0400184 info->property_data[property_idx].force_dirty = force_dirty;
Clarence Ip7aa390f2016-05-26 21:06:54 -0400185
186 /* always attach property, if created */
187 if (*prop) {
188 drm_object_attach_property(info->base, *prop, init);
189 ++info->install_count;
190 }
191 }
192}
193
Clarence Ip5fc00c52016-09-23 15:03:34 -0400194void msm_property_install_range(struct msm_property_info *info,
195 const char *name, int flags, uint64_t min, uint64_t max,
196 uint64_t init, uint32_t property_idx)
197{
198 _msm_property_install_integer(info, name, flags,
199 min, max, init, property_idx, false);
200}
201
202void msm_property_install_volatile_range(struct msm_property_info *info,
203 const char *name, int flags, uint64_t min, uint64_t max,
204 uint64_t init, uint32_t property_idx)
205{
206 _msm_property_install_integer(info, name, flags,
207 min, max, init, property_idx, true);
208}
209
Clarence Ip7aa390f2016-05-26 21:06:54 -0400210void msm_property_install_rotation(struct msm_property_info *info,
211 unsigned int supported_rotations, uint32_t property_idx)
212{
213 struct drm_property **prop;
214
215 if (!info)
216 return;
217
218 ++info->install_request;
219
220 if (property_idx >= info->property_count) {
221 DRM_ERROR("invalid property index %d\n", property_idx);
222 } else {
223 prop = &info->property_array[property_idx];
224 /*
225 * Properties need to be attached to each drm object that
226 * uses them, but only need to be created once
227 */
228 if (*prop == 0) {
229 *prop = drm_mode_create_rotation_property(info->dev,
230 supported_rotations);
231 if (*prop == 0)
232 DRM_ERROR("create rotation property failed\n");
233 }
234
235 /* save init value for later */
236 info->property_data[property_idx].default_value = 0;
Clarence Ip5fc00c52016-09-23 15:03:34 -0400237 info->property_data[property_idx].force_dirty = false;
Clarence Ip7aa390f2016-05-26 21:06:54 -0400238
239 /* always attach property, if created */
240 if (*prop) {
241 drm_object_attach_property(info->base, *prop, 0);
242 ++info->install_count;
243 }
244 }
245}
246
247void msm_property_install_enum(struct msm_property_info *info,
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -0400248 const char *name, int flags, int is_bitmask,
Clarence Ip7aa390f2016-05-26 21:06:54 -0400249 const struct drm_prop_enum_list *values, int num_values,
250 uint32_t property_idx)
251{
252 struct drm_property **prop;
253
254 if (!info)
255 return;
256
257 ++info->install_request;
258
259 if (!name || !values || !num_values ||
260 (property_idx >= info->property_count)) {
261 DRM_ERROR("invalid argument(s), %s\n", name ? name : "null");
262 } else {
263 prop = &info->property_array[property_idx];
264 /*
265 * Properties need to be attached to each drm object that
266 * uses them, but only need to be created once
267 */
268 if (*prop == 0) {
269 /* 'bitmask' is a special type of 'enum' */
270 if (is_bitmask)
271 *prop = drm_property_create_bitmask(info->dev,
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -0400272 DRM_MODE_PROP_BITMASK | flags,
273 name, values, num_values, -1);
Clarence Ip7aa390f2016-05-26 21:06:54 -0400274 else
275 *prop = drm_property_create_enum(info->dev,
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -0400276 DRM_MODE_PROP_ENUM | flags,
277 name, values, num_values);
Clarence Ip7aa390f2016-05-26 21:06:54 -0400278 if (*prop == 0)
279 DRM_ERROR("create %s property failed\n", name);
280 }
281
282 /* save init value for later */
283 info->property_data[property_idx].default_value = 0;
Clarence Ip5fc00c52016-09-23 15:03:34 -0400284 info->property_data[property_idx].force_dirty = false;
Clarence Ip7aa390f2016-05-26 21:06:54 -0400285
Clarence Ip946ff6e2017-09-08 15:47:26 -0400286 /* select first defined value for enums */
287 if (!is_bitmask)
288 info->property_data[property_idx].default_value =
289 values->type;
290
Clarence Ip7aa390f2016-05-26 21:06:54 -0400291 /* always attach property, if created */
292 if (*prop) {
Clarence Ip946ff6e2017-09-08 15:47:26 -0400293 drm_object_attach_property(info->base, *prop,
294 info->property_data
295 [property_idx].default_value);
Clarence Ip7aa390f2016-05-26 21:06:54 -0400296 ++info->install_count;
297 }
298 }
299}
300
301void msm_property_install_blob(struct msm_property_info *info,
302 const char *name, int flags, uint32_t property_idx)
303{
304 struct drm_property **prop;
305
306 if (!info)
307 return;
308
309 ++info->install_request;
310
311 if (!name || (property_idx >= info->blob_count)) {
312 DRM_ERROR("invalid argument(s), %s\n", name ? name : "null");
313 } else {
314 prop = &info->property_array[property_idx];
315 /*
316 * Properties need to be attached to each drm object that
317 * uses them, but only need to be created once
318 */
319 if (*prop == 0) {
320 /* use 'create' for blob property place holder */
321 *prop = drm_property_create(info->dev,
322 DRM_MODE_PROP_BLOB | flags, name, 0);
323 if (*prop == 0)
324 DRM_ERROR("create %s property failed\n", name);
325 }
326
327 /* save init value for later */
328 info->property_data[property_idx].default_value = 0;
Clarence Ip5fc00c52016-09-23 15:03:34 -0400329 info->property_data[property_idx].force_dirty = true;
Clarence Ip7aa390f2016-05-26 21:06:54 -0400330
331 /* always attach property, if created */
332 if (*prop) {
333 drm_object_attach_property(info->base, *prop, -1);
334 ++info->install_count;
335 }
336 }
337}
338
339int msm_property_install_get_status(struct msm_property_info *info)
340{
341 int rc = -ENOMEM;
342
343 if (info && (info->install_request == info->install_count))
344 rc = 0;
345
346 return rc;
347}
348
349int msm_property_index(struct msm_property_info *info,
350 struct drm_property *property)
351{
352 uint32_t count;
353 int32_t idx;
354 int rc = -EINVAL;
355
356 if (!info || !property) {
357 DRM_ERROR("invalid argument(s)\n");
358 } else {
359 /*
360 * Linear search, but start from last found index. This will
361 * help if any single property is accessed multiple times in a
362 * row. Ideally, we could keep a list of properties sorted in
363 * the order of most recent access, but that may be overkill
364 * for now.
365 */
366 mutex_lock(&info->property_lock);
367 idx = info->recent_idx;
368 count = info->property_count;
369 while (count) {
370 --count;
371
372 /* stop searching on match */
373 if (info->property_array[idx] == property) {
374 info->recent_idx = idx;
375 rc = idx;
376 break;
377 }
378
379 /* move to next valid index */
380 if (--idx < 0)
381 idx = info->property_count - 1;
382 }
383 mutex_unlock(&info->property_lock);
384 }
385
386 return rc;
387}
388
Clarence Ip4a2955d2017-07-04 18:04:33 -0400389int msm_property_set_dirty(struct msm_property_info *info,
390 struct msm_property_state *property_state,
391 int property_idx)
Clarence Ip96b5b272017-06-14 10:29:48 -0400392{
Clarence Ip4a2955d2017-07-04 18:04:33 -0400393 if (!info || !property_state || !property_state->values) {
394 DRM_ERROR("invalid argument(s)\n");
Clarence Ip96b5b272017-06-14 10:29:48 -0400395 return -EINVAL;
396 }
397 mutex_lock(&info->property_lock);
Clarence Ip4a2955d2017-07-04 18:04:33 -0400398 _msm_property_set_dirty_no_lock(info, property_state, property_idx);
Clarence Ip96b5b272017-06-14 10:29:48 -0400399 mutex_unlock(&info->property_lock);
400 return 0;
401}
402
Clarence Ip7aa390f2016-05-26 21:06:54 -0400403int msm_property_atomic_set(struct msm_property_info *info,
Clarence Ip4a2955d2017-07-04 18:04:33 -0400404 struct msm_property_state *property_state,
Clarence Ip7aa390f2016-05-26 21:06:54 -0400405 struct drm_property *property, uint64_t val)
406{
407 struct drm_property_blob *blob;
408 int property_idx, rc = -EINVAL;
409
Lloyd Atkinsone08229c2017-10-02 17:53:30 -0400410 if (!info || !property_state) {
411 DRM_ERROR("invalid argument(s)\n");
412 return -EINVAL;
413 }
414
Clarence Ip7aa390f2016-05-26 21:06:54 -0400415 property_idx = msm_property_index(info, property);
Lloyd Atkinsone08229c2017-10-02 17:53:30 -0400416 if ((property_idx == -EINVAL) || !property_state->values) {
417 DRM_ERROR("invalid argument(s)\n");
Clarence Ip7aa390f2016-05-26 21:06:54 -0400418 } else {
419 /* extra handling for incoming properties */
420 mutex_lock(&info->property_lock);
Lloyd Atkinsone08229c2017-10-02 17:53:30 -0400421 if (val && (property->flags & DRM_MODE_PROP_BLOB) &&
Clarence Ip4a2955d2017-07-04 18:04:33 -0400422 (property_idx < info->blob_count)) {
Clarence Ip7aa390f2016-05-26 21:06:54 -0400423 /* DRM lookup also takes a reference */
424 blob = drm_property_lookup_blob(info->dev,
425 (uint32_t)val);
426 if (!blob) {
Lloyd Atkinsone08229c2017-10-02 17:53:30 -0400427 DRM_ERROR("prop %d blob id 0x%llx not found\n",
428 property_idx, val);
Clarence Ip7aa390f2016-05-26 21:06:54 -0400429 val = 0;
430 } else {
431 DBG("Blob %u saved", blob->base.id);
432 val = blob->base.id;
433
434 /* save blob - need to clear previous ref */
Clarence Ip4a2955d2017-07-04 18:04:33 -0400435 if (property_state->values[property_idx].blob)
Clarence Ip7aa390f2016-05-26 21:06:54 -0400436 drm_property_unreference_blob(
Clarence Ip4a2955d2017-07-04 18:04:33 -0400437 property_state->values[
438 property_idx].blob);
439 property_state->values[property_idx].blob =
440 blob;
Clarence Ip7aa390f2016-05-26 21:06:54 -0400441 }
442 }
Clarence Ip913624e2016-06-23 14:56:32 -0400443
444 /* update value and flag as dirty */
Clarence Ip4a2955d2017-07-04 18:04:33 -0400445 if (property_state->values[property_idx].value != val ||
Clarence Ip5fc00c52016-09-23 15:03:34 -0400446 info->property_data[property_idx].force_dirty) {
Clarence Ip4a2955d2017-07-04 18:04:33 -0400447 property_state->values[property_idx].value = val;
448 _msm_property_set_dirty_no_lock(info, property_state,
449 property_idx);
Clarence Ip913624e2016-06-23 14:56:32 -0400450
Clarence Ip282dad62016-09-27 17:07:35 -0400451 DBG("%s - %lld", property->name, val);
452 }
453 mutex_unlock(&info->property_lock);
Clarence Ip7aa390f2016-05-26 21:06:54 -0400454 rc = 0;
455 }
456
457 return rc;
458}
459
460int msm_property_atomic_get(struct msm_property_info *info,
Clarence Ip4a2955d2017-07-04 18:04:33 -0400461 struct msm_property_state *property_state,
Clarence Ip7aa390f2016-05-26 21:06:54 -0400462 struct drm_property *property, uint64_t *val)
463{
464 int property_idx, rc = -EINVAL;
465
466 property_idx = msm_property_index(info, property);
Clarence Ip4a2955d2017-07-04 18:04:33 -0400467 if (!info || (property_idx == -EINVAL) ||
468 !property_state->values || !val) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700469 DRM_DEBUG("Invalid argument(s)\n");
Clarence Ip7aa390f2016-05-26 21:06:54 -0400470 } else {
471 mutex_lock(&info->property_lock);
Clarence Ip4a2955d2017-07-04 18:04:33 -0400472 *val = property_state->values[property_idx].value;
Clarence Ip7aa390f2016-05-26 21:06:54 -0400473 mutex_unlock(&info->property_lock);
474 rc = 0;
475 }
476
477 return rc;
478}
479
480void *msm_property_alloc_state(struct msm_property_info *info)
481{
482 void *state = NULL;
483
484 if (!info) {
485 DRM_ERROR("invalid property info\n");
486 return NULL;
487 }
488
489 mutex_lock(&info->property_lock);
490 if (info->state_cache_size)
491 state = info->state_cache[--(info->state_cache_size)];
492 mutex_unlock(&info->property_lock);
493
494 if (!state && info->state_size)
495 state = kmalloc(info->state_size, GFP_KERNEL);
496
497 if (!state)
498 DRM_ERROR("failed to allocate state\n");
499
500 return state;
501}
502
503/**
504 * _msm_property_free_state - helper function for freeing local state objects
505 * @info: Pointer to property info container struct
506 * @st: Pointer to state object
507 */
508static void _msm_property_free_state(struct msm_property_info *info, void *st)
509{
510 if (!info || !st)
511 return;
512
513 mutex_lock(&info->property_lock);
514 if (info->state_cache_size < MSM_PROP_STATE_CACHE_SIZE)
515 info->state_cache[(info->state_cache_size)++] = st;
516 else
517 kfree(st);
518 mutex_unlock(&info->property_lock);
519}
520
521void msm_property_reset_state(struct msm_property_info *info, void *state,
Clarence Ip4a2955d2017-07-04 18:04:33 -0400522 struct msm_property_state *property_state,
523 struct msm_property_value *property_values)
Clarence Ip7aa390f2016-05-26 21:06:54 -0400524{
525 uint32_t i;
526
527 if (!info) {
528 DRM_ERROR("invalid property info\n");
529 return;
530 }
531
532 if (state)
533 memset(state, 0, info->state_size);
534
Clarence Ip4a2955d2017-07-04 18:04:33 -0400535 if (property_state) {
536 property_state->property_count = info->property_count;
537 property_state->values = property_values;
538 INIT_LIST_HEAD(&property_state->dirty_list);
539 }
540
Clarence Ip7aa390f2016-05-26 21:06:54 -0400541 /*
542 * Assign default property values. This helper is mostly used
543 * to initialize newly created state objects.
544 */
545 if (property_values)
Clarence Ip4a2955d2017-07-04 18:04:33 -0400546 for (i = 0; i < info->property_count; ++i) {
547 property_values[i].value =
Clarence Ip7aa390f2016-05-26 21:06:54 -0400548 info->property_data[i].default_value;
Clarence Ip4a2955d2017-07-04 18:04:33 -0400549 property_values[i].blob = NULL;
550 INIT_LIST_HEAD(&property_values[i].dirty_node);
551 }
Clarence Ip7aa390f2016-05-26 21:06:54 -0400552}
553
554void msm_property_duplicate_state(struct msm_property_info *info,
555 void *old_state, void *state,
Clarence Ip4a2955d2017-07-04 18:04:33 -0400556 struct msm_property_state *property_state,
557 struct msm_property_value *property_values)
Clarence Ip7aa390f2016-05-26 21:06:54 -0400558{
559 uint32_t i;
560
561 if (!info || !old_state || !state) {
562 DRM_ERROR("invalid argument(s)\n");
563 return;
564 }
565
566 memcpy(state, old_state, info->state_size);
567
Clarence Ip4a2955d2017-07-04 18:04:33 -0400568 if (!property_state)
569 return;
570
571 INIT_LIST_HEAD(&property_state->dirty_list);
572 property_state->values = property_values;
573
574 if (property_state->values)
575 /* add ref count for blobs and initialize dirty nodes */
576 for (i = 0; i < info->property_count; ++i) {
577 if (property_state->values[i].blob)
578 drm_property_reference_blob(
579 property_state->values[i].blob);
580 INIT_LIST_HEAD(&property_state->values[i].dirty_node);
581 }
Clarence Ip7aa390f2016-05-26 21:06:54 -0400582}
583
584void msm_property_destroy_state(struct msm_property_info *info, void *state,
Clarence Ip4a2955d2017-07-04 18:04:33 -0400585 struct msm_property_state *property_state)
Clarence Ip7aa390f2016-05-26 21:06:54 -0400586{
587 uint32_t i;
588
589 if (!info || !state) {
590 DRM_ERROR("invalid argument(s)\n");
591 return;
592 }
Clarence Ip4a2955d2017-07-04 18:04:33 -0400593 if (property_state && property_state->values) {
Clarence Ip7aa390f2016-05-26 21:06:54 -0400594 /* remove ref count for blobs */
Clarence Ip4a2955d2017-07-04 18:04:33 -0400595 for (i = 0; i < info->property_count; ++i)
596 if (property_state->values[i].blob) {
Clarence Ip7aa390f2016-05-26 21:06:54 -0400597 drm_property_unreference_blob(
Clarence Ip4a2955d2017-07-04 18:04:33 -0400598 property_state->values[i].blob);
599 property_state->values[i].blob = NULL;
600 }
Clarence Ip7aa390f2016-05-26 21:06:54 -0400601 }
602
603 _msm_property_free_state(info, state);
604}
605
606void *msm_property_get_blob(struct msm_property_info *info,
Clarence Ip4a2955d2017-07-04 18:04:33 -0400607 struct msm_property_state *property_state,
Clarence Ip7aa390f2016-05-26 21:06:54 -0400608 size_t *byte_len,
609 uint32_t property_idx)
610{
611 struct drm_property_blob *blob;
612 size_t len = 0;
613 void *rc = 0;
614
Clarence Ip4a2955d2017-07-04 18:04:33 -0400615 if (!info || !property_state || !property_state->values ||
616 (property_idx >= info->blob_count)) {
Clarence Ip7aa390f2016-05-26 21:06:54 -0400617 DRM_ERROR("invalid argument(s)\n");
618 } else {
Clarence Ip4a2955d2017-07-04 18:04:33 -0400619 blob = property_state->values[property_idx].blob;
Clarence Ip7aa390f2016-05-26 21:06:54 -0400620 if (blob) {
621 len = blob->length;
622 rc = &blob->data;
623 }
624 }
625
626 if (byte_len)
627 *byte_len = len;
628
629 return rc;
630}
631
632int msm_property_set_blob(struct msm_property_info *info,
633 struct drm_property_blob **blob_reference,
634 void *blob_data,
635 size_t byte_len,
636 uint32_t property_idx)
637{
638 struct drm_property_blob *blob = NULL;
639 int rc = -EINVAL;
640
641 if (!info || !blob_reference || (property_idx >= info->blob_count)) {
642 DRM_ERROR("invalid argument(s)\n");
643 } else {
644 /* create blob */
645 if (blob_data && byte_len) {
646 blob = drm_property_create_blob(info->dev,
647 byte_len,
648 blob_data);
649 if (IS_ERR_OR_NULL(blob)) {
650 rc = PTR_ERR(blob);
651 DRM_ERROR("failed to create blob, %d\n", rc);
652 goto exit;
653 }
654 }
655
656 /* update drm object */
657 rc = drm_object_property_set_value(info->base,
658 info->property_array[property_idx],
659 blob ? blob->base.id : 0);
660 if (rc) {
661 DRM_ERROR("failed to set blob to property\n");
662 if (blob)
663 drm_property_unreference_blob(blob);
664 goto exit;
665 }
666
667 /* update local reference */
668 if (*blob_reference)
669 drm_property_unreference_blob(*blob_reference);
670 *blob_reference = blob;
671 }
672
673exit:
674 return rc;
675}
676
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400677int msm_property_set_property(struct msm_property_info *info,
Clarence Ip4a2955d2017-07-04 18:04:33 -0400678 struct msm_property_state *property_state,
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400679 uint32_t property_idx,
680 uint64_t val)
681{
682 int rc = -EINVAL;
683
684 if (!info || (property_idx >= info->property_count) ||
Clarence Ip4a2955d2017-07-04 18:04:33 -0400685 property_idx < info->blob_count ||
686 !property_state || !property_state->values) {
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400687 DRM_ERROR("invalid argument(s)\n");
688 } else {
Lloyd Atkinson13cee812016-08-16 16:10:31 -0400689 struct drm_property *drm_prop;
690
691 mutex_lock(&info->property_lock);
692
693 /* update cached value */
Clarence Ip4a2955d2017-07-04 18:04:33 -0400694 property_state->values[property_idx].value = val;
Lloyd Atkinson13cee812016-08-16 16:10:31 -0400695
696 /* update the new default value for immutables */
697 drm_prop = info->property_array[property_idx];
698 if (drm_prop->flags & DRM_MODE_PROP_IMMUTABLE)
699 info->property_data[property_idx].default_value = val;
700
701 mutex_unlock(&info->property_lock);
702
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400703 /* update drm object */
Lloyd Atkinson13cee812016-08-16 16:10:31 -0400704 rc = drm_object_property_set_value(info->base, drm_prop, val);
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400705 if (rc)
706 DRM_ERROR("failed set property value, idx %d rc %d\n",
707 property_idx, rc);
Lloyd Atkinson13cee812016-08-16 16:10:31 -0400708
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400709 }
710
711 return rc;
712}
713