sun4i_tcon.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260
  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_encoder.h>
  17. #include <drm/drm_modes.h>
  18. #include <drm/drm_of.h>
  19. #include <drm/drm_panel.h>
  20. #include <uapi/drm/drm_mode.h>
  21. #include <linux/component.h>
  22. #include <linux/ioport.h>
  23. #include <linux/of_address.h>
  24. #include <linux/of_device.h>
  25. #include <linux/of_irq.h>
  26. #include <linux/regmap.h>
  27. #include <linux/reset.h>
  28. #include "sun4i_crtc.h"
  29. #include "sun4i_dotclock.h"
  30. #include "sun4i_drv.h"
  31. #include "sun4i_lvds.h"
  32. #include "sun4i_rgb.h"
  33. #include "sun4i_tcon.h"
  34. #include "sunxi_engine.h"
  35. static struct drm_connector *sun4i_tcon_get_connector(const struct drm_encoder *encoder)
  36. {
  37. struct drm_connector *connector;
  38. struct drm_connector_list_iter iter;
  39. drm_connector_list_iter_begin(encoder->dev, &iter);
  40. drm_for_each_connector_iter(connector, &iter)
  41. if (connector->encoder == encoder) {
  42. drm_connector_list_iter_end(&iter);
  43. return connector;
  44. }
  45. drm_connector_list_iter_end(&iter);
  46. return NULL;
  47. }
  48. static int sun4i_tcon_get_pixel_depth(const struct drm_encoder *encoder)
  49. {
  50. struct drm_connector *connector;
  51. struct drm_display_info *info;
  52. connector = sun4i_tcon_get_connector(encoder);
  53. if (!connector)
  54. return -EINVAL;
  55. info = &connector->display_info;
  56. if (info->num_bus_formats != 1)
  57. return -EINVAL;
  58. switch (info->bus_formats[0]) {
  59. case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
  60. return 18;
  61. case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
  62. case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
  63. return 24;
  64. }
  65. return -EINVAL;
  66. }
  67. static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
  68. bool enabled)
  69. {
  70. struct clk *clk;
  71. switch (channel) {
  72. case 0:
  73. WARN_ON(!tcon->quirks->has_channel_0);
  74. regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
  75. SUN4I_TCON0_CTL_TCON_ENABLE,
  76. enabled ? SUN4I_TCON0_CTL_TCON_ENABLE : 0);
  77. clk = tcon->dclk;
  78. break;
  79. case 1:
  80. WARN_ON(!tcon->quirks->has_channel_1);
  81. regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
  82. SUN4I_TCON1_CTL_TCON_ENABLE,
  83. enabled ? SUN4I_TCON1_CTL_TCON_ENABLE : 0);
  84. clk = tcon->sclk1;
  85. break;
  86. default:
  87. DRM_WARN("Unknown channel... doing nothing\n");
  88. return;
  89. }
  90. if (enabled) {
  91. clk_prepare_enable(clk);
  92. clk_rate_exclusive_get(clk);
  93. } else {
  94. clk_rate_exclusive_put(clk);
  95. clk_disable_unprepare(clk);
  96. }
  97. }
  98. static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon,
  99. const struct drm_encoder *encoder,
  100. bool enabled)
  101. {
  102. if (enabled) {
  103. u8 val;
  104. regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_IF_REG,
  105. SUN4I_TCON0_LVDS_IF_EN,
  106. SUN4I_TCON0_LVDS_IF_EN);
  107. /*
  108. * As their name suggest, these values only apply to the A31
  109. * and later SoCs. We'll have to rework this when merging
  110. * support for the older SoCs.
  111. */
  112. regmap_write(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
  113. SUN6I_TCON0_LVDS_ANA0_C(2) |
  114. SUN6I_TCON0_LVDS_ANA0_V(3) |
  115. SUN6I_TCON0_LVDS_ANA0_PD(2) |
  116. SUN6I_TCON0_LVDS_ANA0_EN_LDO);
  117. udelay(2);
  118. regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
  119. SUN6I_TCON0_LVDS_ANA0_EN_MB,
  120. SUN6I_TCON0_LVDS_ANA0_EN_MB);
  121. udelay(2);
  122. regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
  123. SUN6I_TCON0_LVDS_ANA0_EN_DRVC,
  124. SUN6I_TCON0_LVDS_ANA0_EN_DRVC);
  125. if (sun4i_tcon_get_pixel_depth(encoder) == 18)
  126. val = 7;
  127. else
  128. val = 0xf;
  129. regmap_write_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
  130. SUN6I_TCON0_LVDS_ANA0_EN_DRVD(0xf),
  131. SUN6I_TCON0_LVDS_ANA0_EN_DRVD(val));
  132. } else {
  133. regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_IF_REG,
  134. SUN4I_TCON0_LVDS_IF_EN, 0);
  135. }
  136. }
  137. void sun4i_tcon_set_status(struct sun4i_tcon *tcon,
  138. const struct drm_encoder *encoder,
  139. bool enabled)
  140. {
  141. bool is_lvds = false;
  142. int channel;
  143. switch (encoder->encoder_type) {
  144. case DRM_MODE_ENCODER_LVDS:
  145. is_lvds = true;
  146. /* Fallthrough */
  147. case DRM_MODE_ENCODER_NONE:
  148. channel = 0;
  149. break;
  150. case DRM_MODE_ENCODER_TMDS:
  151. case DRM_MODE_ENCODER_TVDAC:
  152. channel = 1;
  153. break;
  154. default:
  155. DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
  156. return;
  157. }
  158. if (is_lvds && !enabled)
  159. sun4i_tcon_lvds_set_status(tcon, encoder, false);
  160. regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
  161. SUN4I_TCON_GCTL_TCON_ENABLE,
  162. enabled ? SUN4I_TCON_GCTL_TCON_ENABLE : 0);
  163. if (is_lvds && enabled)
  164. sun4i_tcon_lvds_set_status(tcon, encoder, true);
  165. sun4i_tcon_channel_set_status(tcon, channel, enabled);
  166. }
  167. void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
  168. {
  169. u32 mask, val = 0;
  170. DRM_DEBUG_DRIVER("%sabling VBLANK interrupt\n", enable ? "En" : "Dis");
  171. mask = SUN4I_TCON_GINT0_VBLANK_ENABLE(0) |
  172. SUN4I_TCON_GINT0_VBLANK_ENABLE(1);
  173. if (enable)
  174. val = mask;
  175. regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG, mask, val);
  176. }
  177. EXPORT_SYMBOL(sun4i_tcon_enable_vblank);
  178. /*
  179. * This function is a helper for TCON output muxing. The TCON output
  180. * muxing control register in earlier SoCs (without the TCON TOP block)
  181. * are located in TCON0. This helper returns a pointer to TCON0's
  182. * sun4i_tcon structure, or NULL if not found.
  183. */
  184. static struct sun4i_tcon *sun4i_get_tcon0(struct drm_device *drm)
  185. {
  186. struct sun4i_drv *drv = drm->dev_private;
  187. struct sun4i_tcon *tcon;
  188. list_for_each_entry(tcon, &drv->tcon_list, list)
  189. if (tcon->id == 0)
  190. return tcon;
  191. dev_warn(drm->dev,
  192. "TCON0 not found, display output muxing may not work\n");
  193. return NULL;
  194. }
  195. void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
  196. const struct drm_encoder *encoder)
  197. {
  198. int ret = -ENOTSUPP;
  199. if (tcon->quirks->set_mux)
  200. ret = tcon->quirks->set_mux(tcon, encoder);
  201. DRM_DEBUG_DRIVER("Muxing encoder %s to CRTC %s: %d\n",
  202. encoder->name, encoder->crtc->name, ret);
  203. }
  204. static int sun4i_tcon_get_clk_delay(const struct drm_display_mode *mode,
  205. int channel)
  206. {
  207. int delay = mode->vtotal - mode->vdisplay;
  208. if (mode->flags & DRM_MODE_FLAG_INTERLACE)
  209. delay /= 2;
  210. if (channel == 1)
  211. delay -= 2;
  212. delay = min(delay, 30);
  213. DRM_DEBUG_DRIVER("TCON %d clock delay %u\n", channel, delay);
  214. return delay;
  215. }
  216. static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon,
  217. const struct drm_display_mode *mode)
  218. {
  219. /* Configure the dot clock */
  220. clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);
  221. /* Set the resolution */
  222. regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
  223. SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
  224. SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
  225. }
  226. static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon,
  227. const struct drm_encoder *encoder,
  228. const struct drm_display_mode *mode)
  229. {
  230. unsigned int bp;
  231. u8 clk_delay;
  232. u32 reg, val = 0;
  233. WARN_ON(!tcon->quirks->has_channel_0);
  234. tcon->dclk_min_div = 7;
  235. tcon->dclk_max_div = 7;
  236. sun4i_tcon0_mode_set_common(tcon, mode);
  237. /* Adjust clock delay */
  238. clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
  239. regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
  240. SUN4I_TCON0_CTL_CLK_DELAY_MASK,
  241. SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));
  242. /*
  243. * This is called a backporch in the register documentation,
  244. * but it really is the back porch + hsync
  245. */
  246. bp = mode->crtc_htotal - mode->crtc_hsync_start;
  247. DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
  248. mode->crtc_htotal, bp);
  249. /* Set horizontal display timings */
  250. regmap_write(tcon->regs, SUN4I_TCON0_BASIC1_REG,
  251. SUN4I_TCON0_BASIC1_H_TOTAL(mode->htotal) |
  252. SUN4I_TCON0_BASIC1_H_BACKPORCH(bp));
  253. /*
  254. * This is called a backporch in the register documentation,
  255. * but it really is the back porch + hsync
  256. */
  257. bp = mode->crtc_vtotal - mode->crtc_vsync_start;
  258. DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
  259. mode->crtc_vtotal, bp);
  260. /* Set vertical display timings */
  261. regmap_write(tcon->regs, SUN4I_TCON0_BASIC2_REG,
  262. SUN4I_TCON0_BASIC2_V_TOTAL(mode->crtc_vtotal * 2) |
  263. SUN4I_TCON0_BASIC2_V_BACKPORCH(bp));
  264. reg = SUN4I_TCON0_LVDS_IF_CLK_SEL_TCON0 |
  265. SUN4I_TCON0_LVDS_IF_DATA_POL_NORMAL |
  266. SUN4I_TCON0_LVDS_IF_CLK_POL_NORMAL;
  267. if (sun4i_tcon_get_pixel_depth(encoder) == 24)
  268. reg |= SUN4I_TCON0_LVDS_IF_BITWIDTH_24BITS;
  269. else
  270. reg |= SUN4I_TCON0_LVDS_IF_BITWIDTH_18BITS;
  271. regmap_write(tcon->regs, SUN4I_TCON0_LVDS_IF_REG, reg);
  272. /* Setup the polarity of the various signals */
  273. if (!(mode->flags & DRM_MODE_FLAG_PHSYNC))
  274. val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE;
  275. if (!(mode->flags & DRM_MODE_FLAG_PVSYNC))
  276. val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
  277. regmap_write(tcon->regs, SUN4I_TCON0_IO_POL_REG, val);
  278. /* Map output pins to channel 0 */
  279. regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
  280. SUN4I_TCON_GCTL_IOMAP_MASK,
  281. SUN4I_TCON_GCTL_IOMAP_TCON0);
  282. /* Enable the output on the pins */
  283. regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0xe0000000);
  284. }
  285. static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
  286. const struct drm_display_mode *mode)
  287. {
  288. struct drm_panel *panel = tcon->panel;
  289. struct drm_connector *connector = panel->connector;
  290. struct drm_display_info display_info = connector->display_info;
  291. unsigned int bp, hsync, vsync;
  292. u8 clk_delay;
  293. u32 val = 0;
  294. WARN_ON(!tcon->quirks->has_channel_0);
  295. tcon->dclk_min_div = 6;
  296. tcon->dclk_max_div = 127;
  297. sun4i_tcon0_mode_set_common(tcon, mode);
  298. /* Adjust clock delay */
  299. clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
  300. regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
  301. SUN4I_TCON0_CTL_CLK_DELAY_MASK,
  302. SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));
  303. /*
  304. * This is called a backporch in the register documentation,
  305. * but it really is the back porch + hsync
  306. */
  307. bp = mode->crtc_htotal - mode->crtc_hsync_start;
  308. DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
  309. mode->crtc_htotal, bp);
  310. /* Set horizontal display timings */
  311. regmap_write(tcon->regs, SUN4I_TCON0_BASIC1_REG,
  312. SUN4I_TCON0_BASIC1_H_TOTAL(mode->crtc_htotal) |
  313. SUN4I_TCON0_BASIC1_H_BACKPORCH(bp));
  314. /*
  315. * This is called a backporch in the register documentation,
  316. * but it really is the back porch + hsync
  317. */
  318. bp = mode->crtc_vtotal - mode->crtc_vsync_start;
  319. DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
  320. mode->crtc_vtotal, bp);
  321. /* Set vertical display timings */
  322. regmap_write(tcon->regs, SUN4I_TCON0_BASIC2_REG,
  323. SUN4I_TCON0_BASIC2_V_TOTAL(mode->crtc_vtotal * 2) |
  324. SUN4I_TCON0_BASIC2_V_BACKPORCH(bp));
  325. /* Set Hsync and Vsync length */
  326. hsync = mode->crtc_hsync_end - mode->crtc_hsync_start;
  327. vsync = mode->crtc_vsync_end - mode->crtc_vsync_start;
  328. DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync);
  329. regmap_write(tcon->regs, SUN4I_TCON0_BASIC3_REG,
  330. SUN4I_TCON0_BASIC3_V_SYNC(vsync) |
  331. SUN4I_TCON0_BASIC3_H_SYNC(hsync));
  332. /* Setup the polarity of the various signals */
  333. if (mode->flags & DRM_MODE_FLAG_PHSYNC)
  334. val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE;
  335. if (mode->flags & DRM_MODE_FLAG_PVSYNC)
  336. val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
  337. /*
  338. * On A20 and similar SoCs, the only way to achieve Positive Edge
  339. * (Rising Edge), is setting dclk clock phase to 2/3(240°).
  340. * By default TCON works in Negative Edge(Falling Edge),
  341. * this is why phase is set to 0 in that case.
  342. * Unfortunately there's no way to logically invert dclk through
  343. * IO_POL register.
  344. * The only acceptable way to work, triple checked with scope,
  345. * is using clock phase set to 0° for Negative Edge and set to 240°
  346. * for Positive Edge.
  347. * On A33 and similar SoCs there would be a 90° phase option,
  348. * but it divides also dclk by 2.
  349. * Following code is a way to avoid quirks all around TCON
  350. * and DOTCLOCK drivers.
  351. */
  352. if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)
  353. clk_set_phase(tcon->dclk, 240);
  354. if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE)
  355. clk_set_phase(tcon->dclk, 0);
  356. regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG,
  357. SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE,
  358. val);
  359. /* Map output pins to channel 0 */
  360. regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
  361. SUN4I_TCON_GCTL_IOMAP_MASK,
  362. SUN4I_TCON_GCTL_IOMAP_TCON0);
  363. /* Enable the output on the pins */
  364. regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0);
  365. }
  366. static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
  367. const struct drm_display_mode *mode)
  368. {
  369. unsigned int bp, hsync, vsync, vtotal;
  370. u8 clk_delay;
  371. u32 val;
  372. WARN_ON(!tcon->quirks->has_channel_1);
  373. /* Configure the dot clock */
  374. clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000);
  375. /* Adjust clock delay */
  376. clk_delay = sun4i_tcon_get_clk_delay(mode, 1);
  377. regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
  378. SUN4I_TCON1_CTL_CLK_DELAY_MASK,
  379. SUN4I_TCON1_CTL_CLK_DELAY(clk_delay));
  380. /* Set interlaced mode */
  381. if (mode->flags & DRM_MODE_FLAG_INTERLACE)
  382. val = SUN4I_TCON1_CTL_INTERLACE_ENABLE;
  383. else
  384. val = 0;
  385. regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
  386. SUN4I_TCON1_CTL_INTERLACE_ENABLE,
  387. val);
  388. /* Set the input resolution */
  389. regmap_write(tcon->regs, SUN4I_TCON1_BASIC0_REG,
  390. SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay) |
  391. SUN4I_TCON1_BASIC0_Y(mode->crtc_vdisplay));
  392. /* Set the upscaling resolution */
  393. regmap_write(tcon->regs, SUN4I_TCON1_BASIC1_REG,
  394. SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay) |
  395. SUN4I_TCON1_BASIC1_Y(mode->crtc_vdisplay));
  396. /* Set the output resolution */
  397. regmap_write(tcon->regs, SUN4I_TCON1_BASIC2_REG,
  398. SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay) |
  399. SUN4I_TCON1_BASIC2_Y(mode->crtc_vdisplay));
  400. /* Set horizontal display timings */
  401. bp = mode->crtc_htotal - mode->crtc_hsync_start;
  402. DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
  403. mode->htotal, bp);
  404. regmap_write(tcon->regs, SUN4I_TCON1_BASIC3_REG,
  405. SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal) |
  406. SUN4I_TCON1_BASIC3_H_BACKPORCH(bp));
  407. bp = mode->crtc_vtotal - mode->crtc_vsync_start;
  408. DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
  409. mode->crtc_vtotal, bp);
  410. /*
  411. * The vertical resolution needs to be doubled in all
  412. * cases. We could use crtc_vtotal and always multiply by two,
  413. * but that leads to a rounding error in interlace when vtotal
  414. * is odd.
  415. *
  416. * This happens with TV's PAL for example, where vtotal will
  417. * be 625, crtc_vtotal 312, and thus crtc_vtotal * 2 will be
  418. * 624, which apparently confuses the hardware.
  419. *
  420. * To work around this, we will always use vtotal, and
  421. * multiply by two only if we're not in interlace.
  422. */
  423. vtotal = mode->vtotal;
  424. if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
  425. vtotal = vtotal * 2;
  426. /* Set vertical display timings */
  427. regmap_write(tcon->regs, SUN4I_TCON1_BASIC4_REG,
  428. SUN4I_TCON1_BASIC4_V_TOTAL(vtotal) |
  429. SUN4I_TCON1_BASIC4_V_BACKPORCH(bp));
  430. /* Set Hsync and Vsync length */
  431. hsync = mode->crtc_hsync_end - mode->crtc_hsync_start;
  432. vsync = mode->crtc_vsync_end - mode->crtc_vsync_start;
  433. DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync);
  434. regmap_write(tcon->regs, SUN4I_TCON1_BASIC5_REG,
  435. SUN4I_TCON1_BASIC5_V_SYNC(vsync) |
  436. SUN4I_TCON1_BASIC5_H_SYNC(hsync));
  437. /* Map output pins to channel 1 */
  438. regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
  439. SUN4I_TCON_GCTL_IOMAP_MASK,
  440. SUN4I_TCON_GCTL_IOMAP_TCON1);
  441. }
  442. void sun4i_tcon_mode_set(struct sun4i_tcon *tcon,
  443. const struct drm_encoder *encoder,
  444. const struct drm_display_mode *mode)
  445. {
  446. switch (encoder->encoder_type) {
  447. case DRM_MODE_ENCODER_LVDS:
  448. sun4i_tcon0_mode_set_lvds(tcon, encoder, mode);
  449. break;
  450. case DRM_MODE_ENCODER_NONE:
  451. sun4i_tcon0_mode_set_rgb(tcon, mode);
  452. sun4i_tcon_set_mux(tcon, 0, encoder);
  453. break;
  454. case DRM_MODE_ENCODER_TVDAC:
  455. case DRM_MODE_ENCODER_TMDS:
  456. sun4i_tcon1_mode_set(tcon, mode);
  457. sun4i_tcon_set_mux(tcon, 1, encoder);
  458. break;
  459. default:
  460. DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
  461. }
  462. }
  463. EXPORT_SYMBOL(sun4i_tcon_mode_set);
  464. static void sun4i_tcon_finish_page_flip(struct drm_device *dev,
  465. struct sun4i_crtc *scrtc)
  466. {
  467. unsigned long flags;
  468. spin_lock_irqsave(&dev->event_lock, flags);
  469. if (scrtc->event) {
  470. drm_crtc_send_vblank_event(&scrtc->crtc, scrtc->event);
  471. drm_crtc_vblank_put(&scrtc->crtc);
  472. scrtc->event = NULL;
  473. }
  474. spin_unlock_irqrestore(&dev->event_lock, flags);
  475. }
  476. static irqreturn_t sun4i_tcon_handler(int irq, void *private)
  477. {
  478. struct sun4i_tcon *tcon = private;
  479. struct drm_device *drm = tcon->drm;
  480. struct sun4i_crtc *scrtc = tcon->crtc;
  481. struct sunxi_engine *engine = scrtc->engine;
  482. unsigned int status;
  483. regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
  484. if (!(status & (SUN4I_TCON_GINT0_VBLANK_INT(0) |
  485. SUN4I_TCON_GINT0_VBLANK_INT(1))))
  486. return IRQ_NONE;
  487. drm_crtc_handle_vblank(&scrtc->crtc);
  488. sun4i_tcon_finish_page_flip(drm, scrtc);
  489. /* Acknowledge the interrupt */
  490. regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG,
  491. SUN4I_TCON_GINT0_VBLANK_INT(0) |
  492. SUN4I_TCON_GINT0_VBLANK_INT(1),
  493. 0);
  494. if (engine->ops->vblank_quirk)
  495. engine->ops->vblank_quirk(engine);
  496. return IRQ_HANDLED;
  497. }
  498. static int sun4i_tcon_init_clocks(struct device *dev,
  499. struct sun4i_tcon *tcon)
  500. {
  501. tcon->clk = devm_clk_get(dev, "ahb");
  502. if (IS_ERR(tcon->clk)) {
  503. dev_err(dev, "Couldn't get the TCON bus clock\n");
  504. return PTR_ERR(tcon->clk);
  505. }
  506. clk_prepare_enable(tcon->clk);
  507. if (tcon->quirks->has_channel_0) {
  508. tcon->sclk0 = devm_clk_get(dev, "tcon-ch0");
  509. if (IS_ERR(tcon->sclk0)) {
  510. dev_err(dev, "Couldn't get the TCON channel 0 clock\n");
  511. return PTR_ERR(tcon->sclk0);
  512. }
  513. }
  514. if (tcon->quirks->has_channel_1) {
  515. tcon->sclk1 = devm_clk_get(dev, "tcon-ch1");
  516. if (IS_ERR(tcon->sclk1)) {
  517. dev_err(dev, "Couldn't get the TCON channel 1 clock\n");
  518. return PTR_ERR(tcon->sclk1);
  519. }
  520. }
  521. return 0;
  522. }
  523. static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
  524. {
  525. clk_disable_unprepare(tcon->clk);
  526. }
  527. static int sun4i_tcon_init_irq(struct device *dev,
  528. struct sun4i_tcon *tcon)
  529. {
  530. struct platform_device *pdev = to_platform_device(dev);
  531. int irq, ret;
  532. irq = platform_get_irq(pdev, 0);
  533. if (irq < 0) {
  534. dev_err(dev, "Couldn't retrieve the TCON interrupt\n");
  535. return irq;
  536. }
  537. ret = devm_request_irq(dev, irq, sun4i_tcon_handler, 0,
  538. dev_name(dev), tcon);
  539. if (ret) {
  540. dev_err(dev, "Couldn't request the IRQ\n");
  541. return ret;
  542. }
  543. return 0;
  544. }
  545. static struct regmap_config sun4i_tcon_regmap_config = {
  546. .reg_bits = 32,
  547. .val_bits = 32,
  548. .reg_stride = 4,
  549. .max_register = 0x800,
  550. };
  551. static int sun4i_tcon_init_regmap(struct device *dev,
  552. struct sun4i_tcon *tcon)
  553. {
  554. struct platform_device *pdev = to_platform_device(dev);
  555. struct resource *res;
  556. void __iomem *regs;
  557. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  558. regs = devm_ioremap_resource(dev, res);
  559. if (IS_ERR(regs))
  560. return PTR_ERR(regs);
  561. tcon->regs = devm_regmap_init_mmio(dev, regs,
  562. &sun4i_tcon_regmap_config);
  563. if (IS_ERR(tcon->regs)) {
  564. dev_err(dev, "Couldn't create the TCON regmap\n");
  565. return PTR_ERR(tcon->regs);
  566. }
  567. /* Make sure the TCON is disabled and all IRQs are off */
  568. regmap_write(tcon->regs, SUN4I_TCON_GCTL_REG, 0);
  569. regmap_write(tcon->regs, SUN4I_TCON_GINT0_REG, 0);
  570. regmap_write(tcon->regs, SUN4I_TCON_GINT1_REG, 0);
  571. /* Disable IO lines and set them to tristate */
  572. regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, ~0);
  573. regmap_write(tcon->regs, SUN4I_TCON1_IO_TRI_REG, ~0);
  574. return 0;
  575. }
  576. /*
  577. * On SoCs with the old display pipeline design (Display Engine 1.0),
  578. * the TCON is always tied to just one backend. Hence we can traverse
  579. * the of_graph upwards to find the backend our tcon is connected to,
  580. * and take its ID as our own.
  581. *
  582. * We can either identify backends from their compatible strings, which
  583. * means maintaining a large list of them. Or, since the backend is
  584. * registered and binded before the TCON, we can just go through the
  585. * list of registered backends and compare the device node.
  586. *
  587. * As the structures now store engines instead of backends, here this
  588. * function in fact searches the corresponding engine, and the ID is
  589. * requested via the get_id function of the engine.
  590. */
  591. static struct sunxi_engine *
  592. sun4i_tcon_find_engine_traverse(struct sun4i_drv *drv,
  593. struct device_node *node)
  594. {
  595. struct device_node *port, *ep, *remote;
  596. struct sunxi_engine *engine = ERR_PTR(-EINVAL);
  597. port = of_graph_get_port_by_id(node, 0);
  598. if (!port)
  599. return ERR_PTR(-EINVAL);
  600. /*
  601. * This only works if there is only one path from the TCON
  602. * to any display engine. Otherwise the probe order of the
  603. * TCONs and display engines is not guaranteed. They may
  604. * either bind to the wrong one, or worse, bind to the same
  605. * one if additional checks are not done.
  606. *
  607. * Bail out if there are multiple input connections.
  608. */
  609. if (of_get_available_child_count(port) != 1)
  610. goto out_put_port;
  611. /* Get the first connection without specifying an ID */
  612. ep = of_get_next_available_child(port, NULL);
  613. if (!ep)
  614. goto out_put_port;
  615. remote = of_graph_get_remote_port_parent(ep);
  616. if (!remote)
  617. goto out_put_ep;
  618. /* does this node match any registered engines? */
  619. list_for_each_entry(engine, &drv->engine_list, list)
  620. if (remote == engine->node)
  621. goto out_put_remote;
  622. /* keep looking through upstream ports */
  623. engine = sun4i_tcon_find_engine_traverse(drv, remote);
  624. out_put_remote:
  625. of_node_put(remote);
  626. out_put_ep:
  627. of_node_put(ep);
  628. out_put_port:
  629. of_node_put(port);
  630. return engine;
  631. }
  632. /*
  633. * The device tree binding says that the remote endpoint ID of any
  634. * connection between components, up to and including the TCON, of
  635. * the display pipeline should be equal to the actual ID of the local
  636. * component. Thus we can look at any one of the input connections of
  637. * the TCONs, and use that connection's remote endpoint ID as our own.
  638. *
  639. * Since the user of this function already finds the input port,
  640. * the port is passed in directly without further checks.
  641. */
  642. static int sun4i_tcon_of_get_id_from_port(struct device_node *port)
  643. {
  644. struct device_node *ep;
  645. int ret = -EINVAL;
  646. /* try finding an upstream endpoint */
  647. for_each_available_child_of_node(port, ep) {
  648. struct device_node *remote;
  649. u32 reg;
  650. remote = of_graph_get_remote_endpoint(ep);
  651. if (!remote)
  652. continue;
  653. ret = of_property_read_u32(remote, "reg", &reg);
  654. if (ret)
  655. continue;
  656. ret = reg;
  657. }
  658. return ret;
  659. }
  660. /*
  661. * Once we know the TCON's id, we can look through the list of
  662. * engines to find a matching one. We assume all engines have
  663. * been probed and added to the list.
  664. */
  665. static struct sunxi_engine *sun4i_tcon_get_engine_by_id(struct sun4i_drv *drv,
  666. int id)
  667. {
  668. struct sunxi_engine *engine;
  669. list_for_each_entry(engine, &drv->engine_list, list)
  670. if (engine->id == id)
  671. return engine;
  672. return ERR_PTR(-EINVAL);
  673. }
  674. /*
  675. * On SoCs with the old display pipeline design (Display Engine 1.0),
  676. * we assumed the TCON was always tied to just one backend. However
  677. * this proved not to be the case. On the A31, the TCON can select
  678. * either backend as its source. On the A20 (and likely on the A10),
  679. * the backend can choose which TCON to output to.
  680. *
  681. * The device tree binding says that the remote endpoint ID of any
  682. * connection between components, up to and including the TCON, of
  683. * the display pipeline should be equal to the actual ID of the local
  684. * component. Thus we should be able to look at any one of the input
  685. * connections of the TCONs, and use that connection's remote endpoint
  686. * ID as our own.
  687. *
  688. * However the connections between the backend and TCON were assumed
  689. * to be always singular, and their endpoit IDs were all incorrectly
  690. * set to 0. This means for these old device trees, we cannot just look
  691. * up the remote endpoint ID of a TCON input endpoint. TCON1 would be
  692. * incorrectly identified as TCON0.
  693. *
  694. * This function first checks if the TCON node has 2 input endpoints.
  695. * If so, then the device tree is a corrected version, and it will use
  696. * sun4i_tcon_of_get_id() and sun4i_tcon_get_engine_by_id() from above
  697. * to fetch the ID and engine directly. If not, then it is likely an
  698. * old device trees, where the endpoint IDs were incorrect, but did not
  699. * have endpoint connections between the backend and TCON across
  700. * different display pipelines. It will fall back to the old method of
  701. * traversing the of_graph to try and find a matching engine by device
  702. * node.
  703. *
  704. * In the case of single display pipeline device trees, either method
  705. * works.
  706. */
  707. static struct sunxi_engine *sun4i_tcon_find_engine(struct sun4i_drv *drv,
  708. struct device_node *node)
  709. {
  710. struct device_node *port;
  711. struct sunxi_engine *engine;
  712. port = of_graph_get_port_by_id(node, 0);
  713. if (!port)
  714. return ERR_PTR(-EINVAL);
  715. /*
  716. * Is this a corrected device tree with cross pipeline
  717. * connections between the backend and TCON?
  718. */
  719. if (of_get_child_count(port) > 1) {
  720. /* Get our ID directly from an upstream endpoint */
  721. int id = sun4i_tcon_of_get_id_from_port(port);
  722. /* Get our engine by matching our ID */
  723. engine = sun4i_tcon_get_engine_by_id(drv, id);
  724. of_node_put(port);
  725. return engine;
  726. }
  727. /* Fallback to old method by traversing input endpoints */
  728. of_node_put(port);
  729. return sun4i_tcon_find_engine_traverse(drv, node);
  730. }
  731. static int sun4i_tcon_bind(struct device *dev, struct device *master,
  732. void *data)
  733. {
  734. struct drm_device *drm = data;
  735. struct sun4i_drv *drv = drm->dev_private;
  736. struct sunxi_engine *engine;
  737. struct device_node *remote;
  738. struct sun4i_tcon *tcon;
  739. struct reset_control *edp_rstc;
  740. bool has_lvds_rst, has_lvds_alt, can_lvds;
  741. int ret;
  742. engine = sun4i_tcon_find_engine(drv, dev->of_node);
  743. if (IS_ERR(engine)) {
  744. dev_err(dev, "Couldn't find matching engine\n");
  745. return -EPROBE_DEFER;
  746. }
  747. tcon = devm_kzalloc(dev, sizeof(*tcon), GFP_KERNEL);
  748. if (!tcon)
  749. return -ENOMEM;
  750. dev_set_drvdata(dev, tcon);
  751. tcon->drm = drm;
  752. tcon->dev = dev;
  753. tcon->id = engine->id;
  754. tcon->quirks = of_device_get_match_data(dev);
  755. tcon->lcd_rst = devm_reset_control_get(dev, "lcd");
  756. if (IS_ERR(tcon->lcd_rst)) {
  757. dev_err(dev, "Couldn't get our reset line\n");
  758. return PTR_ERR(tcon->lcd_rst);
  759. }
  760. if (tcon->quirks->needs_edp_reset) {
  761. edp_rstc = devm_reset_control_get_shared(dev, "edp");
  762. if (IS_ERR(edp_rstc)) {
  763. dev_err(dev, "Couldn't get edp reset line\n");
  764. return PTR_ERR(edp_rstc);
  765. }
  766. ret = reset_control_deassert(edp_rstc);
  767. if (ret) {
  768. dev_err(dev, "Couldn't deassert edp reset line\n");
  769. return ret;
  770. }
  771. }
  772. /* Make sure our TCON is reset */
  773. ret = reset_control_reset(tcon->lcd_rst);
  774. if (ret) {
  775. dev_err(dev, "Couldn't deassert our reset line\n");
  776. return ret;
  777. }
  778. if (tcon->quirks->supports_lvds) {
  779. /*
  780. * This can only be made optional since we've had DT
  781. * nodes without the LVDS reset properties.
  782. *
  783. * If the property is missing, just disable LVDS, and
  784. * print a warning.
  785. */
  786. tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds");
  787. if (IS_ERR(tcon->lvds_rst)) {
  788. dev_err(dev, "Couldn't get our reset line\n");
  789. return PTR_ERR(tcon->lvds_rst);
  790. } else if (tcon->lvds_rst) {
  791. has_lvds_rst = true;
  792. reset_control_reset(tcon->lvds_rst);
  793. } else {
  794. has_lvds_rst = false;
  795. }
  796. /*
  797. * This can only be made optional since we've had DT
  798. * nodes without the LVDS reset properties.
  799. *
  800. * If the property is missing, just disable LVDS, and
  801. * print a warning.
  802. */
  803. if (tcon->quirks->has_lvds_alt) {
  804. tcon->lvds_pll = devm_clk_get(dev, "lvds-alt");
  805. if (IS_ERR(tcon->lvds_pll)) {
  806. if (PTR_ERR(tcon->lvds_pll) == -ENOENT) {
  807. has_lvds_alt = false;
  808. } else {
  809. dev_err(dev, "Couldn't get the LVDS PLL\n");
  810. return PTR_ERR(tcon->lvds_pll);
  811. }
  812. } else {
  813. has_lvds_alt = true;
  814. }
  815. }
  816. if (!has_lvds_rst ||
  817. (tcon->quirks->has_lvds_alt && !has_lvds_alt)) {
  818. dev_warn(dev, "Missing LVDS properties, Please upgrade your DT\n");
  819. dev_warn(dev, "LVDS output disabled\n");
  820. can_lvds = false;
  821. } else {
  822. can_lvds = true;
  823. }
  824. } else {
  825. can_lvds = false;
  826. }
  827. ret = sun4i_tcon_init_clocks(dev, tcon);
  828. if (ret) {
  829. dev_err(dev, "Couldn't init our TCON clocks\n");
  830. goto err_assert_reset;
  831. }
  832. ret = sun4i_tcon_init_regmap(dev, tcon);
  833. if (ret) {
  834. dev_err(dev, "Couldn't init our TCON regmap\n");
  835. goto err_free_clocks;
  836. }
  837. if (tcon->quirks->has_channel_0) {
  838. ret = sun4i_dclk_create(dev, tcon);
  839. if (ret) {
  840. dev_err(dev, "Couldn't create our TCON dot clock\n");
  841. goto err_free_clocks;
  842. }
  843. }
  844. ret = sun4i_tcon_init_irq(dev, tcon);
  845. if (ret) {
  846. dev_err(dev, "Couldn't init our TCON interrupts\n");
  847. goto err_free_dotclock;
  848. }
  849. tcon->crtc = sun4i_crtc_init(drm, engine, tcon);
  850. if (IS_ERR(tcon->crtc)) {
  851. dev_err(dev, "Couldn't create our CRTC\n");
  852. ret = PTR_ERR(tcon->crtc);
  853. goto err_free_dotclock;
  854. }
  855. /*
  856. * If we have an LVDS panel connected to the TCON, we should
  857. * just probe the LVDS connector. Otherwise, just probe RGB as
  858. * we used to.
  859. */
  860. remote = of_graph_get_remote_node(dev->of_node, 1, 0);
  861. if (of_device_is_compatible(remote, "panel-lvds"))
  862. if (can_lvds)
  863. ret = sun4i_lvds_init(drm, tcon);
  864. else
  865. ret = -EINVAL;
  866. else
  867. ret = sun4i_rgb_init(drm, tcon);
  868. of_node_put(remote);
  869. if (ret < 0)
  870. goto err_free_dotclock;
  871. if (tcon->quirks->needs_de_be_mux) {
  872. /*
  873. * We assume there is no dynamic muxing of backends
  874. * and TCONs, so we select the backend with same ID.
  875. *
  876. * While dynamic selection might be interesting, since
  877. * the CRTC is tied to the TCON, while the layers are
  878. * tied to the backends, this means, we will need to
  879. * switch between groups of layers. There might not be
  880. * a way to represent this constraint in DRM.
  881. */
  882. regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
  883. SUN4I_TCON0_CTL_SRC_SEL_MASK,
  884. tcon->id);
  885. regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
  886. SUN4I_TCON1_CTL_SRC_SEL_MASK,
  887. tcon->id);
  888. }
  889. list_add_tail(&tcon->list, &drv->tcon_list);
  890. return 0;
  891. err_free_dotclock:
  892. if (tcon->quirks->has_channel_0)
  893. sun4i_dclk_free(tcon);
  894. err_free_clocks:
  895. sun4i_tcon_free_clocks(tcon);
  896. err_assert_reset:
  897. reset_control_assert(tcon->lcd_rst);
  898. return ret;
  899. }
  900. static void sun4i_tcon_unbind(struct device *dev, struct device *master,
  901. void *data)
  902. {
  903. struct sun4i_tcon *tcon = dev_get_drvdata(dev);
  904. list_del(&tcon->list);
  905. if (tcon->quirks->has_channel_0)
  906. sun4i_dclk_free(tcon);
  907. sun4i_tcon_free_clocks(tcon);
  908. }
  909. static const struct component_ops sun4i_tcon_ops = {
  910. .bind = sun4i_tcon_bind,
  911. .unbind = sun4i_tcon_unbind,
  912. };
  913. static int sun4i_tcon_probe(struct platform_device *pdev)
  914. {
  915. struct device_node *node = pdev->dev.of_node;
  916. struct drm_bridge *bridge;
  917. struct drm_panel *panel;
  918. int ret;
  919. ret = drm_of_find_panel_or_bridge(node, 1, 0, &panel, &bridge);
  920. if (ret == -EPROBE_DEFER)
  921. return ret;
  922. return component_add(&pdev->dev, &sun4i_tcon_ops);
  923. }
  924. static int sun4i_tcon_remove(struct platform_device *pdev)
  925. {
  926. component_del(&pdev->dev, &sun4i_tcon_ops);
  927. return 0;
  928. }
  929. /* platform specific TCON muxing callbacks */
  930. static int sun4i_a10_tcon_set_mux(struct sun4i_tcon *tcon,
  931. const struct drm_encoder *encoder)
  932. {
  933. struct sun4i_tcon *tcon0 = sun4i_get_tcon0(encoder->dev);
  934. u32 shift;
  935. if (!tcon0)
  936. return -EINVAL;
  937. switch (encoder->encoder_type) {
  938. case DRM_MODE_ENCODER_TMDS:
  939. /* HDMI */
  940. shift = 8;
  941. break;
  942. default:
  943. return -EINVAL;
  944. }
  945. regmap_update_bits(tcon0->regs, SUN4I_TCON_MUX_CTRL_REG,
  946. 0x3 << shift, tcon->id << shift);
  947. return 0;
  948. }
  949. static int sun5i_a13_tcon_set_mux(struct sun4i_tcon *tcon,
  950. const struct drm_encoder *encoder)
  951. {
  952. u32 val;
  953. if (encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)
  954. val = 1;
  955. else
  956. val = 0;
  957. /*
  958. * FIXME: Undocumented bits
  959. */
  960. return regmap_write(tcon->regs, SUN4I_TCON_MUX_CTRL_REG, val);
  961. }
  962. static int sun6i_tcon_set_mux(struct sun4i_tcon *tcon,
  963. const struct drm_encoder *encoder)
  964. {
  965. struct sun4i_tcon *tcon0 = sun4i_get_tcon0(encoder->dev);
  966. u32 shift;
  967. if (!tcon0)
  968. return -EINVAL;
  969. switch (encoder->encoder_type) {
  970. case DRM_MODE_ENCODER_TMDS:
  971. /* HDMI */
  972. shift = 8;
  973. break;
  974. default:
  975. /* TODO A31 has MIPI DSI but A31s does not */
  976. return -EINVAL;
  977. }
  978. regmap_update_bits(tcon0->regs, SUN4I_TCON_MUX_CTRL_REG,
  979. 0x3 << shift, tcon->id << shift);
  980. return 0;
  981. }
  982. static const struct sun4i_tcon_quirks sun4i_a10_quirks = {
  983. .has_channel_0 = true,
  984. .has_channel_1 = true,
  985. .set_mux = sun4i_a10_tcon_set_mux,
  986. };
  987. static const struct sun4i_tcon_quirks sun5i_a13_quirks = {
  988. .has_channel_0 = true,
  989. .has_channel_1 = true,
  990. .set_mux = sun5i_a13_tcon_set_mux,
  991. };
  992. static const struct sun4i_tcon_quirks sun6i_a31_quirks = {
  993. .has_channel_0 = true,
  994. .has_channel_1 = true,
  995. .has_lvds_alt = true,
  996. .needs_de_be_mux = true,
  997. .set_mux = sun6i_tcon_set_mux,
  998. };
  999. static const struct sun4i_tcon_quirks sun6i_a31s_quirks = {
  1000. .has_channel_0 = true,
  1001. .has_channel_1 = true,
  1002. .needs_de_be_mux = true,
  1003. };
  1004. static const struct sun4i_tcon_quirks sun7i_a20_quirks = {
  1005. .has_channel_0 = true,
  1006. .has_channel_1 = true,
  1007. /* Same display pipeline structure as A10 */
  1008. .set_mux = sun4i_a10_tcon_set_mux,
  1009. };
  1010. static const struct sun4i_tcon_quirks sun8i_a33_quirks = {
  1011. .has_channel_0 = true,
  1012. .has_lvds_alt = true,
  1013. };
  1014. static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = {
  1015. .supports_lvds = true,
  1016. .has_channel_0 = true,
  1017. };
  1018. static const struct sun4i_tcon_quirks sun8i_a83t_tv_quirks = {
  1019. .has_channel_1 = true,
  1020. };
  1021. static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
  1022. .has_channel_0 = true,
  1023. };
  1024. static const struct sun4i_tcon_quirks sun9i_a80_tcon_lcd_quirks = {
  1025. .has_channel_0 = true,
  1026. .needs_edp_reset = true,
  1027. };
  1028. static const struct sun4i_tcon_quirks sun9i_a80_tcon_tv_quirks = {
  1029. .has_channel_1 = true,
  1030. .needs_edp_reset = true,
  1031. };
  1032. /* sun4i_drv uses this list to check if a device node is a TCON */
  1033. const struct of_device_id sun4i_tcon_of_table[] = {
  1034. { .compatible = "allwinner,sun4i-a10-tcon", .data = &sun4i_a10_quirks },
  1035. { .compatible = "allwinner,sun5i-a13-tcon", .data = &sun5i_a13_quirks },
  1036. { .compatible = "allwinner,sun6i-a31-tcon", .data = &sun6i_a31_quirks },
  1037. { .compatible = "allwinner,sun6i-a31s-tcon", .data = &sun6i_a31s_quirks },
  1038. { .compatible = "allwinner,sun7i-a20-tcon", .data = &sun7i_a20_quirks },
  1039. { .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },
  1040. { .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks },
  1041. { .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks },
  1042. { .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks },
  1043. { .compatible = "allwinner,sun9i-a80-tcon-lcd", .data = &sun9i_a80_tcon_lcd_quirks },
  1044. { .compatible = "allwinner,sun9i-a80-tcon-tv", .data = &sun9i_a80_tcon_tv_quirks },
  1045. { }
  1046. };
  1047. MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table);
  1048. EXPORT_SYMBOL(sun4i_tcon_of_table);
  1049. static struct platform_driver sun4i_tcon_platform_driver = {
  1050. .probe = sun4i_tcon_probe,
  1051. .remove = sun4i_tcon_remove,
  1052. .driver = {
  1053. .name = "sun4i-tcon",
  1054. .of_match_table = sun4i_tcon_of_table,
  1055. },
  1056. };
  1057. module_platform_driver(sun4i_tcon_platform_driver);
  1058. MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
  1059. MODULE_DESCRIPTION("Allwinner A10 Timing Controller Driver");
  1060. MODULE_LICENSE("GPL");