sun4i_backend.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. /*
  2. * Copyright (C) 2015 Free Electrons
  3. * Copyright (C) 2015 NextThing Co
  4. *
  5. * Maxime Ripard <maxime.ripard@free-electrons.com>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. */
  12. #include <drm/drmP.h>
  13. #include <drm/drm_atomic_helper.h>
  14. #include <drm/drm_crtc.h>
  15. #include <drm/drm_crtc_helper.h>
  16. #include <drm/drm_fb_cma_helper.h>
  17. #include <drm/drm_gem_cma_helper.h>
  18. #include <drm/drm_plane_helper.h>
  19. #include <linux/component.h>
  20. #include <linux/reset.h>
  21. #include "sun4i_backend.h"
  22. #include "sun4i_drv.h"
  23. static u32 sunxi_rgb2yuv_coef[12] = {
  24. 0x00000107, 0x00000204, 0x00000064, 0x00000108,
  25. 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
  26. 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
  27. };
  28. void sun4i_backend_apply_color_correction(struct sun4i_backend *backend)
  29. {
  30. int i;
  31. DRM_DEBUG_DRIVER("Applying RGB to YUV color correction\n");
  32. /* Set color correction */
  33. regmap_write(backend->regs, SUN4I_BACKEND_OCCTL_REG,
  34. SUN4I_BACKEND_OCCTL_ENABLE);
  35. for (i = 0; i < 12; i++)
  36. regmap_write(backend->regs, SUN4I_BACKEND_OCRCOEF_REG(i),
  37. sunxi_rgb2yuv_coef[i]);
  38. }
  39. EXPORT_SYMBOL(sun4i_backend_apply_color_correction);
  40. void sun4i_backend_disable_color_correction(struct sun4i_backend *backend)
  41. {
  42. DRM_DEBUG_DRIVER("Disabling color correction\n");
  43. /* Disable color correction */
  44. regmap_update_bits(backend->regs, SUN4I_BACKEND_OCCTL_REG,
  45. SUN4I_BACKEND_OCCTL_ENABLE, 0);
  46. }
  47. EXPORT_SYMBOL(sun4i_backend_disable_color_correction);
  48. void sun4i_backend_commit(struct sun4i_backend *backend)
  49. {
  50. DRM_DEBUG_DRIVER("Committing changes\n");
  51. regmap_write(backend->regs, SUN4I_BACKEND_REGBUFFCTL_REG,
  52. SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS |
  53. SUN4I_BACKEND_REGBUFFCTL_LOADCTL);
  54. }
  55. EXPORT_SYMBOL(sun4i_backend_commit);
  56. void sun4i_backend_layer_enable(struct sun4i_backend *backend,
  57. int layer, bool enable)
  58. {
  59. u32 val;
  60. DRM_DEBUG_DRIVER("Enabling layer %d\n", layer);
  61. if (enable)
  62. val = SUN4I_BACKEND_MODCTL_LAY_EN(layer);
  63. else
  64. val = 0;
  65. regmap_update_bits(backend->regs, SUN4I_BACKEND_MODCTL_REG,
  66. SUN4I_BACKEND_MODCTL_LAY_EN(layer), val);
  67. }
  68. EXPORT_SYMBOL(sun4i_backend_layer_enable);
  69. static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane,
  70. u32 format, u32 *mode)
  71. {
  72. if ((plane->type == DRM_PLANE_TYPE_PRIMARY) &&
  73. (format == DRM_FORMAT_ARGB8888))
  74. format = DRM_FORMAT_XRGB8888;
  75. switch (format) {
  76. case DRM_FORMAT_ARGB8888:
  77. *mode = SUN4I_BACKEND_LAY_FBFMT_ARGB8888;
  78. break;
  79. case DRM_FORMAT_ARGB4444:
  80. *mode = SUN4I_BACKEND_LAY_FBFMT_ARGB4444;
  81. break;
  82. case DRM_FORMAT_ARGB1555:
  83. *mode = SUN4I_BACKEND_LAY_FBFMT_ARGB1555;
  84. break;
  85. case DRM_FORMAT_RGBA5551:
  86. *mode = SUN4I_BACKEND_LAY_FBFMT_RGBA5551;
  87. break;
  88. case DRM_FORMAT_RGBA4444:
  89. *mode = SUN4I_BACKEND_LAY_FBFMT_RGBA4444;
  90. break;
  91. case DRM_FORMAT_XRGB8888:
  92. *mode = SUN4I_BACKEND_LAY_FBFMT_XRGB8888;
  93. break;
  94. case DRM_FORMAT_RGB888:
  95. *mode = SUN4I_BACKEND_LAY_FBFMT_RGB888;
  96. break;
  97. case DRM_FORMAT_RGB565:
  98. *mode = SUN4I_BACKEND_LAY_FBFMT_RGB565;
  99. break;
  100. default:
  101. return -EINVAL;
  102. }
  103. return 0;
  104. }
  105. int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
  106. int layer, struct drm_plane *plane)
  107. {
  108. struct drm_plane_state *state = plane->state;
  109. struct drm_framebuffer *fb = state->fb;
  110. DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
  111. if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
  112. DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n",
  113. state->crtc_w, state->crtc_h);
  114. regmap_write(backend->regs, SUN4I_BACKEND_DISSIZE_REG,
  115. SUN4I_BACKEND_DISSIZE(state->crtc_w,
  116. state->crtc_h));
  117. }
  118. /* Set the line width */
  119. DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
  120. regmap_write(backend->regs, SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
  121. fb->pitches[0] * 8);
  122. /* Set height and width */
  123. DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
  124. state->crtc_w, state->crtc_h);
  125. regmap_write(backend->regs, SUN4I_BACKEND_LAYSIZE_REG(layer),
  126. SUN4I_BACKEND_LAYSIZE(state->crtc_w,
  127. state->crtc_h));
  128. /* Set base coordinates */
  129. DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
  130. state->crtc_x, state->crtc_y);
  131. regmap_write(backend->regs, SUN4I_BACKEND_LAYCOOR_REG(layer),
  132. SUN4I_BACKEND_LAYCOOR(state->crtc_x,
  133. state->crtc_y));
  134. return 0;
  135. }
  136. EXPORT_SYMBOL(sun4i_backend_update_layer_coord);
  137. int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
  138. int layer, struct drm_plane *plane)
  139. {
  140. struct drm_plane_state *state = plane->state;
  141. struct drm_framebuffer *fb = state->fb;
  142. bool interlaced = false;
  143. u32 val;
  144. int ret;
  145. if (plane->state->crtc)
  146. interlaced = plane->state->crtc->state->adjusted_mode.flags
  147. & DRM_MODE_FLAG_INTERLACE;
  148. regmap_update_bits(backend->regs, SUN4I_BACKEND_MODCTL_REG,
  149. SUN4I_BACKEND_MODCTL_ITLMOD_EN,
  150. interlaced ? SUN4I_BACKEND_MODCTL_ITLMOD_EN : 0);
  151. DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n",
  152. interlaced ? "on" : "off");
  153. ret = sun4i_backend_drm_format_to_layer(plane, fb->format->format,
  154. &val);
  155. if (ret) {
  156. DRM_DEBUG_DRIVER("Invalid format\n");
  157. return val;
  158. }
  159. regmap_update_bits(backend->regs, SUN4I_BACKEND_ATTCTL_REG1(layer),
  160. SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
  161. return 0;
  162. }
  163. EXPORT_SYMBOL(sun4i_backend_update_layer_formats);
  164. int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
  165. int layer, struct drm_plane *plane)
  166. {
  167. struct drm_plane_state *state = plane->state;
  168. struct drm_framebuffer *fb = state->fb;
  169. struct drm_gem_cma_object *gem;
  170. u32 lo_paddr, hi_paddr;
  171. dma_addr_t paddr;
  172. int bpp;
  173. /* Get the physical address of the buffer in memory */
  174. gem = drm_fb_cma_get_gem_obj(fb, 0);
  175. DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
  176. /* Compute the start of the displayed memory */
  177. bpp = fb->format->cpp[0];
  178. paddr = gem->paddr + fb->offsets[0];
  179. paddr += (state->src_x >> 16) * bpp;
  180. paddr += (state->src_y >> 16) * fb->pitches[0];
  181. DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
  182. /* Write the 32 lower bits of the address (in bits) */
  183. lo_paddr = paddr << 3;
  184. DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr);
  185. regmap_write(backend->regs, SUN4I_BACKEND_LAYFB_L32ADD_REG(layer),
  186. lo_paddr);
  187. /* And the upper bits */
  188. hi_paddr = paddr >> 29;
  189. DRM_DEBUG_DRIVER("Setting address high bits to 0x%x\n", hi_paddr);
  190. regmap_update_bits(backend->regs, SUN4I_BACKEND_LAYFB_H4ADD_REG,
  191. SUN4I_BACKEND_LAYFB_H4ADD_MSK(layer),
  192. SUN4I_BACKEND_LAYFB_H4ADD(layer, hi_paddr));
  193. return 0;
  194. }
  195. EXPORT_SYMBOL(sun4i_backend_update_layer_buffer);
  196. static int sun4i_backend_init_sat(struct device *dev) {
  197. struct sun4i_backend *backend = dev_get_drvdata(dev);
  198. int ret;
  199. backend->sat_reset = devm_reset_control_get(dev, "sat");
  200. if (IS_ERR(backend->sat_reset)) {
  201. dev_err(dev, "Couldn't get the SAT reset line\n");
  202. return PTR_ERR(backend->sat_reset);
  203. }
  204. ret = reset_control_deassert(backend->sat_reset);
  205. if (ret) {
  206. dev_err(dev, "Couldn't deassert the SAT reset line\n");
  207. return ret;
  208. }
  209. backend->sat_clk = devm_clk_get(dev, "sat");
  210. if (IS_ERR(backend->sat_clk)) {
  211. dev_err(dev, "Couldn't get our SAT clock\n");
  212. ret = PTR_ERR(backend->sat_clk);
  213. goto err_assert_reset;
  214. }
  215. ret = clk_prepare_enable(backend->sat_clk);
  216. if (ret) {
  217. dev_err(dev, "Couldn't enable the SAT clock\n");
  218. return ret;
  219. }
  220. return 0;
  221. err_assert_reset:
  222. reset_control_assert(backend->sat_reset);
  223. return ret;
  224. }
  225. static int sun4i_backend_free_sat(struct device *dev) {
  226. struct sun4i_backend *backend = dev_get_drvdata(dev);
  227. clk_disable_unprepare(backend->sat_clk);
  228. reset_control_assert(backend->sat_reset);
  229. return 0;
  230. }
  231. static struct regmap_config sun4i_backend_regmap_config = {
  232. .reg_bits = 32,
  233. .val_bits = 32,
  234. .reg_stride = 4,
  235. .max_register = 0x5800,
  236. };
  237. static int sun4i_backend_bind(struct device *dev, struct device *master,
  238. void *data)
  239. {
  240. struct platform_device *pdev = to_platform_device(dev);
  241. struct drm_device *drm = data;
  242. struct sun4i_drv *drv = drm->dev_private;
  243. struct sun4i_backend *backend;
  244. struct resource *res;
  245. void __iomem *regs;
  246. int i, ret;
  247. backend = devm_kzalloc(dev, sizeof(*backend), GFP_KERNEL);
  248. if (!backend)
  249. return -ENOMEM;
  250. dev_set_drvdata(dev, backend);
  251. drv->backend = backend;
  252. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  253. regs = devm_ioremap_resource(dev, res);
  254. if (IS_ERR(regs))
  255. return PTR_ERR(regs);
  256. backend->regs = devm_regmap_init_mmio(dev, regs,
  257. &sun4i_backend_regmap_config);
  258. if (IS_ERR(backend->regs)) {
  259. dev_err(dev, "Couldn't create the backend0 regmap\n");
  260. return PTR_ERR(backend->regs);
  261. }
  262. backend->reset = devm_reset_control_get(dev, NULL);
  263. if (IS_ERR(backend->reset)) {
  264. dev_err(dev, "Couldn't get our reset line\n");
  265. return PTR_ERR(backend->reset);
  266. }
  267. ret = reset_control_deassert(backend->reset);
  268. if (ret) {
  269. dev_err(dev, "Couldn't deassert our reset line\n");
  270. return ret;
  271. }
  272. backend->bus_clk = devm_clk_get(dev, "ahb");
  273. if (IS_ERR(backend->bus_clk)) {
  274. dev_err(dev, "Couldn't get the backend bus clock\n");
  275. ret = PTR_ERR(backend->bus_clk);
  276. goto err_assert_reset;
  277. }
  278. clk_prepare_enable(backend->bus_clk);
  279. backend->mod_clk = devm_clk_get(dev, "mod");
  280. if (IS_ERR(backend->mod_clk)) {
  281. dev_err(dev, "Couldn't get the backend module clock\n");
  282. ret = PTR_ERR(backend->mod_clk);
  283. goto err_disable_bus_clk;
  284. }
  285. clk_prepare_enable(backend->mod_clk);
  286. backend->ram_clk = devm_clk_get(dev, "ram");
  287. if (IS_ERR(backend->ram_clk)) {
  288. dev_err(dev, "Couldn't get the backend RAM clock\n");
  289. ret = PTR_ERR(backend->ram_clk);
  290. goto err_disable_mod_clk;
  291. }
  292. clk_prepare_enable(backend->ram_clk);
  293. if (of_device_is_compatible(dev->of_node,
  294. "allwinner,sun8i-a33-display-backend")) {
  295. ret = sun4i_backend_init_sat(dev);
  296. if (ret) {
  297. dev_err(dev, "Couldn't init SAT resources\n");
  298. goto err_disable_ram_clk;
  299. }
  300. }
  301. /* Reset the registers */
  302. for (i = 0x800; i < 0x1000; i += 4)
  303. regmap_write(backend->regs, i, 0);
  304. /* Disable registers autoloading */
  305. regmap_write(backend->regs, SUN4I_BACKEND_REGBUFFCTL_REG,
  306. SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS);
  307. /* Enable the backend */
  308. regmap_write(backend->regs, SUN4I_BACKEND_MODCTL_REG,
  309. SUN4I_BACKEND_MODCTL_DEBE_EN |
  310. SUN4I_BACKEND_MODCTL_START_CTL);
  311. return 0;
  312. err_disable_ram_clk:
  313. clk_disable_unprepare(backend->ram_clk);
  314. err_disable_mod_clk:
  315. clk_disable_unprepare(backend->mod_clk);
  316. err_disable_bus_clk:
  317. clk_disable_unprepare(backend->bus_clk);
  318. err_assert_reset:
  319. reset_control_assert(backend->reset);
  320. return ret;
  321. }
  322. static void sun4i_backend_unbind(struct device *dev, struct device *master,
  323. void *data)
  324. {
  325. struct sun4i_backend *backend = dev_get_drvdata(dev);
  326. if (of_device_is_compatible(dev->of_node,
  327. "allwinner,sun8i-a33-display-backend"))
  328. sun4i_backend_free_sat(dev);
  329. clk_disable_unprepare(backend->ram_clk);
  330. clk_disable_unprepare(backend->mod_clk);
  331. clk_disable_unprepare(backend->bus_clk);
  332. reset_control_assert(backend->reset);
  333. }
  334. static const struct component_ops sun4i_backend_ops = {
  335. .bind = sun4i_backend_bind,
  336. .unbind = sun4i_backend_unbind,
  337. };
  338. static int sun4i_backend_probe(struct platform_device *pdev)
  339. {
  340. return component_add(&pdev->dev, &sun4i_backend_ops);
  341. }
  342. static int sun4i_backend_remove(struct platform_device *pdev)
  343. {
  344. component_del(&pdev->dev, &sun4i_backend_ops);
  345. return 0;
  346. }
  347. static const struct of_device_id sun4i_backend_of_table[] = {
  348. { .compatible = "allwinner,sun5i-a13-display-backend" },
  349. { .compatible = "allwinner,sun6i-a31-display-backend" },
  350. { .compatible = "allwinner,sun8i-a33-display-backend" },
  351. { }
  352. };
  353. MODULE_DEVICE_TABLE(of, sun4i_backend_of_table);
  354. static struct platform_driver sun4i_backend_platform_driver = {
  355. .probe = sun4i_backend_probe,
  356. .remove = sun4i_backend_remove,
  357. .driver = {
  358. .name = "sun4i-backend",
  359. .of_match_table = sun4i_backend_of_table,
  360. },
  361. };
  362. module_platform_driver(sun4i_backend_platform_driver);
  363. MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
  364. MODULE_DESCRIPTION("Allwinner A10 Display Backend Driver");
  365. MODULE_LICENSE("GPL");