Merge v5.6-rc1 into drm-misc-fixes
authorMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
Wed, 12 Feb 2020 13:08:59 +0000 (14:08 +0100)
committerMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
Wed, 12 Feb 2020 13:08:59 +0000 (14:08 +0100)
We're based on v5.6, need v5.6-rc1 at least. :)

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
1  2 
drivers/gpu/drm/bridge/tc358767.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/panfrost/panfrost_drv.c
drivers/gpu/drm/panfrost/panfrost_job.c
drivers/gpu/drm/sun4i/sun4i_drv.c

index b0b0ccbb059d6425b99d13fe21c9243f410dd8aa,3709e5ace7246086b3b4d172bdd5a7218cbf6306..fbdb42d4e772ecf87666fe28191559f06afd8cf1
@@@ -297,7 -297,7 +297,7 @@@ static inline int tc_poll_timeout(struc
  
  static int tc_aux_wait_busy(struct tc_data *tc)
  {
 -      return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0, 1000, 100000);
 +      return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0, 100, 100000);
  }
  
  static int tc_aux_write_data(struct tc_data *tc, const void *data,
@@@ -640,7 -640,7 +640,7 @@@ static int tc_aux_link_setup(struct tc_
        if (ret)
                goto err;
  
 -      ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
 +      ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 100, 100000);
        if (ret == -ETIMEDOUT) {
                dev_err(tc->dev, "Timeout waiting for PHY to become ready");
                return ret;
@@@ -876,7 -876,7 +876,7 @@@ static int tc_wait_link_training(struc
        int ret;
  
        ret = tc_poll_timeout(tc, DP0_LTSTAT, LT_LOOPDONE,
 -                            LT_LOOPDONE, 1, 1000);
 +                            LT_LOOPDONE, 500, 100000);
        if (ret) {
                dev_err(tc->dev, "Link training timeout waiting for LT_LOOPDONE!\n");
                return ret;
@@@ -949,7 -949,7 +949,7 @@@ static int tc_main_link_enable(struct t
        dp_phy_ctrl &= ~(DP_PHY_RST | PHY_M1_RST | PHY_M0_RST);
        ret = regmap_write(tc->regmap, DP_PHY_CTRL, dp_phy_ctrl);
  
 -      ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
 +      ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 500, 100000);
        if (ret) {
                dev_err(dev, "timeout waiting for phy become ready");
                return ret;
@@@ -1346,7 -1346,7 +1346,7 @@@ static int tc_connector_get_modes(struc
                return 0;
        }
  
-       count = drm_panel_get_modes(tc->panel);
+       count = drm_panel_get_modes(tc->panel, connector);
        if (count > 0)
                return count;
  
index 105bb5f401666834571eba65a5b22b00026f59c8,20cdaf3146b844b7fc2cd7ad3f752fda681b831d..cce0b1bba591fea5df2cb55c3ed57e64ed5019bd
@@@ -76,6 -76,11 +76,11 @@@ static int drm_dp_send_dpcd_write(struc
  
  static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
                                    struct drm_dp_mst_branch *mstb);
+ static void
+ drm_dp_send_clear_payload_id_table(struct drm_dp_mst_topology_mgr *mgr,
+                                  struct drm_dp_mst_branch *mstb);
  static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr,
                                           struct drm_dp_mst_branch *mstb,
                                           struct drm_dp_mst_port *port);
@@@ -517,8 -522,10 +522,10 @@@ drm_dp_decode_sideband_req(const struc
                        }
  
                        if (failed) {
-                               for (i = 0; i < r->num_transactions; i++)
+                               for (i = 0; i < r->num_transactions; i++) {
+                                       tx = &r->transactions[i];
                                        kfree(tx->bytes);
+                               }
                                return -ENOMEM;
                        }
  
@@@ -846,6 -853,7 +853,7 @@@ static bool drm_dp_sideband_parse_enum_
  {
        int idx = 1;
        repmsg->u.path_resources.port_number = (raw->msg[idx] >> 4) & 0xf;
+       repmsg->u.path_resources.fec_capable = raw->msg[idx] & 0x1;
        idx++;
        if (idx > raw->curlen)
                goto fail_len;
@@@ -950,6 -958,8 +958,8 @@@ static bool drm_dp_sideband_parse_reply
        case DP_POWER_DOWN_PHY:
        case DP_POWER_UP_PHY:
                return drm_dp_sideband_parse_power_updown_phy_ack(raw, msg);
+       case DP_CLEAR_PAYLOAD_ID_TABLE:
+               return true; /* since there's nothing to parse */
        default:
                DRM_ERROR("Got unknown reply 0x%02x (%s)\n", msg->req_type,
                          drm_dp_mst_req_type_str(msg->req_type));
@@@ -1048,6 -1058,15 +1058,15 @@@ static int build_link_address(struct dr
        return 0;
  }
  
+ static int build_clear_payload_id_table(struct drm_dp_sideband_msg_tx *msg)
+ {
+       struct drm_dp_sideband_msg_req_body req;
+       req.req_type = DP_CLEAR_PAYLOAD_ID_TABLE;
+       drm_dp_encode_sideband_req(&req, msg);
+       return 0;
+ }
  static int build_enum_path_resources(struct drm_dp_sideband_msg_tx *msg, int port_num)
  {
        struct drm_dp_sideband_msg_req_body req;
@@@ -2175,6 -2194,7 +2194,7 @@@ drm_dp_mst_topology_unlink_port(struct 
                                struct drm_dp_mst_port *port)
  {
        mutex_lock(&mgr->lock);
+       port->parent->num_ports--;
        list_del(&port->next);
        mutex_unlock(&mgr->lock);
        drm_dp_mst_topology_put_port(port);
@@@ -2199,6 -2219,9 +2219,9 @@@ drm_dp_mst_add_port(struct drm_device *
        port->aux.dev = dev->dev;
        port->aux.is_remote = true;
  
+       /* initialize the MST downstream port's AUX crc work queue */
+       drm_dp_remote_aux_init(&port->aux);
        /*
         * Make sure the memory allocation for our parent branch stays
         * around until our own memory allocation is released
@@@ -2275,6 -2298,7 +2298,7 @@@ drm_dp_mst_handle_link_address_port(str
                mutex_lock(&mgr->lock);
                drm_dp_mst_topology_get_port(port);
                list_add(&port->next, &mstb->ports);
+               mstb->num_ports++;
                mutex_unlock(&mgr->lock);
        }
  
@@@ -2564,10 -2588,14 +2588,14 @@@ static void drm_dp_mst_link_probe_work(
        struct drm_device *dev = mgr->dev;
        struct drm_dp_mst_branch *mstb;
        int ret;
+       bool clear_payload_id_table;
  
        mutex_lock(&mgr->probe_lock);
  
        mutex_lock(&mgr->lock);
+       clear_payload_id_table = !mgr->payload_id_table_cleared;
+       mgr->payload_id_table_cleared = true;
        mstb = mgr->mst_primary;
        if (mstb) {
                ret = drm_dp_mst_topology_try_get_mstb(mstb);
                return;
        }
  
+       /*
+        * Certain branch devices seem to incorrectly report an available_pbn
+        * of 0 on downstream sinks, even after clearing the
+        * DP_PAYLOAD_ALLOCATE_* registers in
+        * drm_dp_mst_topology_mgr_set_mst(). Namely, the CableMatters USB-C
+        * 2x DP hub. Sending a CLEAR_PAYLOAD_ID_TABLE message seems to make
+        * things work again.
+        */
+       if (clear_payload_id_table) {
+               DRM_DEBUG_KMS("Clearing payload ID table\n");
+               drm_dp_send_clear_payload_id_table(mgr, mstb);
+       }
        ret = drm_dp_check_and_send_link_address(mgr, mstb);
        drm_dp_mst_topology_put_mstb(mstb);
  
        return ret < 0 ? ret : changed;
  }
  
+ void drm_dp_send_clear_payload_id_table(struct drm_dp_mst_topology_mgr *mgr,
+                                       struct drm_dp_mst_branch *mstb)
+ {
+       struct drm_dp_sideband_msg_tx *txmsg;
+       int len, ret;
+       txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
+       if (!txmsg)
+               return;
+       txmsg->dst = mstb;
+       len = build_clear_payload_id_table(txmsg);
+       drm_dp_queue_down_tx(mgr, txmsg);
+       ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
+       if (ret > 0 && txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK)
+               DRM_DEBUG_KMS("clear payload table id nak received\n");
+       kfree(txmsg);
+ }
  static int
  drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr,
                                struct drm_dp_mst_branch *mstb,
                                      path_res->avail_payload_bw_number);
                        port->available_pbn =
                                path_res->avail_payload_bw_number;
+                       port->fec_capable = path_res->fec_capable;
                }
        }
  
@@@ -3435,6 -3499,7 +3499,7 @@@ static int drm_dp_get_vc_payload_bw(u8 
  int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool mst_state)
  {
        int ret = 0;
+       int i = 0;
        struct drm_dp_mst_branch *mstb = NULL;
  
        mutex_lock(&mgr->lock);
                /* this can fail if the device is gone */
                drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, 0);
                ret = 0;
+               mutex_lock(&mgr->payload_lock);
                memset(mgr->payloads, 0, mgr->max_payloads * sizeof(struct drm_dp_payload));
                mgr->payload_mask = 0;
                set_bit(0, &mgr->payload_mask);
+               for (i = 0; i < mgr->max_payloads; i++) {
+                       struct drm_dp_vcpi *vcpi = mgr->proposed_vcpis[i];
+                       if (vcpi) {
+                               vcpi->vcpi = 0;
+                               vcpi->num_slots = 0;
+                       }
+                       mgr->proposed_vcpis[i] = NULL;
+               }
                mgr->vcpi_mask = 0;
+               mutex_unlock(&mgr->payload_lock);
+               mgr->payload_id_table_cleared = false;
        }
  
  out_unlock:
@@@ -3760,8 -3838,7 +3838,8 @@@ drm_dp_mst_process_up_req(struct drm_dp
                else if (msg->req_type == DP_RESOURCE_STATUS_NOTIFY)
                        guid = msg->u.resource_stat.guid;
  
 -              mstb = drm_dp_get_mst_branch_device_by_guid(mgr, guid);
 +              if (guid)
 +                      mstb = drm_dp_get_mst_branch_device_by_guid(mgr, guid);
        } else {
                mstb = drm_dp_get_mst_branch_device(mgr, hdr->lct, hdr->rad);
        }
@@@ -4072,6 -4149,7 +4150,7 @@@ static int drm_dp_init_vcpi(struct drm_
   * @mgr: MST topology manager for the port
   * @port: port to find vcpi slots for
   * @pbn: bandwidth required for the mode in PBN
+  * @pbn_div: divider for DSC mode that takes FEC into account
   *
   * Allocates VCPI slots to @port, replacing any previous VCPI allocations it
   * may have had. Any atomic drivers which support MST must call this function
   */
  int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state,
                                  struct drm_dp_mst_topology_mgr *mgr,
-                                 struct drm_dp_mst_port *port, int pbn)
+                                 struct drm_dp_mst_port *port, int pbn,
+                                 int pbn_div)
  {
        struct drm_dp_mst_topology_state *topology_state;
        struct drm_dp_vcpi_allocation *pos, *vcpi = NULL;
-       int prev_slots, req_slots;
+       int prev_slots, prev_bw, req_slots;
  
        topology_state = drm_atomic_get_mst_topology_state(state, mgr);
        if (IS_ERR(topology_state))
                if (pos->port == port) {
                        vcpi = pos;
                        prev_slots = vcpi->vcpi;
+                       prev_bw = vcpi->pbn;
  
                        /*
                         * This should never happen, unless the driver tries
                        break;
                }
        }
-       if (!vcpi)
+       if (!vcpi) {
                prev_slots = 0;
+               prev_bw = 0;
+       }
+       if (pbn_div <= 0)
+               pbn_div = mgr->pbn_div;
  
-       req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div);
+       req_slots = DIV_ROUND_UP(pbn, pbn_div);
  
        DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] [MST PORT:%p] VCPI %d -> %d\n",
                         port->connector->base.id, port->connector->name,
                         port, prev_slots, req_slots);
+       DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] [MST PORT:%p] PBN %d -> %d\n",
+                        port->connector->base.id, port->connector->name,
+                        port, prev_bw, pbn);
  
        /* Add the new allocation to the state */
        if (!vcpi) {
                list_add(&vcpi->next, &topology_state->vcpis);
        }
        vcpi->vcpi = req_slots;
+       vcpi->pbn = pbn;
  
        return req_slots;
  }
@@@ -4398,10 -4487,11 +4488,11 @@@ EXPORT_SYMBOL(drm_dp_check_act_status)
   * drm_dp_calc_pbn_mode() - Calculate the PBN for a mode.
   * @clock: dot clock for the mode
   * @bpp: bpp for the mode.
+  * @dsc: DSC mode. If true, bpp has units of 1/16 of a bit per pixel
   *
   * This uses the formula in the spec to calculate the PBN value for a mode.
   */
- int drm_dp_calc_pbn_mode(int clock, int bpp)
+ int drm_dp_calc_pbn_mode(int clock, int bpp, bool dsc)
  {
        /*
         * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006
         * peak_kbps *= (1006/1000)
         * peak_kbps *= (64/54)
         * peak_kbps *= 8    convert to bytes
+        *
+        * If the bpp is in units of 1/16, further divide by 16. Put this
+        * factor in the numerator rather than the denominator to avoid
+        * integer overflow
         */
+       if (dsc)
+               return DIV_ROUND_UP_ULL(mul_u32_u32(clock * (bpp / 16), 64 * 1006),
+                                       8 * 54 * 1000 * 1000);
        return DIV_ROUND_UP_ULL(mul_u32_u32(clock * bpp, 64 * 1006),
                                8 * 54 * 1000 * 1000);
  }
@@@ -4714,9 -4813,61 +4814,61 @@@ static void drm_dp_mst_destroy_state(st
        kfree(mst_state);
  }
  
+ static bool drm_dp_mst_port_downstream_of_branch(struct drm_dp_mst_port *port,
+                                                struct drm_dp_mst_branch *branch)
+ {
+       while (port->parent) {
+               if (port->parent == branch)
+                       return true;
+               if (port->parent->port_parent)
+                       port = port->parent->port_parent;
+               else
+                       break;
+       }
+       return false;
+ }
+ static inline
+ int drm_dp_mst_atomic_check_bw_limit(struct drm_dp_mst_branch *branch,
+                                    struct drm_dp_mst_topology_state *mst_state)
+ {
+       struct drm_dp_mst_port *port;
+       struct drm_dp_vcpi_allocation *vcpi;
+       int pbn_limit = 0, pbn_used = 0;
+       list_for_each_entry(port, &branch->ports, next) {
+               if (port->mstb)
+                       if (drm_dp_mst_atomic_check_bw_limit(port->mstb, mst_state))
+                               return -ENOSPC;
+               if (port->available_pbn > 0)
+                       pbn_limit = port->available_pbn;
+       }
+       DRM_DEBUG_ATOMIC("[MST BRANCH:%p] branch has %d PBN available\n",
+                        branch, pbn_limit);
+       list_for_each_entry(vcpi, &mst_state->vcpis, next) {
+               if (!vcpi->pbn)
+                       continue;
+               if (drm_dp_mst_port_downstream_of_branch(vcpi->port, branch))
+                       pbn_used += vcpi->pbn;
+       }
+       DRM_DEBUG_ATOMIC("[MST BRANCH:%p] branch used %d PBN\n",
+                        branch, pbn_used);
+       if (pbn_used > pbn_limit) {
+               DRM_DEBUG_ATOMIC("[MST BRANCH:%p] No available bandwidth\n",
+                                branch);
+               return -ENOSPC;
+       }
+       return 0;
+ }
  static inline int
- drm_dp_mst_atomic_check_topology_state(struct drm_dp_mst_topology_mgr *mgr,
-                                      struct drm_dp_mst_topology_state *mst_state)
+ drm_dp_mst_atomic_check_vcpi_alloc_limit(struct drm_dp_mst_topology_mgr *mgr,
+                                        struct drm_dp_mst_topology_state *mst_state)
  {
        struct drm_dp_vcpi_allocation *vcpi;
        int avail_slots = 63, payload_count = 0;
        return 0;
  }
  
+ /**
+  * drm_dp_mst_add_affected_dsc_crtcs
+  * @state: Pointer to the new struct drm_dp_mst_topology_state
+  * @mgr: MST topology manager
+  *
+  * Whenever there is a change in mst topology
+  * DSC configuration would have to be recalculated
+  * therefore we need to trigger modeset on all affected
+  * CRTCs in that topology
+  *
+  * See also:
+  * drm_dp_mst_atomic_enable_dsc()
+  */
+ int drm_dp_mst_add_affected_dsc_crtcs(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr)
+ {
+       struct drm_dp_mst_topology_state *mst_state;
+       struct drm_dp_vcpi_allocation *pos;
+       struct drm_connector *connector;
+       struct drm_connector_state *conn_state;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *crtc_state;
+       mst_state = drm_atomic_get_mst_topology_state(state, mgr);
+       if (IS_ERR(mst_state))
+               return -EINVAL;
+       list_for_each_entry(pos, &mst_state->vcpis, next) {
+               connector = pos->port->connector;
+               if (!connector)
+                       return -EINVAL;
+               conn_state = drm_atomic_get_connector_state(state, connector);
+               if (IS_ERR(conn_state))
+                       return PTR_ERR(conn_state);
+               crtc = conn_state->crtc;
+               if (WARN_ON(!crtc))
+                       return -EINVAL;
+               if (!drm_dp_mst_dsc_aux_for_port(pos->port))
+                       continue;
+               crtc_state = drm_atomic_get_crtc_state(mst_state->base.state, crtc);
+               if (IS_ERR(crtc_state))
+                       return PTR_ERR(crtc_state);
+               DRM_DEBUG_ATOMIC("[MST MGR:%p] Setting mode_changed flag on CRTC %p\n",
+                                mgr, crtc);
+               crtc_state->mode_changed = true;
+       }
+       return 0;
+ }
+ EXPORT_SYMBOL(drm_dp_mst_add_affected_dsc_crtcs);
+ /**
+  * drm_dp_mst_atomic_enable_dsc - Set DSC Enable Flag to On/Off
+  * @state: Pointer to the new drm_atomic_state
+  * @port: Pointer to the affected MST Port
+  * @pbn: Newly recalculated bw required for link with DSC enabled
+  * @pbn_div: Divider to calculate correct number of pbn per slot
+  * @enable: Boolean flag to enable or disable DSC on the port
+  *
+  * This function enables DSC on the given Port
+  * by recalculating its vcpi from pbn provided
+  * and sets dsc_enable flag to keep track of which
+  * ports have DSC enabled
+  *
+  */
+ int drm_dp_mst_atomic_enable_dsc(struct drm_atomic_state *state,
+                                struct drm_dp_mst_port *port,
+                                int pbn, int pbn_div,
+                                bool enable)
+ {
+       struct drm_dp_mst_topology_state *mst_state;
+       struct drm_dp_vcpi_allocation *pos;
+       bool found = false;
+       int vcpi = 0;
+       mst_state = drm_atomic_get_mst_topology_state(state, port->mgr);
+       if (IS_ERR(mst_state))
+               return PTR_ERR(mst_state);
+       list_for_each_entry(pos, &mst_state->vcpis, next) {
+               if (pos->port == port) {
+                       found = true;
+                       break;
+               }
+       }
+       if (!found) {
+               DRM_DEBUG_ATOMIC("[MST PORT:%p] Couldn't find VCPI allocation in mst state %p\n",
+                                port, mst_state);
+               return -EINVAL;
+       }
+       if (pos->dsc_enabled == enable) {
+               DRM_DEBUG_ATOMIC("[MST PORT:%p] DSC flag is already set to %d, returning %d VCPI slots\n",
+                                port, enable, pos->vcpi);
+               vcpi = pos->vcpi;
+       }
+       if (enable) {
+               vcpi = drm_dp_atomic_find_vcpi_slots(state, port->mgr, port, pbn, pbn_div);
+               DRM_DEBUG_ATOMIC("[MST PORT:%p] Enabling DSC flag, reallocating %d VCPI slots on the port\n",
+                                port, vcpi);
+               if (vcpi < 0)
+                       return -EINVAL;
+       }
+       pos->dsc_enabled = enable;
+       return vcpi;
+ }
+ EXPORT_SYMBOL(drm_dp_mst_atomic_enable_dsc);
  /**
   * drm_dp_mst_atomic_check - Check that the new state of an MST topology in an
   * atomic update is valid
@@@ -4781,7 -5054,13 +5055,13 @@@ int drm_dp_mst_atomic_check(struct drm_
        int i, ret = 0;
  
        for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) {
-               ret = drm_dp_mst_atomic_check_topology_state(mgr, mst_state);
+               if (!mgr->mst_state)
+                       continue;
+               ret = drm_dp_mst_atomic_check_vcpi_alloc_limit(mgr, mst_state);
+               if (ret)
+                       break;
+               ret = drm_dp_mst_atomic_check_bw_limit(mgr->mst_primary, mst_state);
                if (ret)
                        break;
        }
@@@ -5045,3 -5324,173 +5325,173 @@@ static void drm_dp_mst_unregister_i2c_b
  {
        i2c_del_adapter(&aux->ddc);
  }
+ /**
+  * drm_dp_mst_is_virtual_dpcd() - Is the given port a virtual DP Peer Device
+  * @port: The port to check
+  *
+  * A single physical MST hub object can be represented in the topology
+  * by multiple branches, with virtual ports between those branches.
+  *
+  * As of DP1.4, An MST hub with internal (virtual) ports must expose
+  * certain DPCD registers over those ports. See sections 2.6.1.1.1
+  * and 2.6.1.1.2 of Display Port specification v1.4 for details.
+  *
+  * May acquire mgr->lock
+  *
+  * Returns:
+  * true if the port is a virtual DP peer device, false otherwise
+  */
+ static bool drm_dp_mst_is_virtual_dpcd(struct drm_dp_mst_port *port)
+ {
+       struct drm_dp_mst_port *downstream_port;
+       if (!port || port->dpcd_rev < DP_DPCD_REV_14)
+               return false;
+       /* Virtual DP Sink (Internal Display Panel) */
+       if (port->port_num >= 8)
+               return true;
+       /* DP-to-HDMI Protocol Converter */
+       if (port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV &&
+           !port->mcs &&
+           port->ldps)
+               return true;
+       /* DP-to-DP */
+       mutex_lock(&port->mgr->lock);
+       if (port->pdt == DP_PEER_DEVICE_MST_BRANCHING &&
+           port->mstb &&
+           port->mstb->num_ports == 2) {
+               list_for_each_entry(downstream_port, &port->mstb->ports, next) {
+                       if (downstream_port->pdt == DP_PEER_DEVICE_SST_SINK &&
+                           !downstream_port->input) {
+                               mutex_unlock(&port->mgr->lock);
+                               return true;
+                       }
+               }
+       }
+       mutex_unlock(&port->mgr->lock);
+       return false;
+ }
+ /**
+  * drm_dp_mst_dsc_aux_for_port() - Find the correct aux for DSC
+  * @port: The port to check. A leaf of the MST tree with an attached display.
+  *
+  * Depending on the situation, DSC may be enabled via the endpoint aux,
+  * the immediately upstream aux, or the connector's physical aux.
+  *
+  * This is both the correct aux to read DSC_CAPABILITY and the
+  * correct aux to write DSC_ENABLED.
+  *
+  * This operation can be expensive (up to four aux reads), so
+  * the caller should cache the return.
+  *
+  * Returns:
+  * NULL if DSC cannot be enabled on this port, otherwise the aux device
+  */
+ struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port)
+ {
+       struct drm_dp_mst_port *immediate_upstream_port;
+       struct drm_dp_mst_port *fec_port;
+       struct drm_dp_desc desc = { 0 };
+       u8 endpoint_fec;
+       u8 endpoint_dsc;
+       if (!port)
+               return NULL;
+       if (port->parent->port_parent)
+               immediate_upstream_port = port->parent->port_parent;
+       else
+               immediate_upstream_port = NULL;
+       fec_port = immediate_upstream_port;
+       while (fec_port) {
+               /*
+                * Each physical link (i.e. not a virtual port) between the
+                * output and the primary device must support FEC
+                */
+               if (!drm_dp_mst_is_virtual_dpcd(fec_port) &&
+                   !fec_port->fec_capable)
+                       return NULL;
+               fec_port = fec_port->parent->port_parent;
+       }
+       /* DP-to-DP peer device */
+       if (drm_dp_mst_is_virtual_dpcd(immediate_upstream_port)) {
+               u8 upstream_dsc;
+               if (drm_dp_dpcd_read(&port->aux,
+                                    DP_DSC_SUPPORT, &endpoint_dsc, 1) != 1)
+                       return NULL;
+               if (drm_dp_dpcd_read(&port->aux,
+                                    DP_FEC_CAPABILITY, &endpoint_fec, 1) != 1)
+                       return NULL;
+               if (drm_dp_dpcd_read(&immediate_upstream_port->aux,
+                                    DP_DSC_SUPPORT, &upstream_dsc, 1) != 1)
+                       return NULL;
+               /* Enpoint decompression with DP-to-DP peer device */
+               if ((endpoint_dsc & DP_DSC_DECOMPRESSION_IS_SUPPORTED) &&
+                   (endpoint_fec & DP_FEC_CAPABLE) &&
+                   (upstream_dsc & 0x2) /* DSC passthrough */)
+                       return &port->aux;
+               /* Virtual DPCD decompression with DP-to-DP peer device */
+               return &immediate_upstream_port->aux;
+       }
+       /* Virtual DPCD decompression with DP-to-HDMI or Virtual DP Sink */
+       if (drm_dp_mst_is_virtual_dpcd(port))
+               return &port->aux;
+       /*
+        * Synaptics quirk
+        * Applies to ports for which:
+        * - Physical aux has Synaptics OUI
+        * - DPv1.4 or higher
+        * - Port is on primary branch device
+        * - Not a VGA adapter (DP_DWN_STRM_PORT_TYPE_ANALOG)
+        */
+       if (drm_dp_read_desc(port->mgr->aux, &desc, true))
+               return NULL;
+       if (drm_dp_has_quirk(&desc, DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) &&
+           port->mgr->dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14 &&
+           port->parent == port->mgr->mst_primary) {
+               u8 downstreamport;
+               if (drm_dp_dpcd_read(&port->aux, DP_DOWNSTREAMPORT_PRESENT,
+                                    &downstreamport, 1) < 0)
+                       return NULL;
+               if ((downstreamport & DP_DWN_STRM_PORT_PRESENT) &&
+                  ((downstreamport & DP_DWN_STRM_PORT_TYPE_MASK)
+                    != DP_DWN_STRM_PORT_TYPE_ANALOG))
+                       return port->mgr->aux;
+       }
+       /*
+        * The check below verifies if the MST sink
+        * connected to the GPU is capable of DSC -
+        * therefore the endpoint needs to be
+        * both DSC and FEC capable.
+        */
+       if (drm_dp_dpcd_read(&port->aux,
+          DP_DSC_SUPPORT, &endpoint_dsc, 1) != 1)
+               return NULL;
+       if (drm_dp_dpcd_read(&port->aux,
+          DP_FEC_CAPABILITY, &endpoint_fec, 1) != 1)
+               return NULL;
+       if ((endpoint_dsc & DP_DSC_DECOMPRESSION_IS_SUPPORTED) &&
+          (endpoint_fec & DP_FEC_CAPABLE))
+               return &port->aux;
+       return NULL;
+ }
+ EXPORT_SYMBOL(drm_dp_mst_dsc_aux_for_port);
index 273d67e251c2e3eead67808e111d574039ed00d6,6da59f476aba6b793c238dc8ac65bd74e1647be7..b7a618db3ee223ec491ba66279b6c46e634146a1
@@@ -166,7 -166,6 +166,7 @@@ panfrost_lookup_bos(struct drm_device *
                        break;
                }
  
 +              atomic_inc(&bo->gpu_usecount);
                job->mappings[i] = mapping;
        }
  
