hub.c 20 KB

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