msm_prop.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  4. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
  5. */
  6. #include "msm_prop.h"
  7. void msm_property_init(struct msm_property_info *info,
  8. struct drm_mode_object *base,
  9. struct drm_device *dev,
  10. struct drm_property **property_array,
  11. struct msm_property_data *property_data,
  12. uint32_t property_count,
  13. uint32_t blob_count,
  14. uint32_t state_size)
  15. {
  16. /* prevent access if any of these are NULL */
  17. if (!base || !dev || !property_array || !property_data) {
  18. property_count = 0;
  19. blob_count = 0;
  20. DRM_ERROR("invalid arguments, forcing zero properties\n");
  21. return;
  22. }
  23. /* can't have more blob properties than total properties */
  24. if (blob_count > property_count) {
  25. blob_count = property_count;
  26. DBG("Capping number of blob properties to %d", blob_count);
  27. }
  28. if (!info) {
  29. DRM_ERROR("info pointer is NULL\n");
  30. } else {
  31. info->base = base;
  32. info->dev = dev;
  33. info->property_array = property_array;
  34. info->property_data = property_data;
  35. info->property_count = property_count;
  36. info->blob_count = blob_count;
  37. info->install_request = 0;
  38. info->install_count = 0;
  39. info->recent_idx = 0;
  40. info->is_active = false;
  41. info->state_size = state_size;
  42. info->state_cache_size = 0;
  43. mutex_init(&info->property_lock);
  44. memset(property_data,
  45. 0,
  46. sizeof(struct msm_property_data) *
  47. property_count);
  48. }
  49. }
  50. void msm_property_destroy(struct msm_property_info *info)
  51. {
  52. if (!info)
  53. return;
  54. /* free state cache */
  55. while (info->state_cache_size > 0)
  56. kfree(info->state_cache[--(info->state_cache_size)]);
  57. mutex_destroy(&info->property_lock);
  58. }
  59. int msm_property_pop_dirty(struct msm_property_info *info,
  60. struct msm_property_state *property_state)
  61. {
  62. struct list_head *item;
  63. int rc = 0;
  64. if (!info || !property_state || !property_state->values) {
  65. DRM_ERROR("invalid argument(s)\n");
  66. return -EINVAL;
  67. }
  68. WARN_ON(!mutex_is_locked(&info->property_lock));
  69. if (list_empty(&property_state->dirty_list)) {
  70. rc = -EAGAIN;
  71. } else {
  72. item = property_state->dirty_list.next;
  73. list_del_init(item);
  74. rc = container_of(item, struct msm_property_value, dirty_node)
  75. - property_state->values;
  76. DRM_DEBUG_KMS("property %d dirty\n", rc);
  77. }
  78. return rc;
  79. }
  80. /**
  81. * _msm_property_set_dirty_no_lock - flag given property as being dirty
  82. * This function doesn't mutex protect the
  83. * dirty linked list.
  84. * @info: Pointer to property info container struct
  85. * @property_state: Pointer to property state container struct
  86. * @property_idx: Property index
  87. */
  88. static void _msm_property_set_dirty_no_lock(
  89. struct msm_property_info *info,
  90. struct msm_property_state *property_state,
  91. uint32_t property_idx)
  92. {
  93. if (!info || !property_state || !property_state->values ||
  94. property_idx >= info->property_count) {
  95. DRM_ERROR("invalid argument(s), idx %u\n", property_idx);
  96. return;
  97. }
  98. /* avoid re-inserting if already dirty */
  99. if (!list_empty(&property_state->values[property_idx].dirty_node)) {
  100. DRM_DEBUG_KMS("property %u already dirty\n", property_idx);
  101. return;
  102. }
  103. list_add_tail(&property_state->values[property_idx].dirty_node,
  104. &property_state->dirty_list);
  105. }
  106. bool msm_property_is_dirty(
  107. struct msm_property_info *info,
  108. struct msm_property_state *property_state,
  109. uint32_t property_idx)
  110. {
  111. if (!info || !property_state || !property_state->values ||
  112. property_idx >= info->property_count) {
  113. DRM_ERROR("invalid argument(s), idx %u\n", property_idx);
  114. return false;
  115. }
  116. return !list_empty(&property_state->values[property_idx].dirty_node);
  117. }
  118. /**
  119. * _msm_property_install_integer - install standard drm range property
  120. * @info: Pointer to property info container struct
  121. * @name: Property name
  122. * @flags: Other property type flags, e.g. DRM_MODE_PROP_IMMUTABLE
  123. * @min: Min property value
  124. * @max: Max property value
  125. * @init: Default Property value
  126. * @property_idx: Property index
  127. * @force_dirty: Whether or not to filter 'dirty' status on unchanged values
  128. */
  129. static void _msm_property_install_integer(struct msm_property_info *info,
  130. const char *name, int flags, uint64_t min, uint64_t max,
  131. uint64_t init, uint32_t property_idx, bool force_dirty)
  132. {
  133. struct drm_property **prop;
  134. if (!info)
  135. return;
  136. ++info->install_request;
  137. if (!name || (property_idx >= info->property_count)) {
  138. DRM_ERROR("invalid argument(s), %s\n", name ? name : "null");
  139. } else {
  140. prop = &info->property_array[property_idx];
  141. /*
  142. * Properties need to be attached to each drm object that
  143. * uses them, but only need to be created once
  144. */
  145. if (!*prop) {
  146. *prop = drm_property_create_range(info->dev,
  147. flags, name, min, max);
  148. if (!*prop)
  149. DRM_ERROR("create %s property failed\n", name);
  150. }
  151. /* save init value for later */
  152. info->property_data[property_idx].default_value = init;
  153. info->property_data[property_idx].force_dirty = force_dirty;
  154. /* always attach property, if created */
  155. if (*prop) {
  156. drm_object_attach_property(info->base, *prop, init);
  157. ++info->install_count;
  158. }
  159. }
  160. }
  161. void msm_property_install_range(struct msm_property_info *info,
  162. const char *name, int flags, uint64_t min, uint64_t max,
  163. uint64_t init, uint32_t property_idx)
  164. {
  165. _msm_property_install_integer(info, name, flags,
  166. min, max, init, property_idx, false);
  167. }
  168. void msm_property_install_volatile_range(struct msm_property_info *info,
  169. const char *name, int flags, uint64_t min, uint64_t max,
  170. uint64_t init, uint32_t property_idx)
  171. {
  172. _msm_property_install_integer(info, name, flags,
  173. min, max, init, property_idx, true);
  174. }
  175. /**
  176. * msm_property_install_enum_helper - install standard drm enum/bitmask property
  177. * This function is added as a helper function called within msm_property_install_enum
  178. * or msm_property_install_volatile_enum depending on whether we want to set the
  179. * enum property as dirty or not dirty.
  180. * @info: Pointer to property info container struct
  181. * @name: Property name
  182. * @flags: Other property type flags, e.g. DRM_MODE_PROP_IMMUTABLE
  183. * @is_bitmask: Set to non-zero to create a bitmask property, rather than an
  184. * enumeration one
  185. * @values: Array of allowable enumeration/bitmask values
  186. * @num_values: Size of values array
  187. * @init_idx: index of the values array entry to initialize the property
  188. * @property_idx: Property index
  189. * @force_dirty: Whether or not to filter 'dirty' status on unchanged values
  190. */
  191. void msm_property_install_enum_helper(struct msm_property_info *info,
  192. const char *name, int flags, int is_bitmask,
  193. const struct drm_prop_enum_list *values, int num_values,
  194. u32 init_idx, uint32_t property_idx, bool force_dirty)
  195. {
  196. struct drm_property **prop;
  197. if (!info)
  198. return;
  199. ++info->install_request;
  200. if (!name || !values || !num_values ||
  201. (property_idx >= info->property_count)) {
  202. DRM_ERROR("invalid argument(s), %s\n", name ? name : "null");
  203. } else {
  204. prop = &info->property_array[property_idx];
  205. /*
  206. * Properties need to be attached to each drm object that
  207. * uses them, but only need to be created once
  208. */
  209. if (!*prop) {
  210. /* 'bitmask' is a special type of 'enum' */
  211. if (is_bitmask)
  212. *prop = drm_property_create_bitmask(info->dev,
  213. DRM_MODE_PROP_BITMASK | flags,
  214. name, values, num_values, -1);
  215. else
  216. *prop = drm_property_create_enum(info->dev,
  217. DRM_MODE_PROP_ENUM | flags,
  218. name, values, num_values);
  219. if (!*prop)
  220. DRM_ERROR("create %s property failed\n", name);
  221. }
  222. /* save init value for later */
  223. info->property_data[property_idx].default_value = 0;
  224. info->property_data[property_idx].force_dirty = force_dirty;
  225. /* initialize with the given idx if valid */
  226. if (!is_bitmask && init_idx && (init_idx < num_values))
  227. info->property_data[property_idx].default_value =
  228. values[init_idx].type;
  229. /* always attach property, if created */
  230. if (*prop) {
  231. drm_object_attach_property(info->base, *prop,
  232. info->property_data
  233. [property_idx].default_value);
  234. ++info->install_count;
  235. }
  236. }
  237. }
  238. void msm_property_install_volatile_enum(struct msm_property_info *info,
  239. const char *name, int flags, int is_bitmask,
  240. const struct drm_prop_enum_list *values, int num_values,
  241. u32 init_idx, uint32_t property_idx)
  242. {
  243. msm_property_install_enum_helper(info, name, flags, is_bitmask,
  244. values, num_values, init_idx, property_idx, true);
  245. }
  246. void msm_property_install_enum(struct msm_property_info *info,
  247. const char *name, int flags, int is_bitmask,
  248. const struct drm_prop_enum_list *values, int num_values,
  249. u32 init_idx, uint32_t property_idx)
  250. {
  251. msm_property_install_enum_helper(info, name, flags, is_bitmask,
  252. values, num_values, init_idx, property_idx, false);
  253. }
  254. void msm_property_install_blob(struct msm_property_info *info,
  255. const char *name, int flags, uint32_t property_idx)
  256. {
  257. struct drm_property **prop;
  258. if (!info)
  259. return;
  260. ++info->install_request;
  261. if (!name || (property_idx >= info->blob_count)) {
  262. DRM_ERROR("invalid argument(s), %s\n", name ? name : "null");
  263. } else {
  264. prop = &info->property_array[property_idx];
  265. /*
  266. * Properties need to be attached to each drm object that
  267. * uses them, but only need to be created once
  268. */
  269. if (!*prop) {
  270. /* use 'create' for blob property place holder */
  271. *prop = drm_property_create(info->dev,
  272. DRM_MODE_PROP_BLOB | flags, name, 0);
  273. if (!*prop)
  274. DRM_ERROR("create %s property failed\n", name);
  275. }
  276. /* save init value for later */
  277. info->property_data[property_idx].default_value = 0;
  278. info->property_data[property_idx].force_dirty = true;
  279. /* always attach property, if created */
  280. if (*prop) {
  281. drm_object_attach_property(info->base, *prop, -1);
  282. ++info->install_count;
  283. }
  284. }
  285. }
  286. int msm_property_install_get_status(struct msm_property_info *info)
  287. {
  288. int rc = -ENOMEM;
  289. if (info && (info->install_request == info->install_count))
  290. rc = 0;
  291. return rc;
  292. }
  293. int msm_property_index(struct msm_property_info *info,
  294. struct drm_property *property)
  295. {
  296. uint32_t count;
  297. int32_t idx;
  298. int rc = -EINVAL;
  299. if (!info || !property) {
  300. DRM_ERROR("invalid argument(s)\n");
  301. } else {
  302. /*
  303. * Linear search, but start from last found index. This will
  304. * help if any single property is accessed multiple times in a
  305. * row. Ideally, we could keep a list of properties sorted in
  306. * the order of most recent access, but that may be overkill
  307. * for now.
  308. */
  309. mutex_lock(&info->property_lock);
  310. idx = info->recent_idx;
  311. count = info->property_count;
  312. while (count) {
  313. --count;
  314. /* stop searching on match */
  315. if (info->property_array[idx] == property) {
  316. info->recent_idx = idx;
  317. rc = idx;
  318. break;
  319. }
  320. /* move to next valid index */
  321. if (--idx < 0)
  322. idx = info->property_count - 1;
  323. }
  324. mutex_unlock(&info->property_lock);
  325. }
  326. return rc;
  327. }
  328. int msm_property_set_dirty(struct msm_property_info *info,
  329. struct msm_property_state *property_state,
  330. int property_idx)
  331. {
  332. if (!info || !property_state || !property_state->values) {
  333. DRM_ERROR("invalid argument(s)\n");
  334. return -EINVAL;
  335. }
  336. mutex_lock(&info->property_lock);
  337. _msm_property_set_dirty_no_lock(info, property_state, property_idx);
  338. mutex_unlock(&info->property_lock);
  339. return 0;
  340. }
  341. int msm_property_atomic_set(struct msm_property_info *info,
  342. struct msm_property_state *property_state,
  343. struct drm_property *property, uint64_t val)
  344. {
  345. struct drm_property_blob *blob;
  346. int property_idx, rc = -EINVAL;
  347. if (!info || !property_state) {
  348. DRM_ERROR("invalid argument(s)\n");
  349. return -EINVAL;
  350. }
  351. property_idx = msm_property_index(info, property);
  352. if ((property_idx == -EINVAL) || !property_state->values) {
  353. DRM_ERROR("invalid argument(s)\n");
  354. } else {
  355. /* extra handling for incoming properties */
  356. mutex_lock(&info->property_lock);
  357. if ((property->flags & DRM_MODE_PROP_BLOB) &&
  358. (property_idx < info->blob_count)) {
  359. /* need to clear previous ref */
  360. if (property_state->values[property_idx].blob)
  361. drm_property_blob_put(
  362. property_state->values[
  363. property_idx].blob);
  364. /* DRM lookup also takes a reference */
  365. blob = drm_property_lookup_blob(info->dev,
  366. (uint32_t)val);
  367. if (val && !blob) {
  368. DRM_ERROR("prop %d blob id 0x%llx not found\n",
  369. property_idx, val);
  370. val = 0;
  371. } else {
  372. if (blob) {
  373. DBG("Blob %u saved", blob->base.id);
  374. val = blob->base.id;
  375. }
  376. /* save the new blob */
  377. property_state->values[property_idx].blob =
  378. blob;
  379. }
  380. }
  381. /* update value and flag as dirty */
  382. if (property_state->values[property_idx].value != val ||
  383. info->property_data[property_idx].force_dirty) {
  384. property_state->values[property_idx].value = val;
  385. _msm_property_set_dirty_no_lock(info, property_state,
  386. property_idx);
  387. DBG("%s - %lld", property->name, val);
  388. }
  389. mutex_unlock(&info->property_lock);
  390. rc = 0;
  391. }
  392. return rc;
  393. }
  394. int msm_property_atomic_get(struct msm_property_info *info,
  395. struct msm_property_state *property_state,
  396. struct drm_property *property, uint64_t *val)
  397. {
  398. int property_idx, rc = -EINVAL;
  399. property_idx = msm_property_index(info, property);
  400. if (!info || (property_idx == -EINVAL) ||
  401. !property_state->values || !val) {
  402. DRM_DEBUG("Invalid argument(s)\n");
  403. } else {
  404. mutex_lock(&info->property_lock);
  405. *val = property_state->values[property_idx].value;
  406. mutex_unlock(&info->property_lock);
  407. rc = 0;
  408. }
  409. return rc;
  410. }
  411. void *msm_property_alloc_state(struct msm_property_info *info)
  412. {
  413. void *state = NULL;
  414. if (!info) {
  415. DRM_ERROR("invalid property info\n");
  416. return NULL;
  417. }
  418. mutex_lock(&info->property_lock);
  419. if (info->state_cache_size)
  420. state = info->state_cache[--(info->state_cache_size)];
  421. mutex_unlock(&info->property_lock);
  422. if (!state && info->state_size)
  423. state = kzalloc(info->state_size, GFP_KERNEL);
  424. if (!state)
  425. DRM_ERROR("failed to allocate state\n");
  426. return state;
  427. }
  428. /**
  429. * _msm_property_free_state - helper function for freeing local state objects
  430. * @info: Pointer to property info container struct
  431. * @st: Pointer to state object
  432. */
  433. static void _msm_property_free_state(struct msm_property_info *info, void *st)
  434. {
  435. if (!info || !st)
  436. return;
  437. mutex_lock(&info->property_lock);
  438. if (info->state_cache_size < MSM_PROP_STATE_CACHE_SIZE)
  439. info->state_cache[(info->state_cache_size)++] = st;
  440. else
  441. kfree(st);
  442. mutex_unlock(&info->property_lock);
  443. }
  444. void msm_property_reset_state(struct msm_property_info *info, void *state,
  445. struct msm_property_state *property_state,
  446. struct msm_property_value *property_values)
  447. {
  448. uint32_t i;
  449. if (!info) {
  450. DRM_ERROR("invalid property info\n");
  451. return;
  452. }
  453. if (state)
  454. memset(state, 0, info->state_size);
  455. if (property_state) {
  456. property_state->property_count = info->property_count;
  457. property_state->values = property_values;
  458. INIT_LIST_HEAD(&property_state->dirty_list);
  459. }
  460. /*
  461. * Assign default property values. This helper is mostly used
  462. * to initialize newly created state objects.
  463. */
  464. if (property_values)
  465. for (i = 0; i < info->property_count; ++i) {
  466. property_values[i].value =
  467. info->property_data[i].default_value;
  468. property_values[i].blob = NULL;
  469. INIT_LIST_HEAD(&property_values[i].dirty_node);
  470. }
  471. }
  472. void msm_property_duplicate_state(struct msm_property_info *info,
  473. void *old_state, void *state,
  474. struct msm_property_state *property_state,
  475. struct msm_property_value *property_values)
  476. {
  477. uint32_t i;
  478. if (!info || !old_state || !state) {
  479. DRM_ERROR("invalid argument(s)\n");
  480. return;
  481. }
  482. memcpy(state, old_state, info->state_size);
  483. if (!property_state)
  484. return;
  485. INIT_LIST_HEAD(&property_state->dirty_list);
  486. property_state->values = property_values;
  487. if (property_state->values)
  488. /* add ref count for blobs and initialize dirty nodes */
  489. for (i = 0; i < info->property_count; ++i) {
  490. if (property_state->values[i].blob)
  491. drm_property_blob_get(
  492. property_state->values[i].blob);
  493. INIT_LIST_HEAD(&property_state->values[i].dirty_node);
  494. }
  495. }
  496. void msm_property_destroy_state(struct msm_property_info *info, void *state,
  497. struct msm_property_state *property_state)
  498. {
  499. uint32_t i;
  500. if (!info || !state) {
  501. DRM_ERROR("invalid argument(s)\n");
  502. return;
  503. }
  504. if (property_state && property_state->values) {
  505. /* remove ref count for blobs */
  506. for (i = 0; i < info->property_count; ++i)
  507. if (property_state->values[i].blob) {
  508. drm_property_blob_put(
  509. property_state->values[i].blob);
  510. property_state->values[i].blob = NULL;
  511. }
  512. }
  513. _msm_property_free_state(info, state);
  514. }
  515. void *msm_property_get_blob(struct msm_property_info *info,
  516. struct msm_property_state *property_state,
  517. size_t *byte_len,
  518. uint32_t property_idx)
  519. {
  520. struct drm_property_blob *blob;
  521. size_t len = 0;
  522. void *rc = 0;
  523. if (!info || !property_state || !property_state->values ||
  524. (property_idx >= info->blob_count)) {
  525. DRM_ERROR("invalid argument(s)\n");
  526. } else {
  527. blob = property_state->values[property_idx].blob;
  528. if (blob) {
  529. len = blob->length;
  530. rc = blob->data;
  531. }
  532. }
  533. if (byte_len)
  534. *byte_len = len;
  535. return rc;
  536. }
  537. int msm_property_set_blob(struct msm_property_info *info,
  538. struct drm_property_blob **blob_reference,
  539. void *blob_data,
  540. size_t byte_len,
  541. uint32_t property_idx)
  542. {
  543. struct drm_property_blob *blob = NULL;
  544. int rc = -EINVAL;
  545. if (!info || !blob_reference || (property_idx >= info->blob_count)) {
  546. DRM_ERROR("invalid argument(s)\n");
  547. } else {
  548. /* create blob */
  549. if (blob_data && byte_len) {
  550. blob = drm_property_create_blob(info->dev,
  551. byte_len,
  552. blob_data);
  553. if (IS_ERR_OR_NULL(blob)) {
  554. rc = PTR_ERR(blob);
  555. DRM_ERROR("failed to create blob, %d\n", rc);
  556. goto exit;
  557. }
  558. }
  559. /* update drm object */
  560. rc = drm_object_property_set_value(info->base,
  561. info->property_array[property_idx],
  562. blob ? blob->base.id : 0);
  563. if (rc) {
  564. DRM_ERROR("failed to set blob to property\n");
  565. if (blob)
  566. drm_property_blob_put(blob);
  567. goto exit;
  568. }
  569. /* update local reference */
  570. if (*blob_reference)
  571. drm_property_blob_put(*blob_reference);
  572. *blob_reference = blob;
  573. }
  574. exit:
  575. return rc;
  576. }
  577. int msm_property_set_property(struct msm_property_info *info,
  578. struct msm_property_state *property_state,
  579. uint32_t property_idx,
  580. uint64_t val)
  581. {
  582. int rc = -EINVAL;
  583. if (!info || (property_idx >= info->property_count) ||
  584. property_idx < info->blob_count ||
  585. !property_state || !property_state->values) {
  586. DRM_ERROR("invalid argument(s)\n");
  587. } else {
  588. struct drm_property *drm_prop;
  589. mutex_lock(&info->property_lock);
  590. /* update cached value */
  591. property_state->values[property_idx].value = val;
  592. /* update the new default value for immutables */
  593. drm_prop = info->property_array[property_idx];
  594. if (drm_prop->flags & DRM_MODE_PROP_IMMUTABLE)
  595. info->property_data[property_idx].default_value = val;
  596. mutex_unlock(&info->property_lock);
  597. /* update drm object */
  598. rc = drm_object_property_set_value(info->base, drm_prop, val);
  599. if (rc)
  600. DRM_ERROR("failed set property value, idx %d rc %d\n",
  601. property_idx, rc);
  602. }
  603. return rc;
  604. }