hub.c 23 KB

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