Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2017 NVIDIA CORPORATION.  All rights reserved.
0004  */
0005 
0006 #include <linux/clk.h>
0007 #include <linux/delay.h>
0008 #include <linux/dma-mapping.h>
0009 #include <linux/host1x.h>
0010 #include <linux/module.h>
0011 #include <linux/of.h>
0012 #include <linux/of_device.h>
0013 #include <linux/of_graph.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/pm_runtime.h>
0016 #include <linux/reset.h>
0017 
0018 #include <drm/drm_atomic.h>
0019 #include <drm/drm_atomic_helper.h>
0020 #include <drm/drm_blend.h>
0021 #include <drm/drm_fourcc.h>
0022 #include <drm/drm_framebuffer.h>
0023 #include <drm/drm_probe_helper.h>
0024 
0025 #include "drm.h"
0026 #include "dc.h"
0027 #include "plane.h"
0028 
0029 #define NFB 24
0030 
0031 static const u32 tegra_shared_plane_formats[] = {
0032     DRM_FORMAT_ARGB1555,
0033     DRM_FORMAT_RGB565,
0034     DRM_FORMAT_RGBA5551,
0035     DRM_FORMAT_ARGB8888,
0036     DRM_FORMAT_ABGR8888,
0037     /* new on Tegra114 */
0038     DRM_FORMAT_ABGR4444,
0039     DRM_FORMAT_ABGR1555,
0040     DRM_FORMAT_BGRA5551,
0041     DRM_FORMAT_XRGB1555,
0042     DRM_FORMAT_RGBX5551,
0043     DRM_FORMAT_XBGR1555,
0044     DRM_FORMAT_BGRX5551,
0045     DRM_FORMAT_BGR565,
0046     DRM_FORMAT_XRGB8888,
0047     DRM_FORMAT_XBGR8888,
0048     /* planar formats */
0049     DRM_FORMAT_UYVY,
0050     DRM_FORMAT_YUYV,
0051     DRM_FORMAT_YUV420,
0052     DRM_FORMAT_YUV422,
0053 };
0054 
0055 static const u64 tegra_shared_plane_modifiers[] = {
0056     DRM_FORMAT_MOD_LINEAR,
0057     DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0),
0058     DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1),
0059     DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2),
0060     DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3),
0061     DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4),
0062     DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5),
0063     /*
0064      * The GPU sector layout is only supported on Tegra194, but these will
0065      * be filtered out later on by ->format_mod_supported() on SoCs where
0066      * it isn't supported.
0067      */
0068     DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT,
0069     DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT,
0070     DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT,
0071     DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT,
0072     DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT,
0073     DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT,
0074     /* sentinel */
0075     DRM_FORMAT_MOD_INVALID
0076 };
0077 
0078 static inline unsigned int tegra_plane_offset(struct tegra_plane *plane,
0079                           unsigned int offset)
0080 {
0081     if (offset >= 0x500 && offset <= 0x581) {
0082         offset = 0x000 + (offset - 0x500);
0083         return plane->offset + offset;
0084     }
0085 
0086     if (offset >= 0x700 && offset <= 0x73c) {
0087         offset = 0x180 + (offset - 0x700);
0088         return plane->offset + offset;
0089     }
0090 
0091     if (offset >= 0x800 && offset <= 0x83e) {
0092         offset = 0x1c0 + (offset - 0x800);
0093         return plane->offset + offset;
0094     }
0095 
0096     dev_WARN(plane->dc->dev, "invalid offset: %x\n", offset);
0097 
0098     return plane->offset + offset;
0099 }
0100 
0101 static inline u32 tegra_plane_readl(struct tegra_plane *plane,
0102                     unsigned int offset)
0103 {
0104     return tegra_dc_readl(plane->dc, tegra_plane_offset(plane, offset));
0105 }
0106 
0107 static inline void tegra_plane_writel(struct tegra_plane *plane, u32 value,
0108                       unsigned int offset)
0109 {
0110     tegra_dc_writel(plane->dc, value, tegra_plane_offset(plane, offset));
0111 }
0112 
0113 static int tegra_windowgroup_enable(struct tegra_windowgroup *wgrp)
0114 {
0115     int err = 0;
0116 
0117     mutex_lock(&wgrp->lock);
0118 
0119     if (wgrp->usecount == 0) {
0120         err = host1x_client_resume(wgrp->parent);
0121         if (err < 0) {
0122             dev_err(wgrp->parent->dev, "failed to resume: %d\n", err);
0123             goto unlock;
0124         }
0125 
0126         reset_control_deassert(wgrp->rst);
0127     }
0128 
0129     wgrp->usecount++;
0130 
0131 unlock:
0132     mutex_unlock(&wgrp->lock);
0133     return err;
0134 }
0135 
0136 static void tegra_windowgroup_disable(struct tegra_windowgroup *wgrp)
0137 {
0138     int err;
0139 
0140     mutex_lock(&wgrp->lock);
0141 
0142     if (wgrp->usecount == 1) {
0143         err = reset_control_assert(wgrp->rst);
0144         if (err < 0) {
0145             pr_err("failed to assert reset for window group %u\n",
0146                    wgrp->index);
0147         }
0148 
0149         host1x_client_suspend(wgrp->parent);
0150     }
0151 
0152     wgrp->usecount--;
0153     mutex_unlock(&wgrp->lock);
0154 }
0155 
0156 int tegra_display_hub_prepare(struct tegra_display_hub *hub)
0157 {
0158     unsigned int i;
0159 
0160     /*
0161      * XXX Enabling/disabling windowgroups needs to happen when the owner
0162      * display controller is disabled. There's currently no good point at
0163      * which this could be executed, so unconditionally enable all window
0164      * groups for now.
0165      */
0166     for (i = 0; i < hub->soc->num_wgrps; i++) {
0167         struct tegra_windowgroup *wgrp = &hub->wgrps[i];
0168 
0169         /* Skip orphaned window group whose parent DC is disabled */
0170         if (wgrp->parent)
0171             tegra_windowgroup_enable(wgrp);
0172     }
0173 
0174     return 0;
0175 }
0176 
0177 void tegra_display_hub_cleanup(struct tegra_display_hub *hub)
0178 {
0179     unsigned int i;
0180 
0181     /*
0182      * XXX Remove this once window groups can be more fine-grainedly
0183      * enabled and disabled.
0184      */
0185     for (i = 0; i < hub->soc->num_wgrps; i++) {
0186         struct tegra_windowgroup *wgrp = &hub->wgrps[i];
0187 
0188         /* Skip orphaned window group whose parent DC is disabled */
0189         if (wgrp->parent)
0190             tegra_windowgroup_disable(wgrp);
0191     }
0192 }
0193 
0194 static void tegra_shared_plane_update(struct tegra_plane *plane)
0195 {
0196     struct tegra_dc *dc = plane->dc;
0197     unsigned long timeout;
0198     u32 mask, value;
0199 
0200     mask = COMMON_UPDATE | WIN_A_UPDATE << plane->base.index;
0201     tegra_dc_writel(dc, mask, DC_CMD_STATE_CONTROL);
0202 
0203     timeout = jiffies + msecs_to_jiffies(1000);
0204 
0205     while (time_before(jiffies, timeout)) {
0206         value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
0207         if ((value & mask) == 0)
0208             break;
0209 
0210         usleep_range(100, 400);
0211     }
0212 }
0213 
0214 static void tegra_shared_plane_activate(struct tegra_plane *plane)
0215 {
0216     struct tegra_dc *dc = plane->dc;
0217     unsigned long timeout;
0218     u32 mask, value;
0219 
0220     mask = COMMON_ACTREQ | WIN_A_ACT_REQ << plane->base.index;
0221     tegra_dc_writel(dc, mask, DC_CMD_STATE_CONTROL);
0222 
0223     timeout = jiffies + msecs_to_jiffies(1000);
0224 
0225     while (time_before(jiffies, timeout)) {
0226         value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
0227         if ((value & mask) == 0)
0228             break;
0229 
0230         usleep_range(100, 400);
0231     }
0232 }
0233 
0234 static unsigned int
0235 tegra_shared_plane_get_owner(struct tegra_plane *plane, struct tegra_dc *dc)
0236 {
0237     unsigned int offset =
0238         tegra_plane_offset(plane, DC_WIN_CORE_WINDOWGROUP_SET_CONTROL);
0239 
0240     return tegra_dc_readl(dc, offset) & OWNER_MASK;
0241 }
0242 
0243 static bool tegra_dc_owns_shared_plane(struct tegra_dc *dc,
0244                        struct tegra_plane *plane)
0245 {
0246     struct device *dev = dc->dev;
0247 
0248     if (tegra_shared_plane_get_owner(plane, dc) == dc->pipe) {
0249         if (plane->dc == dc)
0250             return true;
0251 
0252         dev_WARN(dev, "head %u owns window %u but is not attached\n",
0253              dc->pipe, plane->index);
0254     }
0255 
0256     return false;
0257 }
0258 
0259 static int tegra_shared_plane_set_owner(struct tegra_plane *plane,
0260                     struct tegra_dc *new)
0261 {
0262     unsigned int offset =
0263         tegra_plane_offset(plane, DC_WIN_CORE_WINDOWGROUP_SET_CONTROL);
0264     struct tegra_dc *old = plane->dc, *dc = new ? new : old;
0265     struct device *dev = new ? new->dev : old->dev;
0266     unsigned int owner, index = plane->index;
0267     u32 value;
0268 
0269     value = tegra_dc_readl(dc, offset);
0270     owner = value & OWNER_MASK;
0271 
0272     if (new && (owner != OWNER_MASK && owner != new->pipe)) {
0273         dev_WARN(dev, "window %u owned by head %u\n", index, owner);
0274         return -EBUSY;
0275     }
0276 
0277     /*
0278      * This seems to happen whenever the head has been disabled with one
0279      * or more windows being active. This is harmless because we'll just
0280      * reassign the window to the new head anyway.
0281      */
0282     if (old && owner == OWNER_MASK)
0283         dev_dbg(dev, "window %u not owned by head %u but %u\n", index,
0284             old->pipe, owner);
0285 
0286     value &= ~OWNER_MASK;
0287 
0288     if (new)
0289         value |= OWNER(new->pipe);
0290     else
0291         value |= OWNER_MASK;
0292 
0293     tegra_dc_writel(dc, value, offset);
0294 
0295     plane->dc = new;
0296 
0297     return 0;
0298 }
0299 
0300 static void tegra_shared_plane_setup_scaler(struct tegra_plane *plane)
0301 {
0302     static const unsigned int coeffs[192] = {
0303         0x00000000, 0x3c70e400, 0x3bb037e4, 0x0c51cc9c,
0304         0x00100001, 0x3bf0dbfa, 0x3d00f406, 0x3fe003ff,
0305         0x00300002, 0x3b80cbf5, 0x3da1040d, 0x3fb003fe,
0306         0x00400002, 0x3b20bff1, 0x3e511015, 0x3f9003fc,
0307         0x00500002, 0x3ad0b3ed, 0x3f21201d, 0x3f5003fb,
0308         0x00500003, 0x3aa0a3e9, 0x3ff13026, 0x3f2007f9,
0309         0x00500403, 0x3a7097e6, 0x00e1402f, 0x3ee007f7,
0310         0x00500403, 0x3a608be4, 0x01d14c38, 0x3ea00bf6,
0311         0x00500403, 0x3a507fe2, 0x02e15c42, 0x3e500ff4,
0312         0x00500402, 0x3a6073e1, 0x03f16c4d, 0x3e000ff2,
0313         0x00400402, 0x3a706be0, 0x05117858, 0x3db013f0,
0314         0x00300402, 0x3a905fe0, 0x06318863, 0x3d6017ee,
0315         0x00300402, 0x3ab057e0, 0x0771986e, 0x3d001beb,
0316         0x00200001, 0x3af04fe1, 0x08a1a47a, 0x3cb023e9,
0317         0x00100001, 0x3b2047e2, 0x09e1b485, 0x3c6027e7,
0318         0x00100000, 0x3b703fe2, 0x0b11c091, 0x3c002fe6,
0319         0x3f203800, 0x0391103f, 0x3ff0a014, 0x0811606c,
0320         0x3f2037ff, 0x0351083c, 0x03e11842, 0x3f203c00,
0321         0x3f302fff, 0x03010439, 0x04311c45, 0x3f104401,
0322         0x3f302fff, 0x02c0fc35, 0x04812448, 0x3f104802,
0323         0x3f4027ff, 0x0270f832, 0x04c1284b, 0x3f205003,
0324         0x3f4023ff, 0x0230f030, 0x0511304e, 0x3f205403,
0325         0x3f601fff, 0x01f0e82d, 0x05613451, 0x3f205c04,
0326         0x3f701bfe, 0x01b0e02a, 0x05a13c54, 0x3f306006,
0327         0x3f7017fe, 0x0170d827, 0x05f14057, 0x3f406807,
0328         0x3f8017ff, 0x0140d424, 0x0641445a, 0x3f406c08,
0329         0x3fa013ff, 0x0100cc22, 0x0681485d, 0x3f507409,
0330         0x3fa00fff, 0x00d0c41f, 0x06d14c60, 0x3f607c0b,
0331         0x3fc00fff, 0x0090bc1c, 0x07115063, 0x3f80840c,
0332         0x3fd00bff, 0x0070b41a, 0x07515465, 0x3f908c0e,
0333         0x3fe007ff, 0x0040b018, 0x07915868, 0x3fb0900f,
0334         0x3ff00400, 0x0010a816, 0x07d15c6a, 0x3fd09811,
0335         0x00a04c0e, 0x0460f442, 0x0240a827, 0x05c15859,
0336         0x0090440d, 0x0440f040, 0x0480fc43, 0x00b05010,
0337         0x0080400c, 0x0410ec3e, 0x04910044, 0x00d05411,
0338         0x0070380b, 0x03f0e83d, 0x04b10846, 0x00e05812,
0339         0x0060340a, 0x03d0e43b, 0x04d10c48, 0x00f06013,
0340         0x00503009, 0x03b0e039, 0x04e11449, 0x01106415,
0341         0x00402c08, 0x0390d838, 0x05011c4b, 0x01206c16,
0342         0x00302807, 0x0370d436, 0x0511204c, 0x01407018,
0343         0x00302406, 0x0340d034, 0x0531244e, 0x01507419,
0344         0x00202005, 0x0320cc32, 0x05412c50, 0x01707c1b,
0345         0x00101c04, 0x0300c431, 0x05613451, 0x0180801d,
0346         0x00101803, 0x02e0c02f, 0x05713853, 0x01a0881e,
0347         0x00101002, 0x02b0bc2d, 0x05814054, 0x01c08c20,
0348         0x00000c02, 0x02a0b82c, 0x05914455, 0x01e09421,
0349         0x00000801, 0x0280b02a, 0x05a14c57, 0x02009c23,
0350         0x00000400, 0x0260ac28, 0x05b15458, 0x0220a025,
0351     };
0352     unsigned int ratio, row, column;
0353 
0354     for (ratio = 0; ratio <= 2; ratio++) {
0355         for (row = 0; row <= 15; row++) {
0356             for (column = 0; column <= 3; column++) {
0357                 unsigned int index = (ratio << 6) + (row << 2) + column;
0358                 u32 value;
0359 
0360                 value = COEFF_INDEX(index) | COEFF_DATA(coeffs[index]);
0361                 tegra_plane_writel(plane, value,
0362                            DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_COEFF);
0363             }
0364         }
0365     }
0366 }
0367 
0368 static void tegra_dc_assign_shared_plane(struct tegra_dc *dc,
0369                      struct tegra_plane *plane)
0370 {
0371     u32 value;
0372     int err;
0373 
0374     if (!tegra_dc_owns_shared_plane(dc, plane)) {
0375         err = tegra_shared_plane_set_owner(plane, dc);
0376         if (err < 0)
0377             return;
0378     }
0379 
0380     value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_LINEBUF_CONFIG);
0381     value |= MODE_FOUR_LINES;
0382     tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_LINEBUF_CONFIG);
0383 
0384     value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_FETCH_METER);
0385     value = SLOTS(1);
0386     tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_FETCH_METER);
0387 
0388     /* disable watermark */
0389     value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLA);
0390     value &= ~LATENCY_CTL_MODE_ENABLE;
0391     tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLA);
0392 
0393     value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLB);
0394     value |= WATERMARK_MASK;
0395     tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLB);
0396 
0397     /* pipe meter */
0398     value = tegra_plane_readl(plane, DC_WIN_CORE_PRECOMP_WGRP_PIPE_METER);
0399     value = PIPE_METER_INT(0) | PIPE_METER_FRAC(0);
0400     tegra_plane_writel(plane, value, DC_WIN_CORE_PRECOMP_WGRP_PIPE_METER);
0401 
0402     /* mempool entries */
0403     value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_POOL_CONFIG);
0404     value = MEMPOOL_ENTRIES(0x331);
0405     tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_POOL_CONFIG);
0406 
0407     value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_THREAD_GROUP);
0408     value &= ~THREAD_NUM_MASK;
0409     value |= THREAD_NUM(plane->base.index);
0410     value |= THREAD_GROUP_ENABLE;
0411     tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_THREAD_GROUP);
0412 
0413     tegra_shared_plane_setup_scaler(plane);
0414 
0415     tegra_shared_plane_update(plane);
0416     tegra_shared_plane_activate(plane);
0417 }
0418 
0419 static void tegra_dc_remove_shared_plane(struct tegra_dc *dc,
0420                      struct tegra_plane *plane)
0421 {
0422     tegra_shared_plane_set_owner(plane, NULL);
0423 }
0424 
0425 static int tegra_shared_plane_atomic_check(struct drm_plane *plane,
0426                        struct drm_atomic_state *state)
0427 {
0428     struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
0429                                          plane);
0430     struct tegra_plane_state *plane_state = to_tegra_plane_state(new_plane_state);
0431     struct tegra_shared_plane *tegra = to_tegra_shared_plane(plane);
0432     struct tegra_bo_tiling *tiling = &plane_state->tiling;
0433     struct tegra_dc *dc = to_tegra_dc(new_plane_state->crtc);
0434     int err;
0435 
0436     /* no need for further checks if the plane is being disabled */
0437     if (!new_plane_state->crtc || !new_plane_state->fb)
0438         return 0;
0439 
0440     err = tegra_plane_format(new_plane_state->fb->format->format,
0441                  &plane_state->format,
0442                  &plane_state->swap);
0443     if (err < 0)
0444         return err;
0445 
0446     err = tegra_fb_get_tiling(new_plane_state->fb, tiling);
0447     if (err < 0)
0448         return err;
0449 
0450     if (tiling->mode == TEGRA_BO_TILING_MODE_BLOCK &&
0451         !dc->soc->supports_block_linear) {
0452         DRM_ERROR("hardware doesn't support block linear mode\n");
0453         return -EINVAL;
0454     }
0455 
0456     if (tiling->sector_layout == TEGRA_BO_SECTOR_LAYOUT_GPU &&
0457         !dc->soc->supports_sector_layout) {
0458         DRM_ERROR("hardware doesn't support GPU sector layout\n");
0459         return -EINVAL;
0460     }
0461 
0462     /*
0463      * Tegra doesn't support different strides for U and V planes so we
0464      * error out if the user tries to display a framebuffer with such a
0465      * configuration.
0466      */
0467     if (new_plane_state->fb->format->num_planes > 2) {
0468         if (new_plane_state->fb->pitches[2] != new_plane_state->fb->pitches[1]) {
0469             DRM_ERROR("unsupported UV-plane configuration\n");
0470             return -EINVAL;
0471         }
0472     }
0473 
0474     /* XXX scaling is not yet supported, add a check here */
0475 
0476     err = tegra_plane_state_add(&tegra->base, new_plane_state);
0477     if (err < 0)
0478         return err;
0479 
0480     return 0;
0481 }
0482 
0483 static void tegra_shared_plane_atomic_disable(struct drm_plane *plane,
0484                           struct drm_atomic_state *state)
0485 {
0486     struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
0487                                        plane);
0488     struct tegra_plane *p = to_tegra_plane(plane);
0489     struct tegra_dc *dc;
0490     u32 value;
0491     int err;
0492 
0493     /* rien ne va plus */
0494     if (!old_state || !old_state->crtc)
0495         return;
0496 
0497     dc = to_tegra_dc(old_state->crtc);
0498 
0499     err = host1x_client_resume(&dc->client);
0500     if (err < 0) {
0501         dev_err(dc->dev, "failed to resume: %d\n", err);
0502         return;
0503     }
0504 
0505     /*
0506      * XXX Legacy helpers seem to sometimes call ->atomic_disable() even
0507      * on planes that are already disabled. Make sure we fallback to the
0508      * head for this particular state instead of crashing.
0509      */
0510     if (WARN_ON(p->dc == NULL))
0511         p->dc = dc;
0512 
0513     value = tegra_plane_readl(p, DC_WIN_WIN_OPTIONS);
0514     value &= ~WIN_ENABLE;
0515     tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS);
0516 
0517     tegra_dc_remove_shared_plane(dc, p);
0518 
0519     host1x_client_suspend(&dc->client);
0520 }
0521 
0522 static inline u32 compute_phase_incr(fixed20_12 in, unsigned int out)
0523 {
0524     u64 tmp, tmp1, tmp2;
0525 
0526     tmp = (u64)dfixed_trunc(in);
0527     tmp2 = (u64)out;
0528     tmp1 = (tmp << NFB) + (tmp2 >> 1);
0529     do_div(tmp1, tmp2);
0530 
0531     return lower_32_bits(tmp1);
0532 }
0533 
0534 static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
0535                          struct drm_atomic_state *state)
0536 {
0537     struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
0538                                        plane);
0539     struct tegra_plane_state *tegra_plane_state = to_tegra_plane_state(new_state);
0540     struct tegra_dc *dc = to_tegra_dc(new_state->crtc);
0541     unsigned int zpos = new_state->normalized_zpos;
0542     struct drm_framebuffer *fb = new_state->fb;
0543     struct tegra_plane *p = to_tegra_plane(plane);
0544     u32 value, min_width, bypass = 0;
0545     dma_addr_t base, addr_flag = 0;
0546     unsigned int bpc, planes;
0547     bool yuv;
0548     int err;
0549 
0550     /* rien ne va plus */
0551     if (!new_state->crtc || !new_state->fb)
0552         return;
0553 
0554     if (!new_state->visible) {
0555         tegra_shared_plane_atomic_disable(plane, state);
0556         return;
0557     }
0558 
0559     err = host1x_client_resume(&dc->client);
0560     if (err < 0) {
0561         dev_err(dc->dev, "failed to resume: %d\n", err);
0562         return;
0563     }
0564 
0565     yuv = tegra_plane_format_is_yuv(tegra_plane_state->format, &planes, &bpc);
0566 
0567     tegra_dc_assign_shared_plane(dc, p);
0568 
0569     tegra_plane_writel(p, VCOUNTER, DC_WIN_CORE_ACT_CONTROL);
0570 
0571     /* blending */
0572     value = BLEND_FACTOR_DST_ALPHA_ZERO | BLEND_FACTOR_SRC_ALPHA_K2 |
0573         BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_SRC |
0574         BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC;
0575     tegra_plane_writel(p, value, DC_WIN_BLEND_MATCH_SELECT);
0576 
0577     value = BLEND_FACTOR_DST_ALPHA_ZERO | BLEND_FACTOR_SRC_ALPHA_K2 |
0578         BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_SRC |
0579         BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC;
0580     tegra_plane_writel(p, value, DC_WIN_BLEND_NOMATCH_SELECT);
0581 
0582     value = K2(255) | K1(255) | WINDOW_LAYER_DEPTH(255 - zpos);
0583     tegra_plane_writel(p, value, DC_WIN_BLEND_LAYER_CONTROL);
0584 
0585     /* scaling */
0586     min_width = min(new_state->src_w >> 16, new_state->crtc_w);
0587 
0588     value = tegra_plane_readl(p, DC_WINC_PRECOMP_WGRP_PIPE_CAPC);
0589 
0590     if (min_width < MAX_PIXELS_5TAP444(value)) {
0591         value = HORIZONTAL_TAPS_5 | VERTICAL_TAPS_5;
0592     } else {
0593         value = tegra_plane_readl(p, DC_WINC_PRECOMP_WGRP_PIPE_CAPE);
0594 
0595         if (min_width < MAX_PIXELS_2TAP444(value))
0596             value = HORIZONTAL_TAPS_2 | VERTICAL_TAPS_2;
0597         else
0598             dev_err(dc->dev, "invalid minimum width: %u\n", min_width);
0599     }
0600 
0601     value = HORIZONTAL_TAPS_5 | VERTICAL_TAPS_5;
0602     tegra_plane_writel(p, value, DC_WIN_WINDOWGROUP_SET_CONTROL_INPUT_SCALER);
0603 
0604     if (new_state->src_w != new_state->crtc_w << 16) {
0605         fixed20_12 width = dfixed_init(new_state->src_w >> 16);
0606         u32 incr = compute_phase_incr(width, new_state->crtc_w) & ~0x1;
0607         u32 init = (1 << (NFB - 1)) + (incr >> 1);
0608 
0609         tegra_plane_writel(p, incr, DC_WIN_SET_INPUT_SCALER_HPHASE_INCR);
0610         tegra_plane_writel(p, init, DC_WIN_SET_INPUT_SCALER_H_START_PHASE);
0611     } else {
0612         bypass |= INPUT_SCALER_HBYPASS;
0613     }
0614 
0615     if (new_state->src_h != new_state->crtc_h << 16) {
0616         fixed20_12 height = dfixed_init(new_state->src_h >> 16);
0617         u32 incr = compute_phase_incr(height, new_state->crtc_h) & ~0x1;
0618         u32 init = (1 << (NFB - 1)) + (incr >> 1);
0619 
0620         tegra_plane_writel(p, incr, DC_WIN_SET_INPUT_SCALER_VPHASE_INCR);
0621         tegra_plane_writel(p, init, DC_WIN_SET_INPUT_SCALER_V_START_PHASE);
0622     } else {
0623         bypass |= INPUT_SCALER_VBYPASS;
0624     }
0625 
0626     tegra_plane_writel(p, bypass, DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE);
0627 
0628     /* disable compression */
0629     tegra_plane_writel(p, 0, DC_WINBUF_CDE_CONTROL);
0630 
0631 #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
0632     /*
0633      * Physical address bit 39 in Tegra194 is used as a switch for special
0634      * logic that swizzles the memory using either the legacy Tegra or the
0635      * dGPU sector layout.
0636      */
0637     if (tegra_plane_state->tiling.sector_layout == TEGRA_BO_SECTOR_LAYOUT_GPU)
0638         addr_flag = BIT_ULL(39);
0639 #endif
0640 
0641     base = tegra_plane_state->iova[0] + fb->offsets[0];
0642     base |= addr_flag;
0643 
0644     tegra_plane_writel(p, tegra_plane_state->format, DC_WIN_COLOR_DEPTH);
0645     tegra_plane_writel(p, 0, DC_WIN_PRECOMP_WGRP_PARAMS);
0646 
0647     value = V_POSITION(new_state->crtc_y) |
0648         H_POSITION(new_state->crtc_x);
0649     tegra_plane_writel(p, value, DC_WIN_POSITION);
0650 
0651     value = V_SIZE(new_state->crtc_h) | H_SIZE(new_state->crtc_w);
0652     tegra_plane_writel(p, value, DC_WIN_SIZE);
0653 
0654     value = WIN_ENABLE | COLOR_EXPAND;
0655     tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS);
0656 
0657     value = V_SIZE(new_state->src_h >> 16) | H_SIZE(new_state->src_w >> 16);
0658     tegra_plane_writel(p, value, DC_WIN_CROPPED_SIZE);
0659 
0660     tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI);
0661     tegra_plane_writel(p, lower_32_bits(base), DC_WINBUF_START_ADDR);
0662 
0663     value = PITCH(fb->pitches[0]);
0664     tegra_plane_writel(p, value, DC_WIN_PLANAR_STORAGE);
0665 
0666     if (yuv && planes > 1) {
0667         base = tegra_plane_state->iova[1] + fb->offsets[1];
0668         base |= addr_flag;
0669 
0670         tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI_U);
0671         tegra_plane_writel(p, lower_32_bits(base), DC_WINBUF_START_ADDR_U);
0672 
0673         if (planes > 2) {
0674             base = tegra_plane_state->iova[2] + fb->offsets[2];
0675             base |= addr_flag;
0676 
0677             tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI_V);
0678             tegra_plane_writel(p, lower_32_bits(base), DC_WINBUF_START_ADDR_V);
0679         }
0680 
0681         value = PITCH_U(fb->pitches[1]);
0682 
0683         if (planes > 2)
0684             value |= PITCH_V(fb->pitches[2]);
0685 
0686         tegra_plane_writel(p, value, DC_WIN_PLANAR_STORAGE_UV);
0687     } else {
0688         tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_U);
0689         tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_HI_U);
0690         tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_V);
0691         tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_HI_V);
0692         tegra_plane_writel(p, 0, DC_WIN_PLANAR_STORAGE_UV);
0693     }
0694 
0695     value = CLAMP_BEFORE_BLEND | INPUT_RANGE_FULL;
0696 
0697     if (yuv) {
0698         if (bpc < 12)
0699             value |= DEGAMMA_YUV8_10;
0700         else
0701             value |= DEGAMMA_YUV12;
0702 
0703         /* XXX parameterize */
0704         value |= COLOR_SPACE_YUV_2020;
0705     } else {
0706         if (!tegra_plane_format_is_indexed(tegra_plane_state->format))
0707             value |= DEGAMMA_SRGB;
0708     }
0709 
0710     tegra_plane_writel(p, value, DC_WIN_SET_PARAMS);
0711 
0712     value = OFFSET_X(new_state->src_y >> 16) |
0713         OFFSET_Y(new_state->src_x >> 16);
0714     tegra_plane_writel(p, value, DC_WINBUF_CROPPED_POINT);
0715 
0716     if (dc->soc->supports_block_linear) {
0717         unsigned long height = tegra_plane_state->tiling.value;
0718 
0719         /* XXX */
0720         switch (tegra_plane_state->tiling.mode) {
0721         case TEGRA_BO_TILING_MODE_PITCH:
0722             value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(0) |
0723                 DC_WINBUF_SURFACE_KIND_PITCH;
0724             break;
0725 
0726         /* XXX not supported on Tegra186 and later */
0727         case TEGRA_BO_TILING_MODE_TILED:
0728             value = DC_WINBUF_SURFACE_KIND_TILED;
0729             break;
0730 
0731         case TEGRA_BO_TILING_MODE_BLOCK:
0732             value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) |
0733                 DC_WINBUF_SURFACE_KIND_BLOCK;
0734             break;
0735         }
0736 
0737         tegra_plane_writel(p, value, DC_WINBUF_SURFACE_KIND);
0738     }
0739 
0740     /* disable gamut CSC */
0741     value = tegra_plane_readl(p, DC_WIN_WINDOW_SET_CONTROL);
0742     value &= ~CONTROL_CSC_ENABLE;
0743     tegra_plane_writel(p, value, DC_WIN_WINDOW_SET_CONTROL);
0744 
0745     host1x_client_suspend(&dc->client);
0746 }
0747 
0748 static const struct drm_plane_helper_funcs tegra_shared_plane_helper_funcs = {
0749     .prepare_fb = tegra_plane_prepare_fb,
0750     .cleanup_fb = tegra_plane_cleanup_fb,
0751     .atomic_check = tegra_shared_plane_atomic_check,
0752     .atomic_update = tegra_shared_plane_atomic_update,
0753     .atomic_disable = tegra_shared_plane_atomic_disable,
0754 };
0755 
0756 struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
0757                         struct tegra_dc *dc,
0758                         unsigned int wgrp,
0759                         unsigned int index)
0760 {
0761     enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY;
0762     struct tegra_drm *tegra = drm->dev_private;
0763     struct tegra_display_hub *hub = tegra->hub;
0764     struct tegra_shared_plane *plane;
0765     unsigned int possible_crtcs;
0766     unsigned int num_formats;
0767     const u64 *modifiers;
0768     struct drm_plane *p;
0769     const u32 *formats;
0770     int err;
0771 
0772     plane = kzalloc(sizeof(*plane), GFP_KERNEL);
0773     if (!plane)
0774         return ERR_PTR(-ENOMEM);
0775 
0776     plane->base.offset = 0x0a00 + 0x0300 * index;
0777     plane->base.index = index;
0778 
0779     plane->wgrp = &hub->wgrps[wgrp];
0780     plane->wgrp->parent = &dc->client;
0781 
0782     p = &plane->base.base;
0783 
0784     /* planes can be assigned to arbitrary CRTCs */
0785     possible_crtcs = BIT(tegra->num_crtcs) - 1;
0786 
0787     num_formats = ARRAY_SIZE(tegra_shared_plane_formats);
0788     formats = tegra_shared_plane_formats;
0789     modifiers = tegra_shared_plane_modifiers;
0790 
0791     err = drm_universal_plane_init(drm, p, possible_crtcs,
0792                        &tegra_plane_funcs, formats,
0793                        num_formats, modifiers, type, NULL);
0794     if (err < 0) {
0795         kfree(plane);
0796         return ERR_PTR(err);
0797     }
0798 
0799     drm_plane_helper_add(p, &tegra_shared_plane_helper_funcs);
0800     drm_plane_create_zpos_property(p, 0, 0, 255);
0801 
0802     return p;
0803 }
0804 
0805 static struct drm_private_state *
0806 tegra_display_hub_duplicate_state(struct drm_private_obj *obj)
0807 {
0808     struct tegra_display_hub_state *state;
0809 
0810     state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
0811     if (!state)
0812         return NULL;
0813 
0814     __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
0815 
0816     return &state->base;
0817 }
0818 
0819 static void tegra_display_hub_destroy_state(struct drm_private_obj *obj,
0820                         struct drm_private_state *state)
0821 {
0822     struct tegra_display_hub_state *hub_state =
0823         to_tegra_display_hub_state(state);
0824 
0825     kfree(hub_state);
0826 }
0827 
0828 static const struct drm_private_state_funcs tegra_display_hub_state_funcs = {
0829     .atomic_duplicate_state = tegra_display_hub_duplicate_state,
0830     .atomic_destroy_state = tegra_display_hub_destroy_state,
0831 };
0832 
0833 static struct tegra_display_hub_state *
0834 tegra_display_hub_get_state(struct tegra_display_hub *hub,
0835                 struct drm_atomic_state *state)
0836 {
0837     struct drm_private_state *priv;
0838 
0839     priv = drm_atomic_get_private_obj_state(state, &hub->base);
0840     if (IS_ERR(priv))
0841         return ERR_CAST(priv);
0842 
0843     return to_tegra_display_hub_state(priv);
0844 }
0845 
0846 int tegra_display_hub_atomic_check(struct drm_device *drm,
0847                    struct drm_atomic_state *state)
0848 {
0849     struct tegra_drm *tegra = drm->dev_private;
0850     struct tegra_display_hub_state *hub_state;
0851     struct drm_crtc_state *old, *new;
0852     struct drm_crtc *crtc;
0853     unsigned int i;
0854 
0855     if (!tegra->hub)
0856         return 0;
0857 
0858     hub_state = tegra_display_hub_get_state(tegra->hub, state);
0859     if (IS_ERR(hub_state))
0860         return PTR_ERR(hub_state);
0861 
0862     /*
0863      * The display hub display clock needs to be fed by the display clock
0864      * with the highest frequency to ensure proper functioning of all the
0865      * displays.
0866      *
0867      * Note that this isn't used before Tegra186, but it doesn't hurt and
0868      * conditionalizing it would make the code less clean.
0869      */
0870     for_each_oldnew_crtc_in_state(state, crtc, old, new, i) {
0871         struct tegra_dc_state *dc = to_dc_state(new);
0872 
0873         if (new->active) {
0874             if (!hub_state->clk || dc->pclk > hub_state->rate) {
0875                 hub_state->dc = to_tegra_dc(dc->base.crtc);
0876                 hub_state->clk = hub_state->dc->clk;
0877                 hub_state->rate = dc->pclk;
0878             }
0879         }
0880     }
0881 
0882     return 0;
0883 }
0884 
0885 static void tegra_display_hub_update(struct tegra_dc *dc)
0886 {
0887     u32 value;
0888     int err;
0889 
0890     err = host1x_client_resume(&dc->client);
0891     if (err < 0) {
0892         dev_err(dc->dev, "failed to resume: %d\n", err);
0893         return;
0894     }
0895 
0896     value = tegra_dc_readl(dc, DC_CMD_IHUB_COMMON_MISC_CTL);
0897     value &= ~LATENCY_EVENT;
0898     tegra_dc_writel(dc, value, DC_CMD_IHUB_COMMON_MISC_CTL);
0899 
0900     value = tegra_dc_readl(dc, DC_DISP_IHUB_COMMON_DISPLAY_FETCH_METER);
0901     value = CURS_SLOTS(1) | WGRP_SLOTS(1);
0902     tegra_dc_writel(dc, value, DC_DISP_IHUB_COMMON_DISPLAY_FETCH_METER);
0903 
0904     tegra_dc_writel(dc, COMMON_UPDATE, DC_CMD_STATE_CONTROL);
0905     tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
0906     tegra_dc_writel(dc, COMMON_ACTREQ, DC_CMD_STATE_CONTROL);
0907     tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
0908 
0909     host1x_client_suspend(&dc->client);
0910 }
0911 
0912 void tegra_display_hub_atomic_commit(struct drm_device *drm,
0913                      struct drm_atomic_state *state)
0914 {
0915     struct tegra_drm *tegra = drm->dev_private;
0916     struct tegra_display_hub *hub = tegra->hub;
0917     struct tegra_display_hub_state *hub_state;
0918     struct device *dev = hub->client.dev;
0919     int err;
0920 
0921     hub_state = to_tegra_display_hub_state(hub->base.state);
0922 
0923     if (hub_state->clk) {
0924         err = clk_set_rate(hub_state->clk, hub_state->rate);
0925         if (err < 0)
0926             dev_err(dev, "failed to set rate of %pC to %lu Hz\n",
0927                 hub_state->clk, hub_state->rate);
0928 
0929         err = clk_set_parent(hub->clk_disp, hub_state->clk);
0930         if (err < 0)
0931             dev_err(dev, "failed to set parent of %pC to %pC: %d\n",
0932                 hub->clk_disp, hub_state->clk, err);
0933     }
0934 
0935     if (hub_state->dc)
0936         tegra_display_hub_update(hub_state->dc);
0937 }
0938 
0939 static int tegra_display_hub_init(struct host1x_client *client)
0940 {
0941     struct tegra_display_hub *hub = to_tegra_display_hub(client);
0942     struct drm_device *drm = dev_get_drvdata(client->host);
0943     struct tegra_drm *tegra = drm->dev_private;
0944     struct tegra_display_hub_state *state;
0945 
0946     state = kzalloc(sizeof(*state), GFP_KERNEL);
0947     if (!state)
0948         return -ENOMEM;
0949 
0950     drm_atomic_private_obj_init(drm, &hub->base, &state->base,
0951                     &tegra_display_hub_state_funcs);
0952 
0953     tegra->hub = hub;
0954 
0955     return 0;
0956 }
0957 
0958 static int tegra_display_hub_exit(struct host1x_client *client)
0959 {
0960     struct drm_device *drm = dev_get_drvdata(client->host);
0961     struct tegra_drm *tegra = drm->dev_private;
0962 
0963     drm_atomic_private_obj_fini(&tegra->hub->base);
0964     tegra->hub = NULL;
0965 
0966     return 0;
0967 }
0968 
0969 static int tegra_display_hub_runtime_suspend(struct host1x_client *client)
0970 {
0971     struct tegra_display_hub *hub = to_tegra_display_hub(client);
0972     struct device *dev = client->dev;
0973     unsigned int i = hub->num_heads;
0974     int err;
0975 
0976     err = reset_control_assert(hub->rst);
0977     if (err < 0)
0978         return err;
0979 
0980     while (i--)
0981         clk_disable_unprepare(hub->clk_heads[i]);
0982 
0983     clk_disable_unprepare(hub->clk_hub);
0984     clk_disable_unprepare(hub->clk_dsc);
0985     clk_disable_unprepare(hub->clk_disp);
0986 
0987     pm_runtime_put_sync(dev);
0988 
0989     return 0;
0990 }
0991 
0992 static int tegra_display_hub_runtime_resume(struct host1x_client *client)
0993 {
0994     struct tegra_display_hub *hub = to_tegra_display_hub(client);
0995     struct device *dev = client->dev;
0996     unsigned int i;
0997     int err;
0998 
0999     err = pm_runtime_resume_and_get(dev);
1000     if (err < 0) {
1001         dev_err(dev, "failed to get runtime PM: %d\n", err);
1002         return err;
1003     }
1004 
1005     err = clk_prepare_enable(hub->clk_disp);
1006     if (err < 0)
1007         goto put_rpm;
1008 
1009     err = clk_prepare_enable(hub->clk_dsc);
1010     if (err < 0)
1011         goto disable_disp;
1012 
1013     err = clk_prepare_enable(hub->clk_hub);
1014     if (err < 0)
1015         goto disable_dsc;
1016 
1017     for (i = 0; i < hub->num_heads; i++) {
1018         err = clk_prepare_enable(hub->clk_heads[i]);
1019         if (err < 0)
1020             goto disable_heads;
1021     }
1022 
1023     err = reset_control_deassert(hub->rst);
1024     if (err < 0)
1025         goto disable_heads;
1026 
1027     return 0;
1028 
1029 disable_heads:
1030     while (i--)
1031         clk_disable_unprepare(hub->clk_heads[i]);
1032 
1033     clk_disable_unprepare(hub->clk_hub);
1034 disable_dsc:
1035     clk_disable_unprepare(hub->clk_dsc);
1036 disable_disp:
1037     clk_disable_unprepare(hub->clk_disp);
1038 put_rpm:
1039     pm_runtime_put_sync(dev);
1040     return err;
1041 }
1042 
1043 static const struct host1x_client_ops tegra_display_hub_ops = {
1044     .init = tegra_display_hub_init,
1045     .exit = tegra_display_hub_exit,
1046     .suspend = tegra_display_hub_runtime_suspend,
1047     .resume = tegra_display_hub_runtime_resume,
1048 };
1049 
1050 static int tegra_display_hub_probe(struct platform_device *pdev)
1051 {
1052     u64 dma_mask = dma_get_mask(pdev->dev.parent);
1053     struct device_node *child = NULL;
1054     struct tegra_display_hub *hub;
1055     struct clk *clk;
1056     unsigned int i;
1057     int err;
1058 
1059     err = dma_coerce_mask_and_coherent(&pdev->dev, dma_mask);
1060     if (err < 0) {
1061         dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err);
1062         return err;
1063     }
1064 
1065     hub = devm_kzalloc(&pdev->dev, sizeof(*hub), GFP_KERNEL);
1066     if (!hub)
1067         return -ENOMEM;
1068 
1069     hub->soc = of_device_get_match_data(&pdev->dev);
1070 
1071     hub->clk_disp = devm_clk_get(&pdev->dev, "disp");
1072     if (IS_ERR(hub->clk_disp)) {
1073         err = PTR_ERR(hub->clk_disp);
1074         return err;
1075     }
1076 
1077     if (hub->soc->supports_dsc) {
1078         hub->clk_dsc = devm_clk_get(&pdev->dev, "dsc");
1079         if (IS_ERR(hub->clk_dsc)) {
1080             err = PTR_ERR(hub->clk_dsc);
1081             return err;
1082         }
1083     }
1084 
1085     hub->clk_hub = devm_clk_get(&pdev->dev, "hub");
1086     if (IS_ERR(hub->clk_hub)) {
1087         err = PTR_ERR(hub->clk_hub);
1088         return err;
1089     }
1090 
1091     hub->rst = devm_reset_control_get(&pdev->dev, "misc");
1092     if (IS_ERR(hub->rst)) {
1093         err = PTR_ERR(hub->rst);
1094         return err;
1095     }
1096 
1097     hub->wgrps = devm_kcalloc(&pdev->dev, hub->soc->num_wgrps,
1098                   sizeof(*hub->wgrps), GFP_KERNEL);
1099     if (!hub->wgrps)
1100         return -ENOMEM;
1101 
1102     for (i = 0; i < hub->soc->num_wgrps; i++) {
1103         struct tegra_windowgroup *wgrp = &hub->wgrps[i];
1104         char id[8];
1105 
1106         snprintf(id, sizeof(id), "wgrp%u", i);
1107         mutex_init(&wgrp->lock);
1108         wgrp->usecount = 0;
1109         wgrp->index = i;
1110 
1111         wgrp->rst = devm_reset_control_get(&pdev->dev, id);
1112         if (IS_ERR(wgrp->rst))
1113             return PTR_ERR(wgrp->rst);
1114 
1115         err = reset_control_assert(wgrp->rst);
1116         if (err < 0)
1117             return err;
1118     }
1119 
1120     hub->num_heads = of_get_child_count(pdev->dev.of_node);
1121 
1122     hub->clk_heads = devm_kcalloc(&pdev->dev, hub->num_heads, sizeof(clk),
1123                       GFP_KERNEL);
1124     if (!hub->clk_heads)
1125         return -ENOMEM;
1126 
1127     for (i = 0; i < hub->num_heads; i++) {
1128         child = of_get_next_child(pdev->dev.of_node, child);
1129         if (!child) {
1130             dev_err(&pdev->dev, "failed to find node for head %u\n",
1131                 i);
1132             return -ENODEV;
1133         }
1134 
1135         clk = devm_get_clk_from_child(&pdev->dev, child, "dc");
1136         if (IS_ERR(clk)) {
1137             dev_err(&pdev->dev, "failed to get clock for head %u\n",
1138                 i);
1139             of_node_put(child);
1140             return PTR_ERR(clk);
1141         }
1142 
1143         hub->clk_heads[i] = clk;
1144     }
1145 
1146     of_node_put(child);
1147 
1148     /* XXX: enable clock across reset? */
1149     err = reset_control_assert(hub->rst);
1150     if (err < 0)
1151         return err;
1152 
1153     platform_set_drvdata(pdev, hub);
1154     pm_runtime_enable(&pdev->dev);
1155 
1156     INIT_LIST_HEAD(&hub->client.list);
1157     hub->client.ops = &tegra_display_hub_ops;
1158     hub->client.dev = &pdev->dev;
1159 
1160     err = host1x_client_register(&hub->client);
1161     if (err < 0)
1162         dev_err(&pdev->dev, "failed to register host1x client: %d\n",
1163             err);
1164 
1165     err = devm_of_platform_populate(&pdev->dev);
1166     if (err < 0)
1167         goto unregister;
1168 
1169     return err;
1170 
1171 unregister:
1172     host1x_client_unregister(&hub->client);
1173     pm_runtime_disable(&pdev->dev);
1174     return err;
1175 }
1176 
1177 static int tegra_display_hub_remove(struct platform_device *pdev)
1178 {
1179     struct tegra_display_hub *hub = platform_get_drvdata(pdev);
1180     unsigned int i;
1181     int err;
1182 
1183     err = host1x_client_unregister(&hub->client);
1184     if (err < 0) {
1185         dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
1186             err);
1187     }
1188 
1189     for (i = 0; i < hub->soc->num_wgrps; i++) {
1190         struct tegra_windowgroup *wgrp = &hub->wgrps[i];
1191 
1192         mutex_destroy(&wgrp->lock);
1193     }
1194 
1195     pm_runtime_disable(&pdev->dev);
1196 
1197     return err;
1198 }
1199 
1200 static const struct tegra_display_hub_soc tegra186_display_hub = {
1201     .num_wgrps = 6,
1202     .supports_dsc = true,
1203 };
1204 
1205 static const struct tegra_display_hub_soc tegra194_display_hub = {
1206     .num_wgrps = 6,
1207     .supports_dsc = false,
1208 };
1209 
1210 static const struct of_device_id tegra_display_hub_of_match[] = {
1211     {
1212         .compatible = "nvidia,tegra194-display",
1213         .data = &tegra194_display_hub
1214     }, {
1215         .compatible = "nvidia,tegra186-display",
1216         .data = &tegra186_display_hub
1217     }, {
1218         /* sentinel */
1219     }
1220 };
1221 MODULE_DEVICE_TABLE(of, tegra_display_hub_of_match);
1222 
1223 struct platform_driver tegra_display_hub_driver = {
1224     .driver = {
1225         .name = "tegra-display-hub",
1226         .of_match_table = tegra_display_hub_of_match,
1227     },
1228     .probe = tegra_display_hub_probe,
1229     .remove = tegra_display_hub_remove,
1230 };