tinydrm-helpers.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. /*
  2. * Copyright (C) 2016 Noralf Trønnes
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. */
  9. #include <linux/backlight.h>
  10. #include <linux/dma-buf.h>
  11. #include <linux/pm.h>
  12. #include <linux/spi/spi.h>
  13. #include <linux/swab.h>
  14. #include <drm/tinydrm/tinydrm.h>
  15. #include <drm/tinydrm/tinydrm-helpers.h>
  16. static unsigned int spi_max;
  17. module_param(spi_max, uint, 0400);
  18. MODULE_PARM_DESC(spi_max, "Set a lower SPI max transfer size");
  19. /**
  20. * tinydrm_merge_clips - Merge clip rectangles
  21. * @dst: Destination clip rectangle
  22. * @src: Source clip rectangle(s)
  23. * @num_clips: Number of @src clip rectangles
  24. * @flags: Dirty fb ioctl flags
  25. * @max_width: Maximum width of @dst
  26. * @max_height: Maximum height of @dst
  27. *
  28. * This function merges @src clip rectangle(s) into @dst. If @src is NULL,
  29. * @max_width and @min_width is used to set a full @dst clip rectangle.
  30. *
  31. * Returns:
  32. * true if it's a full clip, false otherwise
  33. */
  34. bool tinydrm_merge_clips(struct drm_clip_rect *dst,
  35. struct drm_clip_rect *src, unsigned int num_clips,
  36. unsigned int flags, u32 max_width, u32 max_height)
  37. {
  38. unsigned int i;
  39. if (!src || !num_clips) {
  40. dst->x1 = 0;
  41. dst->x2 = max_width;
  42. dst->y1 = 0;
  43. dst->y2 = max_height;
  44. return true;
  45. }
  46. dst->x1 = ~0;
  47. dst->y1 = ~0;
  48. dst->x2 = 0;
  49. dst->y2 = 0;
  50. for (i = 0; i < num_clips; i++) {
  51. if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY)
  52. i++;
  53. dst->x1 = min(dst->x1, src[i].x1);
  54. dst->x2 = max(dst->x2, src[i].x2);
  55. dst->y1 = min(dst->y1, src[i].y1);
  56. dst->y2 = max(dst->y2, src[i].y2);
  57. }
  58. if (dst->x2 > max_width || dst->y2 > max_height ||
  59. dst->x1 >= dst->x2 || dst->y1 >= dst->y2) {
  60. DRM_DEBUG_KMS("Illegal clip: x1=%u, x2=%u, y1=%u, y2=%u\n",
  61. dst->x1, dst->x2, dst->y1, dst->y2);
  62. dst->x1 = 0;
  63. dst->y1 = 0;
  64. dst->x2 = max_width;
  65. dst->y2 = max_height;
  66. }
  67. return (dst->x2 - dst->x1) == max_width &&
  68. (dst->y2 - dst->y1) == max_height;
  69. }
  70. EXPORT_SYMBOL(tinydrm_merge_clips);
  71. /**
  72. * tinydrm_memcpy - Copy clip buffer
  73. * @dst: Destination buffer
  74. * @vaddr: Source buffer
  75. * @fb: DRM framebuffer
  76. * @clip: Clip rectangle area to copy
  77. */
  78. void tinydrm_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb,
  79. struct drm_clip_rect *clip)
  80. {
  81. unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0);
  82. unsigned int pitch = fb->pitches[0];
  83. void *src = vaddr + (clip->y1 * pitch) + (clip->x1 * cpp);
  84. size_t len = (clip->x2 - clip->x1) * cpp;
  85. unsigned int y;
  86. for (y = clip->y1; y < clip->y2; y++) {
  87. memcpy(dst, src, len);
  88. src += pitch;
  89. dst += len;
  90. }
  91. }
  92. EXPORT_SYMBOL(tinydrm_memcpy);
  93. /**
  94. * tinydrm_swab16 - Swap bytes into clip buffer
  95. * @dst: RGB565 destination buffer
  96. * @vaddr: RGB565 source buffer
  97. * @fb: DRM framebuffer
  98. * @clip: Clip rectangle area to copy
  99. */
  100. void tinydrm_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb,
  101. struct drm_clip_rect *clip)
  102. {
  103. size_t len = (clip->x2 - clip->x1) * sizeof(u16);
  104. unsigned int x, y;
  105. u16 *src, *buf;
  106. /*
  107. * The cma memory is write-combined so reads are uncached.
  108. * Speed up by fetching one line at a time.
  109. */
  110. buf = kmalloc(len, GFP_KERNEL);
  111. if (!buf)
  112. return;
  113. for (y = clip->y1; y < clip->y2; y++) {
  114. src = vaddr + (y * fb->pitches[0]);
  115. src += clip->x1;
  116. memcpy(buf, src, len);
  117. src = buf;
  118. for (x = clip->x1; x < clip->x2; x++)
  119. *dst++ = swab16(*src++);
  120. }
  121. kfree(buf);
  122. }
  123. EXPORT_SYMBOL(tinydrm_swab16);
  124. /**
  125. * tinydrm_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer
  126. * @dst: RGB565 destination buffer
  127. * @vaddr: XRGB8888 source buffer
  128. * @fb: DRM framebuffer
  129. * @clip: Clip rectangle area to copy
  130. * @swap: Swap bytes
  131. *
  132. * Drivers can use this function for RGB565 devices that don't natively
  133. * support XRGB8888.
  134. */
  135. void tinydrm_xrgb8888_to_rgb565(u16 *dst, void *vaddr,
  136. struct drm_framebuffer *fb,
  137. struct drm_clip_rect *clip, bool swap)
  138. {
  139. size_t len = (clip->x2 - clip->x1) * sizeof(u32);
  140. unsigned int x, y;
  141. u32 *src, *buf;
  142. u16 val16;
  143. buf = kmalloc(len, GFP_KERNEL);
  144. if (!buf)
  145. return;
  146. for (y = clip->y1; y < clip->y2; y++) {
  147. src = vaddr + (y * fb->pitches[0]);
  148. src += clip->x1;
  149. memcpy(buf, src, len);
  150. src = buf;
  151. for (x = clip->x1; x < clip->x2; x++) {
  152. val16 = ((*src & 0x00F80000) >> 8) |
  153. ((*src & 0x0000FC00) >> 5) |
  154. ((*src & 0x000000F8) >> 3);
  155. src++;
  156. if (swap)
  157. *dst++ = swab16(val16);
  158. else
  159. *dst++ = val16;
  160. }
  161. }
  162. kfree(buf);
  163. }
  164. EXPORT_SYMBOL(tinydrm_xrgb8888_to_rgb565);
  165. /**
  166. * tinydrm_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale
  167. * @dst: 8-bit grayscale destination buffer
  168. * @vaddr: XRGB8888 source buffer
  169. * @fb: DRM framebuffer
  170. * @clip: Clip rectangle area to copy
  171. *
  172. * Drm doesn't have native monochrome or grayscale support.
  173. * Such drivers can announce the commonly supported XR24 format to userspace
  174. * and use this function to convert to the native format.
  175. *
  176. * Monochrome drivers will use the most significant bit,
  177. * where 1 means foreground color and 0 background color.
  178. *
  179. * ITU BT.601 is used for the RGB -> luma (brightness) conversion.
  180. */
  181. void tinydrm_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
  182. struct drm_clip_rect *clip)
  183. {
  184. unsigned int len = (clip->x2 - clip->x1) * sizeof(u32);
  185. unsigned int x, y;
  186. void *buf;
  187. u32 *src;
  188. if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888))
  189. return;
  190. /*
  191. * The cma memory is write-combined so reads are uncached.
  192. * Speed up by fetching one line at a time.
  193. */
  194. buf = kmalloc(len, GFP_KERNEL);
  195. if (!buf)
  196. return;
  197. for (y = clip->y1; y < clip->y2; y++) {
  198. src = vaddr + (y * fb->pitches[0]);
  199. src += clip->x1;
  200. memcpy(buf, src, len);
  201. src = buf;
  202. for (x = clip->x1; x < clip->x2; x++) {
  203. u8 r = (*src & 0x00ff0000) >> 16;
  204. u8 g = (*src & 0x0000ff00) >> 8;
  205. u8 b = *src & 0x000000ff;
  206. /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
  207. *dst++ = (3 * r + 6 * g + b) / 10;
  208. src++;
  209. }
  210. }
  211. kfree(buf);
  212. }
  213. EXPORT_SYMBOL(tinydrm_xrgb8888_to_gray8);
  214. /**
  215. * tinydrm_of_find_backlight - Find backlight device in device-tree
  216. * @dev: Device
  217. *
  218. * This function looks for a DT node pointed to by a property named 'backlight'
  219. * and uses of_find_backlight_by_node() to get the backlight device.
  220. * Additionally if the brightness property is zero, it is set to
  221. * max_brightness.
  222. *
  223. * Returns:
  224. * NULL if there's no backlight property.
  225. * Error pointer -EPROBE_DEFER if the DT node is found, but no backlight device
  226. * is found.
  227. * If the backlight device is found, a pointer to the structure is returned.
  228. */
  229. struct backlight_device *tinydrm_of_find_backlight(struct device *dev)
  230. {
  231. struct backlight_device *backlight;
  232. struct device_node *np;
  233. np = of_parse_phandle(dev->of_node, "backlight", 0);
  234. if (!np)
  235. return NULL;
  236. backlight = of_find_backlight_by_node(np);
  237. of_node_put(np);
  238. if (!backlight)
  239. return ERR_PTR(-EPROBE_DEFER);
  240. if (!backlight->props.brightness) {
  241. backlight->props.brightness = backlight->props.max_brightness;
  242. DRM_DEBUG_KMS("Backlight brightness set to %d\n",
  243. backlight->props.brightness);
  244. }
  245. return backlight;
  246. }
  247. EXPORT_SYMBOL(tinydrm_of_find_backlight);
  248. /**
  249. * tinydrm_enable_backlight - Enable backlight helper
  250. * @backlight: Backlight device
  251. *
  252. * Returns:
  253. * Zero on success, negative error code on failure.
  254. */
  255. int tinydrm_enable_backlight(struct backlight_device *backlight)
  256. {
  257. unsigned int old_state;
  258. int ret;
  259. if (!backlight)
  260. return 0;
  261. old_state = backlight->props.state;
  262. backlight->props.state &= ~BL_CORE_FBBLANK;
  263. DRM_DEBUG_KMS("Backlight state: 0x%x -> 0x%x\n", old_state,
  264. backlight->props.state);
  265. ret = backlight_update_status(backlight);
  266. if (ret)
  267. DRM_ERROR("Failed to enable backlight %d\n", ret);
  268. return ret;
  269. }
  270. EXPORT_SYMBOL(tinydrm_enable_backlight);
  271. /**
  272. * tinydrm_disable_backlight - Disable backlight helper
  273. * @backlight: Backlight device
  274. *
  275. * Returns:
  276. * Zero on success, negative error code on failure.
  277. */
  278. int tinydrm_disable_backlight(struct backlight_device *backlight)
  279. {
  280. unsigned int old_state;
  281. int ret;
  282. if (!backlight)
  283. return 0;
  284. old_state = backlight->props.state;
  285. backlight->props.state |= BL_CORE_FBBLANK;
  286. DRM_DEBUG_KMS("Backlight state: 0x%x -> 0x%x\n", old_state,
  287. backlight->props.state);
  288. ret = backlight_update_status(backlight);
  289. if (ret)
  290. DRM_ERROR("Failed to disable backlight %d\n", ret);
  291. return ret;
  292. }
  293. EXPORT_SYMBOL(tinydrm_disable_backlight);
  294. #if IS_ENABLED(CONFIG_SPI)
  295. /**
  296. * tinydrm_spi_max_transfer_size - Determine max SPI transfer size
  297. * @spi: SPI device
  298. * @max_len: Maximum buffer size needed (optional)
  299. *
  300. * This function returns the maximum size to use for SPI transfers. It checks
  301. * the SPI master, the optional @max_len and the module parameter spi_max and
  302. * returns the smallest.
  303. *
  304. * Returns:
  305. * Maximum size for SPI transfers
  306. */
  307. size_t tinydrm_spi_max_transfer_size(struct spi_device *spi, size_t max_len)
  308. {
  309. size_t ret;
  310. ret = min(spi_max_transfer_size(spi), spi->master->max_dma_len);
  311. if (max_len)
  312. ret = min(ret, max_len);
  313. if (spi_max)
  314. ret = min_t(size_t, ret, spi_max);
  315. ret &= ~0x3;
  316. if (ret < 4)
  317. ret = 4;
  318. return ret;
  319. }
  320. EXPORT_SYMBOL(tinydrm_spi_max_transfer_size);
  321. /**
  322. * tinydrm_spi_bpw_supported - Check if bits per word is supported
  323. * @spi: SPI device
  324. * @bpw: Bits per word
  325. *
  326. * This function checks to see if the SPI master driver supports @bpw.
  327. *
  328. * Returns:
  329. * True if @bpw is supported, false otherwise.
  330. */
  331. bool tinydrm_spi_bpw_supported(struct spi_device *spi, u8 bpw)
  332. {
  333. u32 bpw_mask = spi->master->bits_per_word_mask;
  334. if (bpw == 8)
  335. return true;
  336. if (!bpw_mask) {
  337. dev_warn_once(&spi->dev,
  338. "bits_per_word_mask not set, assume 8-bit only\n");
  339. return false;
  340. }
  341. if (bpw_mask & SPI_BPW_MASK(bpw))
  342. return true;
  343. return false;
  344. }
  345. EXPORT_SYMBOL(tinydrm_spi_bpw_supported);
  346. static void
  347. tinydrm_dbg_spi_print(struct spi_device *spi, struct spi_transfer *tr,
  348. const void *buf, int idx, bool tx)
  349. {
  350. u32 speed_hz = tr->speed_hz ? tr->speed_hz : spi->max_speed_hz;
  351. char linebuf[3 * 32];
  352. hex_dump_to_buffer(buf, tr->len, 16,
  353. DIV_ROUND_UP(tr->bits_per_word, 8),
  354. linebuf, sizeof(linebuf), false);
  355. printk(KERN_DEBUG
  356. " tr(%i): speed=%u%s, bpw=%i, len=%u, %s_buf=[%s%s]\n", idx,
  357. speed_hz > 1000000 ? speed_hz / 1000000 : speed_hz / 1000,
  358. speed_hz > 1000000 ? "MHz" : "kHz", tr->bits_per_word, tr->len,
  359. tx ? "tx" : "rx", linebuf, tr->len > 16 ? " ..." : "");
  360. }
  361. /* called through tinydrm_dbg_spi_message() */
  362. void _tinydrm_dbg_spi_message(struct spi_device *spi, struct spi_message *m)
  363. {
  364. struct spi_transfer *tmp;
  365. int i = 0;
  366. list_for_each_entry(tmp, &m->transfers, transfer_list) {
  367. if (tmp->tx_buf)
  368. tinydrm_dbg_spi_print(spi, tmp, tmp->tx_buf, i, true);
  369. if (tmp->rx_buf)
  370. tinydrm_dbg_spi_print(spi, tmp, tmp->rx_buf, i, false);
  371. i++;
  372. }
  373. }
  374. EXPORT_SYMBOL(_tinydrm_dbg_spi_message);
  375. /**
  376. * tinydrm_spi_transfer - SPI transfer helper
  377. * @spi: SPI device
  378. * @speed_hz: Override speed (optional)
  379. * @header: Optional header transfer
  380. * @bpw: Bits per word
  381. * @buf: Buffer to transfer
  382. * @len: Buffer length
  383. *
  384. * This SPI transfer helper breaks up the transfer of @buf into chunks which
  385. * the SPI master driver can handle. If the machine is Little Endian and the
  386. * SPI master driver doesn't support 16 bits per word, it swaps the bytes and
  387. * does a 8-bit transfer.
  388. * If @header is set, it is prepended to each SPI message.
  389. *
  390. * Returns:
  391. * Zero on success, negative error code on failure.
  392. */
  393. int tinydrm_spi_transfer(struct spi_device *spi, u32 speed_hz,
  394. struct spi_transfer *header, u8 bpw, const void *buf,
  395. size_t len)
  396. {
  397. struct spi_transfer tr = {
  398. .bits_per_word = bpw,
  399. .speed_hz = speed_hz,
  400. };
  401. struct spi_message m;
  402. u16 *swap_buf = NULL;
  403. size_t max_chunk;
  404. size_t chunk;
  405. int ret = 0;
  406. if (WARN_ON_ONCE(bpw != 8 && bpw != 16))
  407. return -EINVAL;
  408. max_chunk = tinydrm_spi_max_transfer_size(spi, 0);
  409. if (drm_debug & DRM_UT_DRIVER)
  410. pr_debug("[drm:%s] bpw=%u, max_chunk=%zu, transfers:\n",
  411. __func__, bpw, max_chunk);
  412. if (bpw == 16 && !tinydrm_spi_bpw_supported(spi, 16)) {
  413. tr.bits_per_word = 8;
  414. if (tinydrm_machine_little_endian()) {
  415. swap_buf = kmalloc(min(len, max_chunk), GFP_KERNEL);
  416. if (!swap_buf)
  417. return -ENOMEM;
  418. }
  419. }
  420. spi_message_init(&m);
  421. if (header)
  422. spi_message_add_tail(header, &m);
  423. spi_message_add_tail(&tr, &m);
  424. while (len) {
  425. chunk = min(len, max_chunk);
  426. tr.tx_buf = buf;
  427. tr.len = chunk;
  428. if (swap_buf) {
  429. const u16 *buf16 = buf;
  430. unsigned int i;
  431. for (i = 0; i < chunk / 2; i++)
  432. swap_buf[i] = swab16(buf16[i]);
  433. tr.tx_buf = swap_buf;
  434. }
  435. buf += chunk;
  436. len -= chunk;
  437. tinydrm_dbg_spi_message(spi, &m);
  438. ret = spi_sync(spi, &m);
  439. if (ret)
  440. return ret;
  441. }
  442. return 0;
  443. }
  444. EXPORT_SYMBOL(tinydrm_spi_transfer);
  445. #endif /* CONFIG_SPI */