sun4i_backend.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  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_XRGB8888:
  80. *mode = SUN4I_BACKEND_LAY_FBFMT_XRGB8888;
  81. break;
  82. case DRM_FORMAT_RGB888:
  83. *mode = SUN4I_BACKEND_LAY_FBFMT_RGB888;
  84. break;
  85. default:
  86. return -EINVAL;
  87. }
  88. return 0;
  89. }
  90. int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
  91. int layer, struct drm_plane *plane)
  92. {
  93. struct drm_plane_state *state = plane->state;
  94. struct drm_framebuffer *fb = state->fb;
  95. DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
  96. if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
  97. DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n",
  98. state->crtc_w, state->crtc_h);
  99. regmap_write(backend->regs, SUN4I_BACKEND_DISSIZE_REG,
  100. SUN4I_BACKEND_DISSIZE(state->crtc_w,
  101. state->crtc_h));
  102. }
  103. /* Set the line width */
  104. DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
  105. regmap_write(backend->regs, SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
  106. fb->pitches[0] * 8);
  107. /* Set height and width */
  108. DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
  109. state->crtc_w, state->crtc_h);
  110. regmap_write(backend->regs, SUN4I_BACKEND_LAYSIZE_REG(layer),
  111. SUN4I_BACKEND_LAYSIZE(state->crtc_w,
  112. state->crtc_h));
  113. /* Set base coordinates */
  114. DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
  115. state->crtc_x, state->crtc_y);
  116. regmap_write(backend->regs, SUN4I_BACKEND_LAYCOOR_REG(layer),
  117. SUN4I_BACKEND_LAYCOOR(state->crtc_x,
  118. state->crtc_y));
  119. return 0;
  120. }
  121. EXPORT_SYMBOL(sun4i_backend_update_layer_coord);
  122. int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
  123. int layer, struct drm_plane *plane)
  124. {
  125. struct drm_plane_state *state = plane->state;
  126. struct drm_framebuffer *fb = state->fb;
  127. bool interlaced = false;
  128. u32 val;
  129. int ret;
  130. if (plane->state->crtc)
  131. interlaced = plane->state->crtc->state->adjusted_mode.flags
  132. & DRM_MODE_FLAG_INTERLACE;
  133. regmap_update_bits(backend->regs, SUN4I_BACKEND_MODCTL_REG,
  134. SUN4I_BACKEND_MODCTL_ITLMOD_EN,
  135. interlaced ? SUN4I_BACKEND_MODCTL_ITLMOD_EN : 0);
  136. DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n",
  137. interlaced ? "on" : "off");
  138. ret = sun4i_backend_drm_format_to_layer(plane, fb->pixel_format, &val);
  139. if (ret) {
  140. DRM_DEBUG_DRIVER("Invalid format\n");
  141. return ret;
  142. }
  143. regmap_update_bits(backend->regs, SUN4I_BACKEND_ATTCTL_REG1(layer),
  144. SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
  145. return 0;
  146. }
  147. EXPORT_SYMBOL(sun4i_backend_update_layer_formats);
  148. int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
  149. int layer, struct drm_plane *plane)
  150. {
  151. struct drm_plane_state *state = plane->state;
  152. struct drm_framebuffer *fb = state->fb;
  153. struct drm_gem_cma_object *gem;
  154. u32 lo_paddr, hi_paddr;
  155. dma_addr_t paddr;
  156. int bpp;
  157. /* Get the physical address of the buffer in memory */
  158. gem = drm_fb_cma_get_gem_obj(fb, 0);
  159. DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
  160. /* Compute the start of the displayed memory */
  161. bpp = drm_format_plane_cpp(fb->pixel_format, 0);
  162. paddr = gem->paddr + fb->offsets[0];
  163. paddr += (state->src_x >> 16) * bpp;
  164. paddr += (state->src_y >> 16) * fb->pitches[0];
  165. DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
  166. /* Write the 32 lower bits of the address (in bits) */
  167. lo_paddr = paddr << 3;
  168. DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr);
  169. regmap_write(backend->regs, SUN4I_BACKEND_LAYFB_L32ADD_REG(layer),
  170. lo_paddr);
  171. /* And the upper bits */
  172. hi_paddr = paddr >> 29;
  173. DRM_DEBUG_DRIVER("Setting address high bits to 0x%x\n", hi_paddr);
  174. regmap_update_bits(backend->regs, SUN4I_BACKEND_LAYFB_H4ADD_REG,
  175. SUN4I_BACKEND_LAYFB_H4ADD_MSK(layer),
  176. SUN4I_BACKEND_LAYFB_H4ADD(layer, hi_paddr));
  177. return 0;
  178. }
  179. EXPORT_SYMBOL(sun4i_backend_update_layer_buffer);
  180. static int sun4i_backend_init_sat(struct device *dev) {
  181. struct sun4i_backend *backend = dev_get_drvdata(dev);
  182. int ret;
  183. backend->sat_reset = devm_reset_control_get(dev, "sat");
  184. if (IS_ERR(backend->sat_reset)) {
  185. dev_err(dev, "Couldn't get the SAT reset line\n");
  186. return PTR_ERR(backend->sat_reset);
  187. }
  188. ret = reset_control_deassert(backend->sat_reset);
  189. if (ret) {
  190. dev_err(dev, "Couldn't deassert the SAT reset line\n");
  191. return ret;
  192. }
  193. backend->sat_clk = devm_clk_get(dev, "sat");
  194. if (IS_ERR(backend->sat_clk)) {
  195. dev_err(dev, "Couldn't get our SAT clock\n");
  196. ret = PTR_ERR(backend->sat_clk);
  197. goto err_assert_reset;
  198. }
  199. ret = clk_prepare_enable(backend->sat_clk);
  200. if (ret) {
  201. dev_err(dev, "Couldn't enable the SAT clock\n");
  202. return ret;
  203. }
  204. return 0;
  205. err_assert_reset:
  206. reset_control_assert(backend->sat_reset);
  207. return ret;
  208. }
  209. static int sun4i_backend_free_sat(struct device *dev) {
  210. struct sun4i_backend *backend = dev_get_drvdata(dev);
  211. clk_disable_unprepare(backend->sat_clk);
  212. reset_control_assert(backend->sat_reset);
  213. return 0;
  214. }
  215. static struct regmap_config sun4i_backend_regmap_config = {
  216. .reg_bits = 32,
  217. .val_bits = 32,
  218. .reg_stride = 4,
  219. .max_register = 0x5800,
  220. };
  221. static int sun4i_backend_bind(struct device *dev, struct device *master,
  222. void *data)
  223. {
  224. struct platform_device *pdev = to_platform_device(dev);
  225. struct drm_device *drm = data;
  226. struct sun4i_drv *drv = drm->dev_private;
  227. struct sun4i_backend *backend;
  228. struct resource *res;
  229. void __iomem *regs;
  230. int i, ret;
  231. backend = devm_kzalloc(dev, sizeof(*backend), GFP_KERNEL);
  232. if (!backend)
  233. return -ENOMEM;
  234. dev_set_drvdata(dev, backend);
  235. drv->backend = backend;
  236. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  237. regs = devm_ioremap_resource(dev, res);
  238. if (IS_ERR(regs))
  239. return PTR_ERR(regs);
  240. backend->regs = devm_regmap_init_mmio(dev, regs,
  241. &sun4i_backend_regmap_config);
  242. if (IS_ERR(backend->regs)) {
  243. dev_err(dev, "Couldn't create the backend0 regmap\n");
  244. return PTR_ERR(backend->regs);
  245. }
  246. backend->reset = devm_reset_control_get(dev, NULL);
  247. if (IS_ERR(backend->reset)) {
  248. dev_err(dev, "Couldn't get our reset line\n");
  249. return PTR_ERR(backend->reset);
  250. }
  251. ret = reset_control_deassert(backend->reset);
  252. if (ret) {
  253. dev_err(dev, "Couldn't deassert our reset line\n");
  254. return ret;
  255. }
  256. backend->bus_clk = devm_clk_get(dev, "ahb");
  257. if (IS_ERR(backend->bus_clk)) {
  258. dev_err(dev, "Couldn't get the backend bus clock\n");
  259. ret = PTR_ERR(backend->bus_clk);
  260. goto err_assert_reset;
  261. }
  262. clk_prepare_enable(backend->bus_clk);
  263. backend->mod_clk = devm_clk_get(dev, "mod");
  264. if (IS_ERR(backend->mod_clk)) {
  265. dev_err(dev, "Couldn't get the backend module clock\n");
  266. ret = PTR_ERR(backend->mod_clk);
  267. goto err_disable_bus_clk;
  268. }
  269. clk_prepare_enable(backend->mod_clk);
  270. backend->ram_clk = devm_clk_get(dev, "ram");
  271. if (IS_ERR(backend->ram_clk)) {
  272. dev_err(dev, "Couldn't get the backend RAM clock\n");
  273. ret = PTR_ERR(backend->ram_clk);
  274. goto err_disable_mod_clk;
  275. }
  276. clk_prepare_enable(backend->ram_clk);
  277. if (of_device_is_compatible(dev->of_node,
  278. "allwinner,sun8i-a33-display-backend")) {
  279. ret = sun4i_backend_init_sat(dev);
  280. if (ret) {
  281. dev_err(dev, "Couldn't init SAT resources\n");
  282. goto err_disable_ram_clk;
  283. }
  284. }
  285. /* Reset the registers */
  286. for (i = 0x800; i < 0x1000; i += 4)
  287. regmap_write(backend->regs, i, 0);
  288. /* Disable registers autoloading */
  289. regmap_write(backend->regs, SUN4I_BACKEND_REGBUFFCTL_REG,
  290. SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS);
  291. /* Enable the backend */
  292. regmap_write(backend->regs, SUN4I_BACKEND_MODCTL_REG,
  293. SUN4I_BACKEND_MODCTL_DEBE_EN |
  294. SUN4I_BACKEND_MODCTL_START_CTL);
  295. return 0;
  296. err_disable_ram_clk:
  297. clk_disable_unprepare(backend->ram_clk);
  298. err_disable_mod_clk:
  299. clk_disable_unprepare(backend->mod_clk);
  300. err_disable_bus_clk:
  301. clk_disable_unprepare(backend->bus_clk);
  302. err_assert_reset:
  303. reset_control_assert(backend->reset);
  304. return ret;
  305. }
  306. static void sun4i_backend_unbind(struct device *dev, struct device *master,
  307. void *data)
  308. {
  309. struct sun4i_backend *backend = dev_get_drvdata(dev);
  310. if (of_device_is_compatible(dev->of_node,
  311. "allwinner,sun8i-a33-display-backend"))
  312. sun4i_backend_free_sat(dev);
  313. clk_disable_unprepare(backend->ram_clk);
  314. clk_disable_unprepare(backend->mod_clk);
  315. clk_disable_unprepare(backend->bus_clk);
  316. reset_control_assert(backend->reset);
  317. }
  318. static struct component_ops sun4i_backend_ops = {
  319. .bind = sun4i_backend_bind,
  320. .unbind = sun4i_backend_unbind,
  321. };
  322. static int sun4i_backend_probe(struct platform_device *pdev)
  323. {
  324. return component_add(&pdev->dev, &sun4i_backend_ops);
  325. }
  326. static int sun4i_backend_remove(struct platform_device *pdev)
  327. {
  328. component_del(&pdev->dev, &sun4i_backend_ops);
  329. return 0;
  330. }
  331. static const struct of_device_id sun4i_backend_of_table[] = {
  332. { .compatible = "allwinner,sun5i-a13-display-backend" },
  333. { .compatible = "allwinner,sun6i-a31-display-backend" },
  334. { .compatible = "allwinner,sun8i-a33-display-backend" },
  335. { }
  336. };
  337. MODULE_DEVICE_TABLE(of, sun4i_backend_of_table);
  338. static struct platform_driver sun4i_backend_platform_driver = {
  339. .probe = sun4i_backend_probe,
  340. .remove = sun4i_backend_remove,
  341. .driver = {
  342. .name = "sun4i-backend",
  343. .of_match_table = sun4i_backend_of_table,
  344. },
  345. };
  346. module_platform_driver(sun4i_backend_platform_driver);
  347. MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
  348. MODULE_DESCRIPTION("Allwinner A10 Display Backend Driver");
  349. MODULE_LICENSE("GPL");