sun8i_mixer.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. /*
  2. * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
  3. *
  4. * Based on sun4i_backend.c, which is:
  5. * Copyright (C) 2015 Free Electrons
  6. * Copyright (C) 2015 NextThing Co
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. */
  13. #include <drm/drmP.h>
  14. #include <drm/drm_atomic_helper.h>
  15. #include <drm/drm_crtc.h>
  16. #include <drm/drm_crtc_helper.h>
  17. #include <drm/drm_fb_cma_helper.h>
  18. #include <drm/drm_gem_cma_helper.h>
  19. #include <drm/drm_plane_helper.h>
  20. #include <linux/component.h>
  21. #include <linux/dma-mapping.h>
  22. #include <linux/of_device.h>
  23. #include <linux/of_graph.h>
  24. #include <linux/reset.h>
  25. #include "sun4i_drv.h"
  26. #include "sun8i_mixer.h"
  27. #include "sun8i_ui_layer.h"
  28. #include "sun8i_vi_layer.h"
  29. #include "sunxi_engine.h"
  30. static const struct de2_fmt_info de2_formats[] = {
  31. {
  32. .drm_fmt = DRM_FORMAT_ARGB8888,
  33. .de2_fmt = SUN8I_MIXER_FBFMT_ARGB8888,
  34. .rgb = true,
  35. .csc = SUN8I_CSC_MODE_OFF,
  36. },
  37. {
  38. .drm_fmt = DRM_FORMAT_ABGR8888,
  39. .de2_fmt = SUN8I_MIXER_FBFMT_ABGR8888,
  40. .rgb = true,
  41. .csc = SUN8I_CSC_MODE_OFF,
  42. },
  43. {
  44. .drm_fmt = DRM_FORMAT_RGBA8888,
  45. .de2_fmt = SUN8I_MIXER_FBFMT_RGBA8888,
  46. .rgb = true,
  47. .csc = SUN8I_CSC_MODE_OFF,
  48. },
  49. {
  50. .drm_fmt = DRM_FORMAT_BGRA8888,
  51. .de2_fmt = SUN8I_MIXER_FBFMT_BGRA8888,
  52. .rgb = true,
  53. .csc = SUN8I_CSC_MODE_OFF,
  54. },
  55. {
  56. .drm_fmt = DRM_FORMAT_XRGB8888,
  57. .de2_fmt = SUN8I_MIXER_FBFMT_XRGB8888,
  58. .rgb = true,
  59. .csc = SUN8I_CSC_MODE_OFF,
  60. },
  61. {
  62. .drm_fmt = DRM_FORMAT_XBGR8888,
  63. .de2_fmt = SUN8I_MIXER_FBFMT_XBGR8888,
  64. .rgb = true,
  65. .csc = SUN8I_CSC_MODE_OFF,
  66. },
  67. {
  68. .drm_fmt = DRM_FORMAT_RGBX8888,
  69. .de2_fmt = SUN8I_MIXER_FBFMT_RGBX8888,
  70. .rgb = true,
  71. .csc = SUN8I_CSC_MODE_OFF,
  72. },
  73. {
  74. .drm_fmt = DRM_FORMAT_BGRX8888,
  75. .de2_fmt = SUN8I_MIXER_FBFMT_BGRX8888,
  76. .rgb = true,
  77. .csc = SUN8I_CSC_MODE_OFF,
  78. },
  79. {
  80. .drm_fmt = DRM_FORMAT_RGB888,
  81. .de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
  82. .rgb = true,
  83. .csc = SUN8I_CSC_MODE_OFF,
  84. },
  85. {
  86. .drm_fmt = DRM_FORMAT_BGR888,
  87. .de2_fmt = SUN8I_MIXER_FBFMT_BGR888,
  88. .rgb = true,
  89. .csc = SUN8I_CSC_MODE_OFF,
  90. },
  91. {
  92. .drm_fmt = DRM_FORMAT_RGB565,
  93. .de2_fmt = SUN8I_MIXER_FBFMT_RGB565,
  94. .rgb = true,
  95. .csc = SUN8I_CSC_MODE_OFF,
  96. },
  97. {
  98. .drm_fmt = DRM_FORMAT_BGR565,
  99. .de2_fmt = SUN8I_MIXER_FBFMT_BGR565,
  100. .rgb = true,
  101. .csc = SUN8I_CSC_MODE_OFF,
  102. },
  103. {
  104. .drm_fmt = DRM_FORMAT_ARGB4444,
  105. .de2_fmt = SUN8I_MIXER_FBFMT_ARGB4444,
  106. .rgb = true,
  107. .csc = SUN8I_CSC_MODE_OFF,
  108. },
  109. {
  110. /* for DE2 VI layer which ignores alpha */
  111. .drm_fmt = DRM_FORMAT_XRGB4444,
  112. .de2_fmt = SUN8I_MIXER_FBFMT_ARGB4444,
  113. .rgb = true,
  114. .csc = SUN8I_CSC_MODE_OFF,
  115. },
  116. {
  117. .drm_fmt = DRM_FORMAT_ABGR4444,
  118. .de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
  119. .rgb = true,
  120. .csc = SUN8I_CSC_MODE_OFF,
  121. },
  122. {
  123. /* for DE2 VI layer which ignores alpha */
  124. .drm_fmt = DRM_FORMAT_XBGR4444,
  125. .de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
  126. .rgb = true,
  127. .csc = SUN8I_CSC_MODE_OFF,
  128. },
  129. {
  130. .drm_fmt = DRM_FORMAT_RGBA4444,
  131. .de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
  132. .rgb = true,
  133. .csc = SUN8I_CSC_MODE_OFF,
  134. },
  135. {
  136. /* for DE2 VI layer which ignores alpha */
  137. .drm_fmt = DRM_FORMAT_RGBX4444,
  138. .de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
  139. .rgb = true,
  140. .csc = SUN8I_CSC_MODE_OFF,
  141. },
  142. {
  143. .drm_fmt = DRM_FORMAT_BGRA4444,
  144. .de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
  145. .rgb = true,
  146. .csc = SUN8I_CSC_MODE_OFF,
  147. },
  148. {
  149. /* for DE2 VI layer which ignores alpha */
  150. .drm_fmt = DRM_FORMAT_BGRX4444,
  151. .de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
  152. .rgb = true,
  153. .csc = SUN8I_CSC_MODE_OFF,
  154. },
  155. {
  156. .drm_fmt = DRM_FORMAT_ARGB1555,
  157. .de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
  158. .rgb = true,
  159. .csc = SUN8I_CSC_MODE_OFF,
  160. },
  161. {
  162. /* for DE2 VI layer which ignores alpha */
  163. .drm_fmt = DRM_FORMAT_XRGB1555,
  164. .de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
  165. .rgb = true,
  166. .csc = SUN8I_CSC_MODE_OFF,
  167. },
  168. {
  169. .drm_fmt = DRM_FORMAT_ABGR1555,
  170. .de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
  171. .rgb = true,
  172. .csc = SUN8I_CSC_MODE_OFF,
  173. },
  174. {
  175. /* for DE2 VI layer which ignores alpha */
  176. .drm_fmt = DRM_FORMAT_XBGR1555,
  177. .de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
  178. .rgb = true,
  179. .csc = SUN8I_CSC_MODE_OFF,
  180. },
  181. {
  182. .drm_fmt = DRM_FORMAT_RGBA5551,
  183. .de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
  184. .rgb = true,
  185. .csc = SUN8I_CSC_MODE_OFF,
  186. },
  187. {
  188. /* for DE2 VI layer which ignores alpha */
  189. .drm_fmt = DRM_FORMAT_RGBX5551,
  190. .de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
  191. .rgb = true,
  192. .csc = SUN8I_CSC_MODE_OFF,
  193. },
  194. {
  195. .drm_fmt = DRM_FORMAT_BGRA5551,
  196. .de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
  197. .rgb = true,
  198. .csc = SUN8I_CSC_MODE_OFF,
  199. },
  200. {
  201. /* for DE2 VI layer which ignores alpha */
  202. .drm_fmt = DRM_FORMAT_BGRX5551,
  203. .de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
  204. .rgb = true,
  205. .csc = SUN8I_CSC_MODE_OFF,
  206. },
  207. {
  208. .drm_fmt = DRM_FORMAT_UYVY,
  209. .de2_fmt = SUN8I_MIXER_FBFMT_UYVY,
  210. .rgb = false,
  211. .csc = SUN8I_CSC_MODE_YUV2RGB,
  212. },
  213. {
  214. .drm_fmt = DRM_FORMAT_VYUY,
  215. .de2_fmt = SUN8I_MIXER_FBFMT_VYUY,
  216. .rgb = false,
  217. .csc = SUN8I_CSC_MODE_YUV2RGB,
  218. },
  219. {
  220. .drm_fmt = DRM_FORMAT_YUYV,
  221. .de2_fmt = SUN8I_MIXER_FBFMT_YUYV,
  222. .rgb = false,
  223. .csc = SUN8I_CSC_MODE_YUV2RGB,
  224. },
  225. {
  226. .drm_fmt = DRM_FORMAT_YVYU,
  227. .de2_fmt = SUN8I_MIXER_FBFMT_YVYU,
  228. .rgb = false,
  229. .csc = SUN8I_CSC_MODE_YUV2RGB,
  230. },
  231. {
  232. .drm_fmt = DRM_FORMAT_NV16,
  233. .de2_fmt = SUN8I_MIXER_FBFMT_NV16,
  234. .rgb = false,
  235. .csc = SUN8I_CSC_MODE_YUV2RGB,
  236. },
  237. {
  238. .drm_fmt = DRM_FORMAT_NV61,
  239. .de2_fmt = SUN8I_MIXER_FBFMT_NV61,
  240. .rgb = false,
  241. .csc = SUN8I_CSC_MODE_YUV2RGB,
  242. },
  243. {
  244. .drm_fmt = DRM_FORMAT_NV12,
  245. .de2_fmt = SUN8I_MIXER_FBFMT_NV12,
  246. .rgb = false,
  247. .csc = SUN8I_CSC_MODE_YUV2RGB,
  248. },
  249. {
  250. .drm_fmt = DRM_FORMAT_NV21,
  251. .de2_fmt = SUN8I_MIXER_FBFMT_NV21,
  252. .rgb = false,
  253. .csc = SUN8I_CSC_MODE_YUV2RGB,
  254. },
  255. {
  256. .drm_fmt = DRM_FORMAT_YUV422,
  257. .de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
  258. .rgb = false,
  259. .csc = SUN8I_CSC_MODE_YUV2RGB,
  260. },
  261. {
  262. .drm_fmt = DRM_FORMAT_YUV420,
  263. .de2_fmt = SUN8I_MIXER_FBFMT_YUV420,
  264. .rgb = false,
  265. .csc = SUN8I_CSC_MODE_YUV2RGB,
  266. },
  267. {
  268. .drm_fmt = DRM_FORMAT_YUV411,
  269. .de2_fmt = SUN8I_MIXER_FBFMT_YUV411,
  270. .rgb = false,
  271. .csc = SUN8I_CSC_MODE_YUV2RGB,
  272. },
  273. {
  274. .drm_fmt = DRM_FORMAT_YVU422,
  275. .de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
  276. .rgb = false,
  277. .csc = SUN8I_CSC_MODE_YVU2RGB,
  278. },
  279. {
  280. .drm_fmt = DRM_FORMAT_YVU420,
  281. .de2_fmt = SUN8I_MIXER_FBFMT_YUV420,
  282. .rgb = false,
  283. .csc = SUN8I_CSC_MODE_YVU2RGB,
  284. },
  285. {
  286. .drm_fmt = DRM_FORMAT_YVU411,
  287. .de2_fmt = SUN8I_MIXER_FBFMT_YUV411,
  288. .rgb = false,
  289. .csc = SUN8I_CSC_MODE_YVU2RGB,
  290. },
  291. };
  292. const struct de2_fmt_info *sun8i_mixer_format_info(u32 format)
  293. {
  294. unsigned int i;
  295. for (i = 0; i < ARRAY_SIZE(de2_formats); ++i)
  296. if (de2_formats[i].drm_fmt == format)
  297. return &de2_formats[i];
  298. return NULL;
  299. }
  300. static void sun8i_mixer_commit(struct sunxi_engine *engine)
  301. {
  302. DRM_DEBUG_DRIVER("Committing changes\n");
  303. regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
  304. SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
  305. }
  306. static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
  307. struct sunxi_engine *engine)
  308. {
  309. struct drm_plane **planes;
  310. struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
  311. int i;
  312. planes = devm_kcalloc(drm->dev,
  313. mixer->cfg->vi_num + mixer->cfg->ui_num + 1,
  314. sizeof(*planes), GFP_KERNEL);
  315. if (!planes)
  316. return ERR_PTR(-ENOMEM);
  317. for (i = 0; i < mixer->cfg->vi_num; i++) {
  318. struct sun8i_vi_layer *layer;
  319. layer = sun8i_vi_layer_init_one(drm, mixer, i);
  320. if (IS_ERR(layer)) {
  321. dev_err(drm->dev,
  322. "Couldn't initialize overlay plane\n");
  323. return ERR_CAST(layer);
  324. };
  325. planes[i] = &layer->plane;
  326. };
  327. for (i = 0; i < mixer->cfg->ui_num; i++) {
  328. struct sun8i_ui_layer *layer;
  329. layer = sun8i_ui_layer_init_one(drm, mixer, i);
  330. if (IS_ERR(layer)) {
  331. dev_err(drm->dev, "Couldn't initialize %s plane\n",
  332. i ? "overlay" : "primary");
  333. return ERR_CAST(layer);
  334. };
  335. planes[mixer->cfg->vi_num + i] = &layer->plane;
  336. };
  337. return planes;
  338. }
  339. static const struct sunxi_engine_ops sun8i_engine_ops = {
  340. .commit = sun8i_mixer_commit,
  341. .layers_init = sun8i_layers_init,
  342. };
  343. static struct regmap_config sun8i_mixer_regmap_config = {
  344. .reg_bits = 32,
  345. .val_bits = 32,
  346. .reg_stride = 4,
  347. .max_register = 0xbfffc, /* guessed */
  348. };
  349. static int sun8i_mixer_of_get_id(struct device_node *node)
  350. {
  351. struct device_node *port, *ep;
  352. int ret = -EINVAL;
  353. /* output is port 1 */
  354. port = of_graph_get_port_by_id(node, 1);
  355. if (!port)
  356. return -EINVAL;
  357. /* try to find downstream endpoint */
  358. for_each_available_child_of_node(port, ep) {
  359. struct device_node *remote;
  360. u32 reg;
  361. remote = of_graph_get_remote_endpoint(ep);
  362. if (!remote)
  363. continue;
  364. ret = of_property_read_u32(remote, "reg", &reg);
  365. if (!ret) {
  366. of_node_put(remote);
  367. of_node_put(ep);
  368. of_node_put(port);
  369. return reg;
  370. }
  371. of_node_put(remote);
  372. }
  373. of_node_put(port);
  374. return ret;
  375. }
  376. static int sun8i_mixer_bind(struct device *dev, struct device *master,
  377. void *data)
  378. {
  379. struct platform_device *pdev = to_platform_device(dev);
  380. struct drm_device *drm = data;
  381. struct sun4i_drv *drv = drm->dev_private;
  382. struct sun8i_mixer *mixer;
  383. struct resource *res;
  384. void __iomem *regs;
  385. int plane_cnt;
  386. int i, ret;
  387. /*
  388. * The mixer uses single 32-bit register to store memory
  389. * addresses, so that it cannot deal with 64-bit memory
  390. * addresses.
  391. * Restrict the DMA mask so that the mixer won't be
  392. * allocated some memory that is too high.
  393. */
  394. ret = dma_set_mask(dev, DMA_BIT_MASK(32));
  395. if (ret) {
  396. dev_err(dev, "Cannot do 32-bit DMA.\n");
  397. return ret;
  398. }
  399. mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
  400. if (!mixer)
  401. return -ENOMEM;
  402. dev_set_drvdata(dev, mixer);
  403. mixer->engine.ops = &sun8i_engine_ops;
  404. mixer->engine.node = dev->of_node;
  405. /*
  406. * While this function can fail, we shouldn't do anything
  407. * if this happens. Some early DE2 DT entries don't provide
  408. * mixer id but work nevertheless because matching between
  409. * TCON and mixer is done by comparing node pointers (old
  410. * way) instead comparing ids. If this function fails and
  411. * id is needed, it will fail during id matching anyway.
  412. */
  413. mixer->engine.id = sun8i_mixer_of_get_id(dev->of_node);
  414. mixer->cfg = of_device_get_match_data(dev);
  415. if (!mixer->cfg)
  416. return -EINVAL;
  417. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  418. regs = devm_ioremap_resource(dev, res);
  419. if (IS_ERR(regs))
  420. return PTR_ERR(regs);
  421. mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
  422. &sun8i_mixer_regmap_config);
  423. if (IS_ERR(mixer->engine.regs)) {
  424. dev_err(dev, "Couldn't create the mixer regmap\n");
  425. return PTR_ERR(mixer->engine.regs);
  426. }
  427. mixer->reset = devm_reset_control_get(dev, NULL);
  428. if (IS_ERR(mixer->reset)) {
  429. dev_err(dev, "Couldn't get our reset line\n");
  430. return PTR_ERR(mixer->reset);
  431. }
  432. ret = reset_control_deassert(mixer->reset);
  433. if (ret) {
  434. dev_err(dev, "Couldn't deassert our reset line\n");
  435. return ret;
  436. }
  437. mixer->bus_clk = devm_clk_get(dev, "bus");
  438. if (IS_ERR(mixer->bus_clk)) {
  439. dev_err(dev, "Couldn't get the mixer bus clock\n");
  440. ret = PTR_ERR(mixer->bus_clk);
  441. goto err_assert_reset;
  442. }
  443. clk_prepare_enable(mixer->bus_clk);
  444. mixer->mod_clk = devm_clk_get(dev, "mod");
  445. if (IS_ERR(mixer->mod_clk)) {
  446. dev_err(dev, "Couldn't get the mixer module clock\n");
  447. ret = PTR_ERR(mixer->mod_clk);
  448. goto err_disable_bus_clk;
  449. }
  450. /*
  451. * It seems that we need to enforce that rate for whatever
  452. * reason for the mixer to be functional. Make sure it's the
  453. * case.
  454. */
  455. if (mixer->cfg->mod_rate)
  456. clk_set_rate(mixer->mod_clk, mixer->cfg->mod_rate);
  457. clk_prepare_enable(mixer->mod_clk);
  458. list_add_tail(&mixer->engine.list, &drv->engine_list);
  459. /* Reset the registers */
  460. for (i = 0x0; i < 0x20000; i += 4)
  461. regmap_write(mixer->engine.regs, i, 0);
  462. /* Enable the mixer */
  463. regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
  464. SUN8I_MIXER_GLOBAL_CTL_RT_EN);
  465. /* Set background color to black */
  466. regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR,
  467. SUN8I_MIXER_BLEND_COLOR_BLACK);
  468. /*
  469. * Set fill color of bottom plane to black. Generally not needed
  470. * except when VI plane is at bottom (zpos = 0) and enabled.
  471. */
  472. regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL,
  473. SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
  474. regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(0),
  475. SUN8I_MIXER_BLEND_COLOR_BLACK);
  476. plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
  477. for (i = 0; i < plane_cnt; i++)
  478. regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_MODE(i),
  479. SUN8I_MIXER_BLEND_MODE_DEF);
  480. regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL,
  481. SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
  482. return 0;
  483. err_disable_bus_clk:
  484. clk_disable_unprepare(mixer->bus_clk);
  485. err_assert_reset:
  486. reset_control_assert(mixer->reset);
  487. return ret;
  488. }
  489. static void sun8i_mixer_unbind(struct device *dev, struct device *master,
  490. void *data)
  491. {
  492. struct sun8i_mixer *mixer = dev_get_drvdata(dev);
  493. list_del(&mixer->engine.list);
  494. clk_disable_unprepare(mixer->mod_clk);
  495. clk_disable_unprepare(mixer->bus_clk);
  496. reset_control_assert(mixer->reset);
  497. }
  498. static const struct component_ops sun8i_mixer_ops = {
  499. .bind = sun8i_mixer_bind,
  500. .unbind = sun8i_mixer_unbind,
  501. };
  502. static int sun8i_mixer_probe(struct platform_device *pdev)
  503. {
  504. return component_add(&pdev->dev, &sun8i_mixer_ops);
  505. }
  506. static int sun8i_mixer_remove(struct platform_device *pdev)
  507. {
  508. component_del(&pdev->dev, &sun8i_mixer_ops);
  509. return 0;
  510. }
  511. static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = {
  512. .ccsc = 0,
  513. .scaler_mask = 0xf,
  514. .ui_num = 3,
  515. .vi_num = 1,
  516. };
  517. static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = {
  518. .ccsc = 1,
  519. .scaler_mask = 0x3,
  520. .ui_num = 1,
  521. .vi_num = 1,
  522. };
  523. static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
  524. .ccsc = 0,
  525. .mod_rate = 432000000,
  526. .scaler_mask = 0xf,
  527. .ui_num = 3,
  528. .vi_num = 1,
  529. };
  530. static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
  531. .vi_num = 2,
  532. .ui_num = 1,
  533. .scaler_mask = 0x3,
  534. .ccsc = 0,
  535. .mod_rate = 150000000,
  536. };
  537. static const struct of_device_id sun8i_mixer_of_table[] = {
  538. {
  539. .compatible = "allwinner,sun8i-a83t-de2-mixer-0",
  540. .data = &sun8i_a83t_mixer0_cfg,
  541. },
  542. {
  543. .compatible = "allwinner,sun8i-a83t-de2-mixer-1",
  544. .data = &sun8i_a83t_mixer1_cfg,
  545. },
  546. {
  547. .compatible = "allwinner,sun8i-h3-de2-mixer-0",
  548. .data = &sun8i_h3_mixer0_cfg,
  549. },
  550. {
  551. .compatible = "allwinner,sun8i-v3s-de2-mixer",
  552. .data = &sun8i_v3s_mixer_cfg,
  553. },
  554. { }
  555. };
  556. MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
  557. static struct platform_driver sun8i_mixer_platform_driver = {
  558. .probe = sun8i_mixer_probe,
  559. .remove = sun8i_mixer_remove,
  560. .driver = {
  561. .name = "sun8i-mixer",
  562. .of_match_table = sun8i_mixer_of_table,
  563. },
  564. };
  565. module_platform_driver(sun8i_mixer_platform_driver);
  566. MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
  567. MODULE_DESCRIPTION("Allwinner DE2 Mixer driver");
  568. MODULE_LICENSE("GPL");