hub.c 23 KB

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