meson_dw_hdmi.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919
  1. /*
  2. * Copyright (C) 2016 BayLibre, SAS
  3. * Author: Neil Armstrong <narmstrong@baylibre.com>
  4. * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation; either version 2 of the
  9. * License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <linux/kernel.h>
  20. #include <linux/module.h>
  21. #include <linux/component.h>
  22. #include <linux/of_graph.h>
  23. #include <linux/reset.h>
  24. #include <linux/clk.h>
  25. #include <drm/drmP.h>
  26. #include <drm/drm_edid.h>
  27. #include <drm/drm_crtc_helper.h>
  28. #include <drm/drm_atomic_helper.h>
  29. #include <drm/bridge/dw_hdmi.h>
  30. #include <uapi/linux/media-bus-format.h>
  31. #include <uapi/linux/videodev2.h>
  32. #include "meson_drv.h"
  33. #include "meson_venc.h"
  34. #include "meson_vclk.h"
  35. #include "meson_dw_hdmi.h"
  36. #include "meson_registers.h"
  37. #define DRIVER_NAME "meson-dw-hdmi"
  38. #define DRIVER_DESC "Amlogic Meson HDMI-TX DRM driver"
  39. /**
  40. * DOC: HDMI Output
  41. *
  42. * HDMI Output is composed of :
  43. *
  44. * - A Synopsys DesignWare HDMI Controller IP
  45. * - A TOP control block controlling the Clocks and PHY
  46. * - A custom HDMI PHY in order convert video to TMDS signal
  47. *
  48. * .. code::
  49. *
  50. * ___________________________________
  51. * | HDMI TOP |<= HPD
  52. * |___________________________________|
  53. * | | |
  54. * | Synopsys HDMI | HDMI PHY |=> TMDS
  55. * | Controller |________________|
  56. * |___________________________________|<=> DDC
  57. *
  58. *
  59. * The HDMI TOP block only supports HPD sensing.
  60. * The Synopsys HDMI Controller interrupt is routed
  61. * through the TOP Block interrupt.
  62. * Communication to the TOP Block and the Synopsys
  63. * HDMI Controller is done a pair of addr+read/write
  64. * registers.
  65. * The HDMI PHY is configured by registers in the
  66. * HHI register block.
  67. *
  68. * Pixel data arrives in 4:4:4 format from the VENC
  69. * block and the VPU HDMI mux selects either the ENCI
  70. * encoder for the 576i or 480i formats or the ENCP
  71. * encoder for all the other formats including
  72. * interlaced HD formats.
  73. * The VENC uses a DVI encoder on top of the ENCI
  74. * or ENCP encoders to generate DVI timings for the
  75. * HDMI controller.
  76. *
  77. * GXBB, GXL and GXM embeds the Synopsys DesignWare
  78. * HDMI TX IP version 2.01a with HDCP and I2C & S/PDIF
  79. * audio source interfaces.
  80. *
  81. * We handle the following features :
  82. *
  83. * - HPD Rise & Fall interrupt
  84. * - HDMI Controller Interrupt
  85. * - HDMI PHY Init for 480i to 1080p60
  86. * - VENC & HDMI Clock setup for 480i to 1080p60
  87. * - VENC Mode setup for 480i to 1080p60
  88. *
  89. * What is missing :
  90. *
  91. * - PHY, Clock and Mode setup for 2k && 4k modes
  92. * - SDDC Scrambling mode for HDMI 2.0a
  93. * - HDCP Setup
  94. * - CEC Management
  95. */
  96. /* TOP Block Communication Channel */
  97. #define HDMITX_TOP_ADDR_REG 0x0
  98. #define HDMITX_TOP_DATA_REG 0x4
  99. #define HDMITX_TOP_CTRL_REG 0x8
  100. /* Controller Communication Channel */
  101. #define HDMITX_DWC_ADDR_REG 0x10
  102. #define HDMITX_DWC_DATA_REG 0x14
  103. #define HDMITX_DWC_CTRL_REG 0x18
  104. /* HHI Registers */
  105. #define HHI_MEM_PD_REG0 0x100 /* 0x40 */
  106. #define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 */
  107. #define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 */
  108. #define HHI_HDMI_PHY_CNTL1 0x3a4 /* 0xe9 */
  109. #define HHI_HDMI_PHY_CNTL2 0x3a8 /* 0xea */
  110. #define HHI_HDMI_PHY_CNTL3 0x3ac /* 0xeb */
  111. static DEFINE_SPINLOCK(reg_lock);
  112. enum meson_venc_source {
  113. MESON_VENC_SOURCE_NONE = 0,
  114. MESON_VENC_SOURCE_ENCI = 1,
  115. MESON_VENC_SOURCE_ENCP = 2,
  116. };
  117. struct meson_dw_hdmi {
  118. struct drm_encoder encoder;
  119. struct dw_hdmi_plat_data dw_plat_data;
  120. struct meson_drm *priv;
  121. struct device *dev;
  122. void __iomem *hdmitx;
  123. struct reset_control *hdmitx_apb;
  124. struct reset_control *hdmitx_ctrl;
  125. struct reset_control *hdmitx_phy;
  126. struct clk *hdmi_pclk;
  127. struct clk *venci_clk;
  128. u32 irq_stat;
  129. };
  130. #define encoder_to_meson_dw_hdmi(x) \
  131. container_of(x, struct meson_dw_hdmi, encoder)
  132. static inline int dw_hdmi_is_compatible(struct meson_dw_hdmi *dw_hdmi,
  133. const char *compat)
  134. {
  135. return of_device_is_compatible(dw_hdmi->dev->of_node, compat);
  136. }
  137. /* PHY (via TOP bridge) and Controller dedicated register interface */
  138. static unsigned int dw_hdmi_top_read(struct meson_dw_hdmi *dw_hdmi,
  139. unsigned int addr)
  140. {
  141. unsigned long flags;
  142. unsigned int data;
  143. spin_lock_irqsave(&reg_lock, flags);
  144. /* ADDR must be written twice */
  145. writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
  146. writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
  147. /* Read needs a second DATA read */
  148. data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
  149. data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
  150. spin_unlock_irqrestore(&reg_lock, flags);
  151. return data;
  152. }
  153. static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi,
  154. unsigned int addr, unsigned int data)
  155. {
  156. unsigned long flags;
  157. spin_lock_irqsave(&reg_lock, flags);
  158. /* ADDR must be written twice */
  159. writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
  160. writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
  161. /* Write needs single DATA write */
  162. writel(data, dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
  163. spin_unlock_irqrestore(&reg_lock, flags);
  164. }
  165. /* Helper to change specific bits in PHY registers */
  166. static inline void dw_hdmi_top_write_bits(struct meson_dw_hdmi *dw_hdmi,
  167. unsigned int addr,
  168. unsigned int mask,
  169. unsigned int val)
  170. {
  171. unsigned int data = dw_hdmi_top_read(dw_hdmi, addr);
  172. data &= ~mask;
  173. data |= val;
  174. dw_hdmi_top_write(dw_hdmi, addr, data);
  175. }
  176. static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi,
  177. unsigned int addr)
  178. {
  179. unsigned long flags;
  180. unsigned int data;
  181. spin_lock_irqsave(&reg_lock, flags);
  182. /* ADDR must be written twice */
  183. writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
  184. writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
  185. /* Read needs a second DATA read */
  186. data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
  187. data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
  188. spin_unlock_irqrestore(&reg_lock, flags);
  189. return data;
  190. }
  191. static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi,
  192. unsigned int addr, unsigned int data)
  193. {
  194. unsigned long flags;
  195. spin_lock_irqsave(&reg_lock, flags);
  196. /* ADDR must be written twice */
  197. writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
  198. writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
  199. /* Write needs single DATA write */
  200. writel(data, dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
  201. spin_unlock_irqrestore(&reg_lock, flags);
  202. }
  203. /* Helper to change specific bits in controller registers */
  204. static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi,
  205. unsigned int addr,
  206. unsigned int mask,
  207. unsigned int val)
  208. {
  209. unsigned int data = dw_hdmi_dwc_read(dw_hdmi, addr);
  210. data &= ~mask;
  211. data |= val;
  212. dw_hdmi_dwc_write(dw_hdmi, addr, data);
  213. }
  214. /* Bridge */
  215. /* Setup PHY bandwidth modes */
  216. static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi,
  217. struct drm_display_mode *mode)
  218. {
  219. struct meson_drm *priv = dw_hdmi->priv;
  220. unsigned int pixel_clock = mode->clock;
  221. if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
  222. dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) {
  223. if (pixel_clock >= 371250) {
  224. /* 5.94Gbps, 3.7125Gbps */
  225. regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x333d3282);
  226. regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2136315b);
  227. } else if (pixel_clock >= 297000) {
  228. /* 2.97Gbps */
  229. regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303382);
  230. regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2036315b);
  231. } else if (pixel_clock >= 148500) {
  232. /* 1.485Gbps */
  233. regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303362);
  234. regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2016315b);
  235. } else {
  236. /* 742.5Mbps, and below */
  237. regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33604142);
  238. regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x0016315b);
  239. }
  240. } else if (dw_hdmi_is_compatible(dw_hdmi,
  241. "amlogic,meson-gxbb-dw-hdmi")) {
  242. if (pixel_clock >= 371250) {
  243. /* 5.94Gbps, 3.7125Gbps */
  244. regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33353245);
  245. regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2100115b);
  246. } else if (pixel_clock >= 297000) {
  247. /* 2.97Gbps */
  248. regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33634283);
  249. regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0xb000115b);
  250. } else {
  251. /* 1.485Gbps, and below */
  252. regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33632122);
  253. regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2000115b);
  254. }
  255. }
  256. }
  257. static inline void dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi)
  258. {
  259. struct meson_drm *priv = dw_hdmi->priv;
  260. /* Enable and software reset */
  261. regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xf);
  262. mdelay(2);
  263. /* Enable and unreset */
  264. regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xe);
  265. mdelay(2);
  266. }
  267. static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
  268. struct drm_display_mode *mode)
  269. {
  270. struct meson_drm *priv = dw_hdmi->priv;
  271. int vic = drm_match_cea_mode(mode);
  272. unsigned int vclk_freq;
  273. unsigned int venc_freq;
  274. unsigned int hdmi_freq;
  275. vclk_freq = mode->clock;
  276. if (mode->flags & DRM_MODE_FLAG_DBLCLK)
  277. vclk_freq *= 2;
  278. venc_freq = vclk_freq;
  279. hdmi_freq = vclk_freq;
  280. if (meson_venc_hdmi_venc_repeat(vic))
  281. venc_freq *= 2;
  282. vclk_freq = max(venc_freq, hdmi_freq);
  283. if (mode->flags & DRM_MODE_FLAG_DBLCLK)
  284. venc_freq /= 2;
  285. DRM_DEBUG_DRIVER("vclk:%d venc=%d hdmi=%d enci=%d\n",
  286. vclk_freq, venc_freq, hdmi_freq,
  287. priv->venc.hdmi_use_enci);
  288. meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, vclk_freq,
  289. venc_freq, hdmi_freq, priv->venc.hdmi_use_enci);
  290. }
  291. static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
  292. struct drm_display_mode *mode)
  293. {
  294. struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
  295. struct meson_drm *priv = dw_hdmi->priv;
  296. unsigned int wr_clk =
  297. readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING));
  298. DRM_DEBUG_DRIVER("%d:\"%s\"\n", mode->base.id, mode->name);
  299. /* Enable clocks */
  300. regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
  301. /* Bring HDMITX MEM output of power down */
  302. regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0);
  303. /* Bring out of reset */
  304. dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0);
  305. /* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */
  306. dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL,
  307. 0x3, 0x3);
  308. dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL,
  309. 0x3 << 4, 0x3 << 4);
  310. /* Enable normal output to PHY */
  311. dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
  312. /* TMDS pattern setup (TOFIX pattern for 4k2k scrambling) */
  313. dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0x001f001f);
  314. dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, 0x001f001f);
  315. /* Load TMDS pattern */
  316. dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1);
  317. msleep(20);
  318. dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2);
  319. /* Setup PHY parameters */
  320. meson_hdmi_phy_setup_mode(dw_hdmi, mode);
  321. /* Setup PHY */
  322. regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
  323. 0xffff << 16, 0x0390 << 16);
  324. /* BIT_INVERT */
  325. if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
  326. dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi"))
  327. regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
  328. BIT(17), 0);
  329. else
  330. regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
  331. BIT(17), BIT(17));
  332. /* Disable clock, fifo, fifo_wr */
  333. regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0);
  334. msleep(100);
  335. /* Reset PHY 3 times in a row */
  336. dw_hdmi_phy_reset(dw_hdmi);
  337. dw_hdmi_phy_reset(dw_hdmi);
  338. dw_hdmi_phy_reset(dw_hdmi);
  339. /* Temporary Disable VENC video stream */
  340. if (priv->venc.hdmi_use_enci)
  341. writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
  342. else
  343. writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
  344. /* Temporary Disable HDMI video stream to HDMI-TX */
  345. writel_bits_relaxed(0x3, 0,
  346. priv->io_base + _REG(VPU_HDMI_SETTING));
  347. writel_bits_relaxed(0xf << 8, 0,
  348. priv->io_base + _REG(VPU_HDMI_SETTING));
  349. /* Re-Enable VENC video stream */
  350. if (priv->venc.hdmi_use_enci)
  351. writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
  352. else
  353. writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
  354. /* Push back HDMI clock settings */
  355. writel_bits_relaxed(0xf << 8, wr_clk & (0xf << 8),
  356. priv->io_base + _REG(VPU_HDMI_SETTING));
  357. /* Enable and Select HDMI video source for HDMI-TX */
  358. if (priv->venc.hdmi_use_enci)
  359. writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCI,
  360. priv->io_base + _REG(VPU_HDMI_SETTING));
  361. else
  362. writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCP,
  363. priv->io_base + _REG(VPU_HDMI_SETTING));
  364. return 0;
  365. }
  366. static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi,
  367. void *data)
  368. {
  369. struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
  370. struct meson_drm *priv = dw_hdmi->priv;
  371. DRM_DEBUG_DRIVER("\n");
  372. regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0);
  373. }
  374. static enum drm_connector_status dw_hdmi_read_hpd(struct dw_hdmi *hdmi,
  375. void *data)
  376. {
  377. struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
  378. return !!dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_STAT0) ?
  379. connector_status_connected : connector_status_disconnected;
  380. }
  381. static void dw_hdmi_setup_hpd(struct dw_hdmi *hdmi,
  382. void *data)
  383. {
  384. struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
  385. /* Setup HPD Filter */
  386. dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER,
  387. (0xa << 12) | 0xa0);
  388. /* Clear interrupts */
  389. dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
  390. HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL);
  391. /* Unmask interrupts */
  392. dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_INTR_MASKN,
  393. HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL,
  394. HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL);
  395. }
  396. static const struct dw_hdmi_phy_ops meson_dw_hdmi_phy_ops = {
  397. .init = dw_hdmi_phy_init,
  398. .disable = dw_hdmi_phy_disable,
  399. .read_hpd = dw_hdmi_read_hpd,
  400. .setup_hpd = dw_hdmi_setup_hpd,
  401. };
  402. static irqreturn_t dw_hdmi_top_irq(int irq, void *dev_id)
  403. {
  404. struct meson_dw_hdmi *dw_hdmi = dev_id;
  405. u32 stat;
  406. stat = dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_INTR_STAT);
  407. dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat);
  408. /* HPD Events, handle in the threaded interrupt handler */
  409. if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) {
  410. dw_hdmi->irq_stat = stat;
  411. return IRQ_WAKE_THREAD;
  412. }
  413. /* HDMI Controller Interrupt */
  414. if (stat & 1)
  415. return IRQ_NONE;
  416. /* TOFIX Handle HDCP Interrupts */
  417. return IRQ_HANDLED;
  418. }
  419. /* Threaded interrupt handler to manage HPD events */
  420. static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id)
  421. {
  422. struct meson_dw_hdmi *dw_hdmi = dev_id;
  423. u32 stat = dw_hdmi->irq_stat;
  424. /* HPD Events */
  425. if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) {
  426. bool hpd_connected = false;
  427. if (stat & HDMITX_TOP_INTR_HPD_RISE)
  428. hpd_connected = true;
  429. dw_hdmi_setup_rx_sense(dw_hdmi->dev, hpd_connected,
  430. hpd_connected);
  431. drm_helper_hpd_irq_event(dw_hdmi->encoder.dev);
  432. }
  433. return IRQ_HANDLED;
  434. }
  435. /* TOFIX Enable support for non-vic modes */
  436. static enum drm_mode_status dw_hdmi_mode_valid(struct drm_connector *connector,
  437. struct drm_display_mode *mode)
  438. {
  439. unsigned int vclk_freq;
  440. unsigned int venc_freq;
  441. unsigned int hdmi_freq;
  442. int vic = drm_match_cea_mode(mode);
  443. DRM_DEBUG_DRIVER("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
  444. mode->base.id, mode->name, mode->vrefresh, mode->clock,
  445. mode->hdisplay, mode->hsync_start,
  446. mode->hsync_end, mode->htotal,
  447. mode->vdisplay, mode->vsync_start,
  448. mode->vsync_end, mode->vtotal, mode->type, mode->flags);
  449. /* For now, only accept VIC modes */
  450. if (!vic)
  451. return MODE_BAD;
  452. /* For now, filter by supported VIC modes */
  453. if (!meson_venc_hdmi_supported_vic(vic))
  454. return MODE_BAD;
  455. vclk_freq = mode->clock;
  456. /* 480i/576i needs global pixel doubling */
  457. if (mode->flags & DRM_MODE_FLAG_DBLCLK)
  458. vclk_freq *= 2;
  459. venc_freq = vclk_freq;
  460. hdmi_freq = vclk_freq;
  461. /* VENC double pixels for 1080i and 720p modes */
  462. if (meson_venc_hdmi_venc_repeat(vic))
  463. venc_freq *= 2;
  464. vclk_freq = max(venc_freq, hdmi_freq);
  465. if (mode->flags & DRM_MODE_FLAG_DBLCLK)
  466. venc_freq /= 2;
  467. dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,
  468. vclk_freq, venc_freq, hdmi_freq);
  469. /* Finally filter by configurable vclk frequencies */
  470. switch (vclk_freq) {
  471. case 54000:
  472. case 74250:
  473. case 148500:
  474. case 297000:
  475. case 594000:
  476. return MODE_OK;
  477. }
  478. return MODE_CLOCK_RANGE;
  479. }
  480. /* Encoder */
  481. static void meson_venc_hdmi_encoder_destroy(struct drm_encoder *encoder)
  482. {
  483. drm_encoder_cleanup(encoder);
  484. }
  485. static const struct drm_encoder_funcs meson_venc_hdmi_encoder_funcs = {
  486. .destroy = meson_venc_hdmi_encoder_destroy,
  487. };
  488. static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
  489. struct drm_crtc_state *crtc_state,
  490. struct drm_connector_state *conn_state)
  491. {
  492. return 0;
  493. }
  494. static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder)
  495. {
  496. struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
  497. struct meson_drm *priv = dw_hdmi->priv;
  498. DRM_DEBUG_DRIVER("\n");
  499. writel_bits_relaxed(0x3, 0,
  500. priv->io_base + _REG(VPU_HDMI_SETTING));
  501. writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
  502. writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
  503. }
  504. static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder)
  505. {
  506. struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
  507. struct meson_drm *priv = dw_hdmi->priv;
  508. DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP");
  509. if (priv->venc.hdmi_use_enci)
  510. writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
  511. else
  512. writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
  513. }
  514. static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
  515. struct drm_display_mode *mode,
  516. struct drm_display_mode *adjusted_mode)
  517. {
  518. struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
  519. struct meson_drm *priv = dw_hdmi->priv;
  520. int vic = drm_match_cea_mode(mode);
  521. DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n",
  522. mode->base.id, mode->name, vic);
  523. /* Should have been filtered */
  524. if (!vic)
  525. return;
  526. /* VENC + VENC-DVI Mode setup */
  527. meson_venc_hdmi_mode_set(priv, vic, mode);
  528. /* VCLK Set clock */
  529. dw_hdmi_set_vclk(dw_hdmi, mode);
  530. /* Setup YUV444 to HDMI-TX, no 10bit diphering */
  531. writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
  532. }
  533. static const struct drm_encoder_helper_funcs
  534. meson_venc_hdmi_encoder_helper_funcs = {
  535. .atomic_check = meson_venc_hdmi_encoder_atomic_check,
  536. .disable = meson_venc_hdmi_encoder_disable,
  537. .enable = meson_venc_hdmi_encoder_enable,
  538. .mode_set = meson_venc_hdmi_encoder_mode_set,
  539. };
  540. /* DW HDMI Regmap */
  541. static int meson_dw_hdmi_reg_read(void *context, unsigned int reg,
  542. unsigned int *result)
  543. {
  544. *result = dw_hdmi_dwc_read(context, reg);
  545. return 0;
  546. }
  547. static int meson_dw_hdmi_reg_write(void *context, unsigned int reg,
  548. unsigned int val)
  549. {
  550. dw_hdmi_dwc_write(context, reg, val);
  551. return 0;
  552. }
  553. static const struct regmap_config meson_dw_hdmi_regmap_config = {
  554. .reg_bits = 32,
  555. .val_bits = 8,
  556. .reg_read = meson_dw_hdmi_reg_read,
  557. .reg_write = meson_dw_hdmi_reg_write,
  558. .max_register = 0x10000,
  559. };
  560. static bool meson_hdmi_connector_is_available(struct device *dev)
  561. {
  562. struct device_node *ep, *remote;
  563. /* HDMI Connector is on the second port, first endpoint */
  564. ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, 0);
  565. if (!ep)
  566. return false;
  567. /* If the endpoint node exists, consider it enabled */
  568. remote = of_graph_get_remote_port(ep);
  569. if (remote) {
  570. of_node_put(ep);
  571. return true;
  572. }
  573. of_node_put(ep);
  574. of_node_put(remote);
  575. return false;
  576. }
  577. static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
  578. void *data)
  579. {
  580. struct platform_device *pdev = to_platform_device(dev);
  581. struct meson_dw_hdmi *meson_dw_hdmi;
  582. struct drm_device *drm = data;
  583. struct meson_drm *priv = drm->dev_private;
  584. struct dw_hdmi_plat_data *dw_plat_data;
  585. struct drm_encoder *encoder;
  586. struct resource *res;
  587. int irq;
  588. int ret;
  589. DRM_DEBUG_DRIVER("\n");
  590. if (!meson_hdmi_connector_is_available(dev)) {
  591. dev_info(drm->dev, "HDMI Output connector not available\n");
  592. return -ENODEV;
  593. }
  594. meson_dw_hdmi = devm_kzalloc(dev, sizeof(*meson_dw_hdmi),
  595. GFP_KERNEL);
  596. if (!meson_dw_hdmi)
  597. return -ENOMEM;
  598. meson_dw_hdmi->priv = priv;
  599. meson_dw_hdmi->dev = dev;
  600. dw_plat_data = &meson_dw_hdmi->dw_plat_data;
  601. encoder = &meson_dw_hdmi->encoder;
  602. meson_dw_hdmi->hdmitx_apb = devm_reset_control_get_exclusive(dev,
  603. "hdmitx_apb");
  604. if (IS_ERR(meson_dw_hdmi->hdmitx_apb)) {
  605. dev_err(dev, "Failed to get hdmitx_apb reset\n");
  606. return PTR_ERR(meson_dw_hdmi->hdmitx_apb);
  607. }
  608. meson_dw_hdmi->hdmitx_ctrl = devm_reset_control_get_exclusive(dev,
  609. "hdmitx");
  610. if (IS_ERR(meson_dw_hdmi->hdmitx_ctrl)) {
  611. dev_err(dev, "Failed to get hdmitx reset\n");
  612. return PTR_ERR(meson_dw_hdmi->hdmitx_ctrl);
  613. }
  614. meson_dw_hdmi->hdmitx_phy = devm_reset_control_get_exclusive(dev,
  615. "hdmitx_phy");
  616. if (IS_ERR(meson_dw_hdmi->hdmitx_phy)) {
  617. dev_err(dev, "Failed to get hdmitx_phy reset\n");
  618. return PTR_ERR(meson_dw_hdmi->hdmitx_phy);
  619. }
  620. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  621. meson_dw_hdmi->hdmitx = devm_ioremap_resource(dev, res);
  622. if (IS_ERR(meson_dw_hdmi->hdmitx))
  623. return PTR_ERR(meson_dw_hdmi->hdmitx);
  624. meson_dw_hdmi->hdmi_pclk = devm_clk_get(dev, "isfr");
  625. if (IS_ERR(meson_dw_hdmi->hdmi_pclk)) {
  626. dev_err(dev, "Unable to get HDMI pclk\n");
  627. return PTR_ERR(meson_dw_hdmi->hdmi_pclk);
  628. }
  629. clk_prepare_enable(meson_dw_hdmi->hdmi_pclk);
  630. meson_dw_hdmi->venci_clk = devm_clk_get(dev, "venci");
  631. if (IS_ERR(meson_dw_hdmi->venci_clk)) {
  632. dev_err(dev, "Unable to get venci clk\n");
  633. return PTR_ERR(meson_dw_hdmi->venci_clk);
  634. }
  635. clk_prepare_enable(meson_dw_hdmi->venci_clk);
  636. dw_plat_data->regm = devm_regmap_init(dev, NULL, meson_dw_hdmi,
  637. &meson_dw_hdmi_regmap_config);
  638. if (IS_ERR(dw_plat_data->regm))
  639. return PTR_ERR(dw_plat_data->regm);
  640. irq = platform_get_irq(pdev, 0);
  641. if (irq < 0) {
  642. dev_err(dev, "Failed to get hdmi top irq\n");
  643. return irq;
  644. }
  645. ret = devm_request_threaded_irq(dev, irq, dw_hdmi_top_irq,
  646. dw_hdmi_top_thread_irq, IRQF_SHARED,
  647. "dw_hdmi_top_irq", meson_dw_hdmi);
  648. if (ret) {
  649. dev_err(dev, "Failed to request hdmi top irq\n");
  650. return ret;
  651. }
  652. /* Encoder */
  653. drm_encoder_helper_add(encoder, &meson_venc_hdmi_encoder_helper_funcs);
  654. ret = drm_encoder_init(drm, encoder, &meson_venc_hdmi_encoder_funcs,
  655. DRM_MODE_ENCODER_TMDS, "meson_hdmi");
  656. if (ret) {
  657. dev_err(priv->dev, "Failed to init HDMI encoder\n");
  658. return ret;
  659. }
  660. encoder->possible_crtcs = BIT(0);
  661. DRM_DEBUG_DRIVER("encoder initialized\n");
  662. /* Enable clocks */
  663. regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
  664. /* Bring HDMITX MEM output of power down */
  665. regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0);
  666. /* Reset HDMITX APB & TX & PHY */
  667. reset_control_reset(meson_dw_hdmi->hdmitx_apb);
  668. reset_control_reset(meson_dw_hdmi->hdmitx_ctrl);
  669. reset_control_reset(meson_dw_hdmi->hdmitx_phy);
  670. /* Enable APB3 fail on error */
  671. writel_bits_relaxed(BIT(15), BIT(15),
  672. meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG);
  673. writel_bits_relaxed(BIT(15), BIT(15),
  674. meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG);
  675. /* Bring out of reset */
  676. dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_SW_RESET, 0);
  677. msleep(20);
  678. dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_CLK_CNTL, 0xff);
  679. /* Enable HDMI-TX Interrupt */
  680. dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
  681. HDMITX_TOP_INTR_CORE);
  682. dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN,
  683. HDMITX_TOP_INTR_CORE);
  684. /* Bridge / Connector */
  685. dw_plat_data->mode_valid = dw_hdmi_mode_valid;
  686. dw_plat_data->phy_ops = &meson_dw_hdmi_phy_ops;
  687. dw_plat_data->phy_name = "meson_dw_hdmi_phy";
  688. dw_plat_data->phy_data = meson_dw_hdmi;
  689. dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
  690. dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
  691. ret = dw_hdmi_bind(pdev, encoder, &meson_dw_hdmi->dw_plat_data);
  692. if (ret)
  693. return ret;
  694. DRM_DEBUG_DRIVER("HDMI controller initialized\n");
  695. return 0;
  696. }
  697. static void meson_dw_hdmi_unbind(struct device *dev, struct device *master,
  698. void *data)
  699. {
  700. dw_hdmi_unbind(dev);
  701. }
  702. static const struct component_ops meson_dw_hdmi_ops = {
  703. .bind = meson_dw_hdmi_bind,
  704. .unbind = meson_dw_hdmi_unbind,
  705. };
  706. static int meson_dw_hdmi_probe(struct platform_device *pdev)
  707. {
  708. return component_add(&pdev->dev, &meson_dw_hdmi_ops);
  709. }
  710. static int meson_dw_hdmi_remove(struct platform_device *pdev)
  711. {
  712. component_del(&pdev->dev, &meson_dw_hdmi_ops);
  713. return 0;
  714. }
  715. static const struct of_device_id meson_dw_hdmi_of_table[] = {
  716. { .compatible = "amlogic,meson-gxbb-dw-hdmi" },
  717. { .compatible = "amlogic,meson-gxl-dw-hdmi" },
  718. { .compatible = "amlogic,meson-gxm-dw-hdmi" },
  719. { }
  720. };
  721. MODULE_DEVICE_TABLE(of, meson_dw_hdmi_of_table);
  722. static struct platform_driver meson_dw_hdmi_platform_driver = {
  723. .probe = meson_dw_hdmi_probe,
  724. .remove = meson_dw_hdmi_remove,
  725. .driver = {
  726. .name = DRIVER_NAME,
  727. .of_match_table = meson_dw_hdmi_of_table,
  728. },
  729. };
  730. module_platform_driver(meson_dw_hdmi_platform_driver);
  731. MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
  732. MODULE_DESCRIPTION(DRIVER_DESC);
  733. MODULE_LICENSE("GPL");