sun8i_mixer.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
  4. *
  5. * Based on sun4i_backend.c, which is:
  6. * Copyright (C) 2015 Free Electrons
  7. * Copyright (C) 2015 NextThing Co
  8. */
  9. #include <linux/component.h>
  10. #include <linux/dma-mapping.h>
  11. #include <linux/module.h>
  12. #include <linux/of.h>
  13. #include <linux/of_device.h>
  14. #include <linux/of_graph.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/reset.h>
  17. #include <drm/drm_atomic.h>
  18. #include <drm/drm_atomic_helper.h>
  19. #include <drm/drm_crtc.h>
  20. #include <drm/drm_framebuffer.h>
  21. #include <drm/drm_gem_dma_helper.h>
  22. #include <drm/drm_probe_helper.h>
  23. #include "sun4i_drv.h"
  24. #include "sun8i_mixer.h"
  25. #include "sun8i_ui_layer.h"
  26. #include "sun8i_vi_layer.h"
  27. #include "sunxi_engine.h"
  28. struct de2_fmt_info {
  29. u32 drm_fmt;
  30. u32 de2_fmt;
  31. };
  32. static const struct de2_fmt_info de2_formats[] = {
  33. {
  34. .drm_fmt = DRM_FORMAT_ARGB8888,
  35. .de2_fmt = SUN8I_MIXER_FBFMT_ARGB8888,
  36. },
  37. {
  38. .drm_fmt = DRM_FORMAT_ABGR8888,
  39. .de2_fmt = SUN8I_MIXER_FBFMT_ABGR8888,
  40. },
  41. {
  42. .drm_fmt = DRM_FORMAT_RGBA8888,
  43. .de2_fmt = SUN8I_MIXER_FBFMT_RGBA8888,
  44. },
  45. {
  46. .drm_fmt = DRM_FORMAT_BGRA8888,
  47. .de2_fmt = SUN8I_MIXER_FBFMT_BGRA8888,
  48. },
  49. {
  50. .drm_fmt = DRM_FORMAT_XRGB8888,
  51. .de2_fmt = SUN8I_MIXER_FBFMT_XRGB8888,
  52. },
  53. {
  54. .drm_fmt = DRM_FORMAT_XBGR8888,
  55. .de2_fmt = SUN8I_MIXER_FBFMT_XBGR8888,
  56. },
  57. {
  58. .drm_fmt = DRM_FORMAT_RGBX8888,
  59. .de2_fmt = SUN8I_MIXER_FBFMT_RGBX8888,
  60. },
  61. {
  62. .drm_fmt = DRM_FORMAT_BGRX8888,
  63. .de2_fmt = SUN8I_MIXER_FBFMT_BGRX8888,
  64. },
  65. {
  66. .drm_fmt = DRM_FORMAT_RGB888,
  67. .de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
  68. },
  69. {
  70. .drm_fmt = DRM_FORMAT_BGR888,
  71. .de2_fmt = SUN8I_MIXER_FBFMT_BGR888,
  72. },
  73. {
  74. .drm_fmt = DRM_FORMAT_RGB565,
  75. .de2_fmt = SUN8I_MIXER_FBFMT_RGB565,
  76. },
  77. {
  78. .drm_fmt = DRM_FORMAT_BGR565,
  79. .de2_fmt = SUN8I_MIXER_FBFMT_BGR565,
  80. },
  81. {
  82. .drm_fmt = DRM_FORMAT_ARGB4444,
  83. .de2_fmt = SUN8I_MIXER_FBFMT_ARGB4444,
  84. },
  85. {
  86. /* for DE2 VI layer which ignores alpha */
  87. .drm_fmt = DRM_FORMAT_XRGB4444,
  88. .de2_fmt = SUN8I_MIXER_FBFMT_ARGB4444,
  89. },
  90. {
  91. .drm_fmt = DRM_FORMAT_ABGR4444,
  92. .de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
  93. },
  94. {
  95. /* for DE2 VI layer which ignores alpha */
  96. .drm_fmt = DRM_FORMAT_XBGR4444,
  97. .de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
  98. },
  99. {
  100. .drm_fmt = DRM_FORMAT_RGBA4444,
  101. .de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
  102. },
  103. {
  104. /* for DE2 VI layer which ignores alpha */
  105. .drm_fmt = DRM_FORMAT_RGBX4444,
  106. .de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
  107. },
  108. {
  109. .drm_fmt = DRM_FORMAT_BGRA4444,
  110. .de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
  111. },
  112. {
  113. /* for DE2 VI layer which ignores alpha */
  114. .drm_fmt = DRM_FORMAT_BGRX4444,
  115. .de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
  116. },
  117. {
  118. .drm_fmt = DRM_FORMAT_ARGB1555,
  119. .de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
  120. },
  121. {
  122. /* for DE2 VI layer which ignores alpha */
  123. .drm_fmt = DRM_FORMAT_XRGB1555,
  124. .de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
  125. },
  126. {
  127. .drm_fmt = DRM_FORMAT_ABGR1555,
  128. .de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
  129. },
  130. {
  131. /* for DE2 VI layer which ignores alpha */
  132. .drm_fmt = DRM_FORMAT_XBGR1555,
  133. .de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
  134. },
  135. {
  136. .drm_fmt = DRM_FORMAT_RGBA5551,
  137. .de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
  138. },
  139. {
  140. /* for DE2 VI layer which ignores alpha */
  141. .drm_fmt = DRM_FORMAT_RGBX5551,
  142. .de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
  143. },
  144. {
  145. .drm_fmt = DRM_FORMAT_BGRA5551,
  146. .de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
  147. },
  148. {
  149. /* for DE2 VI layer which ignores alpha */
  150. .drm_fmt = DRM_FORMAT_BGRX5551,
  151. .de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
  152. },
  153. {
  154. .drm_fmt = DRM_FORMAT_ARGB2101010,
  155. .de2_fmt = SUN8I_MIXER_FBFMT_ARGB2101010,
  156. },
  157. {
  158. .drm_fmt = DRM_FORMAT_ABGR2101010,
  159. .de2_fmt = SUN8I_MIXER_FBFMT_ABGR2101010,
  160. },
  161. {
  162. .drm_fmt = DRM_FORMAT_RGBA1010102,
  163. .de2_fmt = SUN8I_MIXER_FBFMT_RGBA1010102,
  164. },
  165. {
  166. .drm_fmt = DRM_FORMAT_BGRA1010102,
  167. .de2_fmt = SUN8I_MIXER_FBFMT_BGRA1010102,
  168. },
  169. {
  170. .drm_fmt = DRM_FORMAT_UYVY,
  171. .de2_fmt = SUN8I_MIXER_FBFMT_UYVY,
  172. },
  173. {
  174. .drm_fmt = DRM_FORMAT_VYUY,
  175. .de2_fmt = SUN8I_MIXER_FBFMT_VYUY,
  176. },
  177. {
  178. .drm_fmt = DRM_FORMAT_YUYV,
  179. .de2_fmt = SUN8I_MIXER_FBFMT_YUYV,
  180. },
  181. {
  182. .drm_fmt = DRM_FORMAT_YVYU,
  183. .de2_fmt = SUN8I_MIXER_FBFMT_YVYU,
  184. },
  185. {
  186. .drm_fmt = DRM_FORMAT_NV16,
  187. .de2_fmt = SUN8I_MIXER_FBFMT_NV16,
  188. },
  189. {
  190. .drm_fmt = DRM_FORMAT_NV61,
  191. .de2_fmt = SUN8I_MIXER_FBFMT_NV61,
  192. },
  193. {
  194. .drm_fmt = DRM_FORMAT_NV12,
  195. .de2_fmt = SUN8I_MIXER_FBFMT_NV12,
  196. },
  197. {
  198. .drm_fmt = DRM_FORMAT_NV21,
  199. .de2_fmt = SUN8I_MIXER_FBFMT_NV21,
  200. },
  201. {
  202. .drm_fmt = DRM_FORMAT_YUV422,
  203. .de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
  204. },
  205. {
  206. .drm_fmt = DRM_FORMAT_YUV420,
  207. .de2_fmt = SUN8I_MIXER_FBFMT_YUV420,
  208. },
  209. {
  210. .drm_fmt = DRM_FORMAT_YUV411,
  211. .de2_fmt = SUN8I_MIXER_FBFMT_YUV411,
  212. },
  213. {
  214. .drm_fmt = DRM_FORMAT_YVU422,
  215. .de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
  216. },
  217. {
  218. .drm_fmt = DRM_FORMAT_YVU420,
  219. .de2_fmt = SUN8I_MIXER_FBFMT_YUV420,
  220. },
  221. {
  222. .drm_fmt = DRM_FORMAT_YVU411,
  223. .de2_fmt = SUN8I_MIXER_FBFMT_YUV411,
  224. },
  225. {
  226. .drm_fmt = DRM_FORMAT_P010,
  227. .de2_fmt = SUN8I_MIXER_FBFMT_P010_YUV,
  228. },
  229. {
  230. .drm_fmt = DRM_FORMAT_P210,
  231. .de2_fmt = SUN8I_MIXER_FBFMT_P210_YUV,
  232. },
  233. };
  234. int sun8i_mixer_drm_format_to_hw(u32 format, u32 *hw_format)
  235. {
  236. unsigned int i;
  237. for (i = 0; i < ARRAY_SIZE(de2_formats); ++i)
  238. if (de2_formats[i].drm_fmt == format) {
  239. *hw_format = de2_formats[i].de2_fmt;
  240. return 0;
  241. }
  242. return -EINVAL;
  243. }
  244. static void sun8i_layer_enable(struct sun8i_layer *layer, bool enable)
  245. {
  246. u32 ch_base = sun8i_channel_base(layer->mixer, layer->channel);
  247. u32 val, reg, mask;
  248. if (layer->type == SUN8I_LAYER_TYPE_UI) {
  249. val = enable ? SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN : 0;
  250. mask = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
  251. reg = SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, layer->overlay);
  252. } else {
  253. val = enable ? SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN : 0;
  254. mask = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN;
  255. reg = SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, layer->overlay);
  256. }
  257. regmap_update_bits(layer->mixer->engine.regs, reg, mask, val);
  258. }
  259. static void sun8i_mixer_commit(struct sunxi_engine *engine,
  260. struct drm_crtc *crtc,
  261. struct drm_atomic_state *state)
  262. {
  263. struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
  264. u32 bld_base = sun8i_blender_base(mixer);
  265. struct drm_plane_state *plane_state;
  266. struct drm_plane *plane;
  267. u32 route = 0, pipe_en = 0;
  268. DRM_DEBUG_DRIVER("Committing changes\n");
  269. drm_for_each_plane(plane, state->dev) {
  270. struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
  271. bool enable;
  272. int zpos;
  273. if (!(plane->possible_crtcs & drm_crtc_mask(crtc)) || layer->mixer != mixer)
  274. continue;
  275. plane_state = drm_atomic_get_new_plane_state(state, plane);
  276. if (!plane_state)
  277. plane_state = plane->state;
  278. enable = plane_state->crtc && plane_state->visible;
  279. zpos = plane_state->normalized_zpos;
  280. DRM_DEBUG_DRIVER(" plane %d: chan=%d ovl=%d en=%d zpos=%d\n",
  281. plane->base.id, layer->channel, layer->overlay,
  282. enable, zpos);
  283. /*
  284. * We always update the layer enable bit, because it can clear
  285. * spontaneously for unknown reasons.
  286. */
  287. sun8i_layer_enable(layer, enable);
  288. if (!enable)
  289. continue;
  290. /* Route layer to pipe based on zpos */
  291. route |= layer->channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);
  292. pipe_en |= SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
  293. }
  294. regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), route);
  295. regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
  296. pipe_en | SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
  297. regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
  298. SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
  299. }
  300. static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
  301. struct sunxi_engine *engine)
  302. {
  303. struct drm_plane **planes;
  304. struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
  305. int i;
  306. planes = devm_kcalloc(drm->dev,
  307. mixer->cfg->vi_num + mixer->cfg->ui_num + 1,
  308. sizeof(*planes), GFP_KERNEL);
  309. if (!planes)
  310. return ERR_PTR(-ENOMEM);
  311. for (i = 0; i < mixer->cfg->vi_num; i++) {
  312. struct sun8i_layer *layer;
  313. layer = sun8i_vi_layer_init_one(drm, mixer, i);
  314. if (IS_ERR(layer)) {
  315. dev_err(drm->dev,
  316. "Couldn't initialize overlay plane\n");
  317. return ERR_CAST(layer);
  318. }
  319. planes[i] = &layer->plane;
  320. }
  321. for (i = 0; i < mixer->cfg->ui_num; i++) {
  322. struct sun8i_layer *layer;
  323. layer = sun8i_ui_layer_init_one(drm, mixer, i);
  324. if (IS_ERR(layer)) {
  325. dev_err(drm->dev, "Couldn't initialize %s plane\n",
  326. i ? "overlay" : "primary");
  327. return ERR_CAST(layer);
  328. }
  329. planes[mixer->cfg->vi_num + i] = &layer->plane;
  330. }
  331. return planes;
  332. }
  333. static void sun8i_mixer_mode_set(struct sunxi_engine *engine,
  334. const struct drm_display_mode *mode)
  335. {
  336. struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
  337. u32 bld_base, size, val;
  338. bool interlaced;
  339. bld_base = sun8i_blender_base(mixer);
  340. interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
  341. size = SUN8I_MIXER_SIZE(mode->hdisplay, mode->vdisplay);
  342. DRM_DEBUG_DRIVER("Updating global size W: %u H: %u\n",
  343. mode->hdisplay, mode->vdisplay);
  344. regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_SIZE, size);
  345. regmap_write(engine->regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
  346. if (interlaced)
  347. val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED;
  348. else
  349. val = 0;
  350. regmap_update_bits(engine->regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
  351. SUN8I_MIXER_BLEND_OUTCTL_INTERLACED, val);
  352. DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
  353. interlaced ? "on" : "off");
  354. }
  355. static const struct sunxi_engine_ops sun8i_engine_ops = {
  356. .commit = sun8i_mixer_commit,
  357. .layers_init = sun8i_layers_init,
  358. .mode_set = sun8i_mixer_mode_set,
  359. };
  360. static const struct regmap_config sun8i_mixer_regmap_config = {
  361. .reg_bits = 32,
  362. .val_bits = 32,
  363. .reg_stride = 4,
  364. .max_register = 0xffffc, /* guessed */
  365. };
  366. static int sun8i_mixer_of_get_id(struct device_node *node)
  367. {
  368. struct device_node *ep, *remote;
  369. struct of_endpoint of_ep;
  370. /* Output port is 1, and we want the first endpoint. */
  371. ep = of_graph_get_endpoint_by_regs(node, 1, -1);
  372. if (!ep)
  373. return -EINVAL;
  374. remote = of_graph_get_remote_endpoint(ep);
  375. of_node_put(ep);
  376. if (!remote)
  377. return -EINVAL;
  378. of_graph_parse_endpoint(remote, &of_ep);
  379. of_node_put(remote);
  380. return of_ep.id;
  381. }
  382. static int sun8i_mixer_bind(struct device *dev, struct device *master,
  383. void *data)
  384. {
  385. struct platform_device *pdev = to_platform_device(dev);
  386. struct drm_device *drm = data;
  387. struct sun4i_drv *drv = drm->dev_private;
  388. struct sun8i_mixer *mixer;
  389. void __iomem *regs;
  390. unsigned int base;
  391. int plane_cnt;
  392. int i, ret;
  393. /*
  394. * The mixer uses single 32-bit register to store memory
  395. * addresses, so that it cannot deal with 64-bit memory
  396. * addresses.
  397. * Restrict the DMA mask so that the mixer won't be
  398. * allocated some memory that is too high.
  399. */
  400. ret = dma_set_mask(dev, DMA_BIT_MASK(32));
  401. if (ret) {
  402. dev_err(dev, "Cannot do 32-bit DMA.\n");
  403. return ret;
  404. }
  405. mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
  406. if (!mixer)
  407. return -ENOMEM;
  408. dev_set_drvdata(dev, mixer);
  409. mixer->engine.ops = &sun8i_engine_ops;
  410. mixer->engine.node = dev->of_node;
  411. if (of_property_present(dev->of_node, "iommus")) {
  412. /*
  413. * This assume we have the same DMA constraints for
  414. * all our the mixers in our pipeline. This sounds
  415. * bad, but it has always been the case for us, and
  416. * DRM doesn't do per-device allocation either, so we
  417. * would need to fix DRM first...
  418. */
  419. ret = of_dma_configure(drm->dev, dev->of_node, true);
  420. if (ret)
  421. return ret;
  422. }
  423. /*
  424. * While this function can fail, we shouldn't do anything
  425. * if this happens. Some early DE2 DT entries don't provide
  426. * mixer id but work nevertheless because matching between
  427. * TCON and mixer is done by comparing node pointers (old
  428. * way) instead comparing ids. If this function fails and
  429. * id is needed, it will fail during id matching anyway.
  430. */
  431. mixer->engine.id = sun8i_mixer_of_get_id(dev->of_node);
  432. mixer->cfg = of_device_get_match_data(dev);
  433. if (!mixer->cfg)
  434. return -EINVAL;
  435. regs = devm_platform_ioremap_resource(pdev, 0);
  436. if (IS_ERR(regs))
  437. return PTR_ERR(regs);
  438. mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
  439. &sun8i_mixer_regmap_config);
  440. if (IS_ERR(mixer->engine.regs)) {
  441. dev_err(dev, "Couldn't create the mixer regmap\n");
  442. return PTR_ERR(mixer->engine.regs);
  443. }
  444. mixer->reset = devm_reset_control_get(dev, NULL);
  445. if (IS_ERR(mixer->reset)) {
  446. dev_err(dev, "Couldn't get our reset line\n");
  447. return PTR_ERR(mixer->reset);
  448. }
  449. ret = reset_control_deassert(mixer->reset);
  450. if (ret) {
  451. dev_err(dev, "Couldn't deassert our reset line\n");
  452. return ret;
  453. }
  454. mixer->bus_clk = devm_clk_get(dev, "bus");
  455. if (IS_ERR(mixer->bus_clk)) {
  456. dev_err(dev, "Couldn't get the mixer bus clock\n");
  457. ret = PTR_ERR(mixer->bus_clk);
  458. goto err_assert_reset;
  459. }
  460. clk_prepare_enable(mixer->bus_clk);
  461. mixer->mod_clk = devm_clk_get(dev, "mod");
  462. if (IS_ERR(mixer->mod_clk)) {
  463. dev_err(dev, "Couldn't get the mixer module clock\n");
  464. ret = PTR_ERR(mixer->mod_clk);
  465. goto err_disable_bus_clk;
  466. }
  467. /*
  468. * It seems that we need to enforce that rate for whatever
  469. * reason for the mixer to be functional. Make sure it's the
  470. * case.
  471. */
  472. if (mixer->cfg->mod_rate)
  473. clk_set_rate(mixer->mod_clk, mixer->cfg->mod_rate);
  474. clk_prepare_enable(mixer->mod_clk);
  475. list_add_tail(&mixer->engine.list, &drv->engine_list);
  476. base = sun8i_blender_base(mixer);
  477. /* Reset registers and disable unused sub-engines */
  478. if (mixer->cfg->is_de3) {
  479. for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4)
  480. regmap_write(mixer->engine.regs, i, 0);
  481. regmap_write(mixer->engine.regs, SUN50I_MIXER_FCE_EN, 0);
  482. regmap_write(mixer->engine.regs, SUN50I_MIXER_PEAK_EN, 0);
  483. regmap_write(mixer->engine.regs, SUN50I_MIXER_LCTI_EN, 0);
  484. regmap_write(mixer->engine.regs, SUN50I_MIXER_BLS_EN, 0);
  485. regmap_write(mixer->engine.regs, SUN50I_MIXER_FCC_EN, 0);
  486. regmap_write(mixer->engine.regs, SUN50I_MIXER_DNS_EN, 0);
  487. regmap_write(mixer->engine.regs, SUN50I_MIXER_DRC_EN, 0);
  488. regmap_write(mixer->engine.regs, SUN50I_MIXER_FMT_EN, 0);
  489. regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC0_EN, 0);
  490. regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC1_EN, 0);
  491. } else {
  492. for (i = 0; i < DE2_MIXER_UNIT_SIZE; i += 4)
  493. regmap_write(mixer->engine.regs, i, 0);
  494. regmap_write(mixer->engine.regs, SUN8I_MIXER_FCE_EN, 0);
  495. regmap_write(mixer->engine.regs, SUN8I_MIXER_BWS_EN, 0);
  496. regmap_write(mixer->engine.regs, SUN8I_MIXER_LTI_EN, 0);
  497. regmap_write(mixer->engine.regs, SUN8I_MIXER_PEAK_EN, 0);
  498. regmap_write(mixer->engine.regs, SUN8I_MIXER_ASE_EN, 0);
  499. regmap_write(mixer->engine.regs, SUN8I_MIXER_FCC_EN, 0);
  500. regmap_write(mixer->engine.regs, SUN8I_MIXER_DCSC_EN, 0);
  501. }
  502. /* Enable the mixer */
  503. regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
  504. SUN8I_MIXER_GLOBAL_CTL_RT_EN);
  505. /* Set background color to black */
  506. regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
  507. SUN8I_MIXER_BLEND_COLOR_BLACK);
  508. /*
  509. * Set fill color of bottom plane to black. Generally not needed
  510. * except when VI plane is at bottom (zpos = 0) and enabled.
  511. */
  512. regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
  513. SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
  514. regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
  515. SUN8I_MIXER_BLEND_COLOR_BLACK);
  516. plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
  517. for (i = 0; i < plane_cnt; i++)
  518. regmap_write(mixer->engine.regs,
  519. SUN8I_MIXER_BLEND_MODE(base, i),
  520. SUN8I_MIXER_BLEND_MODE_DEF);
  521. regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
  522. SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
  523. return 0;
  524. err_disable_bus_clk:
  525. clk_disable_unprepare(mixer->bus_clk);
  526. err_assert_reset:
  527. reset_control_assert(mixer->reset);
  528. return ret;
  529. }
  530. static void sun8i_mixer_unbind(struct device *dev, struct device *master,
  531. void *data)
  532. {
  533. struct sun8i_mixer *mixer = dev_get_drvdata(dev);
  534. list_del(&mixer->engine.list);
  535. clk_disable_unprepare(mixer->mod_clk);
  536. clk_disable_unprepare(mixer->bus_clk);
  537. reset_control_assert(mixer->reset);
  538. }
  539. static const struct component_ops sun8i_mixer_ops = {
  540. .bind = sun8i_mixer_bind,
  541. .unbind = sun8i_mixer_unbind,
  542. };
  543. static int sun8i_mixer_probe(struct platform_device *pdev)
  544. {
  545. return component_add(&pdev->dev, &sun8i_mixer_ops);
  546. }
  547. static void sun8i_mixer_remove(struct platform_device *pdev)
  548. {
  549. component_del(&pdev->dev, &sun8i_mixer_ops);
  550. }
  551. static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = {
  552. .ccsc = CCSC_MIXER0_LAYOUT,
  553. .scaler_mask = 0xf,
  554. .scanline_yuv = 2048,
  555. .ui_num = 3,
  556. .vi_num = 1,
  557. };
  558. static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = {
  559. .ccsc = CCSC_MIXER1_LAYOUT,
  560. .scaler_mask = 0x3,
  561. .scanline_yuv = 2048,
  562. .ui_num = 1,
  563. .vi_num = 1,
  564. };
  565. static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
  566. .ccsc = CCSC_MIXER0_LAYOUT,
  567. .mod_rate = 432000000,
  568. .scaler_mask = 0xf,
  569. .scanline_yuv = 2048,
  570. .ui_num = 3,
  571. .vi_num = 1,
  572. };
  573. static const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = {
  574. .ccsc = CCSC_MIXER0_LAYOUT,
  575. .mod_rate = 297000000,
  576. .scaler_mask = 0xf,
  577. .scanline_yuv = 2048,
  578. .ui_num = 3,
  579. .vi_num = 1,
  580. };
  581. static const struct sun8i_mixer_cfg sun8i_r40_mixer1_cfg = {
  582. .ccsc = CCSC_MIXER1_LAYOUT,
  583. .mod_rate = 297000000,
  584. .scaler_mask = 0x3,
  585. .scanline_yuv = 2048,
  586. .ui_num = 1,
  587. .vi_num = 1,
  588. };
  589. static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
  590. .vi_num = 2,
  591. .ui_num = 1,
  592. .scaler_mask = 0x3,
  593. .scanline_yuv = 2048,
  594. .ccsc = CCSC_MIXER0_LAYOUT,
  595. .mod_rate = 150000000,
  596. };
  597. static const struct sun8i_mixer_cfg sun20i_d1_mixer0_cfg = {
  598. .ccsc = CCSC_D1_MIXER0_LAYOUT,
  599. .mod_rate = 297000000,
  600. .scaler_mask = 0x3,
  601. .scanline_yuv = 2048,
  602. .ui_num = 1,
  603. .vi_num = 1,
  604. };
  605. static const struct sun8i_mixer_cfg sun20i_d1_mixer1_cfg = {
  606. .ccsc = CCSC_MIXER1_LAYOUT,
  607. .mod_rate = 297000000,
  608. .scaler_mask = 0x1,
  609. .scanline_yuv = 1024,
  610. .ui_num = 0,
  611. .vi_num = 1,
  612. };
  613. static const struct sun8i_mixer_cfg sun50i_a64_mixer0_cfg = {
  614. .ccsc = CCSC_MIXER0_LAYOUT,
  615. .mod_rate = 297000000,
  616. .scaler_mask = 0xf,
  617. .scanline_yuv = 4096,
  618. .ui_num = 3,
  619. .vi_num = 1,
  620. };
  621. static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = {
  622. .ccsc = CCSC_MIXER1_LAYOUT,
  623. .mod_rate = 297000000,
  624. .scaler_mask = 0x3,
  625. .scanline_yuv = 2048,
  626. .ui_num = 1,
  627. .vi_num = 1,
  628. };
  629. static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
  630. .ccsc = CCSC_MIXER0_LAYOUT,
  631. .is_de3 = true,
  632. .mod_rate = 600000000,
  633. .scaler_mask = 0xf,
  634. .scanline_yuv = 4096,
  635. .ui_num = 3,
  636. .vi_num = 1,
  637. };
  638. static const struct of_device_id sun8i_mixer_of_table[] = {
  639. {
  640. .compatible = "allwinner,sun8i-a83t-de2-mixer-0",
  641. .data = &sun8i_a83t_mixer0_cfg,
  642. },
  643. {
  644. .compatible = "allwinner,sun8i-a83t-de2-mixer-1",
  645. .data = &sun8i_a83t_mixer1_cfg,
  646. },
  647. {
  648. .compatible = "allwinner,sun8i-h3-de2-mixer-0",
  649. .data = &sun8i_h3_mixer0_cfg,
  650. },
  651. {
  652. .compatible = "allwinner,sun8i-r40-de2-mixer-0",
  653. .data = &sun8i_r40_mixer0_cfg,
  654. },
  655. {
  656. .compatible = "allwinner,sun8i-r40-de2-mixer-1",
  657. .data = &sun8i_r40_mixer1_cfg,
  658. },
  659. {
  660. .compatible = "allwinner,sun8i-v3s-de2-mixer",
  661. .data = &sun8i_v3s_mixer_cfg,
  662. },
  663. {
  664. .compatible = "allwinner,sun20i-d1-de2-mixer-0",
  665. .data = &sun20i_d1_mixer0_cfg,
  666. },
  667. {
  668. .compatible = "allwinner,sun20i-d1-de2-mixer-1",
  669. .data = &sun20i_d1_mixer1_cfg,
  670. },
  671. {
  672. .compatible = "allwinner,sun50i-a64-de2-mixer-0",
  673. .data = &sun50i_a64_mixer0_cfg,
  674. },
  675. {
  676. .compatible = "allwinner,sun50i-a64-de2-mixer-1",
  677. .data = &sun50i_a64_mixer1_cfg,
  678. },
  679. {
  680. .compatible = "allwinner,sun50i-h6-de3-mixer-0",
  681. .data = &sun50i_h6_mixer0_cfg,
  682. },
  683. { }
  684. };
  685. MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
  686. static struct platform_driver sun8i_mixer_platform_driver = {
  687. .probe = sun8i_mixer_probe,
  688. .remove_new = sun8i_mixer_remove,
  689. .driver = {
  690. .name = "sun8i-mixer",
  691. .of_match_table = sun8i_mixer_of_table,
  692. },
  693. };
  694. module_platform_driver(sun8i_mixer_platform_driver);
  695. MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
  696. MODULE_DESCRIPTION("Allwinner DE2 Mixer driver");
  697. MODULE_LICENSE("GPL");