You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

408 lines
11 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * DRM driver for ST7789V panels with flexible config
  4. *
  5. * Copyright 2019 Limor Fried
  6. * Copyright 2016 Noralf Trønnes
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. */
  13. #include <linux/backlight.h>
  14. #include <linux/delay.h>
  15. #include <linux/gpio/consumer.h>
  16. #include <linux/module.h>
  17. #include <linux/property.h>
  18. #include <linux/regulator/consumer.h>
  19. #include <linux/spi/spi.h>
  20. #include <drm/drm_atomic_helper.h>
  21. #include <drm/drm_damage_helper.h>
  22. #include <drm/drm_drv.h>
  23. #include <drm/drm_fb_cma_helper.h>
  24. #include <drm/drm_fb_helper.h>
  25. #include <drm/drm_fourcc.h>
  26. #include <drm/drm_gem_cma_helper.h>
  27. #include <drm/drm_gem_framebuffer_helper.h>
  28. #include <drm/drm_mipi_dbi.h>
  29. #include <drm/drm_rect.h>
  30. #include <drm/drm_vblank.h>
  31. #include <drm/drm_modeset_helper.h>
  32. #include <video/mipi_display.h>
  33. #define ST77XX_MADCTL_MY 0x80
  34. #define ST77XX_MADCTL_MX 0x40
  35. #define ST77XX_MADCTL_MV 0x20
  36. #define ST77XX_MADCTL_ML 0x10
  37. #define ST77XX_MADCTL_BGR 0x08
  38. #define ST77XX_MADCTL_RGB 0x00
  39. static u32 col_offset = 0;
  40. static u32 row_offset = 0;
  41. static u8 col_hack_fix_offset = 0;
  42. static short x_offset = 0;
  43. static short y_offset = 0;
  44. static void st7789vada_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
  45. {
  46. struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
  47. struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(fb->dev);
  48. unsigned int height = rect->y2 - rect->y1;
  49. unsigned int width = rect->x2 - rect->x1;
  50. struct mipi_dbi *dbi = &dbidev->dbi;
  51. bool swap = dbi->swap_bytes;
  52. u16 x1, x2, y1, y2;
  53. int idx, ret = 0;
  54. bool full;
  55. void *tr;
  56. if (!dbidev->enabled)
  57. return;
  58. if (!drm_dev_enter(fb->dev, &idx))
  59. return;
  60. full = width == fb->width && height == fb->height;
  61. DRM_DEBUG_KMS("Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect));
  62. if (!dbi->dc || !full || swap ||
  63. fb->format->format == DRM_FORMAT_XRGB8888) {
  64. tr = dbidev->tx_buf;
  65. ret = mipi_dbi_buf_copy(dbidev->tx_buf, fb, rect, swap);
  66. if (ret)
  67. goto err_msg;
  68. } else {
  69. tr = cma_obj->vaddr;
  70. }
  71. x1 = rect->x1 + x_offset;
  72. x2 = rect->x2 - 1 + x_offset;
  73. y1 = rect->y1 + y_offset;
  74. y2 = rect->y2 - 1 + y_offset;
  75. //printk(KERN_INFO "setaddrwin (%d, %d) -> (%d, %d) offsets: %d & %d \n", x1, y1, x2, y2, x_offset, y_offset);
  76. mipi_dbi_command(dbi, MIPI_DCS_SET_COLUMN_ADDRESS,
  77. (x1 >> 8) & 0xFF, x1 & 0xFF,
  78. (x2 >> 8) & 0xFF, x2 & 0xFF);
  79. mipi_dbi_command(dbi, MIPI_DCS_SET_PAGE_ADDRESS,
  80. (y1 >> 8) & 0xFF, y1 & 0xFF,
  81. (y2 >> 8) & 0xFF, y2 & 0xFF);
  82. ret = mipi_dbi_command_buf(dbi, MIPI_DCS_WRITE_MEMORY_START, tr,
  83. width*height * 2);
  84. err_msg:
  85. if (ret)
  86. dev_err_once(fb->dev->dev, "Failed to update display %d\n", ret);
  87. drm_dev_exit(idx);
  88. }
  89. static void st7789vada_pipe_update(struct drm_simple_display_pipe *pipe,
  90. struct drm_plane_state *old_state)
  91. {
  92. struct drm_plane_state *state = pipe->plane.state;
  93. struct drm_crtc *crtc = &pipe->crtc;
  94. struct drm_rect rect;
  95. if (drm_atomic_helper_damage_merged(old_state, state, &rect))
  96. st7789vada_fb_dirty(state->fb, &rect);
  97. if (crtc->state->event) {
  98. spin_lock_irq(&crtc->dev->event_lock);
  99. drm_crtc_send_vblank_event(crtc, crtc->state->event);
  100. spin_unlock_irq(&crtc->dev->event_lock);
  101. crtc->state->event = NULL;
  102. }
  103. }
  104. static struct drm_display_mode st7789vada_mode = {
  105. DRM_SIMPLE_MODE(240, 320, 58, 43),
  106. };
  107. DEFINE_DRM_GEM_CMA_FOPS(st7789vada_fops);
  108. static struct drm_driver st7789vada_driver = {
  109. .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
  110. .fops = &st7789vada_fops,
  111. .release = mipi_dbi_release,
  112. DRM_GEM_CMA_VMAP_DRIVER_OPS,
  113. .debugfs_init = mipi_dbi_debugfs_init,
  114. .name = "st7789vada",
  115. .desc = "ST7789V Adafruit",
  116. .date = "20200727",
  117. .major = 1,
  118. .minor = 0,
  119. };
  120. static const struct of_device_id st7789vada_of_match[] = {
  121. { .compatible = "multi-inno,mi0283qt" },
  122. {},
  123. };
  124. MODULE_DEVICE_TABLE(of, st7789vada_of_match);
  125. static const struct spi_device_id st7789vada_id[] = {
  126. { "st7789vada", 0 },
  127. { },
  128. };
  129. MODULE_DEVICE_TABLE(spi, st7789vada_id);
  130. static void st7789vada_enable(struct drm_simple_display_pipe *pipe,
  131. struct drm_crtc_state *crtc_state,
  132. struct drm_plane_state *plane_state)
  133. {
  134. struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
  135. struct mipi_dbi *dbi = &dbidev->dbi;
  136. u8 addr_mode;
  137. u16 width = st7789vada_mode.htotal;
  138. u16 height = st7789vada_mode.vtotal;
  139. int ret, idx;
  140. //printk(KERN_INFO "w/h %d %d\n", width, height);
  141. if (!drm_dev_enter(pipe->crtc.dev, &idx))
  142. return;
  143. DRM_DEBUG_KMS("\n");
  144. ret = mipi_dbi_poweron_conditional_reset(dbidev);
  145. if (ret < 0)
  146. goto out_exit;
  147. if (ret == 1)
  148. goto out_enable;
  149. mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF);
  150. mipi_dbi_command(dbi, MIPI_DCS_SOFT_RESET);
  151. msleep(150);
  152. mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
  153. msleep(10);
  154. mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, 0x55); // 16 bit color
  155. msleep(10);
  156. mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, 0);
  157. mipi_dbi_command(dbi, MIPI_DCS_SET_COLUMN_ADDRESS, 0, 0, 0, 240);
  158. mipi_dbi_command(dbi, MIPI_DCS_SET_PAGE_ADDRESS, 0, 0, 320>>8, 320&0xFF);
  159. mipi_dbi_command(dbi, MIPI_DCS_ENTER_INVERT_MODE); // odd hack, displays are inverted
  160. mipi_dbi_command(dbi, MIPI_DCS_ENTER_NORMAL_MODE);
  161. msleep(10);
  162. mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
  163. msleep(10);
  164. out_enable:
  165. /* The PiTFT has a hardware reset circuit that
  166. * resets only on power-on and not on each reboot through
  167. * a gpio like the rpi-display does.
  168. * As a result, we need to always apply the rotation value
  169. * regardless of the display "on/off" state.
  170. */
  171. switch (dbidev->rotation) {
  172. default:
  173. addr_mode = 0;
  174. x_offset = col_offset;
  175. y_offset = row_offset;
  176. break;
  177. case 90:
  178. addr_mode = ST77XX_MADCTL_MV | ST77XX_MADCTL_MX;
  179. x_offset = row_offset;
  180. y_offset = col_offset;
  181. break;
  182. case 180:
  183. addr_mode = ST77XX_MADCTL_MX | ST77XX_MADCTL_MY;
  184. x_offset = (240 - width) - col_offset + col_hack_fix_offset;
  185. // hack tweak to account for extra pixel width to make even
  186. y_offset = (320 - height) - row_offset;
  187. break;
  188. case 270:
  189. addr_mode = ST77XX_MADCTL_MV | ST77XX_MADCTL_MY;
  190. x_offset = (320 - height) - row_offset;
  191. y_offset = (240 - width) - col_offset;
  192. break;
  193. }
  194. //printk(KERN_INFO "Rotation offsets %d %d\n", x_offset, y_offset);
  195. mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
  196. mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
  197. mipi_dbi_enable_flush(dbidev, crtc_state, plane_state);
  198. out_exit:
  199. drm_dev_exit(idx);
  200. }
  201. static const struct drm_simple_display_pipe_funcs st7789vada_pipe_funcs = {
  202. .enable = st7789vada_enable,
  203. .disable = mipi_dbi_pipe_disable,
  204. .update = st7789vada_pipe_update,
  205. .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
  206. };
  207. static int st7789vada_probe(struct spi_device *spi)
  208. {
  209. struct device *dev = &spi->dev;
  210. struct mipi_dbi_dev *dbidev;
  211. struct drm_device *drm;
  212. struct mipi_dbi *dbi;
  213. struct gpio_desc *dc;
  214. u32 rotation = 0;
  215. u32 width = 240;
  216. u32 height = 320;
  217. int ret;
  218. dbidev = kzalloc(sizeof(*dbidev), GFP_KERNEL);
  219. if (!dbidev)
  220. return -ENOMEM;
  221. //printk(KERN_INFO "ST7789 fake driver\n");
  222. dbi = &dbidev->dbi;
  223. drm = &dbidev->drm;
  224. ret = devm_drm_dev_init(dev, drm, &st7789vada_driver);
  225. if (ret) {
  226. kfree(dbidev);
  227. return ret;
  228. }
  229. drm_mode_config_init(drm);
  230. dbi->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
  231. if (IS_ERR(dbi->reset)) {
  232. DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n");
  233. return PTR_ERR(dbi->reset);
  234. }
  235. dc = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW);
  236. if (IS_ERR(dc)) {
  237. DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n");
  238. return PTR_ERR(dc);
  239. }
  240. dbidev->regulator = devm_regulator_get(dev, "power");
  241. if (IS_ERR(dbidev->regulator))
  242. return PTR_ERR(dbidev->regulator);
  243. dbidev->backlight = devm_of_find_backlight(dev);
  244. if (IS_ERR(dbidev->backlight))
  245. return PTR_ERR(dbidev->backlight);
  246. device_property_read_u32(dev, "rotation", &rotation);
  247. //printk(KERN_INFO "Rotation %d\n", rotation);
  248. device_property_read_u32(dev, "width", &width);
  249. if (width % 2) {
  250. width +=1; // odd width will cause a kernel panic
  251. col_hack_fix_offset = 3;
  252. } else {
  253. col_hack_fix_offset = 0;
  254. }
  255. //printk(KERN_INFO "Width %d\n", width);
  256. if ((width == 0) || (width > 240)) {
  257. width = 240; // default to full framebuff;
  258. }
  259. device_property_read_u32(dev, "height", &height);
  260. //printk(KERN_INFO "Height %d\n", height);
  261. if ((height == 0) || (height > 320)) {
  262. height = 320; // default to full framebuff;
  263. }
  264. st7789vada_mode.hdisplay = st7789vada_mode.hsync_start =
  265. st7789vada_mode.hsync_end = st7789vada_mode.htotal = width;
  266. st7789vada_mode.vdisplay = st7789vada_mode.vsync_start =
  267. st7789vada_mode.vsync_end = st7789vada_mode.vtotal = height;
  268. device_property_read_u32(dev, "col_offset", &col_offset);
  269. //printk(KERN_INFO "Column offset %d\n", col_offset);
  270. device_property_read_u32(dev, "row_offset", &row_offset);
  271. //printk(KERN_INFO "Row offset %d\n", row_offset);
  272. ret = mipi_dbi_spi_init(spi, dbi, dc);
  273. if (ret)
  274. return ret;
  275. /* Cannot read from this controller via SPI */
  276. dbi->read_commands = NULL;
  277. ret = mipi_dbi_dev_init(dbidev, &st7789vada_pipe_funcs, &st7789vada_mode, rotation);
  278. if (ret)
  279. return ret;
  280. drm_mode_config_reset(drm);
  281. ret = drm_dev_register(drm, 0);
  282. if (ret)
  283. return ret;
  284. spi_set_drvdata(spi, drm);
  285. drm_fbdev_generic_setup(drm, 0);
  286. return 0;
  287. }
  288. static int st7789vada_remove(struct spi_device *spi)
  289. {
  290. struct drm_device *drm = spi_get_drvdata(spi);
  291. drm_dev_unplug(drm);
  292. drm_atomic_helper_shutdown(drm);
  293. return 0;
  294. }
  295. static void st7789vada_shutdown(struct spi_device *spi)
  296. {
  297. drm_atomic_helper_shutdown(spi_get_drvdata(spi));
  298. }
  299. static int __maybe_unused st7789vada_pm_suspend(struct device *dev)
  300. {
  301. return drm_mode_config_helper_suspend(dev_get_drvdata(dev));
  302. }
  303. static int __maybe_unused st7789vada_pm_resume(struct device *dev)
  304. {
  305. drm_mode_config_helper_resume(dev_get_drvdata(dev));
  306. return 0;
  307. }
  308. static const struct dev_pm_ops st7789vada_pm_ops = {
  309. SET_SYSTEM_SLEEP_PM_OPS(st7789vada_pm_suspend, st7789vada_pm_resume)
  310. };
  311. static struct spi_driver st7789vada_spi_driver = {
  312. .driver = {
  313. .name = "st7789vada",
  314. .owner = THIS_MODULE,
  315. .of_match_table = st7789vada_of_match,
  316. .pm = &st7789vada_pm_ops,
  317. },
  318. .id_table = st7789vada_id,
  319. .probe = st7789vada_probe,
  320. .remove = st7789vada_remove,
  321. .shutdown = st7789vada_shutdown,
  322. };
  323. module_spi_driver(st7789vada_spi_driver);
  324. MODULE_DESCRIPTION("Sitronix ST7789V Flexible DRM driver");
  325. MODULE_AUTHOR("Noralf Trønnes + Limor Fried");
  326. MODULE_LICENSE("GPL");