meson_dw_hdmi.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920
  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
  437. dw_hdmi_mode_valid(struct drm_connector *connector,
  438. const struct drm_display_mode *mode)
  439. {
  440. unsigned int vclk_freq;
  441. unsigned int venc_freq;
  442. unsigned int hdmi_freq;
  443. int vic = drm_match_cea_mode(mode);
  444. DRM_DEBUG_DRIVER("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
  445. mode->base.id, mode->name, mode->vrefresh, mode->clock,
  446. mode->hdisplay, mode->hsync_start,
  447. mode->hsync_end, mode->htotal,
  448. mode->vdisplay, mode->vsync_start,
  449. mode->vsync_end, mode->vtotal, mode->type, mode->flags);
  450. /* For now, only accept VIC modes */
  451. if (!vic)
  452. return MODE_BAD;
  453. /* For now, filter by supported VIC modes */
  454. if (!meson_venc_hdmi_supported_vic(vic))
  455. return MODE_BAD;
  456. vclk_freq = mode->clock;
  457. /* 480i/576i needs global pixel doubling */
  458. if (mode->flags & DRM_MODE_FLAG_DBLCLK)
  459. vclk_freq *= 2;
  460. venc_freq = vclk_freq;
  461. hdmi_freq = vclk_freq;
  462. /* VENC double pixels for 1080i and 720p modes */
  463. if (meson_venc_hdmi_venc_repeat(vic))
  464. venc_freq *= 2;
  465. vclk_freq = max(venc_freq, hdmi_freq);
  466. if (mode->flags & DRM_MODE_FLAG_DBLCLK)
  467. venc_freq /= 2;
  468. dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,
  469. vclk_freq, venc_freq, hdmi_freq);
  470. /* Finally filter by configurable vclk frequencies */
  471. switch (vclk_freq) {
  472. case 54000:
  473. case 74250:
  474. case 148500:
  475. case 297000:
  476. case 594000:
  477. return MODE_OK;
  478. }
  479. return MODE_CLOCK_RANGE;
  480. }
  481. /* Encoder */
  482. static void meson_venc_hdmi_encoder_destroy(struct drm_encoder *encoder)
  483. {
  484. drm_encoder_cleanup(encoder);
  485. }
  486. static const struct drm_encoder_funcs meson_venc_hdmi_encoder_funcs = {
  487. .destroy = meson_venc_hdmi_encoder_destroy,
  488. };
  489. static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
  490. struct drm_crtc_state *crtc_state,
  491. struct drm_connector_state *conn_state)
  492. {
  493. return 0;
  494. }
  495. static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder)
  496. {
  497. struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
  498. struct meson_drm *priv = dw_hdmi->priv;
  499. DRM_DEBUG_DRIVER("\n");
  500. writel_bits_relaxed(0x3, 0,
  501. priv->io_base + _REG(VPU_HDMI_SETTING));
  502. writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
  503. writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
  504. }
  505. static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder)
  506. {
  507. struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
  508. struct meson_drm *priv = dw_hdmi->priv;
  509. DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP");
  510. if (priv->venc.hdmi_use_enci)
  511. writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
  512. else
  513. writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
  514. }
  515. static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
  516. struct drm_display_mode *mode,
  517. struct drm_display_mode *adjusted_mode)
  518. {
  519. struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
  520. struct meson_drm *priv = dw_hdmi->priv;
  521. int vic = drm_match_cea_mode(mode);
  522. DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n",
  523. mode->base.id, mode->name, vic);
  524. /* Should have been filtered */
  525. if (!vic)
  526. return;
  527. /* VENC + VENC-DVI Mode setup */
  528. meson_venc_hdmi_mode_set(priv, vic, mode);
  529. /* VCLK Set clock */
  530. dw_hdmi_set_vclk(dw_hdmi, mode);
  531. /* Setup YUV444 to HDMI-TX, no 10bit diphering */
  532. writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
  533. }
  534. static const struct drm_encoder_helper_funcs
  535. meson_venc_hdmi_encoder_helper_funcs = {
  536. .atomic_check = meson_venc_hdmi_encoder_atomic_check,
  537. .disable = meson_venc_hdmi_encoder_disable,
  538. .enable = meson_venc_hdmi_encoder_enable,
  539. .mode_set = meson_venc_hdmi_encoder_mode_set,
  540. };
  541. /* DW HDMI Regmap */
  542. static int meson_dw_hdmi_reg_read(void *context, unsigned int reg,
  543. unsigned int *result)
  544. {
  545. *result = dw_hdmi_dwc_read(context, reg);
  546. return 0;
  547. }
  548. static int meson_dw_hdmi_reg_write(void *context, unsigned int reg,
  549. unsigned int val)
  550. {
  551. dw_hdmi_dwc_write(context, reg, val);
  552. return 0;
  553. }
  554. static const struct regmap_config meson_dw_hdmi_regmap_config = {
  555. .reg_bits = 32,
  556. .val_bits = 8,
  557. .reg_read = meson_dw_hdmi_reg_read,
  558. .reg_write = meson_dw_hdmi_reg_write,
  559. .max_register = 0x10000,
  560. };
  561. static bool meson_hdmi_connector_is_available(struct device *dev)
  562. {
  563. struct device_node *ep, *remote;
  564. /* HDMI Connector is on the second port, first endpoint */
  565. ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, 0);
  566. if (!ep)
  567. return false;
  568. /* If the endpoint node exists, consider it enabled */
  569. remote = of_graph_get_remote_port(ep);
  570. if (remote) {
  571. of_node_put(ep);
  572. return true;
  573. }
  574. of_node_put(ep);
  575. of_node_put(remote);
  576. return false;
  577. }
  578. static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
  579. void *data)
  580. {
  581. struct platform_device *pdev = to_platform_device(dev);
  582. struct meson_dw_hdmi *meson_dw_hdmi;
  583. struct drm_device *drm = data;
  584. struct meson_drm *priv = drm->dev_private;
  585. struct dw_hdmi_plat_data *dw_plat_data;
  586. struct drm_encoder *encoder;
  587. struct resource *res;
  588. int irq;
  589. int ret;
  590. DRM_DEBUG_DRIVER("\n");
  591. if (!meson_hdmi_connector_is_available(dev)) {
  592. dev_info(drm->dev, "HDMI Output connector not available\n");
  593. return -ENODEV;
  594. }
  595. meson_dw_hdmi = devm_kzalloc(dev, sizeof(*meson_dw_hdmi),
  596. GFP_KERNEL);
  597. if (!meson_dw_hdmi)
  598. return -ENOMEM;
  599. meson_dw_hdmi->priv = priv;
  600. meson_dw_hdmi->dev = dev;
  601. dw_plat_data = &meson_dw_hdmi->dw_plat_data;
  602. encoder = &meson_dw_hdmi->encoder;
  603. meson_dw_hdmi->hdmitx_apb = devm_reset_control_get_exclusive(dev,
  604. "hdmitx_apb");
  605. if (IS_ERR(meson_dw_hdmi->hdmitx_apb)) {
  606. dev_err(dev, "Failed to get hdmitx_apb reset\n");
  607. return PTR_ERR(meson_dw_hdmi->hdmitx_apb);
  608. }
  609. meson_dw_hdmi->hdmitx_ctrl = devm_reset_control_get_exclusive(dev,
  610. "hdmitx");
  611. if (IS_ERR(meson_dw_hdmi->hdmitx_ctrl)) {
  612. dev_err(dev, "Failed to get hdmitx reset\n");
  613. return PTR_ERR(meson_dw_hdmi->hdmitx_ctrl);
  614. }
  615. meson_dw_hdmi->hdmitx_phy = devm_reset_control_get_exclusive(dev,
  616. "hdmitx_phy");
  617. if (IS_ERR(meson_dw_hdmi->hdmitx_phy)) {
  618. dev_err(dev, "Failed to get hdmitx_phy reset\n");
  619. return PTR_ERR(meson_dw_hdmi->hdmitx_phy);
  620. }
  621. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  622. meson_dw_hdmi->hdmitx = devm_ioremap_resource(dev, res);
  623. if (IS_ERR(meson_dw_hdmi->hdmitx))
  624. return PTR_ERR(meson_dw_hdmi->hdmitx);
  625. meson_dw_hdmi->hdmi_pclk = devm_clk_get(dev, "isfr");
  626. if (IS_ERR(meson_dw_hdmi->hdmi_pclk)) {
  627. dev_err(dev, "Unable to get HDMI pclk\n");
  628. return PTR_ERR(meson_dw_hdmi->hdmi_pclk);
  629. }
  630. clk_prepare_enable(meson_dw_hdmi->hdmi_pclk);
  631. meson_dw_hdmi->venci_clk = devm_clk_get(dev, "venci");
  632. if (IS_ERR(meson_dw_hdmi->venci_clk)) {
  633. dev_err(dev, "Unable to get venci clk\n");
  634. return PTR_ERR(meson_dw_hdmi->venci_clk);
  635. }
  636. clk_prepare_enable(meson_dw_hdmi->venci_clk);
  637. dw_plat_data->regm = devm_regmap_init(dev, NULL, meson_dw_hdmi,
  638. &meson_dw_hdmi_regmap_config);
  639. if (IS_ERR(dw_plat_data->regm))
  640. return PTR_ERR(dw_plat_data->regm);
  641. irq = platform_get_irq(pdev, 0);
  642. if (irq < 0) {
  643. dev_err(dev, "Failed to get hdmi top irq\n");
  644. return irq;
  645. }
  646. ret = devm_request_threaded_irq(dev, irq, dw_hdmi_top_irq,
  647. dw_hdmi_top_thread_irq, IRQF_SHARED,
  648. "dw_hdmi_top_irq", meson_dw_hdmi);
  649. if (ret) {
  650. dev_err(dev, "Failed to request hdmi top irq\n");
  651. return ret;
  652. }
  653. /* Encoder */
  654. drm_encoder_helper_add(encoder, &meson_venc_hdmi_encoder_helper_funcs);
  655. ret = drm_encoder_init(drm, encoder, &meson_venc_hdmi_encoder_funcs,
  656. DRM_MODE_ENCODER_TMDS, "meson_hdmi");
  657. if (ret) {
  658. dev_err(priv->dev, "Failed to init HDMI encoder\n");
  659. return ret;
  660. }
  661. encoder->possible_crtcs = BIT(0);
  662. DRM_DEBUG_DRIVER("encoder initialized\n");
  663. /* Enable clocks */
  664. regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
  665. /* Bring HDMITX MEM output of power down */
  666. regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0);
  667. /* Reset HDMITX APB & TX & PHY */
  668. reset_control_reset(meson_dw_hdmi->hdmitx_apb);
  669. reset_control_reset(meson_dw_hdmi->hdmitx_ctrl);
  670. reset_control_reset(meson_dw_hdmi->hdmitx_phy);
  671. /* Enable APB3 fail on error */
  672. writel_bits_relaxed(BIT(15), BIT(15),
  673. meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG);
  674. writel_bits_relaxed(BIT(15), BIT(15),
  675. meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG);
  676. /* Bring out of reset */
  677. dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_SW_RESET, 0);
  678. msleep(20);
  679. dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_CLK_CNTL, 0xff);
  680. /* Enable HDMI-TX Interrupt */
  681. dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
  682. HDMITX_TOP_INTR_CORE);
  683. dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN,
  684. HDMITX_TOP_INTR_CORE);
  685. /* Bridge / Connector */
  686. dw_plat_data->mode_valid = dw_hdmi_mode_valid;
  687. dw_plat_data->phy_ops = &meson_dw_hdmi_phy_ops;
  688. dw_plat_data->phy_name = "meson_dw_hdmi_phy";
  689. dw_plat_data->phy_data = meson_dw_hdmi;
  690. dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
  691. dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
  692. ret = dw_hdmi_bind(pdev, encoder, &meson_dw_hdmi->dw_plat_data);
  693. if (ret)
  694. return ret;
  695. DRM_DEBUG_DRIVER("HDMI controller initialized\n");
  696. return 0;
  697. }
  698. static void meson_dw_hdmi_unbind(struct device *dev, struct device *master,
  699. void *data)
  700. {
  701. dw_hdmi_unbind(dev);
  702. }
  703. static const struct component_ops meson_dw_hdmi_ops = {
  704. .bind = meson_dw_hdmi_bind,
  705. .unbind = meson_dw_hdmi_unbind,
  706. };
  707. static int meson_dw_hdmi_probe(struct platform_device *pdev)
  708. {
  709. return component_add(&pdev->dev, &meson_dw_hdmi_ops);
  710. }
  711. static int meson_dw_hdmi_remove(struct platform_device *pdev)
  712. {
  713. component_del(&pdev->dev, &meson_dw_hdmi_ops);
  714. return 0;
  715. }
  716. static const struct of_device_id meson_dw_hdmi_of_table[] = {
  717. { .compatible = "amlogic,meson-gxbb-dw-hdmi" },
  718. { .compatible = "amlogic,meson-gxl-dw-hdmi" },
  719. { .compatible = "amlogic,meson-gxm-dw-hdmi" },
  720. { }
  721. };
  722. MODULE_DEVICE_TABLE(of, meson_dw_hdmi_of_table);
  723. static struct platform_driver meson_dw_hdmi_platform_driver = {
  724. .probe = meson_dw_hdmi_probe,
  725. .remove = meson_dw_hdmi_remove,
  726. .driver = {
  727. .name = DRIVER_NAME,
  728. .of_match_table = meson_dw_hdmi_of_table,
  729. },
  730. };
  731. module_platform_driver(meson_dw_hdmi_platform_driver);
  732. MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
  733. MODULE_DESCRIPTION(DRIVER_DESC);
  734. MODULE_LICENSE("GPL");