drm_color_mgmt.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. /*
  2. * Copyright (c) 2016 Intel Corporation
  3. *
  4. * Permission to use, copy, modify, distribute, and sell this software and its
  5. * documentation for any purpose is hereby granted without fee, provided that
  6. * the above copyright notice appear in all copies and that both that copyright
  7. * notice and this permission notice appear in supporting documentation, and
  8. * that the name of the copyright holders not be used in advertising or
  9. * publicity pertaining to distribution of the software without specific,
  10. * written prior permission. The copyright holders make no representations
  11. * about the suitability of this software for any purpose. It is provided "as
  12. * is" without express or implied warranty.
  13. *
  14. * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15. * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  16. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17. * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18. * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  19. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  20. * OF THIS SOFTWARE.
  21. */
  22. #include <linux/uaccess.h>
  23. #include <drm/drm_color_mgmt.h>
  24. #include <drm/drm_crtc.h>
  25. #include <drm/drm_device.h>
  26. #include <drm/drm_drv.h>
  27. #include <drm/drm_print.h>
  28. #include "drm_crtc_internal.h"
  29. /**
  30. * DOC: overview
  31. *
  32. * Color management or color space adjustments is supported through a set of 5
  33. * properties on the &drm_crtc object. They are set up by calling
  34. * drm_crtc_enable_color_mgmt().
  35. *
  36. * "DEGAMMA_LUT”:
  37. * Blob property to set the degamma lookup table (LUT) mapping pixel data
  38. * from the framebuffer before it is given to the transformation matrix.
  39. * The data is interpreted as an array of &struct drm_color_lut elements.
  40. * Hardware might choose not to use the full precision of the LUT elements
  41. * nor use all the elements of the LUT (for example the hardware might
  42. * choose to interpolate between LUT[0] and LUT[4]).
  43. *
  44. * Setting this to NULL (blob property value set to 0) means a
  45. * linear/pass-thru gamma table should be used. This is generally the
  46. * driver boot-up state too. Drivers can access this blob through
  47. * &drm_crtc_state.degamma_lut.
  48. *
  49. * “DEGAMMA_LUT_SIZE”:
  50. * Unsinged range property to give the size of the lookup table to be set
  51. * on the DEGAMMA_LUT property (the size depends on the underlying
  52. * hardware). If drivers support multiple LUT sizes then they should
  53. * publish the largest size, and sub-sample smaller sized LUTs (e.g. for
  54. * split-gamma modes) appropriately.
  55. *
  56. * “CTM”:
  57. * Blob property to set the current transformation matrix (CTM) apply to
  58. * pixel data after the lookup through the degamma LUT and before the
  59. * lookup through the gamma LUT. The data is interpreted as a struct
  60. * &drm_color_ctm.
  61. *
  62. * Setting this to NULL (blob property value set to 0) means a
  63. * unit/pass-thru matrix should be used. This is generally the driver
  64. * boot-up state too. Drivers can access the blob for the color conversion
  65. * matrix through &drm_crtc_state.ctm.
  66. *
  67. * “GAMMA_LUT”:
  68. * Blob property to set the gamma lookup table (LUT) mapping pixel data
  69. * after the transformation matrix to data sent to the connector. The
  70. * data is interpreted as an array of &struct drm_color_lut elements.
  71. * Hardware might choose not to use the full precision of the LUT elements
  72. * nor use all the elements of the LUT (for example the hardware might
  73. * choose to interpolate between LUT[0] and LUT[4]).
  74. *
  75. * Setting this to NULL (blob property value set to 0) means a
  76. * linear/pass-thru gamma table should be used. This is generally the
  77. * driver boot-up state too. Drivers can access this blob through
  78. * &drm_crtc_state.gamma_lut.
  79. *
  80. * “GAMMA_LUT_SIZE”:
  81. * Unsigned range property to give the size of the lookup table to be set
  82. * on the GAMMA_LUT property (the size depends on the underlying hardware).
  83. * If drivers support multiple LUT sizes then they should publish the
  84. * largest size, and sub-sample smaller sized LUTs (e.g. for split-gamma
  85. * modes) appropriately.
  86. *
  87. * There is also support for a legacy gamma table, which is set up by calling
  88. * drm_mode_crtc_set_gamma_size(). Drivers which support both should use
  89. * drm_atomic_helper_legacy_gamma_set() to alias the legacy gamma ramp with the
  90. * "GAMMA_LUT" property above.
  91. *
  92. * Support for different non RGB color encodings is controlled through
  93. * &drm_plane specific COLOR_ENCODING and COLOR_RANGE properties. They
  94. * are set up by calling drm_plane_create_color_properties().
  95. *
  96. * "COLOR_ENCODING"
  97. * Optional plane enum property to support different non RGB
  98. * color encodings. The driver can provide a subset of standard
  99. * enum values supported by the DRM plane.
  100. *
  101. * "COLOR_RANGE"
  102. * Optional plane enum property to support different non RGB
  103. * color parameter ranges. The driver can provide a subset of
  104. * standard enum values supported by the DRM plane.
  105. */
  106. /**
  107. * drm_color_ctm_s31_32_to_qm_n
  108. *
  109. * @user_input: input value
  110. * @m: number of integer bits, only support m <= 32, include the sign-bit
  111. * @n: number of fractional bits, only support n <= 32
  112. *
  113. * Convert and clamp S31.32 sign-magnitude to Qm.n (signed 2's complement).
  114. * The sign-bit BIT(m+n-1) and above are 0 for positive value and 1 for negative
  115. * the range of value is [-2^(m-1), 2^(m-1) - 2^-n]
  116. *
  117. * For example
  118. * A Q3.12 format number:
  119. * - required bit: 3 + 12 = 15bits
  120. * - range: [-2^2, 2^2 - 2^−15]
  121. *
  122. * NOTE: the m can be zero if all bit_precision are used to present fractional
  123. * bits like Q0.32
  124. */
  125. u64 drm_color_ctm_s31_32_to_qm_n(u64 user_input, u32 m, u32 n)
  126. {
  127. u64 mag = (user_input & ~BIT_ULL(63)) >> (32 - n);
  128. bool negative = !!(user_input & BIT_ULL(63));
  129. s64 val;
  130. WARN_ON(m > 32 || n > 32);
  131. val = clamp_val(mag, 0, negative ?
  132. BIT_ULL(n + m - 1) : BIT_ULL(n + m - 1) - 1);
  133. return negative ? -val : val;
  134. }
  135. EXPORT_SYMBOL(drm_color_ctm_s31_32_to_qm_n);
  136. /**
  137. * drm_crtc_enable_color_mgmt - enable color management properties
  138. * @crtc: DRM CRTC
  139. * @degamma_lut_size: the size of the degamma lut (before CSC)
  140. * @has_ctm: whether to attach ctm_property for CSC matrix
  141. * @gamma_lut_size: the size of the gamma lut (after CSC)
  142. *
  143. * This function lets the driver enable the color correction
  144. * properties on a CRTC. This includes 3 degamma, csc and gamma
  145. * properties that userspace can set and 2 size properties to inform
  146. * the userspace of the lut sizes. Each of the properties are
  147. * optional. The gamma and degamma properties are only attached if
  148. * their size is not 0 and ctm_property is only attached if has_ctm is
  149. * true.
  150. *
  151. * Drivers should use drm_atomic_helper_legacy_gamma_set() to implement the
  152. * legacy &drm_crtc_funcs.gamma_set callback.
  153. */
  154. void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
  155. uint degamma_lut_size,
  156. bool has_ctm,
  157. uint gamma_lut_size)
  158. {
  159. struct drm_device *dev = crtc->dev;
  160. struct drm_mode_config *config = &dev->mode_config;
  161. if (degamma_lut_size) {
  162. drm_object_attach_property(&crtc->base,
  163. config->degamma_lut_property, 0);
  164. drm_object_attach_property(&crtc->base,
  165. config->degamma_lut_size_property,
  166. degamma_lut_size);
  167. }
  168. if (has_ctm)
  169. drm_object_attach_property(&crtc->base,
  170. config->ctm_property, 0);
  171. if (gamma_lut_size) {
  172. drm_object_attach_property(&crtc->base,
  173. config->gamma_lut_property, 0);
  174. drm_object_attach_property(&crtc->base,
  175. config->gamma_lut_size_property,
  176. gamma_lut_size);
  177. }
  178. }
  179. EXPORT_SYMBOL(drm_crtc_enable_color_mgmt);
  180. /**
  181. * drm_mode_crtc_set_gamma_size - set the gamma table size
  182. * @crtc: CRTC to set the gamma table size for
  183. * @gamma_size: size of the gamma table
  184. *
  185. * Drivers which support gamma tables should set this to the supported gamma
  186. * table size when initializing the CRTC. Currently the drm core only supports a
  187. * fixed gamma table size.
  188. *
  189. * Returns:
  190. * Zero on success, negative errno on failure.
  191. */
  192. int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
  193. int gamma_size)
  194. {
  195. uint16_t *r_base, *g_base, *b_base;
  196. int i;
  197. crtc->gamma_size = gamma_size;
  198. crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3,
  199. GFP_KERNEL);
  200. if (!crtc->gamma_store) {
  201. crtc->gamma_size = 0;
  202. return -ENOMEM;
  203. }
  204. r_base = crtc->gamma_store;
  205. g_base = r_base + gamma_size;
  206. b_base = g_base + gamma_size;
  207. for (i = 0; i < gamma_size; i++) {
  208. r_base[i] = i << 8;
  209. g_base[i] = i << 8;
  210. b_base[i] = i << 8;
  211. }
  212. return 0;
  213. }
  214. EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
  215. /**
  216. * drm_mode_gamma_set_ioctl - set the gamma table
  217. * @dev: DRM device
  218. * @data: ioctl data
  219. * @file_priv: DRM file info
  220. *
  221. * Set the gamma table of a CRTC to the one passed in by the user. Userspace can
  222. * inquire the required gamma table size through drm_mode_gamma_get_ioctl.
  223. *
  224. * Called by the user via ioctl.
  225. *
  226. * Returns:
  227. * Zero on success, negative errno on failure.
  228. */
  229. int drm_mode_gamma_set_ioctl(struct drm_device *dev,
  230. void *data, struct drm_file *file_priv)
  231. {
  232. struct drm_mode_crtc_lut *crtc_lut = data;
  233. struct drm_crtc *crtc;
  234. void *r_base, *g_base, *b_base;
  235. int size;
  236. struct drm_modeset_acquire_ctx ctx;
  237. int ret = 0;
  238. if (!drm_core_check_feature(dev, DRIVER_MODESET))
  239. return -EOPNOTSUPP;
  240. crtc = drm_crtc_find(dev, file_priv, crtc_lut->crtc_id);
  241. if (!crtc)
  242. return -ENOENT;
  243. if (crtc->funcs->gamma_set == NULL)
  244. return -ENOSYS;
  245. /* memcpy into gamma store */
  246. if (crtc_lut->gamma_size != crtc->gamma_size)
  247. return -EINVAL;
  248. DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
  249. size = crtc_lut->gamma_size * (sizeof(uint16_t));
  250. r_base = crtc->gamma_store;
  251. if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) {
  252. ret = -EFAULT;
  253. goto out;
  254. }
  255. g_base = r_base + size;
  256. if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) {
  257. ret = -EFAULT;
  258. goto out;
  259. }
  260. b_base = g_base + size;
  261. if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) {
  262. ret = -EFAULT;
  263. goto out;
  264. }
  265. ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base,
  266. crtc->gamma_size, &ctx);
  267. out:
  268. DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
  269. return ret;
  270. }
  271. /**
  272. * drm_mode_gamma_get_ioctl - get the gamma table
  273. * @dev: DRM device
  274. * @data: ioctl data
  275. * @file_priv: DRM file info
  276. *
  277. * Copy the current gamma table into the storage provided. This also provides
  278. * the gamma table size the driver expects, which can be used to size the
  279. * allocated storage.
  280. *
  281. * Called by the user via ioctl.
  282. *
  283. * Returns:
  284. * Zero on success, negative errno on failure.
  285. */
  286. int drm_mode_gamma_get_ioctl(struct drm_device *dev,
  287. void *data, struct drm_file *file_priv)
  288. {
  289. struct drm_mode_crtc_lut *crtc_lut = data;
  290. struct drm_crtc *crtc;
  291. void *r_base, *g_base, *b_base;
  292. int size;
  293. int ret = 0;
  294. if (!drm_core_check_feature(dev, DRIVER_MODESET))
  295. return -EOPNOTSUPP;
  296. crtc = drm_crtc_find(dev, file_priv, crtc_lut->crtc_id);
  297. if (!crtc)
  298. return -ENOENT;
  299. /* memcpy into gamma store */
  300. if (crtc_lut->gamma_size != crtc->gamma_size)
  301. return -EINVAL;
  302. drm_modeset_lock(&crtc->mutex, NULL);
  303. size = crtc_lut->gamma_size * (sizeof(uint16_t));
  304. r_base = crtc->gamma_store;
  305. if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) {
  306. ret = -EFAULT;
  307. goto out;
  308. }
  309. g_base = r_base + size;
  310. if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) {
  311. ret = -EFAULT;
  312. goto out;
  313. }
  314. b_base = g_base + size;
  315. if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) {
  316. ret = -EFAULT;
  317. goto out;
  318. }
  319. out:
  320. drm_modeset_unlock(&crtc->mutex);
  321. return ret;
  322. }
  323. static const char * const color_encoding_name[] = {
  324. [DRM_COLOR_YCBCR_BT601] = "ITU-R BT.601 YCbCr",
  325. [DRM_COLOR_YCBCR_BT709] = "ITU-R BT.709 YCbCr",
  326. [DRM_COLOR_YCBCR_BT2020] = "ITU-R BT.2020 YCbCr",
  327. };
  328. static const char * const color_range_name[] = {
  329. [DRM_COLOR_YCBCR_FULL_RANGE] = "YCbCr full range",
  330. [DRM_COLOR_YCBCR_LIMITED_RANGE] = "YCbCr limited range",
  331. };
  332. /**
  333. * drm_get_color_encoding_name - return a string for color encoding
  334. * @encoding: color encoding to compute name of
  335. *
  336. * In contrast to the other drm_get_*_name functions this one here returns a
  337. * const pointer and hence is threadsafe.
  338. */
  339. const char *drm_get_color_encoding_name(enum drm_color_encoding encoding)
  340. {
  341. if (WARN_ON(encoding >= ARRAY_SIZE(color_encoding_name)))
  342. return "unknown";
  343. return color_encoding_name[encoding];
  344. }
  345. /**
  346. * drm_get_color_range_name - return a string for color range
  347. * @range: color range to compute name of
  348. *
  349. * In contrast to the other drm_get_*_name functions this one here returns a
  350. * const pointer and hence is threadsafe.
  351. */
  352. const char *drm_get_color_range_name(enum drm_color_range range)
  353. {
  354. if (WARN_ON(range >= ARRAY_SIZE(color_range_name)))
  355. return "unknown";
  356. return color_range_name[range];
  357. }
  358. /**
  359. * drm_plane_create_color_properties - color encoding related plane properties
  360. * @plane: plane object
  361. * @supported_encodings: bitfield indicating supported color encodings
  362. * @supported_ranges: bitfileld indicating supported color ranges
  363. * @default_encoding: default color encoding
  364. * @default_range: default color range
  365. *
  366. * Create and attach plane specific COLOR_ENCODING and COLOR_RANGE
  367. * properties to @plane. The supported encodings and ranges should
  368. * be provided in supported_encodings and supported_ranges bitmasks.
  369. * Each bit set in the bitmask indicates that its number as enum
  370. * value is supported.
  371. */
  372. int drm_plane_create_color_properties(struct drm_plane *plane,
  373. u32 supported_encodings,
  374. u32 supported_ranges,
  375. enum drm_color_encoding default_encoding,
  376. enum drm_color_range default_range)
  377. {
  378. struct drm_device *dev = plane->dev;
  379. struct drm_property *prop;
  380. struct drm_prop_enum_list enum_list[max_t(int, DRM_COLOR_ENCODING_MAX,
  381. DRM_COLOR_RANGE_MAX)];
  382. int i, len;
  383. if (WARN_ON(supported_encodings == 0 ||
  384. (supported_encodings & -BIT(DRM_COLOR_ENCODING_MAX)) != 0 ||
  385. (supported_encodings & BIT(default_encoding)) == 0))
  386. return -EINVAL;
  387. if (WARN_ON(supported_ranges == 0 ||
  388. (supported_ranges & -BIT(DRM_COLOR_RANGE_MAX)) != 0 ||
  389. (supported_ranges & BIT(default_range)) == 0))
  390. return -EINVAL;
  391. len = 0;
  392. for (i = 0; i < DRM_COLOR_ENCODING_MAX; i++) {
  393. if ((supported_encodings & BIT(i)) == 0)
  394. continue;
  395. enum_list[len].type = i;
  396. enum_list[len].name = color_encoding_name[i];
  397. len++;
  398. }
  399. prop = drm_property_create_enum(dev, 0, "COLOR_ENCODING",
  400. enum_list, len);
  401. if (!prop)
  402. return -ENOMEM;
  403. plane->color_encoding_property = prop;
  404. drm_object_attach_property(&plane->base, prop, default_encoding);
  405. if (plane->state)
  406. plane->state->color_encoding = default_encoding;
  407. len = 0;
  408. for (i = 0; i < DRM_COLOR_RANGE_MAX; i++) {
  409. if ((supported_ranges & BIT(i)) == 0)
  410. continue;
  411. enum_list[len].type = i;
  412. enum_list[len].name = color_range_name[i];
  413. len++;
  414. }
  415. prop = drm_property_create_enum(dev, 0, "COLOR_RANGE",
  416. enum_list, len);
  417. if (!prop)
  418. return -ENOMEM;
  419. plane->color_range_property = prop;
  420. drm_object_attach_property(&plane->base, prop, default_range);
  421. if (plane->state)
  422. plane->state->color_range = default_range;
  423. return 0;
  424. }
  425. EXPORT_SYMBOL(drm_plane_create_color_properties);
  426. /**
  427. * drm_color_lut_check - check validity of lookup table
  428. * @lut: property blob containing LUT to check
  429. * @tests: bitmask of tests to run
  430. *
  431. * Helper to check whether a userspace-provided lookup table is valid and
  432. * satisfies hardware requirements. Drivers pass a bitmask indicating which of
  433. * the tests in &drm_color_lut_tests should be performed.
  434. *
  435. * Returns 0 on success, -EINVAL on failure.
  436. */
  437. int drm_color_lut_check(const struct drm_property_blob *lut, u32 tests)
  438. {
  439. const struct drm_color_lut *entry;
  440. int i;
  441. if (!lut || !tests)
  442. return 0;
  443. entry = lut->data;
  444. for (i = 0; i < drm_color_lut_size(lut); i++) {
  445. if (tests & DRM_COLOR_LUT_EQUAL_CHANNELS) {
  446. if (entry[i].red != entry[i].blue ||
  447. entry[i].red != entry[i].green) {
  448. DRM_DEBUG_KMS("All LUT entries must have equal r/g/b\n");
  449. return -EINVAL;
  450. }
  451. }
  452. if (i > 0 && tests & DRM_COLOR_LUT_NON_DECREASING) {
  453. if (entry[i].red < entry[i - 1].red ||
  454. entry[i].green < entry[i - 1].green ||
  455. entry[i].blue < entry[i - 1].blue) {
  456. DRM_DEBUG_KMS("LUT entries must never decrease.\n");
  457. return -EINVAL;
  458. }
  459. }
  460. }
  461. return 0;
  462. }
  463. EXPORT_SYMBOL(drm_color_lut_check);