meson_dw_hdmi.c 26 KB

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