hub.c 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved.
  4. */
  5. #include <linux/clk.h>
  6. #include <linux/delay.h>
  7. #include <linux/host1x.h>
  8. #include <linux/module.h>
  9. #include <linux/of.h>
  10. #include <linux/of_device.h>
  11. #include <linux/of_graph.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/pm_runtime.h>
  14. #include <linux/reset.h>
  15. #include <drm/drm_atomic.h>
  16. #include <drm/drm_atomic_helper.h>
  17. #include <drm/drm_fourcc.h>
  18. #include <drm/drm_probe_helper.h>
  19. #include "drm.h"
  20. #include "dc.h"
  21. #include "plane.h"
  22. static const u32 tegra_shared_plane_formats[] = {
  23. DRM_FORMAT_ARGB1555,
  24. DRM_FORMAT_RGB565,
  25. DRM_FORMAT_RGBA5551,
  26. DRM_FORMAT_ARGB8888,
  27. DRM_FORMAT_ABGR8888,
  28. /* new on Tegra114 */
  29. DRM_FORMAT_ABGR4444,
  30. DRM_FORMAT_ABGR1555,
  31. DRM_FORMAT_BGRA5551,
  32. DRM_FORMAT_XRGB1555,
  33. DRM_FORMAT_RGBX5551,
  34. DRM_FORMAT_XBGR1555,
  35. DRM_FORMAT_BGRX5551,
  36. DRM_FORMAT_BGR565,
  37. DRM_FORMAT_XRGB8888,
  38. DRM_FORMAT_XBGR8888,
  39. /* planar formats */
  40. DRM_FORMAT_UYVY,
  41. DRM_FORMAT_YUYV,
  42. DRM_FORMAT_YUV420,
  43. DRM_FORMAT_YUV422,
  44. };
  45. static const u64 tegra_shared_plane_modifiers[] = {
  46. DRM_FORMAT_MOD_LINEAR,
  47. DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0),
  48. DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1),
  49. DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2),
  50. DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3),
  51. DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4),
  52. DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5),
  53. DRM_FORMAT_MOD_INVALID
  54. };
  55. static inline unsigned int tegra_plane_offset(struct tegra_plane *plane,
  56. unsigned int offset)
  57. {
  58. if (offset >= 0x500 && offset <= 0x581) {
  59. offset = 0x000 + (offset - 0x500);
  60. return plane->offset + offset;
  61. }
  62. if (offset >= 0x700 && offset <= 0x73c) {
  63. offset = 0x180 + (offset - 0x700);
  64. return plane->offset + offset;
  65. }
  66. if (offset >= 0x800 && offset <= 0x83e) {
  67. offset = 0x1c0 + (offset - 0x800);
  68. return plane->offset + offset;
  69. }
  70. dev_WARN(plane->dc->dev, "invalid offset: %x\n", offset);
  71. return plane->offset + offset;
  72. }
  73. static inline u32 tegra_plane_readl(struct tegra_plane *plane,
  74. unsigned int offset)
  75. {
  76. return tegra_dc_readl(plane->dc, tegra_plane_offset(plane, offset));
  77. }
  78. static inline void tegra_plane_writel(struct tegra_plane *plane, u32 value,
  79. unsigned int offset)
  80. {
  81. tegra_dc_writel(plane->dc, value, tegra_plane_offset(plane, offset));
  82. }
  83. static int tegra_windowgroup_enable(struct tegra_windowgroup *wgrp)
  84. {
  85. int err = 0;
  86. mutex_lock(&wgrp->lock);
  87. if (wgrp->usecount == 0) {
  88. err = host1x_client_resume(wgrp->parent);
  89. if (err < 0) {
  90. dev_err(wgrp->parent->dev, "failed to resume: %d\n", err);
  91. goto unlock;
  92. }
  93. reset_control_deassert(wgrp->rst);
  94. }
  95. wgrp->usecount++;
  96. unlock:
  97. mutex_unlock(&wgrp->lock);
  98. return err;
  99. }
  100. static void tegra_windowgroup_disable(struct tegra_windowgroup *wgrp)
  101. {
  102. int err;
  103. mutex_lock(&wgrp->lock);
  104. if (wgrp->usecount == 1) {
  105. err = reset_control_assert(wgrp->rst);
  106. if (err < 0) {
  107. pr_err("failed to assert reset for window group %u\n",
  108. wgrp->index);
  109. }
  110. host1x_client_suspend(wgrp->parent);
  111. }
  112. wgrp->usecount--;
  113. mutex_unlock(&wgrp->lock);
  114. }
  115. int tegra_display_hub_prepare(struct tegra_display_hub *hub)
  116. {
  117. unsigned int i;
  118. /*
  119. * XXX Enabling/disabling windowgroups needs to happen when the owner
  120. * display controller is disabled. There's currently no good point at
  121. * which this could be executed, so unconditionally enable all window
  122. * groups for now.
  123. */
  124. for (i = 0; i < hub->soc->num_wgrps; i++) {
  125. struct tegra_windowgroup *wgrp = &hub->wgrps[i];
  126. /* Skip orphaned window group whose parent DC is disabled */
  127. if (wgrp->parent)
  128. tegra_windowgroup_enable(wgrp);
  129. }
  130. return 0;
  131. }
  132. void tegra_display_hub_cleanup(struct tegra_display_hub *hub)
  133. {
  134. unsigned int i;
  135. /*
  136. * XXX Remove this once window groups can be more fine-grainedly
  137. * enabled and disabled.
  138. */
  139. for (i = 0; i < hub->soc->num_wgrps; i++) {
  140. struct tegra_windowgroup *wgrp = &hub->wgrps[i];
  141. /* Skip orphaned window group whose parent DC is disabled */
  142. if (wgrp->parent)
  143. tegra_windowgroup_disable(wgrp);
  144. }
  145. }
  146. static void tegra_shared_plane_update(struct tegra_plane *plane)
  147. {
  148. struct tegra_dc *dc = plane->dc;
  149. unsigned long timeout;
  150. u32 mask, value;
  151. mask = COMMON_UPDATE | WIN_A_UPDATE << plane->base.index;
  152. tegra_dc_writel(dc, mask, DC_CMD_STATE_CONTROL);
  153. timeout = jiffies + msecs_to_jiffies(1000);
  154. while (time_before(jiffies, timeout)) {
  155. value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
  156. if ((value & mask) == 0)
  157. break;
  158. usleep_range(100, 400);
  159. }
  160. }
  161. static void tegra_shared_plane_activate(struct tegra_plane *plane)
  162. {
  163. struct tegra_dc *dc = plane->dc;
  164. unsigned long timeout;
  165. u32 mask, value;
  166. mask = COMMON_ACTREQ | WIN_A_ACT_REQ << plane->base.index;
  167. tegra_dc_writel(dc, mask, DC_CMD_STATE_CONTROL);
  168. timeout = jiffies + msecs_to_jiffies(1000);
  169. while (time_before(jiffies, timeout)) {
  170. value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
  171. if ((value & mask) == 0)
  172. break;
  173. usleep_range(100, 400);
  174. }
  175. }
  176. static unsigned int
  177. tegra_shared_plane_get_owner(struct tegra_plane *plane, struct tegra_dc *dc)
  178. {
  179. unsigned int offset =
  180. tegra_plane_offset(plane, DC_WIN_CORE_WINDOWGROUP_SET_CONTROL);
  181. return tegra_dc_readl(dc, offset) & OWNER_MASK;
  182. }
  183. static bool tegra_dc_owns_shared_plane(struct tegra_dc *dc,
  184. struct tegra_plane *plane)
  185. {
  186. struct device *dev = dc->dev;
  187. if (tegra_shared_plane_get_owner(plane, dc) == dc->pipe) {
  188. if (plane->dc == dc)
  189. return true;
  190. dev_WARN(dev, "head %u owns window %u but is not attached\n",
  191. dc->pipe, plane->index);
  192. }
  193. return false;
  194. }
  195. static int tegra_shared_plane_set_owner(struct tegra_plane *plane,
  196. struct tegra_dc *new)
  197. {
  198. unsigned int offset =
  199. tegra_plane_offset(plane, DC_WIN_CORE_WINDOWGROUP_SET_CONTROL);
  200. struct tegra_dc *old = plane->dc, *dc = new ? new : old;
  201. struct device *dev = new ? new->dev : old->dev;
  202. unsigned int owner, index = plane->index;
  203. u32 value;
  204. value = tegra_dc_readl(dc, offset);
  205. owner = value & OWNER_MASK;
  206. if (new && (owner != OWNER_MASK && owner != new->pipe)) {
  207. dev_WARN(dev, "window %u owned by head %u\n", index, owner);
  208. return -EBUSY;
  209. }
  210. /*
  211. * This seems to happen whenever the head has been disabled with one
  212. * or more windows being active. This is harmless because we'll just
  213. * reassign the window to the new head anyway.
  214. */
  215. if (old && owner == OWNER_MASK)
  216. dev_dbg(dev, "window %u not owned by head %u but %u\n", index,
  217. old->pipe, owner);
  218. value &= ~OWNER_MASK;
  219. if (new)
  220. value |= OWNER(new->pipe);
  221. else
  222. value |= OWNER_MASK;
  223. tegra_dc_writel(dc, value, offset);
  224. plane->dc = new;
  225. return 0;
  226. }
  227. static void tegra_dc_assign_shared_plane(struct tegra_dc *dc,
  228. struct tegra_plane *plane)
  229. {
  230. u32 value;
  231. int err;
  232. if (!tegra_dc_owns_shared_plane(dc, plane)) {
  233. err = tegra_shared_plane_set_owner(plane, dc);
  234. if (err < 0)
  235. return;
  236. }
  237. value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_LINEBUF_CONFIG);
  238. value |= MODE_FOUR_LINES;
  239. tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_LINEBUF_CONFIG);
  240. value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_FETCH_METER);
  241. value = SLOTS(1);
  242. tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_FETCH_METER);
  243. /* disable watermark */
  244. value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLA);
  245. value &= ~LATENCY_CTL_MODE_ENABLE;
  246. tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLA);
  247. value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLB);
  248. value |= WATERMARK_MASK;
  249. tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLB);
  250. /* pipe meter */
  251. value = tegra_plane_readl(plane, DC_WIN_CORE_PRECOMP_WGRP_PIPE_METER);
  252. value = PIPE_METER_INT(0) | PIPE_METER_FRAC(0);
  253. tegra_plane_writel(plane, value, DC_WIN_CORE_PRECOMP_WGRP_PIPE_METER);
  254. /* mempool entries */
  255. value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_POOL_CONFIG);
  256. value = MEMPOOL_ENTRIES(0x331);
  257. tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_POOL_CONFIG);
  258. value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_THREAD_GROUP);
  259. value &= ~THREAD_NUM_MASK;
  260. value |= THREAD_NUM(plane->base.index);
  261. value |= THREAD_GROUP_ENABLE;
  262. tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_THREAD_GROUP);
  263. tegra_shared_plane_update(plane);
  264. tegra_shared_plane_activate(plane);
  265. }
  266. static void tegra_dc_remove_shared_plane(struct tegra_dc *dc,
  267. struct tegra_plane *plane)
  268. {
  269. tegra_shared_plane_set_owner(plane, NULL);
  270. }
  271. static int tegra_shared_plane_atomic_check(struct drm_plane *plane,
  272. struct drm_plane_state *state)
  273. {
  274. struct tegra_plane_state *plane_state = to_tegra_plane_state(state);
  275. struct tegra_shared_plane *tegra = to_tegra_shared_plane(plane);
  276. struct tegra_bo_tiling *tiling = &plane_state->tiling;
  277. struct tegra_dc *dc = to_tegra_dc(state->crtc);
  278. int err;
  279. /* no need for further checks if the plane is being disabled */
  280. if (!state->crtc || !state->fb)
  281. return 0;
  282. err = tegra_plane_format(state->fb->format->format,
  283. &plane_state->format,
  284. &plane_state->swap);
  285. if (err < 0)
  286. return err;
  287. err = tegra_fb_get_tiling(state->fb, tiling);
  288. if (err < 0)
  289. return err;
  290. if (tiling->mode == TEGRA_BO_TILING_MODE_BLOCK &&
  291. !dc->soc->supports_block_linear) {
  292. DRM_ERROR("hardware doesn't support block linear mode\n");
  293. return -EINVAL;
  294. }
  295. /*
  296. * Tegra doesn't support different strides for U and V planes so we
  297. * error out if the user tries to display a framebuffer with such a
  298. * configuration.
  299. */
  300. if (state->fb->format->num_planes > 2) {
  301. if (state->fb->pitches[2] != state->fb->pitches[1]) {
  302. DRM_ERROR("unsupported UV-plane configuration\n");
  303. return -EINVAL;
  304. }
  305. }
  306. /* XXX scaling is not yet supported, add a check here */
  307. err = tegra_plane_state_add(&tegra->base, state);
  308. if (err < 0)
  309. return err;
  310. return 0;
  311. }
  312. static void tegra_shared_plane_atomic_disable(struct drm_plane *plane,
  313. struct drm_plane_state *old_state)
  314. {
  315. struct tegra_plane *p = to_tegra_plane(plane);
  316. struct tegra_dc *dc;
  317. u32 value;
  318. int err;
  319. /* rien ne va plus */
  320. if (!old_state || !old_state->crtc)
  321. return;
  322. dc = to_tegra_dc(old_state->crtc);
  323. err = host1x_client_resume(&dc->client);
  324. if (err < 0) {
  325. dev_err(dc->dev, "failed to resume: %d\n", err);
  326. return;
  327. }
  328. /*
  329. * XXX Legacy helpers seem to sometimes call ->atomic_disable() even
  330. * on planes that are already disabled. Make sure we fallback to the
  331. * head for this particular state instead of crashing.
  332. */
  333. if (WARN_ON(p->dc == NULL))
  334. p->dc = dc;
  335. value = tegra_plane_readl(p, DC_WIN_WIN_OPTIONS);
  336. value &= ~WIN_ENABLE;
  337. tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS);
  338. tegra_dc_remove_shared_plane(dc, p);
  339. host1x_client_suspend(&dc->client);
  340. }
  341. static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
  342. struct drm_plane_state *old_state)
  343. {
  344. struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
  345. struct tegra_dc *dc = to_tegra_dc(plane->state->crtc);
  346. unsigned int zpos = plane->state->normalized_zpos;
  347. struct drm_framebuffer *fb = plane->state->fb;
  348. struct tegra_plane *p = to_tegra_plane(plane);
  349. dma_addr_t base;
  350. u32 value;
  351. int err;
  352. /* rien ne va plus */
  353. if (!plane->state->crtc || !plane->state->fb)
  354. return;
  355. if (!plane->state->visible) {
  356. tegra_shared_plane_atomic_disable(plane, old_state);
  357. return;
  358. }
  359. err = host1x_client_resume(&dc->client);
  360. if (err < 0) {
  361. dev_err(dc->dev, "failed to resume: %d\n", err);
  362. return;
  363. }
  364. tegra_dc_assign_shared_plane(dc, p);
  365. tegra_plane_writel(p, VCOUNTER, DC_WIN_CORE_ACT_CONTROL);
  366. /* blending */
  367. value = BLEND_FACTOR_DST_ALPHA_ZERO | BLEND_FACTOR_SRC_ALPHA_K2 |
  368. BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_SRC |
  369. BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC;
  370. tegra_plane_writel(p, value, DC_WIN_BLEND_MATCH_SELECT);
  371. value = BLEND_FACTOR_DST_ALPHA_ZERO | BLEND_FACTOR_SRC_ALPHA_K2 |
  372. BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_SRC |
  373. BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC;
  374. tegra_plane_writel(p, value, DC_WIN_BLEND_NOMATCH_SELECT);
  375. value = K2(255) | K1(255) | WINDOW_LAYER_DEPTH(255 - zpos);
  376. tegra_plane_writel(p, value, DC_WIN_BLEND_LAYER_CONTROL);
  377. /* bypass scaling */
  378. value = HORIZONTAL_TAPS_5 | VERTICAL_TAPS_5;
  379. tegra_plane_writel(p, value, DC_WIN_WINDOWGROUP_SET_CONTROL_INPUT_SCALER);
  380. value = INPUT_SCALER_VBYPASS | INPUT_SCALER_HBYPASS;
  381. tegra_plane_writel(p, value, DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE);
  382. /* disable compression */
  383. tegra_plane_writel(p, 0, DC_WINBUF_CDE_CONTROL);
  384. base = state->iova[0] + fb->offsets[0];
  385. tegra_plane_writel(p, state->format, DC_WIN_COLOR_DEPTH);
  386. tegra_plane_writel(p, 0, DC_WIN_PRECOMP_WGRP_PARAMS);
  387. value = V_POSITION(plane->state->crtc_y) |
  388. H_POSITION(plane->state->crtc_x);
  389. tegra_plane_writel(p, value, DC_WIN_POSITION);
  390. value = V_SIZE(plane->state->crtc_h) | H_SIZE(plane->state->crtc_w);
  391. tegra_plane_writel(p, value, DC_WIN_SIZE);
  392. value = WIN_ENABLE | COLOR_EXPAND;
  393. tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS);
  394. value = V_SIZE(plane->state->crtc_h) | H_SIZE(plane->state->crtc_w);
  395. tegra_plane_writel(p, value, DC_WIN_CROPPED_SIZE);
  396. tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI);
  397. tegra_plane_writel(p, lower_32_bits(base), DC_WINBUF_START_ADDR);
  398. value = PITCH(fb->pitches[0]);
  399. tegra_plane_writel(p, value, DC_WIN_PLANAR_STORAGE);
  400. value = CLAMP_BEFORE_BLEND | DEGAMMA_SRGB | INPUT_RANGE_FULL;
  401. tegra_plane_writel(p, value, DC_WIN_SET_PARAMS);
  402. value = OFFSET_X(plane->state->src_y >> 16) |
  403. OFFSET_Y(plane->state->src_x >> 16);
  404. tegra_plane_writel(p, value, DC_WINBUF_CROPPED_POINT);
  405. if (dc->soc->supports_block_linear) {
  406. unsigned long height = state->tiling.value;
  407. /* XXX */
  408. switch (state->tiling.mode) {
  409. case TEGRA_BO_TILING_MODE_PITCH:
  410. value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(0) |
  411. DC_WINBUF_SURFACE_KIND_PITCH;
  412. break;
  413. /* XXX not supported on Tegra186 and later */
  414. case TEGRA_BO_TILING_MODE_TILED:
  415. value = DC_WINBUF_SURFACE_KIND_TILED;
  416. break;
  417. case TEGRA_BO_TILING_MODE_BLOCK:
  418. value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) |
  419. DC_WINBUF_SURFACE_KIND_BLOCK;
  420. break;
  421. }
  422. tegra_plane_writel(p, value, DC_WINBUF_SURFACE_KIND);
  423. }
  424. /* disable gamut CSC */
  425. value = tegra_plane_readl(p, DC_WIN_WINDOW_SET_CONTROL);
  426. value &= ~CONTROL_CSC_ENABLE;
  427. tegra_plane_writel(p, value, DC_WIN_WINDOW_SET_CONTROL);
  428. host1x_client_suspend(&dc->client);
  429. }
  430. static const struct drm_plane_helper_funcs tegra_shared_plane_helper_funcs = {
  431. .prepare_fb = tegra_plane_prepare_fb,
  432. .cleanup_fb = tegra_plane_cleanup_fb,
  433. .atomic_check = tegra_shared_plane_atomic_check,
  434. .atomic_update = tegra_shared_plane_atomic_update,
  435. .atomic_disable = tegra_shared_plane_atomic_disable,
  436. };
  437. struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
  438. struct tegra_dc *dc,
  439. unsigned int wgrp,
  440. unsigned int index)
  441. {
  442. enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY;
  443. struct tegra_drm *tegra = drm->dev_private;
  444. struct tegra_display_hub *hub = tegra->hub;
  445. /* planes can be assigned to arbitrary CRTCs */
  446. unsigned int possible_crtcs = 0x7;
  447. struct tegra_shared_plane *plane;
  448. unsigned int num_formats;
  449. const u64 *modifiers;
  450. struct drm_plane *p;
  451. const u32 *formats;
  452. int err;
  453. plane = kzalloc(sizeof(*plane), GFP_KERNEL);
  454. if (!plane)
  455. return ERR_PTR(-ENOMEM);
  456. plane->base.offset = 0x0a00 + 0x0300 * index;
  457. plane->base.index = index;
  458. plane->wgrp = &hub->wgrps[wgrp];
  459. plane->wgrp->parent = &dc->client;
  460. p = &plane->base.base;
  461. num_formats = ARRAY_SIZE(tegra_shared_plane_formats);
  462. formats = tegra_shared_plane_formats;
  463. modifiers = tegra_shared_plane_modifiers;
  464. err = drm_universal_plane_init(drm, p, possible_crtcs,
  465. &tegra_plane_funcs, formats,
  466. num_formats, modifiers, type, NULL);
  467. if (err < 0) {
  468. kfree(plane);
  469. return ERR_PTR(err);
  470. }
  471. drm_plane_helper_add(p, &tegra_shared_plane_helper_funcs);
  472. drm_plane_create_zpos_property(p, 0, 0, 255);
  473. return p;
  474. }
  475. static struct drm_private_state *
  476. tegra_display_hub_duplicate_state(struct drm_private_obj *obj)
  477. {
  478. struct tegra_display_hub_state *state;
  479. state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
  480. if (!state)
  481. return NULL;
  482. __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
  483. return &state->base;
  484. }
  485. static void tegra_display_hub_destroy_state(struct drm_private_obj *obj,
  486. struct drm_private_state *state)
  487. {
  488. struct tegra_display_hub_state *hub_state =
  489. to_tegra_display_hub_state(state);
  490. kfree(hub_state);
  491. }
  492. static const struct drm_private_state_funcs tegra_display_hub_state_funcs = {
  493. .atomic_duplicate_state = tegra_display_hub_duplicate_state,
  494. .atomic_destroy_state = tegra_display_hub_destroy_state,
  495. };
  496. static struct tegra_display_hub_state *
  497. tegra_display_hub_get_state(struct tegra_display_hub *hub,
  498. struct drm_atomic_state *state)
  499. {
  500. struct drm_private_state *priv;
  501. priv = drm_atomic_get_private_obj_state(state, &hub->base);
  502. if (IS_ERR(priv))
  503. return ERR_CAST(priv);
  504. return to_tegra_display_hub_state(priv);
  505. }
  506. int tegra_display_hub_atomic_check(struct drm_device *drm,
  507. struct drm_atomic_state *state)
  508. {
  509. struct tegra_drm *tegra = drm->dev_private;
  510. struct tegra_display_hub_state *hub_state;
  511. struct drm_crtc_state *old, *new;
  512. struct drm_crtc *crtc;
  513. unsigned int i;
  514. if (!tegra->hub)
  515. return 0;
  516. hub_state = tegra_display_hub_get_state(tegra->hub, state);
  517. if (IS_ERR(hub_state))
  518. return PTR_ERR(hub_state);
  519. /*
  520. * The display hub display clock needs to be fed by the display clock
  521. * with the highest frequency to ensure proper functioning of all the
  522. * displays.
  523. *
  524. * Note that this isn't used before Tegra186, but it doesn't hurt and
  525. * conditionalizing it would make the code less clean.
  526. */
  527. for_each_oldnew_crtc_in_state(state, crtc, old, new, i) {
  528. struct tegra_dc_state *dc = to_dc_state(new);
  529. if (new->active) {
  530. if (!hub_state->clk || dc->pclk > hub_state->rate) {
  531. hub_state->dc = to_tegra_dc(dc->base.crtc);
  532. hub_state->clk = hub_state->dc->clk;
  533. hub_state->rate = dc->pclk;
  534. }
  535. }
  536. }
  537. return 0;
  538. }
  539. static void tegra_display_hub_update(struct tegra_dc *dc)
  540. {
  541. u32 value;
  542. int err;
  543. err = host1x_client_resume(&dc->client);
  544. if (err < 0) {
  545. dev_err(dc->dev, "failed to resume: %d\n", err);
  546. return;
  547. }
  548. value = tegra_dc_readl(dc, DC_CMD_IHUB_COMMON_MISC_CTL);
  549. value &= ~LATENCY_EVENT;
  550. tegra_dc_writel(dc, value, DC_CMD_IHUB_COMMON_MISC_CTL);
  551. value = tegra_dc_readl(dc, DC_DISP_IHUB_COMMON_DISPLAY_FETCH_METER);
  552. value = CURS_SLOTS(1) | WGRP_SLOTS(1);
  553. tegra_dc_writel(dc, value, DC_DISP_IHUB_COMMON_DISPLAY_FETCH_METER);
  554. tegra_dc_writel(dc, COMMON_UPDATE, DC_CMD_STATE_CONTROL);
  555. tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
  556. tegra_dc_writel(dc, COMMON_ACTREQ, DC_CMD_STATE_CONTROL);
  557. tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
  558. host1x_client_suspend(&dc->client);
  559. }
  560. void tegra_display_hub_atomic_commit(struct drm_device *drm,
  561. struct drm_atomic_state *state)
  562. {
  563. struct tegra_drm *tegra = drm->dev_private;
  564. struct tegra_display_hub *hub = tegra->hub;
  565. struct tegra_display_hub_state *hub_state;
  566. struct device *dev = hub->client.dev;
  567. int err;
  568. hub_state = to_tegra_display_hub_state(hub->base.state);
  569. if (hub_state->clk) {
  570. err = clk_set_rate(hub_state->clk, hub_state->rate);
  571. if (err < 0)
  572. dev_err(dev, "failed to set rate of %pC to %lu Hz\n",
  573. hub_state->clk, hub_state->rate);
  574. err = clk_set_parent(hub->clk_disp, hub_state->clk);
  575. if (err < 0)
  576. dev_err(dev, "failed to set parent of %pC to %pC: %d\n",
  577. hub->clk_disp, hub_state->clk, err);
  578. }
  579. if (hub_state->dc)
  580. tegra_display_hub_update(hub_state->dc);
  581. }
  582. static int tegra_display_hub_init(struct host1x_client *client)
  583. {
  584. struct tegra_display_hub *hub = to_tegra_display_hub(client);
  585. struct drm_device *drm = dev_get_drvdata(client->host);
  586. struct tegra_drm *tegra = drm->dev_private;
  587. struct tegra_display_hub_state *state;
  588. state = kzalloc(sizeof(*state), GFP_KERNEL);
  589. if (!state)
  590. return -ENOMEM;
  591. drm_atomic_private_obj_init(drm, &hub->base, &state->base,
  592. &tegra_display_hub_state_funcs);
  593. tegra->hub = hub;
  594. return 0;
  595. }
  596. static int tegra_display_hub_exit(struct host1x_client *client)
  597. {
  598. struct drm_device *drm = dev_get_drvdata(client->host);
  599. struct tegra_drm *tegra = drm->dev_private;
  600. drm_atomic_private_obj_fini(&tegra->hub->base);
  601. tegra->hub = NULL;
  602. return 0;
  603. }
  604. static int tegra_display_hub_runtime_suspend(struct host1x_client *client)
  605. {
  606. struct tegra_display_hub *hub = to_tegra_display_hub(client);
  607. struct device *dev = client->dev;
  608. unsigned int i = hub->num_heads;
  609. int err;
  610. err = reset_control_assert(hub->rst);
  611. if (err < 0)
  612. return err;
  613. while (i--)
  614. clk_disable_unprepare(hub->clk_heads[i]);
  615. clk_disable_unprepare(hub->clk_hub);
  616. clk_disable_unprepare(hub->clk_dsc);
  617. clk_disable_unprepare(hub->clk_disp);
  618. pm_runtime_put_sync(dev);
  619. return 0;
  620. }
  621. static int tegra_display_hub_runtime_resume(struct host1x_client *client)
  622. {
  623. struct tegra_display_hub *hub = to_tegra_display_hub(client);
  624. struct device *dev = client->dev;
  625. unsigned int i;
  626. int err;
  627. err = pm_runtime_resume_and_get(dev);
  628. if (err < 0) {
  629. dev_err(dev, "failed to get runtime PM: %d\n", err);
  630. return err;
  631. }
  632. err = clk_prepare_enable(hub->clk_disp);
  633. if (err < 0)
  634. goto put_rpm;
  635. err = clk_prepare_enable(hub->clk_dsc);
  636. if (err < 0)
  637. goto disable_disp;
  638. err = clk_prepare_enable(hub->clk_hub);
  639. if (err < 0)
  640. goto disable_dsc;
  641. for (i = 0; i < hub->num_heads; i++) {
  642. err = clk_prepare_enable(hub->clk_heads[i]);
  643. if (err < 0)
  644. goto disable_heads;
  645. }
  646. err = reset_control_deassert(hub->rst);
  647. if (err < 0)
  648. goto disable_heads;
  649. return 0;
  650. disable_heads:
  651. while (i--)
  652. clk_disable_unprepare(hub->clk_heads[i]);
  653. clk_disable_unprepare(hub->clk_hub);
  654. disable_dsc:
  655. clk_disable_unprepare(hub->clk_dsc);
  656. disable_disp:
  657. clk_disable_unprepare(hub->clk_disp);
  658. put_rpm:
  659. pm_runtime_put_sync(dev);
  660. return err;
  661. }
  662. static const struct host1x_client_ops tegra_display_hub_ops = {
  663. .init = tegra_display_hub_init,
  664. .exit = tegra_display_hub_exit,
  665. .suspend = tegra_display_hub_runtime_suspend,
  666. .resume = tegra_display_hub_runtime_resume,
  667. };
  668. static int tegra_display_hub_probe(struct platform_device *pdev)
  669. {
  670. struct device_node *child = NULL;
  671. struct tegra_display_hub *hub;
  672. struct clk *clk;
  673. unsigned int i;
  674. int err;
  675. hub = devm_kzalloc(&pdev->dev, sizeof(*hub), GFP_KERNEL);
  676. if (!hub)
  677. return -ENOMEM;
  678. hub->soc = of_device_get_match_data(&pdev->dev);
  679. hub->clk_disp = devm_clk_get(&pdev->dev, "disp");
  680. if (IS_ERR(hub->clk_disp)) {
  681. err = PTR_ERR(hub->clk_disp);
  682. return err;
  683. }
  684. if (hub->soc->supports_dsc) {
  685. hub->clk_dsc = devm_clk_get(&pdev->dev, "dsc");
  686. if (IS_ERR(hub->clk_dsc)) {
  687. err = PTR_ERR(hub->clk_dsc);
  688. return err;
  689. }
  690. }
  691. hub->clk_hub = devm_clk_get(&pdev->dev, "hub");
  692. if (IS_ERR(hub->clk_hub)) {
  693. err = PTR_ERR(hub->clk_hub);
  694. return err;
  695. }
  696. hub->rst = devm_reset_control_get(&pdev->dev, "misc");
  697. if (IS_ERR(hub->rst)) {
  698. err = PTR_ERR(hub->rst);
  699. return err;
  700. }
  701. hub->wgrps = devm_kcalloc(&pdev->dev, hub->soc->num_wgrps,
  702. sizeof(*hub->wgrps), GFP_KERNEL);
  703. if (!hub->wgrps)
  704. return -ENOMEM;
  705. for (i = 0; i < hub->soc->num_wgrps; i++) {
  706. struct tegra_windowgroup *wgrp = &hub->wgrps[i];
  707. char id[8];
  708. snprintf(id, sizeof(id), "wgrp%u", i);
  709. mutex_init(&wgrp->lock);
  710. wgrp->usecount = 0;
  711. wgrp->index = i;
  712. wgrp->rst = devm_reset_control_get(&pdev->dev, id);
  713. if (IS_ERR(wgrp->rst))
  714. return PTR_ERR(wgrp->rst);
  715. err = reset_control_assert(wgrp->rst);
  716. if (err < 0)
  717. return err;
  718. }
  719. hub->num_heads = of_get_child_count(pdev->dev.of_node);
  720. hub->clk_heads = devm_kcalloc(&pdev->dev, hub->num_heads, sizeof(clk),
  721. GFP_KERNEL);
  722. if (!hub->clk_heads)
  723. return -ENOMEM;
  724. for (i = 0; i < hub->num_heads; i++) {
  725. child = of_get_next_child(pdev->dev.of_node, child);
  726. if (!child) {
  727. dev_err(&pdev->dev, "failed to find node for head %u\n",
  728. i);
  729. return -ENODEV;
  730. }
  731. clk = devm_get_clk_from_child(&pdev->dev, child, "dc");
  732. if (IS_ERR(clk)) {
  733. dev_err(&pdev->dev, "failed to get clock for head %u\n",
  734. i);
  735. of_node_put(child);
  736. return PTR_ERR(clk);
  737. }
  738. hub->clk_heads[i] = clk;
  739. }
  740. of_node_put(child);
  741. /* XXX: enable clock across reset? */
  742. err = reset_control_assert(hub->rst);
  743. if (err < 0)
  744. return err;
  745. platform_set_drvdata(pdev, hub);
  746. pm_runtime_enable(&pdev->dev);
  747. INIT_LIST_HEAD(&hub->client.list);
  748. hub->client.ops = &tegra_display_hub_ops;
  749. hub->client.dev = &pdev->dev;
  750. err = host1x_client_register(&hub->client);
  751. if (err < 0)
  752. dev_err(&pdev->dev, "failed to register host1x client: %d\n",
  753. err);
  754. err = devm_of_platform_populate(&pdev->dev);
  755. if (err < 0)
  756. goto unregister;
  757. return err;
  758. unregister:
  759. host1x_client_unregister(&hub->client);
  760. pm_runtime_disable(&pdev->dev);
  761. return err;
  762. }
  763. static int tegra_display_hub_remove(struct platform_device *pdev)
  764. {
  765. struct tegra_display_hub *hub = platform_get_drvdata(pdev);
  766. unsigned int i;
  767. int err;
  768. err = host1x_client_unregister(&hub->client);
  769. if (err < 0) {
  770. dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
  771. err);
  772. }
  773. for (i = 0; i < hub->soc->num_wgrps; i++) {
  774. struct tegra_windowgroup *wgrp = &hub->wgrps[i];
  775. mutex_destroy(&wgrp->lock);
  776. }
  777. pm_runtime_disable(&pdev->dev);
  778. return err;
  779. }
  780. static const struct tegra_display_hub_soc tegra186_display_hub = {
  781. .num_wgrps = 6,
  782. .supports_dsc = true,
  783. };
  784. static const struct tegra_display_hub_soc tegra194_display_hub = {
  785. .num_wgrps = 6,
  786. .supports_dsc = false,
  787. };
  788. static const struct of_device_id tegra_display_hub_of_match[] = {
  789. {
  790. .compatible = "nvidia,tegra194-display",
  791. .data = &tegra194_display_hub
  792. }, {
  793. .compatible = "nvidia,tegra186-display",
  794. .data = &tegra186_display_hub
  795. }, {
  796. /* sentinel */
  797. }
  798. };
  799. MODULE_DEVICE_TABLE(of, tegra_display_hub_of_match);
  800. struct platform_driver tegra_display_hub_driver = {
  801. .driver = {
  802. .name = "tegra-display-hub",
  803. .of_match_table = tegra_display_hub_of_match,
  804. },
  805. .probe = tegra_display_hub_probe,
  806. .remove = tegra_display_hub_remove,
  807. };