@@@ -527,15 -526,11 +527,11 @@@ panfrost_postclose(struct drm_device *d
        kfree(panfrost_priv);
  }
  
- /* DRM_AUTH is required on SUBMIT for now, while all clients share a single
-  * address space.  Note that render nodes would be able to submit jobs that
-  * could access BOs from clients authenticated with the master node.
-  */
  static const struct drm_ioctl_desc panfrost_drm_driver_ioctls[] = {
  #define PANFROST_IOCTL(n, func, flags) \
        DRM_IOCTL_DEF_DRV(PANFROST_##n, panfrost_ioctl_##func, flags)
  
-       PANFROST_IOCTL(SUBMIT,          submit,         DRM_RENDER_ALLOW | DRM_AUTH),
+       PANFROST_IOCTL(SUBMIT,          submit,         DRM_RENDER_ALLOW),
        PANFROST_IOCTL(WAIT_BO,         wait_bo,        DRM_RENDER_ALLOW),
        PANFROST_IOCTL(CREATE_BO,       create_bo,      DRM_RENDER_ALLOW),
        PANFROST_IOCTL(MMAP_BO,         mmap_bo,        DRM_RENDER_ALLOW),
index 4d383831c1fc2e09ead48d16fe23dcf513a86d5e,7c36ec675b73dd464b554f177c22b996e131c930..7157dfd7dea3c98661fb604eeb65192bece911a1
@@@ -269,13 -269,8 +269,13 @@@ static void panfrost_job_cleanup(struc
        dma_fence_put(job->render_done_fence);
  
        if (job->mappings) {
 -              for (i = 0; i < job->bo_count; i++)
 +              for (i = 0; i < job->bo_count; i++) {
 +                      if (!job->mappings[i])
 +                              break;
 +
 +                      atomic_dec(&job->mappings[i]->obj->gpu_usecount);
                        panfrost_gem_mapping_put(job->mappings[i]);
 +              }
                kvfree(job->mappings);
        }
  
@@@ -558,12 -553,14 +558,14 @@@ int panfrost_job_open(struct panfrost_f
  {
        struct panfrost_device *pfdev = panfrost_priv->pfdev;
        struct panfrost_job_slot *js = pfdev->js;
-       struct drm_sched_rq *rq;
+       struct drm_gpu_scheduler *sched;
        int ret, i;
  
        for (i = 0; i < NUM_JOB_SLOTS; i++) {
-               rq = &js->queue[i].sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL];
-               ret = drm_sched_entity_init(&panfrost_priv->sched_entity[i], &rq, 1, NULL);
+               sched = &js->queue[i].sched;
+               ret = drm_sched_entity_init(&panfrost_priv->sched_entity[i],
+                                           DRM_SCHED_PRIORITY_NORMAL, &sched,
+                                           1, NULL);
                if (WARN_ON(ret))
                        return ret;
        }
index 5b54eff12cc0c3e7cdc3c12f597f0204f71c15cc,5ae67d526b1de8b753eb724496c64d84706ed1b0..328272ff77d84d737c83327b8aa0ab30268190db
@@@ -85,6 -85,7 +85,6 @@@ static int sun4i_drv_bind(struct devic
        }
  
        drm_mode_config_init(drm);
 -      drm->mode_config.allow_fb_modifiers = true;
  
        ret = component_bind_all(drm->dev, drm);
        if (ret) {
@@@ -345,6 -346,27 +345,27 @@@ static int sun4i_drv_add_endpoints(stru
        return count;
  }
  
+ #ifdef CONFIG_PM_SLEEP
+ static int sun4i_drv_drm_sys_suspend(struct device *dev)
+ {
+       struct drm_device *drm = dev_get_drvdata(dev);
+       return drm_mode_config_helper_suspend(drm);
+ }
+ static int sun4i_drv_drm_sys_resume(struct device *dev)
+ {
+       struct drm_device *drm = dev_get_drvdata(dev);
+       return drm_mode_config_helper_resume(drm);
+ }
+ #endif
+ static const struct dev_pm_ops sun4i_drv_drm_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(sun4i_drv_drm_sys_suspend,
+                               sun4i_drv_drm_sys_resume)
+ };
  static int sun4i_drv_probe(struct platform_device *pdev)
  {
        struct component_match *match = NULL;
@@@ -417,6 -439,7 +438,7 @@@ static struct platform_driver sun4i_drv
        .driver         = {
                .name           = "sun4i-drm",
                .of_match_table = sun4i_drv_of_table,
+               .pm = &sun4i_drv_drm_pm_ops,
        },
  };
  module_platform_driver(sun4i_drv_platform_driver);