tinydrm-helpers.c 11 KB

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