From: Rodrigo Vivi Date: Wed, 23 Feb 2022 19:19:43 +0000 (-0500) Subject: Merge tag 'drm-intel-gt-next-2022-02-17' of git://anongit.freedesktop.org/drm/drm... X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=30424ebae8df0f786835e7a31ad790fa00764f35;p=linux.git Merge tag 'drm-intel-gt-next-2022-02-17' of git://anongit.freedesktop.org/drm/drm-intel into drm-intel-next UAPI Changes: - Weak parallel submission support for execlists Minimal implementation of the parallel submission support for execlists backend that was previously only implemented for GuC. Support one sibling non-virtual engine. Core Changes: - Two backmerges of drm/drm-next for header file renames/changes and i915_regs reorganization Driver Changes: - Add new DG2 subplatform: DG2-G12 (Matt R) - Add new DG2 workarounds (Matt R, Ram, Bruce) - Handle pre-programmed WOPCM registers for DG2+ (Daniele) - Update guc shim control programming on XeHP SDV+ (Daniele) - Add RPL-S C0/D0 stepping information (Anusha) - Improve GuC ADS initialization to work on ARM64 on dGFX (Lucas) - Fix KMD and GuC race on accessing PMU busyness (Umesh) - Use PM timestamp instead of RING TIMESTAMP for reference in PMU with GuC (Umesh) - Report error on invalid reset notification from GuC (John) - Avoid WARN splat by holding RPM wakelock during PXP unbind (Juston) - Fixes to parallel submission implementation (Matt B.) - Improve GuC loading status check/error reports (John) - Tweak TTM LRU priority hint selection (Matt A.) - Align the plane_vma to min_page_size of stolen mem (Ram) - Introduce vma resources and implement async unbinding (Thomas) - Use struct vma_resource instead of struct vma_snapshot (Thomas) - Return some TTM accel move errors instead of trying memcpy move (Thomas) - Fix a race between vma / object destruction and unbinding (Thomas) - Remove short-term pins from execbuf (Maarten) - Update to GuC version 69.0.3 (John, Michal Wa.) - Improvements to GT reset paths in GuC backend (Matt B.) - Use shrinker_release_pages instead of writeback in shmem object hooks (Matt A., Tvrtko) - Use trylock instead of blocking lock when freeing GEM objects (Maarten) - Allocate intel_engine_coredump_alloc with ALLOW_FAIL (Matt B.) - Fixes to object unmapping and purging (Matt A) - Check for wedged device in GuC backend (John) - Avoid lockdep splat by locking dpt_obj around set_cache_level (Maarten) - Allow dead vm to unbind vma's without lock (Maarten) - s/engine->i915/i915/ for DG2 engine workarounds (Matt R) - Use to_gt() helper for GGTT accesses (Michal Wi.) - Selftest improvements (Matt B., Thomas, Ram) - Coding style and compiler warning fixes (Matt B., Jasmine, Andi, Colin, Gustavo, Dan) From: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/Yg4i2aCZvvee5Eai@jlahtine-mobl.ger.corp.intel.com Signed-off-by: Rodrigo Vivi [Fixed conflicts while applying, using the fixups/drm-intel-gt-next.patch from drm-rerere's 1f2b1742abdd ("2022y-02m-23d-16h-07m-57s UTC: drm-tip rerere cache update")] --- 30424ebae8df0f786835e7a31ad790fa00764f35 diff --cc drivers/gpu/drm/dp/drm_dp.c index 0000000000000,6d43325acca56..a20b0f8f24b87 mode 000000,100644..100644 --- a/drivers/gpu/drm/dp/drm_dp.c +++ b/drivers/gpu/drm/dp/drm_dp.c @@@ -1,0 -1,3744 +1,3827 @@@ + /* + * Copyright © 2009 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + #include + #include + + #include "drm_dp_helper_internal.h" + + struct dp_aux_backlight { + struct backlight_device *base; + struct drm_dp_aux *aux; + struct drm_edp_backlight_info info; + bool enabled; + }; + + /** + * DOC: dp helpers + * + * These functions contain some common logic and helpers at various abstraction + * levels to deal with Display Port sink devices and related things like DP aux + * channel transfers, EDID reading over DP aux channels, decoding certain DPCD + * blocks, ... + */ + + /* Helpers for DP link training */ + static u8 dp_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r) + { + return link_status[r - DP_LANE0_1_STATUS]; + } + + static u8 dp_get_lane_status(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane) + { + int i = DP_LANE0_1_STATUS + (lane >> 1); + int s = (lane & 1) * 4; + u8 l = dp_link_status(link_status, i); + + return (l >> s) & 0xf; + } + + bool drm_dp_channel_eq_ok(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane_count) + { + u8 lane_align; + u8 lane_status; + int lane; + + lane_align = dp_link_status(link_status, + DP_LANE_ALIGN_STATUS_UPDATED); + if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0) + return false; + for (lane = 0; lane < lane_count; lane++) { + lane_status = dp_get_lane_status(link_status, lane); + if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS) + return false; + } + return true; + } + EXPORT_SYMBOL(drm_dp_channel_eq_ok); + + bool drm_dp_clock_recovery_ok(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane_count) + { + int lane; + u8 lane_status; + + for (lane = 0; lane < lane_count; lane++) { + lane_status = dp_get_lane_status(link_status, lane); + if ((lane_status & DP_LANE_CR_DONE) == 0) + return false; + } + return true; + } + EXPORT_SYMBOL(drm_dp_clock_recovery_ok); + + u8 drm_dp_get_adjust_request_voltage(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane) + { + int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); + int s = ((lane & 1) ? + DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT : + DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT); + u8 l = dp_link_status(link_status, i); + + return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT; + } + EXPORT_SYMBOL(drm_dp_get_adjust_request_voltage); + + u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane) + { + int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); + int s = ((lane & 1) ? + DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT : + DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT); + u8 l = dp_link_status(link_status, i); + + return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT; + } + EXPORT_SYMBOL(drm_dp_get_adjust_request_pre_emphasis); + + /* DP 2.0 128b/132b */ + u8 drm_dp_get_adjust_tx_ffe_preset(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane) + { + int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); + int s = ((lane & 1) ? + DP_ADJUST_TX_FFE_PRESET_LANE1_SHIFT : + DP_ADJUST_TX_FFE_PRESET_LANE0_SHIFT); + u8 l = dp_link_status(link_status, i); + + return (l >> s) & 0xf; + } + EXPORT_SYMBOL(drm_dp_get_adjust_tx_ffe_preset); + ++/* DP 2.0 errata for 128b/132b */ ++bool drm_dp_128b132b_lane_channel_eq_done(const u8 link_status[DP_LINK_STATUS_SIZE], ++ int lane_count) ++{ ++ u8 lane_align, lane_status; ++ int lane; ++ ++ lane_align = dp_link_status(link_status, DP_LANE_ALIGN_STATUS_UPDATED); ++ if (!(lane_align & DP_INTERLANE_ALIGN_DONE)) ++ return false; ++ ++ for (lane = 0; lane < lane_count; lane++) { ++ lane_status = dp_get_lane_status(link_status, lane); ++ if (!(lane_status & DP_LANE_CHANNEL_EQ_DONE)) ++ return false; ++ } ++ return true; ++} ++EXPORT_SYMBOL(drm_dp_128b132b_lane_channel_eq_done); ++ ++/* DP 2.0 errata for 128b/132b */ ++bool drm_dp_128b132b_lane_symbol_locked(const u8 link_status[DP_LINK_STATUS_SIZE], ++ int lane_count) ++{ ++ u8 lane_status; ++ int lane; ++ ++ for (lane = 0; lane < lane_count; lane++) { ++ lane_status = dp_get_lane_status(link_status, lane); ++ if (!(lane_status & DP_LANE_SYMBOL_LOCKED)) ++ return false; ++ } ++ return true; ++} ++EXPORT_SYMBOL(drm_dp_128b132b_lane_symbol_locked); ++ ++/* DP 2.0 errata for 128b/132b */ ++bool drm_dp_128b132b_eq_interlane_align_done(const u8 link_status[DP_LINK_STATUS_SIZE]) ++{ ++ u8 status = dp_link_status(link_status, DP_LANE_ALIGN_STATUS_UPDATED); ++ ++ return status & DP_128B132B_DPRX_EQ_INTERLANE_ALIGN_DONE; ++} ++EXPORT_SYMBOL(drm_dp_128b132b_eq_interlane_align_done); ++ ++/* DP 2.0 errata for 128b/132b */ ++bool drm_dp_128b132b_cds_interlane_align_done(const u8 link_status[DP_LINK_STATUS_SIZE]) ++{ ++ u8 status = dp_link_status(link_status, DP_LANE_ALIGN_STATUS_UPDATED); ++ ++ return status & DP_128B132B_DPRX_CDS_INTERLANE_ALIGN_DONE; ++} ++EXPORT_SYMBOL(drm_dp_128b132b_cds_interlane_align_done); ++ ++/* DP 2.0 errata for 128b/132b */ ++bool drm_dp_128b132b_link_training_failed(const u8 link_status[DP_LINK_STATUS_SIZE]) ++{ ++ u8 status = dp_link_status(link_status, DP_LANE_ALIGN_STATUS_UPDATED); ++ ++ return status & DP_128B132B_LT_FAILED; ++} ++EXPORT_SYMBOL(drm_dp_128b132b_link_training_failed); ++ + u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZE], + unsigned int lane) + { + unsigned int offset = DP_ADJUST_REQUEST_POST_CURSOR2; + u8 value = dp_link_status(link_status, offset); + + return (value >> (lane << 1)) & 0x3; + } + EXPORT_SYMBOL(drm_dp_get_adjust_request_post_cursor); + + static int __8b10b_clock_recovery_delay_us(const struct drm_dp_aux *aux, u8 rd_interval) + { + if (rd_interval > 4) + drm_dbg_kms(aux->drm_dev, "%s: invalid AUX interval 0x%02x (max 4)\n", + aux->name, rd_interval); + + if (rd_interval == 0) + return 100; + + return rd_interval * 4 * USEC_PER_MSEC; + } + + static int __8b10b_channel_eq_delay_us(const struct drm_dp_aux *aux, u8 rd_interval) + { + if (rd_interval > 4) + drm_dbg_kms(aux->drm_dev, "%s: invalid AUX interval 0x%02x (max 4)\n", + aux->name, rd_interval); + + if (rd_interval == 0) + return 400; + + return rd_interval * 4 * USEC_PER_MSEC; + } + + static int __128b132b_channel_eq_delay_us(const struct drm_dp_aux *aux, u8 rd_interval) + { + switch (rd_interval) { + default: + drm_dbg_kms(aux->drm_dev, "%s: invalid AUX interval 0x%02x\n", + aux->name, rd_interval); + fallthrough; + case DP_128B132B_TRAINING_AUX_RD_INTERVAL_400_US: + return 400; + case DP_128B132B_TRAINING_AUX_RD_INTERVAL_4_MS: + return 4000; + case DP_128B132B_TRAINING_AUX_RD_INTERVAL_8_MS: + return 8000; + case DP_128B132B_TRAINING_AUX_RD_INTERVAL_12_MS: + return 12000; + case DP_128B132B_TRAINING_AUX_RD_INTERVAL_16_MS: + return 16000; + case DP_128B132B_TRAINING_AUX_RD_INTERVAL_32_MS: + return 32000; + case DP_128B132B_TRAINING_AUX_RD_INTERVAL_64_MS: + return 64000; + } + } + + /* + * The link training delays are different for: + * + * - Clock recovery vs. channel equalization + * - DPRX vs. LTTPR + * - 128b/132b vs. 8b/10b + * - DPCD rev 1.3 vs. later + * + * Get the correct delay in us, reading DPCD if necessary. + */ + static int __read_delay(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_CAP_SIZE], + enum drm_dp_phy dp_phy, bool uhbr, bool cr) + { + int (*parse)(const struct drm_dp_aux *aux, u8 rd_interval); + unsigned int offset; + u8 rd_interval, mask; + + if (dp_phy == DP_PHY_DPRX) { + if (uhbr) { + if (cr) + return 100; + + offset = DP_128B132B_TRAINING_AUX_RD_INTERVAL; + mask = DP_128B132B_TRAINING_AUX_RD_INTERVAL_MASK; + parse = __128b132b_channel_eq_delay_us; + } else { + if (cr && dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14) + return 100; + + offset = DP_TRAINING_AUX_RD_INTERVAL; + mask = DP_TRAINING_AUX_RD_MASK; + if (cr) + parse = __8b10b_clock_recovery_delay_us; + else + parse = __8b10b_channel_eq_delay_us; + } + } else { + if (uhbr) { + offset = DP_128B132B_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy); + mask = DP_128B132B_TRAINING_AUX_RD_INTERVAL_MASK; + parse = __128b132b_channel_eq_delay_us; + } else { + if (cr) + return 100; + + offset = DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy); + mask = DP_TRAINING_AUX_RD_MASK; + parse = __8b10b_channel_eq_delay_us; + } + } + + if (offset < DP_RECEIVER_CAP_SIZE) { + rd_interval = dpcd[offset]; + } else { + if (drm_dp_dpcd_readb(aux, offset, &rd_interval) != 1) { + drm_dbg_kms(aux->drm_dev, "%s: failed rd interval read\n", + aux->name); + /* arbitrary default delay */ + return 400; + } + } + + return parse(aux, rd_interval & mask); + } + + int drm_dp_read_clock_recovery_delay(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_CAP_SIZE], + enum drm_dp_phy dp_phy, bool uhbr) + { + return __read_delay(aux, dpcd, dp_phy, uhbr, true); + } + EXPORT_SYMBOL(drm_dp_read_clock_recovery_delay); + + int drm_dp_read_channel_eq_delay(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_CAP_SIZE], + enum drm_dp_phy dp_phy, bool uhbr) + { + return __read_delay(aux, dpcd, dp_phy, uhbr, false); + } + EXPORT_SYMBOL(drm_dp_read_channel_eq_delay); + ++/* Per DP 2.0 Errata */ ++int drm_dp_128b132b_read_aux_rd_interval(struct drm_dp_aux *aux) ++{ ++ int unit; ++ u8 val; ++ ++ if (drm_dp_dpcd_readb(aux, DP_128B132B_TRAINING_AUX_RD_INTERVAL, &val) != 1) { ++ drm_err(aux->drm_dev, "%s: failed rd interval read\n", ++ aux->name); ++ /* default to max */ ++ val = DP_128B132B_TRAINING_AUX_RD_INTERVAL_MASK; ++ } ++ ++ unit = (val & DP_128B132B_TRAINING_AUX_RD_INTERVAL_1MS_UNIT) ? 1 : 2; ++ val &= DP_128B132B_TRAINING_AUX_RD_INTERVAL_MASK; ++ ++ return (val + 1) * unit * 1000; ++} ++EXPORT_SYMBOL(drm_dp_128b132b_read_aux_rd_interval); ++ + void drm_dp_link_train_clock_recovery_delay(const struct drm_dp_aux *aux, + const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + u8 rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] & + DP_TRAINING_AUX_RD_MASK; + int delay_us; + + if (dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14) + delay_us = 100; + else + delay_us = __8b10b_clock_recovery_delay_us(aux, rd_interval); + + usleep_range(delay_us, delay_us * 2); + } + EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay); + + static void __drm_dp_link_train_channel_eq_delay(const struct drm_dp_aux *aux, + u8 rd_interval) + { + int delay_us = __8b10b_channel_eq_delay_us(aux, rd_interval); + + usleep_range(delay_us, delay_us * 2); + } + + void drm_dp_link_train_channel_eq_delay(const struct drm_dp_aux *aux, + const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + __drm_dp_link_train_channel_eq_delay(aux, + dpcd[DP_TRAINING_AUX_RD_INTERVAL] & + DP_TRAINING_AUX_RD_MASK); + } + EXPORT_SYMBOL(drm_dp_link_train_channel_eq_delay); + + void drm_dp_lttpr_link_train_clock_recovery_delay(void) + { + usleep_range(100, 200); + } + EXPORT_SYMBOL(drm_dp_lttpr_link_train_clock_recovery_delay); + + static u8 dp_lttpr_phy_cap(const u8 phy_cap[DP_LTTPR_PHY_CAP_SIZE], int r) + { + return phy_cap[r - DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1]; + } + + void drm_dp_lttpr_link_train_channel_eq_delay(const struct drm_dp_aux *aux, + const u8 phy_cap[DP_LTTPR_PHY_CAP_SIZE]) + { + u8 interval = dp_lttpr_phy_cap(phy_cap, + DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1) & + DP_TRAINING_AUX_RD_MASK; + + __drm_dp_link_train_channel_eq_delay(aux, interval); + } + EXPORT_SYMBOL(drm_dp_lttpr_link_train_channel_eq_delay); + + u8 drm_dp_link_rate_to_bw_code(int link_rate) + { + switch (link_rate) { + case 1000000: + return DP_LINK_BW_10; + case 1350000: + return DP_LINK_BW_13_5; + case 2000000: + return DP_LINK_BW_20; + default: + /* Spec says link_bw = link_rate / 0.27Gbps */ + return link_rate / 27000; + } + } + EXPORT_SYMBOL(drm_dp_link_rate_to_bw_code); + + int drm_dp_bw_code_to_link_rate(u8 link_bw) + { + switch (link_bw) { + case DP_LINK_BW_10: + return 1000000; + case DP_LINK_BW_13_5: + return 1350000; + case DP_LINK_BW_20: + return 2000000; + default: + /* Spec says link_rate = link_bw * 0.27Gbps */ + return link_bw * 27000; + } + } + EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate); + + #define AUX_RETRY_INTERVAL 500 /* us */ + + static inline void + drm_dp_dump_access(const struct drm_dp_aux *aux, + u8 request, uint offset, void *buffer, int ret) + { + const char *arrow = request == DP_AUX_NATIVE_READ ? "->" : "<-"; + + if (ret > 0) + drm_dbg_dp(aux->drm_dev, "%s: 0x%05x AUX %s (ret=%3d) %*ph\n", + aux->name, offset, arrow, ret, min(ret, 20), buffer); + else + drm_dbg_dp(aux->drm_dev, "%s: 0x%05x AUX %s (ret=%3d)\n", + aux->name, offset, arrow, ret); + } + + /** + * DOC: dp helpers + * + * The DisplayPort AUX channel is an abstraction to allow generic, driver- + * independent access to AUX functionality. Drivers can take advantage of + * this by filling in the fields of the drm_dp_aux structure. + * + * Transactions are described using a hardware-independent drm_dp_aux_msg + * structure, which is passed into a driver's .transfer() implementation. + * Both native and I2C-over-AUX transactions are supported. + */ + + static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, + unsigned int offset, void *buffer, size_t size) + { + struct drm_dp_aux_msg msg; + unsigned int retry, native_reply; + int err = 0, ret = 0; + + memset(&msg, 0, sizeof(msg)); + msg.address = offset; + msg.request = request; + msg.buffer = buffer; + msg.size = size; + + mutex_lock(&aux->hw_mutex); + + /* + * The specification doesn't give any recommendation on how often to + * retry native transactions. We used to retry 7 times like for + * aux i2c transactions but real world devices this wasn't + * sufficient, bump to 32 which makes Dell 4k monitors happier. + */ + for (retry = 0; retry < 32; retry++) { + if (ret != 0 && ret != -ETIMEDOUT) { + usleep_range(AUX_RETRY_INTERVAL, + AUX_RETRY_INTERVAL + 100); + } + + ret = aux->transfer(aux, &msg); + if (ret >= 0) { + native_reply = msg.reply & DP_AUX_NATIVE_REPLY_MASK; + if (native_reply == DP_AUX_NATIVE_REPLY_ACK) { + if (ret == size) + goto unlock; + + ret = -EPROTO; + } else + ret = -EIO; + } + + /* + * We want the error we return to be the error we received on + * the first transaction, since we may get a different error the + * next time we retry + */ + if (!err) + err = ret; + } + + drm_dbg_kms(aux->drm_dev, "%s: Too many retries, giving up. First error: %d\n", + aux->name, err); + ret = err; + + unlock: + mutex_unlock(&aux->hw_mutex); + return ret; + } + + /** + * drm_dp_dpcd_read() - read a series of bytes from the DPCD + * @aux: DisplayPort AUX channel (SST or MST) + * @offset: address of the (first) register to read + * @buffer: buffer to store the register values + * @size: number of bytes in @buffer + * + * Returns the number of bytes transferred on success, or a negative error + * code on failure. -EIO is returned if the request was NAKed by the sink or + * if the retry count was exceeded. If not all bytes were transferred, this + * function returns -EPROTO. Errors from the underlying AUX channel transfer + * function, with the exception of -EBUSY (which causes the transaction to + * be retried), are propagated to the caller. + */ + ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset, + void *buffer, size_t size) + { + int ret; + + /* + * HP ZR24w corrupts the first DPCD access after entering power save + * mode. Eg. on a read, the entire buffer will be filled with the same + * byte. Do a throw away read to avoid corrupting anything we care + * about. Afterwards things will work correctly until the monitor + * gets woken up and subsequently re-enters power save mode. + * + * The user pressing any button on the monitor is enough to wake it + * up, so there is no particularly good place to do the workaround. + * We just have to do it before any DPCD access and hope that the + * monitor doesn't power down exactly after the throw away read. + */ + if (!aux->is_remote) { + ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, DP_DPCD_REV, + buffer, 1); + if (ret != 1) + goto out; + } + + if (aux->is_remote) + ret = drm_dp_mst_dpcd_read(aux, offset, buffer, size); + else + ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, offset, + buffer, size); + + out: + drm_dp_dump_access(aux, DP_AUX_NATIVE_READ, offset, buffer, ret); + return ret; + } + EXPORT_SYMBOL(drm_dp_dpcd_read); + + /** + * drm_dp_dpcd_write() - write a series of bytes to the DPCD + * @aux: DisplayPort AUX channel (SST or MST) + * @offset: address of the (first) register to write + * @buffer: buffer containing the values to write + * @size: number of bytes in @buffer + * + * Returns the number of bytes transferred on success, or a negative error + * code on failure. -EIO is returned if the request was NAKed by the sink or + * if the retry count was exceeded. If not all bytes were transferred, this + * function returns -EPROTO. Errors from the underlying AUX channel transfer + * function, with the exception of -EBUSY (which causes the transaction to + * be retried), are propagated to the caller. + */ + ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset, + void *buffer, size_t size) + { + int ret; + + if (aux->is_remote) + ret = drm_dp_mst_dpcd_write(aux, offset, buffer, size); + else + ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_WRITE, offset, + buffer, size); + + drm_dp_dump_access(aux, DP_AUX_NATIVE_WRITE, offset, buffer, ret); + return ret; + } + EXPORT_SYMBOL(drm_dp_dpcd_write); + + /** + * drm_dp_dpcd_read_link_status() - read DPCD link status (bytes 0x202-0x207) + * @aux: DisplayPort AUX channel + * @status: buffer to store the link status in (must be at least 6 bytes) + * + * Returns the number of bytes transferred on success or a negative error + * code on failure. + */ + int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux, + u8 status[DP_LINK_STATUS_SIZE]) + { + return drm_dp_dpcd_read(aux, DP_LANE0_1_STATUS, status, + DP_LINK_STATUS_SIZE); + } + EXPORT_SYMBOL(drm_dp_dpcd_read_link_status); + + /** + * drm_dp_dpcd_read_phy_link_status - get the link status information for a DP PHY + * @aux: DisplayPort AUX channel + * @dp_phy: the DP PHY to get the link status for + * @link_status: buffer to return the status in + * + * Fetch the AUX DPCD registers for the DPRX or an LTTPR PHY link status. The + * layout of the returned @link_status matches the DPCD register layout of the + * DPRX PHY link status. + * + * Returns 0 if the information was read successfully or a negative error code + * on failure. + */ + int drm_dp_dpcd_read_phy_link_status(struct drm_dp_aux *aux, + enum drm_dp_phy dp_phy, + u8 link_status[DP_LINK_STATUS_SIZE]) + { + int ret; + + if (dp_phy == DP_PHY_DPRX) { + ret = drm_dp_dpcd_read(aux, + DP_LANE0_1_STATUS, + link_status, + DP_LINK_STATUS_SIZE); + + if (ret < 0) + return ret; + + WARN_ON(ret != DP_LINK_STATUS_SIZE); + + return 0; + } + + ret = drm_dp_dpcd_read(aux, + DP_LANE0_1_STATUS_PHY_REPEATER(dp_phy), + link_status, + DP_LINK_STATUS_SIZE - 1); + + if (ret < 0) + return ret; + + WARN_ON(ret != DP_LINK_STATUS_SIZE - 1); + + /* Convert the LTTPR to the sink PHY link status layout */ + memmove(&link_status[DP_SINK_STATUS - DP_LANE0_1_STATUS + 1], + &link_status[DP_SINK_STATUS - DP_LANE0_1_STATUS], + DP_LINK_STATUS_SIZE - (DP_SINK_STATUS - DP_LANE0_1_STATUS) - 1); + link_status[DP_SINK_STATUS - DP_LANE0_1_STATUS] = 0; + + return 0; + } + EXPORT_SYMBOL(drm_dp_dpcd_read_phy_link_status); + + static bool is_edid_digital_input_dp(const struct edid *edid) + { + return edid && edid->revision >= 4 && + edid->input & DRM_EDID_INPUT_DIGITAL && + (edid->input & DRM_EDID_DIGITAL_TYPE_MASK) == DRM_EDID_DIGITAL_TYPE_DP; + } + + /** + * drm_dp_downstream_is_type() - is the downstream facing port of certain type? + * @dpcd: DisplayPort configuration data + * @port_cap: port capabilities + * @type: port type to be checked. Can be: + * %DP_DS_PORT_TYPE_DP, %DP_DS_PORT_TYPE_VGA, %DP_DS_PORT_TYPE_DVI, + * %DP_DS_PORT_TYPE_HDMI, %DP_DS_PORT_TYPE_NON_EDID, + * %DP_DS_PORT_TYPE_DP_DUALMODE or %DP_DS_PORT_TYPE_WIRELESS. + * + * Caveat: Only works with DPCD 1.1+ port caps. + * + * Returns: whether the downstream facing port matches the type. + */ + bool drm_dp_downstream_is_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4], u8 type) + { + return drm_dp_is_branch(dpcd) && + dpcd[DP_DPCD_REV] >= 0x11 && + (port_cap[0] & DP_DS_PORT_TYPE_MASK) == type; + } + EXPORT_SYMBOL(drm_dp_downstream_is_type); + + /** + * drm_dp_downstream_is_tmds() - is the downstream facing port TMDS? + * @dpcd: DisplayPort configuration data + * @port_cap: port capabilities + * @edid: EDID + * + * Returns: whether the downstream facing port is TMDS (HDMI/DVI). + */ + bool drm_dp_downstream_is_tmds(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4], + const struct edid *edid) + { + if (dpcd[DP_DPCD_REV] < 0x11) { + switch (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_TYPE_MASK) { + case DP_DWN_STRM_PORT_TYPE_TMDS: + return true; + default: + return false; + } + } + + switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) { + case DP_DS_PORT_TYPE_DP_DUALMODE: + if (is_edid_digital_input_dp(edid)) + return false; + fallthrough; + case DP_DS_PORT_TYPE_DVI: + case DP_DS_PORT_TYPE_HDMI: + return true; + default: + return false; + } + } + EXPORT_SYMBOL(drm_dp_downstream_is_tmds); + + /** + * drm_dp_send_real_edid_checksum() - send back real edid checksum value + * @aux: DisplayPort AUX channel + * @real_edid_checksum: real edid checksum for the last block + * + * Returns: + * True on success + */ + bool drm_dp_send_real_edid_checksum(struct drm_dp_aux *aux, + u8 real_edid_checksum) + { + u8 link_edid_read = 0, auto_test_req = 0, test_resp = 0; + + if (drm_dp_dpcd_read(aux, DP_DEVICE_SERVICE_IRQ_VECTOR, + &auto_test_req, 1) < 1) { + drm_err(aux->drm_dev, "%s: DPCD failed read at register 0x%x\n", + aux->name, DP_DEVICE_SERVICE_IRQ_VECTOR); + return false; + } + auto_test_req &= DP_AUTOMATED_TEST_REQUEST; + + if (drm_dp_dpcd_read(aux, DP_TEST_REQUEST, &link_edid_read, 1) < 1) { + drm_err(aux->drm_dev, "%s: DPCD failed read at register 0x%x\n", + aux->name, DP_TEST_REQUEST); + return false; + } + link_edid_read &= DP_TEST_LINK_EDID_READ; + + if (!auto_test_req || !link_edid_read) { + drm_dbg_kms(aux->drm_dev, "%s: Source DUT does not support TEST_EDID_READ\n", + aux->name); + return false; + } + + if (drm_dp_dpcd_write(aux, DP_DEVICE_SERVICE_IRQ_VECTOR, + &auto_test_req, 1) < 1) { + drm_err(aux->drm_dev, "%s: DPCD failed write at register 0x%x\n", + aux->name, DP_DEVICE_SERVICE_IRQ_VECTOR); + return false; + } + + /* send back checksum for the last edid extension block data */ + if (drm_dp_dpcd_write(aux, DP_TEST_EDID_CHECKSUM, + &real_edid_checksum, 1) < 1) { + drm_err(aux->drm_dev, "%s: DPCD failed write at register 0x%x\n", + aux->name, DP_TEST_EDID_CHECKSUM); + return false; + } + + test_resp |= DP_TEST_EDID_CHECKSUM_WRITE; + if (drm_dp_dpcd_write(aux, DP_TEST_RESPONSE, &test_resp, 1) < 1) { + drm_err(aux->drm_dev, "%s: DPCD failed write at register 0x%x\n", + aux->name, DP_TEST_RESPONSE); + return false; + } + + return true; + } + EXPORT_SYMBOL(drm_dp_send_real_edid_checksum); + + static u8 drm_dp_downstream_port_count(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + u8 port_count = dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_PORT_COUNT_MASK; + + if (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE && port_count > 4) + port_count = 4; + + return port_count; + } + + static int drm_dp_read_extended_dpcd_caps(struct drm_dp_aux *aux, + u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + u8 dpcd_ext[DP_RECEIVER_CAP_SIZE]; + int ret; + + /* + * Prior to DP1.3 the bit represented by + * DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT was reserved. + * If it is set DP_DPCD_REV at 0000h could be at a value less than + * the true capability of the panel. The only way to check is to + * then compare 0000h and 2200h. + */ + if (!(dpcd[DP_TRAINING_AUX_RD_INTERVAL] & + DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT)) + return 0; + + ret = drm_dp_dpcd_read(aux, DP_DP13_DPCD_REV, &dpcd_ext, + sizeof(dpcd_ext)); + if (ret < 0) + return ret; + if (ret != sizeof(dpcd_ext)) + return -EIO; + + if (dpcd[DP_DPCD_REV] > dpcd_ext[DP_DPCD_REV]) { + drm_dbg_kms(aux->drm_dev, + "%s: Extended DPCD rev less than base DPCD rev (%d > %d)\n", + aux->name, dpcd[DP_DPCD_REV], dpcd_ext[DP_DPCD_REV]); + return 0; + } + + if (!memcmp(dpcd, dpcd_ext, sizeof(dpcd_ext))) + return 0; + + drm_dbg_kms(aux->drm_dev, "%s: Base DPCD: %*ph\n", aux->name, DP_RECEIVER_CAP_SIZE, dpcd); + + memcpy(dpcd, dpcd_ext, sizeof(dpcd_ext)); + + return 0; + } + + /** + * drm_dp_read_dpcd_caps() - read DPCD caps and extended DPCD caps if + * available + * @aux: DisplayPort AUX channel + * @dpcd: Buffer to store the resulting DPCD in + * + * Attempts to read the base DPCD caps for @aux. Additionally, this function + * checks for and reads the extended DPRX caps (%DP_DP13_DPCD_REV) if + * present. + * + * Returns: %0 if the DPCD was read successfully, negative error code + * otherwise. + */ + int drm_dp_read_dpcd_caps(struct drm_dp_aux *aux, + u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + int ret; + + ret = drm_dp_dpcd_read(aux, DP_DPCD_REV, dpcd, DP_RECEIVER_CAP_SIZE); + if (ret < 0) + return ret; + if (ret != DP_RECEIVER_CAP_SIZE || dpcd[DP_DPCD_REV] == 0) + return -EIO; + + ret = drm_dp_read_extended_dpcd_caps(aux, dpcd); + if (ret < 0) + return ret; + + drm_dbg_kms(aux->drm_dev, "%s: DPCD: %*ph\n", aux->name, DP_RECEIVER_CAP_SIZE, dpcd); + + return ret; + } + EXPORT_SYMBOL(drm_dp_read_dpcd_caps); + + /** + * drm_dp_read_downstream_info() - read DPCD downstream port info if available + * @aux: DisplayPort AUX channel + * @dpcd: A cached copy of the port's DPCD + * @downstream_ports: buffer to store the downstream port info in + * + * See also: + * drm_dp_downstream_max_clock() + * drm_dp_downstream_max_bpc() + * + * Returns: 0 if either the downstream port info was read successfully or + * there was no downstream info to read, or a negative error code otherwise. + */ + int drm_dp_read_downstream_info(struct drm_dp_aux *aux, + const u8 dpcd[DP_RECEIVER_CAP_SIZE], + u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]) + { + int ret; + u8 len; + + memset(downstream_ports, 0, DP_MAX_DOWNSTREAM_PORTS); + + /* No downstream info to read */ + if (!drm_dp_is_branch(dpcd) || dpcd[DP_DPCD_REV] == DP_DPCD_REV_10) + return 0; + + /* Some branches advertise having 0 downstream ports, despite also advertising they have a + * downstream port present. The DP spec isn't clear on if this is allowed or not, but since + * some branches do it we need to handle it regardless. + */ + len = drm_dp_downstream_port_count(dpcd); + if (!len) + return 0; + + if (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE) + len *= 4; + + ret = drm_dp_dpcd_read(aux, DP_DOWNSTREAM_PORT_0, downstream_ports, len); + if (ret < 0) + return ret; + if (ret != len) + return -EIO; + + drm_dbg_kms(aux->drm_dev, "%s: DPCD DFP: %*ph\n", aux->name, len, downstream_ports); + + return 0; + } + EXPORT_SYMBOL(drm_dp_read_downstream_info); + + /** + * drm_dp_downstream_max_dotclock() - extract downstream facing port max dot clock + * @dpcd: DisplayPort configuration data + * @port_cap: port capabilities + * + * Returns: Downstream facing port max dot clock in kHz on success, + * or 0 if max clock not defined + */ + int drm_dp_downstream_max_dotclock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4]) + { + if (!drm_dp_is_branch(dpcd)) + return 0; + + if (dpcd[DP_DPCD_REV] < 0x11) + return 0; + + switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) { + case DP_DS_PORT_TYPE_VGA: + if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE) == 0) + return 0; + return port_cap[1] * 8000; + default: + return 0; + } + } + EXPORT_SYMBOL(drm_dp_downstream_max_dotclock); + + /** + * drm_dp_downstream_max_tmds_clock() - extract downstream facing port max TMDS clock + * @dpcd: DisplayPort configuration data + * @port_cap: port capabilities + * @edid: EDID + * + * Returns: HDMI/DVI downstream facing port max TMDS clock in kHz on success, + * or 0 if max TMDS clock not defined + */ + int drm_dp_downstream_max_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4], + const struct edid *edid) + { + if (!drm_dp_is_branch(dpcd)) + return 0; + + if (dpcd[DP_DPCD_REV] < 0x11) { + switch (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_TYPE_MASK) { + case DP_DWN_STRM_PORT_TYPE_TMDS: + return 165000; + default: + return 0; + } + } + + switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) { + case DP_DS_PORT_TYPE_DP_DUALMODE: + if (is_edid_digital_input_dp(edid)) + return 0; + /* + * It's left up to the driver to check the + * DP dual mode adapter's max TMDS clock. + * + * Unfortunately it looks like branch devices + * may not fordward that the DP dual mode i2c + * access so we just usually get i2c nak :( + */ + fallthrough; + case DP_DS_PORT_TYPE_HDMI: + /* + * We should perhaps assume 165 MHz when detailed cap + * info is not available. But looks like many typical + * branch devices fall into that category and so we'd + * probably end up with users complaining that they can't + * get high resolution modes with their favorite dongle. + * + * So let's limit to 300 MHz instead since DPCD 1.4 + * HDMI 2.0 DFPs are required to have the detailed cap + * info. So it's more likely we're dealing with a HDMI 1.4 + * compatible* device here. + */ + if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE) == 0) + return 300000; + return port_cap[1] * 2500; + case DP_DS_PORT_TYPE_DVI: + if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE) == 0) + return 165000; + /* FIXME what to do about DVI dual link? */ + return port_cap[1] * 2500; + default: + return 0; + } + } + EXPORT_SYMBOL(drm_dp_downstream_max_tmds_clock); + + /** + * drm_dp_downstream_min_tmds_clock() - extract downstream facing port min TMDS clock + * @dpcd: DisplayPort configuration data + * @port_cap: port capabilities + * @edid: EDID + * + * Returns: HDMI/DVI downstream facing port min TMDS clock in kHz on success, + * or 0 if max TMDS clock not defined + */ + int drm_dp_downstream_min_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4], + const struct edid *edid) + { + if (!drm_dp_is_branch(dpcd)) + return 0; + + if (dpcd[DP_DPCD_REV] < 0x11) { + switch (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_TYPE_MASK) { + case DP_DWN_STRM_PORT_TYPE_TMDS: + return 25000; + default: + return 0; + } + } + + switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) { + case DP_DS_PORT_TYPE_DP_DUALMODE: + if (is_edid_digital_input_dp(edid)) + return 0; + fallthrough; + case DP_DS_PORT_TYPE_DVI: + case DP_DS_PORT_TYPE_HDMI: + /* + * Unclear whether the protocol converter could + * utilize pixel replication. Assume it won't. + */ + return 25000; + default: + return 0; + } + } + EXPORT_SYMBOL(drm_dp_downstream_min_tmds_clock); + + /** + * drm_dp_downstream_max_bpc() - extract downstream facing port max + * bits per component + * @dpcd: DisplayPort configuration data + * @port_cap: downstream facing port capabilities + * @edid: EDID + * + * Returns: Max bpc on success or 0 if max bpc not defined + */ + int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4], + const struct edid *edid) + { + if (!drm_dp_is_branch(dpcd)) + return 0; + + if (dpcd[DP_DPCD_REV] < 0x11) { + switch (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_TYPE_MASK) { + case DP_DWN_STRM_PORT_TYPE_DP: + return 0; + default: + return 8; + } + } + + switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) { + case DP_DS_PORT_TYPE_DP: + return 0; + case DP_DS_PORT_TYPE_DP_DUALMODE: + if (is_edid_digital_input_dp(edid)) + return 0; + fallthrough; + case DP_DS_PORT_TYPE_HDMI: + case DP_DS_PORT_TYPE_DVI: + case DP_DS_PORT_TYPE_VGA: + if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE) == 0) + return 8; + + switch (port_cap[2] & DP_DS_MAX_BPC_MASK) { + case DP_DS_8BPC: + return 8; + case DP_DS_10BPC: + return 10; + case DP_DS_12BPC: + return 12; + case DP_DS_16BPC: + return 16; + default: + return 8; + } + break; + default: + return 8; + } + } + EXPORT_SYMBOL(drm_dp_downstream_max_bpc); + + /** + * drm_dp_downstream_420_passthrough() - determine downstream facing port + * YCbCr 4:2:0 pass-through capability + * @dpcd: DisplayPort configuration data + * @port_cap: downstream facing port capabilities + * + * Returns: whether the downstream facing port can pass through YCbCr 4:2:0 + */ + bool drm_dp_downstream_420_passthrough(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4]) + { + if (!drm_dp_is_branch(dpcd)) + return false; + + if (dpcd[DP_DPCD_REV] < 0x13) + return false; + + switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) { + case DP_DS_PORT_TYPE_DP: + return true; + case DP_DS_PORT_TYPE_HDMI: + if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE) == 0) + return false; + + return port_cap[3] & DP_DS_HDMI_YCBCR420_PASS_THROUGH; + default: + return false; + } + } + EXPORT_SYMBOL(drm_dp_downstream_420_passthrough); + + /** + * drm_dp_downstream_444_to_420_conversion() - determine downstream facing port + * YCbCr 4:4:4->4:2:0 conversion capability + * @dpcd: DisplayPort configuration data + * @port_cap: downstream facing port capabilities + * + * Returns: whether the downstream facing port can convert YCbCr 4:4:4 to 4:2:0 + */ + bool drm_dp_downstream_444_to_420_conversion(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4]) + { + if (!drm_dp_is_branch(dpcd)) + return false; + + if (dpcd[DP_DPCD_REV] < 0x13) + return false; + + switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) { + case DP_DS_PORT_TYPE_HDMI: + if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE) == 0) + return false; + + return port_cap[3] & DP_DS_HDMI_YCBCR444_TO_420_CONV; + default: + return false; + } + } + EXPORT_SYMBOL(drm_dp_downstream_444_to_420_conversion); + + /** + * drm_dp_downstream_rgb_to_ycbcr_conversion() - determine downstream facing port + * RGB->YCbCr conversion capability + * @dpcd: DisplayPort configuration data + * @port_cap: downstream facing port capabilities + * @color_spc: Colorspace for which conversion cap is sought + * + * Returns: whether the downstream facing port can convert RGB->YCbCr for a given + * colorspace. + */ + bool drm_dp_downstream_rgb_to_ycbcr_conversion(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4], + u8 color_spc) + { + if (!drm_dp_is_branch(dpcd)) + return false; + + if (dpcd[DP_DPCD_REV] < 0x13) + return false; + + switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) { + case DP_DS_PORT_TYPE_HDMI: + if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE) == 0) + return false; + + return port_cap[3] & color_spc; + default: + return false; + } + } + EXPORT_SYMBOL(drm_dp_downstream_rgb_to_ycbcr_conversion); + + /** + * drm_dp_downstream_mode() - return a mode for downstream facing port + * @dev: DRM device + * @dpcd: DisplayPort configuration data + * @port_cap: port capabilities + * + * Provides a suitable mode for downstream facing ports without EDID. + * + * Returns: A new drm_display_mode on success or NULL on failure + */ + struct drm_display_mode * + drm_dp_downstream_mode(struct drm_device *dev, + const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4]) + + { + u8 vic; + + if (!drm_dp_is_branch(dpcd)) + return NULL; + + if (dpcd[DP_DPCD_REV] < 0x11) + return NULL; + + switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) { + case DP_DS_PORT_TYPE_NON_EDID: + switch (port_cap[0] & DP_DS_NON_EDID_MASK) { + case DP_DS_NON_EDID_720x480i_60: + vic = 6; + break; + case DP_DS_NON_EDID_720x480i_50: + vic = 21; + break; + case DP_DS_NON_EDID_1920x1080i_60: + vic = 5; + break; + case DP_DS_NON_EDID_1920x1080i_50: + vic = 20; + break; + case DP_DS_NON_EDID_1280x720_60: + vic = 4; + break; + case DP_DS_NON_EDID_1280x720_50: + vic = 19; + break; + default: + return NULL; + } + return drm_display_mode_from_cea_vic(dev, vic); + default: + return NULL; + } + } + EXPORT_SYMBOL(drm_dp_downstream_mode); + + /** + * drm_dp_downstream_id() - identify branch device + * @aux: DisplayPort AUX channel + * @id: DisplayPort branch device id + * + * Returns branch device id on success or NULL on failure + */ + int drm_dp_downstream_id(struct drm_dp_aux *aux, char id[6]) + { + return drm_dp_dpcd_read(aux, DP_BRANCH_ID, id, 6); + } + EXPORT_SYMBOL(drm_dp_downstream_id); + + /** + * drm_dp_downstream_debug() - debug DP branch devices + * @m: pointer for debugfs file + * @dpcd: DisplayPort configuration data + * @port_cap: port capabilities + * @edid: EDID + * @aux: DisplayPort AUX channel + * + */ + void drm_dp_downstream_debug(struct seq_file *m, + const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4], + const struct edid *edid, + struct drm_dp_aux *aux) + { + bool detailed_cap_info = dpcd[DP_DOWNSTREAMPORT_PRESENT] & + DP_DETAILED_CAP_INFO_AVAILABLE; + int clk; + int bpc; + char id[7]; + int len; + uint8_t rev[2]; + int type = port_cap[0] & DP_DS_PORT_TYPE_MASK; + bool branch_device = drm_dp_is_branch(dpcd); + + seq_printf(m, "\tDP branch device present: %s\n", + branch_device ? "yes" : "no"); + + if (!branch_device) + return; + + switch (type) { + case DP_DS_PORT_TYPE_DP: + seq_puts(m, "\t\tType: DisplayPort\n"); + break; + case DP_DS_PORT_TYPE_VGA: + seq_puts(m, "\t\tType: VGA\n"); + break; + case DP_DS_PORT_TYPE_DVI: + seq_puts(m, "\t\tType: DVI\n"); + break; + case DP_DS_PORT_TYPE_HDMI: + seq_puts(m, "\t\tType: HDMI\n"); + break; + case DP_DS_PORT_TYPE_NON_EDID: + seq_puts(m, "\t\tType: others without EDID support\n"); + break; + case DP_DS_PORT_TYPE_DP_DUALMODE: + seq_puts(m, "\t\tType: DP++\n"); + break; + case DP_DS_PORT_TYPE_WIRELESS: + seq_puts(m, "\t\tType: Wireless\n"); + break; + default: + seq_puts(m, "\t\tType: N/A\n"); + } + + memset(id, 0, sizeof(id)); + drm_dp_downstream_id(aux, id); + seq_printf(m, "\t\tID: %s\n", id); + + len = drm_dp_dpcd_read(aux, DP_BRANCH_HW_REV, &rev[0], 1); + if (len > 0) + seq_printf(m, "\t\tHW: %d.%d\n", + (rev[0] & 0xf0) >> 4, rev[0] & 0xf); + + len = drm_dp_dpcd_read(aux, DP_BRANCH_SW_REV, rev, 2); + if (len > 0) + seq_printf(m, "\t\tSW: %d.%d\n", rev[0], rev[1]); + + if (detailed_cap_info) { + clk = drm_dp_downstream_max_dotclock(dpcd, port_cap); + if (clk > 0) + seq_printf(m, "\t\tMax dot clock: %d kHz\n", clk); + + clk = drm_dp_downstream_max_tmds_clock(dpcd, port_cap, edid); + if (clk > 0) + seq_printf(m, "\t\tMax TMDS clock: %d kHz\n", clk); + + clk = drm_dp_downstream_min_tmds_clock(dpcd, port_cap, edid); + if (clk > 0) + seq_printf(m, "\t\tMin TMDS clock: %d kHz\n", clk); + + bpc = drm_dp_downstream_max_bpc(dpcd, port_cap, edid); + + if (bpc > 0) + seq_printf(m, "\t\tMax bpc: %d\n", bpc); + } + } + EXPORT_SYMBOL(drm_dp_downstream_debug); + + /** + * drm_dp_subconnector_type() - get DP branch device type + * @dpcd: DisplayPort configuration data + * @port_cap: port capabilities + */ + enum drm_mode_subconnector + drm_dp_subconnector_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4]) + { + int type; + if (!drm_dp_is_branch(dpcd)) + return DRM_MODE_SUBCONNECTOR_Native; + /* DP 1.0 approach */ + if (dpcd[DP_DPCD_REV] == DP_DPCD_REV_10) { + type = dpcd[DP_DOWNSTREAMPORT_PRESENT] & + DP_DWN_STRM_PORT_TYPE_MASK; + + switch (type) { + case DP_DWN_STRM_PORT_TYPE_TMDS: + /* Can be HDMI or DVI-D, DVI-D is a safer option */ + return DRM_MODE_SUBCONNECTOR_DVID; + case DP_DWN_STRM_PORT_TYPE_ANALOG: + /* Can be VGA or DVI-A, VGA is more popular */ + return DRM_MODE_SUBCONNECTOR_VGA; + case DP_DWN_STRM_PORT_TYPE_DP: + return DRM_MODE_SUBCONNECTOR_DisplayPort; + case DP_DWN_STRM_PORT_TYPE_OTHER: + default: + return DRM_MODE_SUBCONNECTOR_Unknown; + } + } + type = port_cap[0] & DP_DS_PORT_TYPE_MASK; + + switch (type) { + case DP_DS_PORT_TYPE_DP: + case DP_DS_PORT_TYPE_DP_DUALMODE: + return DRM_MODE_SUBCONNECTOR_DisplayPort; + case DP_DS_PORT_TYPE_VGA: + return DRM_MODE_SUBCONNECTOR_VGA; + case DP_DS_PORT_TYPE_DVI: + return DRM_MODE_SUBCONNECTOR_DVID; + case DP_DS_PORT_TYPE_HDMI: + return DRM_MODE_SUBCONNECTOR_HDMIA; + case DP_DS_PORT_TYPE_WIRELESS: + return DRM_MODE_SUBCONNECTOR_Wireless; + case DP_DS_PORT_TYPE_NON_EDID: + default: + return DRM_MODE_SUBCONNECTOR_Unknown; + } + } + EXPORT_SYMBOL(drm_dp_subconnector_type); + + /** + * drm_dp_set_subconnector_property - set subconnector for DP connector + * @connector: connector to set property on + * @status: connector status + * @dpcd: DisplayPort configuration data + * @port_cap: port capabilities + * + * Called by a driver on every detect event. + */ + void drm_dp_set_subconnector_property(struct drm_connector *connector, + enum drm_connector_status status, + const u8 *dpcd, + const u8 port_cap[4]) + { + enum drm_mode_subconnector subconnector = DRM_MODE_SUBCONNECTOR_Unknown; + + if (status == connector_status_connected) + subconnector = drm_dp_subconnector_type(dpcd, port_cap); + drm_object_property_set_value(&connector->base, + connector->dev->mode_config.dp_subconnector_property, + subconnector); + } + EXPORT_SYMBOL(drm_dp_set_subconnector_property); + + /** + * drm_dp_read_sink_count_cap() - Check whether a given connector has a valid sink + * count + * @connector: The DRM connector to check + * @dpcd: A cached copy of the connector's DPCD RX capabilities + * @desc: A cached copy of the connector's DP descriptor + * + * See also: drm_dp_read_sink_count() + * + * Returns: %True if the (e)DP connector has a valid sink count that should + * be probed, %false otherwise. + */ + bool drm_dp_read_sink_count_cap(struct drm_connector *connector, + const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const struct drm_dp_desc *desc) + { + /* Some eDP panels don't set a valid value for the sink count */ + return connector->connector_type != DRM_MODE_CONNECTOR_eDP && + dpcd[DP_DPCD_REV] >= DP_DPCD_REV_11 && + dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT && + !drm_dp_has_quirk(desc, DP_DPCD_QUIRK_NO_SINK_COUNT); + } + EXPORT_SYMBOL(drm_dp_read_sink_count_cap); + + /** + * drm_dp_read_sink_count() - Retrieve the sink count for a given sink + * @aux: The DP AUX channel to use + * + * See also: drm_dp_read_sink_count_cap() + * + * Returns: The current sink count reported by @aux, or a negative error code + * otherwise. + */ + int drm_dp_read_sink_count(struct drm_dp_aux *aux) + { + u8 count; + int ret; + + ret = drm_dp_dpcd_readb(aux, DP_SINK_COUNT, &count); + if (ret < 0) + return ret; + if (ret != 1) + return -EIO; + + return DP_GET_SINK_COUNT(count); + } + EXPORT_SYMBOL(drm_dp_read_sink_count); + + /* + * I2C-over-AUX implementation + */ + + static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter) + { + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | + I2C_FUNC_SMBUS_READ_BLOCK_DATA | + I2C_FUNC_SMBUS_BLOCK_PROC_CALL | + I2C_FUNC_10BIT_ADDR; + } + + static void drm_dp_i2c_msg_write_status_update(struct drm_dp_aux_msg *msg) + { + /* + * In case of i2c defer or short i2c ack reply to a write, + * we need to switch to WRITE_STATUS_UPDATE to drain the + * rest of the message + */ + if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_WRITE) { + msg->request &= DP_AUX_I2C_MOT; + msg->request |= DP_AUX_I2C_WRITE_STATUS_UPDATE; + } + } + + #define AUX_PRECHARGE_LEN 10 /* 10 to 16 */ + #define AUX_SYNC_LEN (16 + 4) /* preamble + AUX_SYNC_END */ + #define AUX_STOP_LEN 4 + #define AUX_CMD_LEN 4 + #define AUX_ADDRESS_LEN 20 + #define AUX_REPLY_PAD_LEN 4 + #define AUX_LENGTH_LEN 8 + + /* + * Calculate the duration of the AUX request/reply in usec. Gives the + * "best" case estimate, ie. successful while as short as possible. + */ + static int drm_dp_aux_req_duration(const struct drm_dp_aux_msg *msg) + { + int len = AUX_PRECHARGE_LEN + AUX_SYNC_LEN + AUX_STOP_LEN + + AUX_CMD_LEN + AUX_ADDRESS_LEN + AUX_LENGTH_LEN; + + if ((msg->request & DP_AUX_I2C_READ) == 0) + len += msg->size * 8; + + return len; + } + + static int drm_dp_aux_reply_duration(const struct drm_dp_aux_msg *msg) + { + int len = AUX_PRECHARGE_LEN + AUX_SYNC_LEN + AUX_STOP_LEN + + AUX_CMD_LEN + AUX_REPLY_PAD_LEN; + + /* + * For read we expect what was asked. For writes there will + * be 0 or 1 data bytes. Assume 0 for the "best" case. + */ + if (msg->request & DP_AUX_I2C_READ) + len += msg->size * 8; + + return len; + } + + #define I2C_START_LEN 1 + #define I2C_STOP_LEN 1 + #define I2C_ADDR_LEN 9 /* ADDRESS + R/W + ACK/NACK */ + #define I2C_DATA_LEN 9 /* DATA + ACK/NACK */ + + /* + * Calculate the length of the i2c transfer in usec, assuming + * the i2c bus speed is as specified. Gives the the "worst" + * case estimate, ie. successful while as long as possible. + * Doesn't account the the "MOT" bit, and instead assumes each + * message includes a START, ADDRESS and STOP. Neither does it + * account for additional random variables such as clock stretching. + */ + static int drm_dp_i2c_msg_duration(const struct drm_dp_aux_msg *msg, + int i2c_speed_khz) + { + /* AUX bitrate is 1MHz, i2c bitrate as specified */ + return DIV_ROUND_UP((I2C_START_LEN + I2C_ADDR_LEN + + msg->size * I2C_DATA_LEN + + I2C_STOP_LEN) * 1000, i2c_speed_khz); + } + + /* + * Determine how many retries should be attempted to successfully transfer + * the specified message, based on the estimated durations of the + * i2c and AUX transfers. + */ + static int drm_dp_i2c_retry_count(const struct drm_dp_aux_msg *msg, + int i2c_speed_khz) + { + int aux_time_us = drm_dp_aux_req_duration(msg) + + drm_dp_aux_reply_duration(msg); + int i2c_time_us = drm_dp_i2c_msg_duration(msg, i2c_speed_khz); + + return DIV_ROUND_UP(i2c_time_us, aux_time_us + AUX_RETRY_INTERVAL); + } + + /* + * FIXME currently assumes 10 kHz as some real world devices seem + * to require it. We should query/set the speed via DPCD if supported. + */ + static int dp_aux_i2c_speed_khz __read_mostly = 10; + module_param_unsafe(dp_aux_i2c_speed_khz, int, 0644); + MODULE_PARM_DESC(dp_aux_i2c_speed_khz, + "Assumed speed of the i2c bus in kHz, (1-400, default 10)"); + + /* + * Transfer a single I2C-over-AUX message and handle various error conditions, + * retrying the transaction as appropriate. It is assumed that the + * &drm_dp_aux.transfer function does not modify anything in the msg other than the + * reply field. + * + * Returns bytes transferred on success, or a negative error code on failure. + */ + static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) + { + unsigned int retry, defer_i2c; + int ret; + /* + * DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device + * is required to retry at least seven times upon receiving AUX_DEFER + * before giving up the AUX transaction. + * + * We also try to account for the i2c bus speed. + */ + int max_retries = max(7, drm_dp_i2c_retry_count(msg, dp_aux_i2c_speed_khz)); + + for (retry = 0, defer_i2c = 0; retry < (max_retries + defer_i2c); retry++) { + ret = aux->transfer(aux, msg); + if (ret < 0) { + if (ret == -EBUSY) + continue; + + /* + * While timeouts can be errors, they're usually normal + * behavior (for instance, when a driver tries to + * communicate with a non-existent DisplayPort device). + * Avoid spamming the kernel log with timeout errors. + */ + if (ret == -ETIMEDOUT) + drm_dbg_kms_ratelimited(aux->drm_dev, "%s: transaction timed out\n", + aux->name); + else + drm_dbg_kms(aux->drm_dev, "%s: transaction failed: %d\n", + aux->name, ret); + return ret; + } + + + switch (msg->reply & DP_AUX_NATIVE_REPLY_MASK) { + case DP_AUX_NATIVE_REPLY_ACK: + /* + * For I2C-over-AUX transactions this isn't enough, we + * need to check for the I2C ACK reply. + */ + break; + + case DP_AUX_NATIVE_REPLY_NACK: + drm_dbg_kms(aux->drm_dev, "%s: native nack (result=%d, size=%zu)\n", + aux->name, ret, msg->size); + return -EREMOTEIO; + + case DP_AUX_NATIVE_REPLY_DEFER: + drm_dbg_kms(aux->drm_dev, "%s: native defer\n", aux->name); + /* + * We could check for I2C bit rate capabilities and if + * available adjust this interval. We could also be + * more careful with DP-to-legacy adapters where a + * long legacy cable may force very low I2C bit rates. + * + * For now just defer for long enough to hopefully be + * safe for all use-cases. + */ + usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100); + continue; + + default: + drm_err(aux->drm_dev, "%s: invalid native reply %#04x\n", + aux->name, msg->reply); + return -EREMOTEIO; + } + + switch (msg->reply & DP_AUX_I2C_REPLY_MASK) { + case DP_AUX_I2C_REPLY_ACK: + /* + * Both native ACK and I2C ACK replies received. We + * can assume the transfer was successful. + */ + if (ret != msg->size) + drm_dp_i2c_msg_write_status_update(msg); + return ret; + + case DP_AUX_I2C_REPLY_NACK: + drm_dbg_kms(aux->drm_dev, "%s: I2C nack (result=%d, size=%zu)\n", + aux->name, ret, msg->size); + aux->i2c_nack_count++; + return -EREMOTEIO; + + case DP_AUX_I2C_REPLY_DEFER: + drm_dbg_kms(aux->drm_dev, "%s: I2C defer\n", aux->name); + /* DP Compliance Test 4.2.2.5 Requirement: + * Must have at least 7 retries for I2C defers on the + * transaction to pass this test + */ + aux->i2c_defer_count++; + if (defer_i2c < 7) + defer_i2c++; + usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100); + drm_dp_i2c_msg_write_status_update(msg); + + continue; + + default: + drm_err(aux->drm_dev, "%s: invalid I2C reply %#04x\n", + aux->name, msg->reply); + return -EREMOTEIO; + } + } + + drm_dbg_kms(aux->drm_dev, "%s: Too many retries, giving up\n", aux->name); + return -EREMOTEIO; + } + + static void drm_dp_i2c_msg_set_request(struct drm_dp_aux_msg *msg, + const struct i2c_msg *i2c_msg) + { + msg->request = (i2c_msg->flags & I2C_M_RD) ? + DP_AUX_I2C_READ : DP_AUX_I2C_WRITE; + if (!(i2c_msg->flags & I2C_M_STOP)) + msg->request |= DP_AUX_I2C_MOT; + } + + /* + * Keep retrying drm_dp_i2c_do_msg until all data has been transferred. + * + * Returns an error code on failure, or a recommended transfer size on success. + */ + static int drm_dp_i2c_drain_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *orig_msg) + { + int err, ret = orig_msg->size; + struct drm_dp_aux_msg msg = *orig_msg; + + while (msg.size > 0) { + err = drm_dp_i2c_do_msg(aux, &msg); + if (err <= 0) + return err == 0 ? -EPROTO : err; + + if (err < msg.size && err < ret) { + drm_dbg_kms(aux->drm_dev, + "%s: Partial I2C reply: requested %zu bytes got %d bytes\n", + aux->name, msg.size, err); + ret = err; + } + + msg.size -= err; + msg.buffer += err; + } + + return ret; + } + + /* + * Bizlink designed DP->DVI-D Dual Link adapters require the I2C over AUX + * packets to be as large as possible. If not, the I2C transactions never + * succeed. Hence the default is maximum. + */ + static int dp_aux_i2c_transfer_size __read_mostly = DP_AUX_MAX_PAYLOAD_BYTES; + module_param_unsafe(dp_aux_i2c_transfer_size, int, 0644); + MODULE_PARM_DESC(dp_aux_i2c_transfer_size, + "Number of bytes to transfer in a single I2C over DP AUX CH message, (1-16, default 16)"); + + static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, + int num) + { + struct drm_dp_aux *aux = adapter->algo_data; + unsigned int i, j; + unsigned transfer_size; + struct drm_dp_aux_msg msg; + int err = 0; + + dp_aux_i2c_transfer_size = clamp(dp_aux_i2c_transfer_size, 1, DP_AUX_MAX_PAYLOAD_BYTES); + + memset(&msg, 0, sizeof(msg)); + + for (i = 0; i < num; i++) { + msg.address = msgs[i].addr; + drm_dp_i2c_msg_set_request(&msg, &msgs[i]); + /* Send a bare address packet to start the transaction. + * Zero sized messages specify an address only (bare + * address) transaction. + */ + msg.buffer = NULL; + msg.size = 0; + err = drm_dp_i2c_do_msg(aux, &msg); + + /* + * Reset msg.request in case in case it got + * changed into a WRITE_STATUS_UPDATE. + */ + drm_dp_i2c_msg_set_request(&msg, &msgs[i]); + + if (err < 0) + break; + /* We want each transaction to be as large as possible, but + * we'll go to smaller sizes if the hardware gives us a + * short reply. + */ + transfer_size = dp_aux_i2c_transfer_size; + for (j = 0; j < msgs[i].len; j += msg.size) { + msg.buffer = msgs[i].buf + j; + msg.size = min(transfer_size, msgs[i].len - j); + + err = drm_dp_i2c_drain_msg(aux, &msg); + + /* + * Reset msg.request in case in case it got + * changed into a WRITE_STATUS_UPDATE. + */ + drm_dp_i2c_msg_set_request(&msg, &msgs[i]); + + if (err < 0) + break; + transfer_size = err; + } + if (err < 0) + break; + } + if (err >= 0) + err = num; + /* Send a bare address packet to close out the transaction. + * Zero sized messages specify an address only (bare + * address) transaction. + */ + msg.request &= ~DP_AUX_I2C_MOT; + msg.buffer = NULL; + msg.size = 0; + (void)drm_dp_i2c_do_msg(aux, &msg); + + return err; + } + + static const struct i2c_algorithm drm_dp_i2c_algo = { + .functionality = drm_dp_i2c_functionality, + .master_xfer = drm_dp_i2c_xfer, + }; + + static struct drm_dp_aux *i2c_to_aux(struct i2c_adapter *i2c) + { + return container_of(i2c, struct drm_dp_aux, ddc); + } + + static void lock_bus(struct i2c_adapter *i2c, unsigned int flags) + { + mutex_lock(&i2c_to_aux(i2c)->hw_mutex); + } + + static int trylock_bus(struct i2c_adapter *i2c, unsigned int flags) + { + return mutex_trylock(&i2c_to_aux(i2c)->hw_mutex); + } + + static void unlock_bus(struct i2c_adapter *i2c, unsigned int flags) + { + mutex_unlock(&i2c_to_aux(i2c)->hw_mutex); + } + + static const struct i2c_lock_operations drm_dp_i2c_lock_ops = { + .lock_bus = lock_bus, + .trylock_bus = trylock_bus, + .unlock_bus = unlock_bus, + }; + + static int drm_dp_aux_get_crc(struct drm_dp_aux *aux, u8 *crc) + { + u8 buf, count; + int ret; + + ret = drm_dp_dpcd_readb(aux, DP_TEST_SINK, &buf); + if (ret < 0) + return ret; + + WARN_ON(!(buf & DP_TEST_SINK_START)); + + ret = drm_dp_dpcd_readb(aux, DP_TEST_SINK_MISC, &buf); + if (ret < 0) + return ret; + + count = buf & DP_TEST_COUNT_MASK; + if (count == aux->crc_count) + return -EAGAIN; /* No CRC yet */ + + aux->crc_count = count; + + /* + * At DP_TEST_CRC_R_CR, there's 6 bytes containing CRC data, 2 bytes + * per component (RGB or CrYCb). + */ + ret = drm_dp_dpcd_read(aux, DP_TEST_CRC_R_CR, crc, 6); + if (ret < 0) + return ret; + + return 0; + } + + static void drm_dp_aux_crc_work(struct work_struct *work) + { + struct drm_dp_aux *aux = container_of(work, struct drm_dp_aux, + crc_work); + struct drm_crtc *crtc; + u8 crc_bytes[6]; + uint32_t crcs[3]; + int ret; + + if (WARN_ON(!aux->crtc)) + return; + + crtc = aux->crtc; + while (crtc->crc.opened) { + drm_crtc_wait_one_vblank(crtc); + if (!crtc->crc.opened) + break; + + ret = drm_dp_aux_get_crc(aux, crc_bytes); + if (ret == -EAGAIN) { + usleep_range(1000, 2000); + ret = drm_dp_aux_get_crc(aux, crc_bytes); + } + + if (ret == -EAGAIN) { + drm_dbg_kms(aux->drm_dev, "%s: Get CRC failed after retrying: %d\n", + aux->name, ret); + continue; + } else if (ret) { + drm_dbg_kms(aux->drm_dev, "%s: Failed to get a CRC: %d\n", aux->name, ret); + continue; + } + + crcs[0] = crc_bytes[0] | crc_bytes[1] << 8; + crcs[1] = crc_bytes[2] | crc_bytes[3] << 8; + crcs[2] = crc_bytes[4] | crc_bytes[5] << 8; + drm_crtc_add_crc_entry(crtc, false, 0, crcs); + } + } + + /** + * drm_dp_remote_aux_init() - minimally initialise a remote aux channel + * @aux: DisplayPort AUX channel + * + * Used for remote aux channel in general. Merely initialize the crc work + * struct. + */ + void drm_dp_remote_aux_init(struct drm_dp_aux *aux) + { + INIT_WORK(&aux->crc_work, drm_dp_aux_crc_work); + } + EXPORT_SYMBOL(drm_dp_remote_aux_init); + + /** + * drm_dp_aux_init() - minimally initialise an aux channel + * @aux: DisplayPort AUX channel + * + * If you need to use the drm_dp_aux's i2c adapter prior to registering it with + * the outside world, call drm_dp_aux_init() first. For drivers which are + * grandparents to their AUX adapters (e.g. the AUX adapter is parented by a + * &drm_connector), you must still call drm_dp_aux_register() once the connector + * has been registered to allow userspace access to the auxiliary DP channel. + * Likewise, for such drivers you should also assign &drm_dp_aux.drm_dev as + * early as possible so that the &drm_device that corresponds to the AUX adapter + * may be mentioned in debugging output from the DRM DP helpers. + * + * For devices which use a separate platform device for their AUX adapters, this + * may be called as early as required by the driver. + * + */ + void drm_dp_aux_init(struct drm_dp_aux *aux) + { + mutex_init(&aux->hw_mutex); + mutex_init(&aux->cec.lock); + INIT_WORK(&aux->crc_work, drm_dp_aux_crc_work); + + aux->ddc.algo = &drm_dp_i2c_algo; + aux->ddc.algo_data = aux; + aux->ddc.retries = 3; + + aux->ddc.lock_ops = &drm_dp_i2c_lock_ops; + } + EXPORT_SYMBOL(drm_dp_aux_init); + + /** + * drm_dp_aux_register() - initialise and register aux channel + * @aux: DisplayPort AUX channel + * + * Automatically calls drm_dp_aux_init() if this hasn't been done yet. This + * should only be called once the parent of @aux, &drm_dp_aux.dev, is + * initialized. For devices which are grandparents of their AUX channels, + * &drm_dp_aux.dev will typically be the &drm_connector &device which + * corresponds to @aux. For these devices, it's advised to call + * drm_dp_aux_register() in &drm_connector_funcs.late_register, and likewise to + * call drm_dp_aux_unregister() in &drm_connector_funcs.early_unregister. + * Functions which don't follow this will likely Oops when + * %CONFIG_DRM_DP_AUX_CHARDEV is enabled. + * + * For devices where the AUX channel is a device that exists independently of + * the &drm_device that uses it, such as SoCs and bridge devices, it is + * recommended to call drm_dp_aux_register() after a &drm_device has been + * assigned to &drm_dp_aux.drm_dev, and likewise to call + * drm_dp_aux_unregister() once the &drm_device should no longer be associated + * with the AUX channel (e.g. on bridge detach). + * + * Drivers which need to use the aux channel before either of the two points + * mentioned above need to call drm_dp_aux_init() in order to use the AUX + * channel before registration. + * + * Returns 0 on success or a negative error code on failure. + */ + int drm_dp_aux_register(struct drm_dp_aux *aux) + { + int ret; + + WARN_ON_ONCE(!aux->drm_dev); + + if (!aux->ddc.algo) + drm_dp_aux_init(aux); + + aux->ddc.class = I2C_CLASS_DDC; + aux->ddc.owner = THIS_MODULE; + aux->ddc.dev.parent = aux->dev; + + strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev), + sizeof(aux->ddc.name)); + + ret = drm_dp_aux_register_devnode(aux); + if (ret) + return ret; + + ret = i2c_add_adapter(&aux->ddc); + if (ret) { + drm_dp_aux_unregister_devnode(aux); + return ret; + } + + return 0; + } + EXPORT_SYMBOL(drm_dp_aux_register); + + /** + * drm_dp_aux_unregister() - unregister an AUX adapter + * @aux: DisplayPort AUX channel + */ + void drm_dp_aux_unregister(struct drm_dp_aux *aux) + { + drm_dp_aux_unregister_devnode(aux); + i2c_del_adapter(&aux->ddc); + } + EXPORT_SYMBOL(drm_dp_aux_unregister); + + #define PSR_SETUP_TIME(x) [DP_PSR_SETUP_TIME_ ## x >> DP_PSR_SETUP_TIME_SHIFT] = (x) + + /** + * drm_dp_psr_setup_time() - PSR setup in time usec + * @psr_cap: PSR capabilities from DPCD + * + * Returns: + * PSR setup time for the panel in microseconds, negative + * error code on failure. + */ + int drm_dp_psr_setup_time(const u8 psr_cap[EDP_PSR_RECEIVER_CAP_SIZE]) + { + static const u16 psr_setup_time_us[] = { + PSR_SETUP_TIME(330), + PSR_SETUP_TIME(275), + PSR_SETUP_TIME(220), + PSR_SETUP_TIME(165), + PSR_SETUP_TIME(110), + PSR_SETUP_TIME(55), + PSR_SETUP_TIME(0), + }; + int i; + + i = (psr_cap[1] & DP_PSR_SETUP_TIME_MASK) >> DP_PSR_SETUP_TIME_SHIFT; + if (i >= ARRAY_SIZE(psr_setup_time_us)) + return -EINVAL; + + return psr_setup_time_us[i]; + } + EXPORT_SYMBOL(drm_dp_psr_setup_time); + + #undef PSR_SETUP_TIME + + /** + * drm_dp_start_crc() - start capture of frame CRCs + * @aux: DisplayPort AUX channel + * @crtc: CRTC displaying the frames whose CRCs are to be captured + * + * Returns 0 on success or a negative error code on failure. + */ + int drm_dp_start_crc(struct drm_dp_aux *aux, struct drm_crtc *crtc) + { + u8 buf; + int ret; + + ret = drm_dp_dpcd_readb(aux, DP_TEST_SINK, &buf); + if (ret < 0) + return ret; + + ret = drm_dp_dpcd_writeb(aux, DP_TEST_SINK, buf | DP_TEST_SINK_START); + if (ret < 0) + return ret; + + aux->crc_count = 0; + aux->crtc = crtc; + schedule_work(&aux->crc_work); + + return 0; + } + EXPORT_SYMBOL(drm_dp_start_crc); + + /** + * drm_dp_stop_crc() - stop capture of frame CRCs + * @aux: DisplayPort AUX channel + * + * Returns 0 on success or a negative error code on failure. + */ + int drm_dp_stop_crc(struct drm_dp_aux *aux) + { + u8 buf; + int ret; + + ret = drm_dp_dpcd_readb(aux, DP_TEST_SINK, &buf); + if (ret < 0) + return ret; + + ret = drm_dp_dpcd_writeb(aux, DP_TEST_SINK, buf & ~DP_TEST_SINK_START); + if (ret < 0) + return ret; + + flush_work(&aux->crc_work); + aux->crtc = NULL; + + return 0; + } + EXPORT_SYMBOL(drm_dp_stop_crc); + + struct dpcd_quirk { + u8 oui[3]; + u8 device_id[6]; + bool is_branch; + u32 quirks; + }; + + #define OUI(first, second, third) { (first), (second), (third) } + #define DEVICE_ID(first, second, third, fourth, fifth, sixth) \ + { (first), (second), (third), (fourth), (fifth), (sixth) } + + #define DEVICE_ID_ANY DEVICE_ID(0, 0, 0, 0, 0, 0) + + static const struct dpcd_quirk dpcd_quirk_list[] = { + /* Analogix 7737 needs reduced M and N at HBR2 link rates */ + { OUI(0x00, 0x22, 0xb9), DEVICE_ID_ANY, true, BIT(DP_DPCD_QUIRK_CONSTANT_N) }, + /* LG LP140WF6-SPM1 eDP panel */ + { OUI(0x00, 0x22, 0xb9), DEVICE_ID('s', 'i', 'v', 'a', 'r', 'T'), false, BIT(DP_DPCD_QUIRK_CONSTANT_N) }, + /* Apple panels need some additional handling to support PSR */ + { OUI(0x00, 0x10, 0xfa), DEVICE_ID_ANY, false, BIT(DP_DPCD_QUIRK_NO_PSR) }, + /* CH7511 seems to leave SINK_COUNT zeroed */ + { OUI(0x00, 0x00, 0x00), DEVICE_ID('C', 'H', '7', '5', '1', '1'), false, BIT(DP_DPCD_QUIRK_NO_SINK_COUNT) }, + /* Synaptics DP1.4 MST hubs can support DSC without virtual DPCD */ + { OUI(0x90, 0xCC, 0x24), DEVICE_ID_ANY, true, BIT(DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) }, + /* Apple MacBookPro 2017 15 inch eDP Retina panel reports too low DP_MAX_LINK_RATE */ + { OUI(0x00, 0x10, 0xfa), DEVICE_ID(101, 68, 21, 101, 98, 97), false, BIT(DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS) }, + }; + + #undef OUI + + /* + * Get a bit mask of DPCD quirks for the sink/branch device identified by + * ident. The quirk data is shared but it's up to the drivers to act on the + * data. + * + * For now, only the OUI (first three bytes) is used, but this may be extended + * to device identification string and hardware/firmware revisions later. + */ + static u32 + drm_dp_get_quirks(const struct drm_dp_dpcd_ident *ident, bool is_branch) + { + const struct dpcd_quirk *quirk; + u32 quirks = 0; + int i; + u8 any_device[] = DEVICE_ID_ANY; + + for (i = 0; i < ARRAY_SIZE(dpcd_quirk_list); i++) { + quirk = &dpcd_quirk_list[i]; + + if (quirk->is_branch != is_branch) + continue; + + if (memcmp(quirk->oui, ident->oui, sizeof(ident->oui)) != 0) + continue; + + if (memcmp(quirk->device_id, any_device, sizeof(any_device)) != 0 && + memcmp(quirk->device_id, ident->device_id, sizeof(ident->device_id)) != 0) + continue; + + quirks |= quirk->quirks; + } + + return quirks; + } + + #undef DEVICE_ID_ANY + #undef DEVICE_ID + + /** + * drm_dp_read_desc - read sink/branch descriptor from DPCD + * @aux: DisplayPort AUX channel + * @desc: Device descriptor to fill from DPCD + * @is_branch: true for branch devices, false for sink devices + * + * Read DPCD 0x400 (sink) or 0x500 (branch) into @desc. Also debug log the + * identification. + * + * Returns 0 on success or a negative error code on failure. + */ + int drm_dp_read_desc(struct drm_dp_aux *aux, struct drm_dp_desc *desc, + bool is_branch) + { + struct drm_dp_dpcd_ident *ident = &desc->ident; + unsigned int offset = is_branch ? DP_BRANCH_OUI : DP_SINK_OUI; + int ret, dev_id_len; + + ret = drm_dp_dpcd_read(aux, offset, ident, sizeof(*ident)); + if (ret < 0) + return ret; + + desc->quirks = drm_dp_get_quirks(ident, is_branch); + + dev_id_len = strnlen(ident->device_id, sizeof(ident->device_id)); + + drm_dbg_kms(aux->drm_dev, + "%s: DP %s: OUI %*phD dev-ID %*pE HW-rev %d.%d SW-rev %d.%d quirks 0x%04x\n", + aux->name, is_branch ? "branch" : "sink", + (int)sizeof(ident->oui), ident->oui, dev_id_len, + ident->device_id, ident->hw_rev >> 4, ident->hw_rev & 0xf, + ident->sw_major_rev, ident->sw_minor_rev, desc->quirks); + + return 0; + } + EXPORT_SYMBOL(drm_dp_read_desc); + + /** + * drm_dp_dsc_sink_max_slice_count() - Get the max slice count + * supported by the DSC sink. + * @dsc_dpcd: DSC capabilities from DPCD + * @is_edp: true if its eDP, false for DP + * + * Read the slice capabilities DPCD register from DSC sink to get + * the maximum slice count supported. This is used to populate + * the DSC parameters in the &struct drm_dsc_config by the driver. + * Driver creates an infoframe using these parameters to populate + * &struct drm_dsc_pps_infoframe. These are sent to the sink using DSC + * infoframe using the helper function drm_dsc_pps_infoframe_pack() + * + * Returns: + * Maximum slice count supported by DSC sink or 0 its invalid + */ + u8 drm_dp_dsc_sink_max_slice_count(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE], + bool is_edp) + { + u8 slice_cap1 = dsc_dpcd[DP_DSC_SLICE_CAP_1 - DP_DSC_SUPPORT]; + + if (is_edp) { + /* For eDP, register DSC_SLICE_CAPABILITIES_1 gives slice count */ + if (slice_cap1 & DP_DSC_4_PER_DP_DSC_SINK) + return 4; + if (slice_cap1 & DP_DSC_2_PER_DP_DSC_SINK) + return 2; + if (slice_cap1 & DP_DSC_1_PER_DP_DSC_SINK) + return 1; + } else { + /* For DP, use values from DSC_SLICE_CAP_1 and DSC_SLICE_CAP2 */ + u8 slice_cap2 = dsc_dpcd[DP_DSC_SLICE_CAP_2 - DP_DSC_SUPPORT]; + + if (slice_cap2 & DP_DSC_24_PER_DP_DSC_SINK) + return 24; + if (slice_cap2 & DP_DSC_20_PER_DP_DSC_SINK) + return 20; + if (slice_cap2 & DP_DSC_16_PER_DP_DSC_SINK) + return 16; + if (slice_cap1 & DP_DSC_12_PER_DP_DSC_SINK) + return 12; + if (slice_cap1 & DP_DSC_10_PER_DP_DSC_SINK) + return 10; + if (slice_cap1 & DP_DSC_8_PER_DP_DSC_SINK) + return 8; + if (slice_cap1 & DP_DSC_6_PER_DP_DSC_SINK) + return 6; + if (slice_cap1 & DP_DSC_4_PER_DP_DSC_SINK) + return 4; + if (slice_cap1 & DP_DSC_2_PER_DP_DSC_SINK) + return 2; + if (slice_cap1 & DP_DSC_1_PER_DP_DSC_SINK) + return 1; + } + + return 0; + } + EXPORT_SYMBOL(drm_dp_dsc_sink_max_slice_count); + + /** + * drm_dp_dsc_sink_line_buf_depth() - Get the line buffer depth in bits + * @dsc_dpcd: DSC capabilities from DPCD + * + * Read the DSC DPCD register to parse the line buffer depth in bits which is + * number of bits of precision within the decoder line buffer supported by + * the DSC sink. This is used to populate the DSC parameters in the + * &struct drm_dsc_config by the driver. + * Driver creates an infoframe using these parameters to populate + * &struct drm_dsc_pps_infoframe. These are sent to the sink using DSC + * infoframe using the helper function drm_dsc_pps_infoframe_pack() + * + * Returns: + * Line buffer depth supported by DSC panel or 0 its invalid + */ + u8 drm_dp_dsc_sink_line_buf_depth(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]) + { + u8 line_buf_depth = dsc_dpcd[DP_DSC_LINE_BUF_BIT_DEPTH - DP_DSC_SUPPORT]; + + switch (line_buf_depth & DP_DSC_LINE_BUF_BIT_DEPTH_MASK) { + case DP_DSC_LINE_BUF_BIT_DEPTH_9: + return 9; + case DP_DSC_LINE_BUF_BIT_DEPTH_10: + return 10; + case DP_DSC_LINE_BUF_BIT_DEPTH_11: + return 11; + case DP_DSC_LINE_BUF_BIT_DEPTH_12: + return 12; + case DP_DSC_LINE_BUF_BIT_DEPTH_13: + return 13; + case DP_DSC_LINE_BUF_BIT_DEPTH_14: + return 14; + case DP_DSC_LINE_BUF_BIT_DEPTH_15: + return 15; + case DP_DSC_LINE_BUF_BIT_DEPTH_16: + return 16; + case DP_DSC_LINE_BUF_BIT_DEPTH_8: + return 8; + } + + return 0; + } + EXPORT_SYMBOL(drm_dp_dsc_sink_line_buf_depth); + + /** + * drm_dp_dsc_sink_supported_input_bpcs() - Get all the input bits per component + * values supported by the DSC sink. + * @dsc_dpcd: DSC capabilities from DPCD + * @dsc_bpc: An array to be filled by this helper with supported + * input bpcs. + * + * Read the DSC DPCD from the sink device to parse the supported bits per + * component values. This is used to populate the DSC parameters + * in the &struct drm_dsc_config by the driver. + * Driver creates an infoframe using these parameters to populate + * &struct drm_dsc_pps_infoframe. These are sent to the sink using DSC + * infoframe using the helper function drm_dsc_pps_infoframe_pack() + * + * Returns: + * Number of input BPC values parsed from the DPCD + */ + int drm_dp_dsc_sink_supported_input_bpcs(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE], + u8 dsc_bpc[3]) + { + int num_bpc = 0; + u8 color_depth = dsc_dpcd[DP_DSC_DEC_COLOR_DEPTH_CAP - DP_DSC_SUPPORT]; + + if (color_depth & DP_DSC_12_BPC) + dsc_bpc[num_bpc++] = 12; + if (color_depth & DP_DSC_10_BPC) + dsc_bpc[num_bpc++] = 10; + if (color_depth & DP_DSC_8_BPC) + dsc_bpc[num_bpc++] = 8; + + return num_bpc; + } + EXPORT_SYMBOL(drm_dp_dsc_sink_supported_input_bpcs); + + /** + * drm_dp_read_lttpr_common_caps - read the LTTPR common capabilities + * @aux: DisplayPort AUX channel + * @caps: buffer to return the capability info in + * + * Read capabilities common to all LTTPRs. + * + * Returns 0 on success or a negative error code on failure. + */ + int drm_dp_read_lttpr_common_caps(struct drm_dp_aux *aux, + u8 caps[DP_LTTPR_COMMON_CAP_SIZE]) + { + int ret; + + ret = drm_dp_dpcd_read(aux, + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, + caps, DP_LTTPR_COMMON_CAP_SIZE); + if (ret < 0) + return ret; + + WARN_ON(ret != DP_LTTPR_COMMON_CAP_SIZE); + + return 0; + } + EXPORT_SYMBOL(drm_dp_read_lttpr_common_caps); + + /** + * drm_dp_read_lttpr_phy_caps - read the capabilities for a given LTTPR PHY + * @aux: DisplayPort AUX channel + * @dp_phy: LTTPR PHY to read the capabilities for + * @caps: buffer to return the capability info in + * + * Read the capabilities for the given LTTPR PHY. + * + * Returns 0 on success or a negative error code on failure. + */ + int drm_dp_read_lttpr_phy_caps(struct drm_dp_aux *aux, + enum drm_dp_phy dp_phy, + u8 caps[DP_LTTPR_PHY_CAP_SIZE]) + { + int ret; + + ret = drm_dp_dpcd_read(aux, + DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy), + caps, DP_LTTPR_PHY_CAP_SIZE); + if (ret < 0) + return ret; + + WARN_ON(ret != DP_LTTPR_PHY_CAP_SIZE); + + return 0; + } + EXPORT_SYMBOL(drm_dp_read_lttpr_phy_caps); + + static u8 dp_lttpr_common_cap(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE], int r) + { + return caps[r - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + } + + /** + * drm_dp_lttpr_count - get the number of detected LTTPRs + * @caps: LTTPR common capabilities + * + * Get the number of detected LTTPRs from the LTTPR common capabilities info. + * + * Returns: + * -ERANGE if more than supported number (8) of LTTPRs are detected + * -EINVAL if the DP_PHY_REPEATER_CNT register contains an invalid value + * otherwise the number of detected LTTPRs + */ + int drm_dp_lttpr_count(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE]) + { + u8 count = dp_lttpr_common_cap(caps, DP_PHY_REPEATER_CNT); + + switch (hweight8(count)) { + case 0: + return 0; + case 1: + return 8 - ilog2(count); + case 8: + return -ERANGE; + default: + return -EINVAL; + } + } + EXPORT_SYMBOL(drm_dp_lttpr_count); + + /** + * drm_dp_lttpr_max_link_rate - get the maximum link rate supported by all LTTPRs + * @caps: LTTPR common capabilities + * + * Returns the maximum link rate supported by all detected LTTPRs. + */ + int drm_dp_lttpr_max_link_rate(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE]) + { + u8 rate = dp_lttpr_common_cap(caps, DP_MAX_LINK_RATE_PHY_REPEATER); + + return drm_dp_bw_code_to_link_rate(rate); + } + EXPORT_SYMBOL(drm_dp_lttpr_max_link_rate); + + /** + * drm_dp_lttpr_max_lane_count - get the maximum lane count supported by all LTTPRs + * @caps: LTTPR common capabilities + * + * Returns the maximum lane count supported by all detected LTTPRs. + */ + int drm_dp_lttpr_max_lane_count(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE]) + { + u8 max_lanes = dp_lttpr_common_cap(caps, DP_MAX_LANE_COUNT_PHY_REPEATER); + + return max_lanes & DP_MAX_LANE_COUNT_MASK; + } + EXPORT_SYMBOL(drm_dp_lttpr_max_lane_count); + + /** + * drm_dp_lttpr_voltage_swing_level_3_supported - check for LTTPR vswing3 support + * @caps: LTTPR PHY capabilities + * + * Returns true if the @caps for an LTTPR TX PHY indicate support for + * voltage swing level 3. + */ + bool + drm_dp_lttpr_voltage_swing_level_3_supported(const u8 caps[DP_LTTPR_PHY_CAP_SIZE]) + { + u8 txcap = dp_lttpr_phy_cap(caps, DP_TRANSMITTER_CAPABILITY_PHY_REPEATER1); + + return txcap & DP_VOLTAGE_SWING_LEVEL_3_SUPPORTED; + } + EXPORT_SYMBOL(drm_dp_lttpr_voltage_swing_level_3_supported); + + /** + * drm_dp_lttpr_pre_emphasis_level_3_supported - check for LTTPR preemph3 support + * @caps: LTTPR PHY capabilities + * + * Returns true if the @caps for an LTTPR TX PHY indicate support for + * pre-emphasis level 3. + */ + bool + drm_dp_lttpr_pre_emphasis_level_3_supported(const u8 caps[DP_LTTPR_PHY_CAP_SIZE]) + { + u8 txcap = dp_lttpr_phy_cap(caps, DP_TRANSMITTER_CAPABILITY_PHY_REPEATER1); + + return txcap & DP_PRE_EMPHASIS_LEVEL_3_SUPPORTED; + } + EXPORT_SYMBOL(drm_dp_lttpr_pre_emphasis_level_3_supported); + + /** + * drm_dp_get_phy_test_pattern() - get the requested pattern from the sink. + * @aux: DisplayPort AUX channel + * @data: DP phy compliance test parameters. + * + * Returns 0 on success or a negative error code on failure. + */ + int drm_dp_get_phy_test_pattern(struct drm_dp_aux *aux, + struct drm_dp_phy_test_params *data) + { + int err; + u8 rate, lanes; + + err = drm_dp_dpcd_readb(aux, DP_TEST_LINK_RATE, &rate); + if (err < 0) + return err; + data->link_rate = drm_dp_bw_code_to_link_rate(rate); + + err = drm_dp_dpcd_readb(aux, DP_TEST_LANE_COUNT, &lanes); + if (err < 0) + return err; + data->num_lanes = lanes & DP_MAX_LANE_COUNT_MASK; + + if (lanes & DP_ENHANCED_FRAME_CAP) + data->enhanced_frame_cap = true; + + err = drm_dp_dpcd_readb(aux, DP_PHY_TEST_PATTERN, &data->phy_pattern); + if (err < 0) + return err; + + switch (data->phy_pattern) { + case DP_PHY_TEST_PATTERN_80BIT_CUSTOM: + err = drm_dp_dpcd_read(aux, DP_TEST_80BIT_CUSTOM_PATTERN_7_0, + &data->custom80, sizeof(data->custom80)); + if (err < 0) + return err; + + break; + case DP_PHY_TEST_PATTERN_CP2520: + err = drm_dp_dpcd_read(aux, DP_TEST_HBR2_SCRAMBLER_RESET, + &data->hbr2_reset, + sizeof(data->hbr2_reset)); + if (err < 0) + return err; + } + + return 0; + } + EXPORT_SYMBOL(drm_dp_get_phy_test_pattern); + + /** + * drm_dp_set_phy_test_pattern() - set the pattern to the sink. + * @aux: DisplayPort AUX channel + * @data: DP phy compliance test parameters. + * @dp_rev: DP revision to use for compliance testing + * + * Returns 0 on success or a negative error code on failure. + */ + int drm_dp_set_phy_test_pattern(struct drm_dp_aux *aux, + struct drm_dp_phy_test_params *data, u8 dp_rev) + { + int err, i; + u8 link_config[2]; + u8 test_pattern; + + link_config[0] = drm_dp_link_rate_to_bw_code(data->link_rate); + link_config[1] = data->num_lanes; + if (data->enhanced_frame_cap) + link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + err = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, link_config, 2); + if (err < 0) + return err; + + test_pattern = data->phy_pattern; + if (dp_rev < 0x12) { + test_pattern = (test_pattern << 2) & + DP_LINK_QUAL_PATTERN_11_MASK; + err = drm_dp_dpcd_writeb(aux, DP_TRAINING_PATTERN_SET, + test_pattern); + if (err < 0) + return err; + } else { + for (i = 0; i < data->num_lanes; i++) { + err = drm_dp_dpcd_writeb(aux, + DP_LINK_QUAL_LANE0_SET + i, + test_pattern); + if (err < 0) + return err; + } + } + + return 0; + } + EXPORT_SYMBOL(drm_dp_set_phy_test_pattern); + + static const char *dp_pixelformat_get_name(enum dp_pixelformat pixelformat) + { + if (pixelformat < 0 || pixelformat > DP_PIXELFORMAT_RESERVED) + return "Invalid"; + + switch (pixelformat) { + case DP_PIXELFORMAT_RGB: + return "RGB"; + case DP_PIXELFORMAT_YUV444: + return "YUV444"; + case DP_PIXELFORMAT_YUV422: + return "YUV422"; + case DP_PIXELFORMAT_YUV420: + return "YUV420"; + case DP_PIXELFORMAT_Y_ONLY: + return "Y_ONLY"; + case DP_PIXELFORMAT_RAW: + return "RAW"; + default: + return "Reserved"; + } + } + + static const char *dp_colorimetry_get_name(enum dp_pixelformat pixelformat, + enum dp_colorimetry colorimetry) + { + if (pixelformat < 0 || pixelformat > DP_PIXELFORMAT_RESERVED) + return "Invalid"; + + switch (colorimetry) { + case DP_COLORIMETRY_DEFAULT: + switch (pixelformat) { + case DP_PIXELFORMAT_RGB: + return "sRGB"; + case DP_PIXELFORMAT_YUV444: + case DP_PIXELFORMAT_YUV422: + case DP_PIXELFORMAT_YUV420: + return "BT.601"; + case DP_PIXELFORMAT_Y_ONLY: + return "DICOM PS3.14"; + case DP_PIXELFORMAT_RAW: + return "Custom Color Profile"; + default: + return "Reserved"; + } + case DP_COLORIMETRY_RGB_WIDE_FIXED: /* and DP_COLORIMETRY_BT709_YCC */ + switch (pixelformat) { + case DP_PIXELFORMAT_RGB: + return "Wide Fixed"; + case DP_PIXELFORMAT_YUV444: + case DP_PIXELFORMAT_YUV422: + case DP_PIXELFORMAT_YUV420: + return "BT.709"; + default: + return "Reserved"; + } + case DP_COLORIMETRY_RGB_WIDE_FLOAT: /* and DP_COLORIMETRY_XVYCC_601 */ + switch (pixelformat) { + case DP_PIXELFORMAT_RGB: + return "Wide Float"; + case DP_PIXELFORMAT_YUV444: + case DP_PIXELFORMAT_YUV422: + case DP_PIXELFORMAT_YUV420: + return "xvYCC 601"; + default: + return "Reserved"; + } + case DP_COLORIMETRY_OPRGB: /* and DP_COLORIMETRY_XVYCC_709 */ + switch (pixelformat) { + case DP_PIXELFORMAT_RGB: + return "OpRGB"; + case DP_PIXELFORMAT_YUV444: + case DP_PIXELFORMAT_YUV422: + case DP_PIXELFORMAT_YUV420: + return "xvYCC 709"; + default: + return "Reserved"; + } + case DP_COLORIMETRY_DCI_P3_RGB: /* and DP_COLORIMETRY_SYCC_601 */ + switch (pixelformat) { + case DP_PIXELFORMAT_RGB: + return "DCI-P3"; + case DP_PIXELFORMAT_YUV444: + case DP_PIXELFORMAT_YUV422: + case DP_PIXELFORMAT_YUV420: + return "sYCC 601"; + default: + return "Reserved"; + } + case DP_COLORIMETRY_RGB_CUSTOM: /* and DP_COLORIMETRY_OPYCC_601 */ + switch (pixelformat) { + case DP_PIXELFORMAT_RGB: + return "Custom Profile"; + case DP_PIXELFORMAT_YUV444: + case DP_PIXELFORMAT_YUV422: + case DP_PIXELFORMAT_YUV420: + return "OpYCC 601"; + default: + return "Reserved"; + } + case DP_COLORIMETRY_BT2020_RGB: /* and DP_COLORIMETRY_BT2020_CYCC */ + switch (pixelformat) { + case DP_PIXELFORMAT_RGB: + return "BT.2020 RGB"; + case DP_PIXELFORMAT_YUV444: + case DP_PIXELFORMAT_YUV422: + case DP_PIXELFORMAT_YUV420: + return "BT.2020 CYCC"; + default: + return "Reserved"; + } + case DP_COLORIMETRY_BT2020_YCC: + switch (pixelformat) { + case DP_PIXELFORMAT_YUV444: + case DP_PIXELFORMAT_YUV422: + case DP_PIXELFORMAT_YUV420: + return "BT.2020 YCC"; + default: + return "Reserved"; + } + default: + return "Invalid"; + } + } + + static const char *dp_dynamic_range_get_name(enum dp_dynamic_range dynamic_range) + { + switch (dynamic_range) { + case DP_DYNAMIC_RANGE_VESA: + return "VESA range"; + case DP_DYNAMIC_RANGE_CTA: + return "CTA range"; + default: + return "Invalid"; + } + } + + static const char *dp_content_type_get_name(enum dp_content_type content_type) + { + switch (content_type) { + case DP_CONTENT_TYPE_NOT_DEFINED: + return "Not defined"; + case DP_CONTENT_TYPE_GRAPHICS: + return "Graphics"; + case DP_CONTENT_TYPE_PHOTO: + return "Photo"; + case DP_CONTENT_TYPE_VIDEO: + return "Video"; + case DP_CONTENT_TYPE_GAME: + return "Game"; + default: + return "Reserved"; + } + } + + void drm_dp_vsc_sdp_log(const char *level, struct device *dev, + const struct drm_dp_vsc_sdp *vsc) + { + #define DP_SDP_LOG(fmt, ...) dev_printk(level, dev, fmt, ##__VA_ARGS__) + DP_SDP_LOG("DP SDP: %s, revision %u, length %u\n", "VSC", + vsc->revision, vsc->length); + DP_SDP_LOG(" pixelformat: %s\n", + dp_pixelformat_get_name(vsc->pixelformat)); + DP_SDP_LOG(" colorimetry: %s\n", + dp_colorimetry_get_name(vsc->pixelformat, vsc->colorimetry)); + DP_SDP_LOG(" bpc: %u\n", vsc->bpc); + DP_SDP_LOG(" dynamic range: %s\n", + dp_dynamic_range_get_name(vsc->dynamic_range)); + DP_SDP_LOG(" content type: %s\n", + dp_content_type_get_name(vsc->content_type)); + #undef DP_SDP_LOG + } + EXPORT_SYMBOL(drm_dp_vsc_sdp_log); + + /** + * drm_dp_get_pcon_max_frl_bw() - maximum frl supported by PCON + * @dpcd: DisplayPort configuration data + * @port_cap: port capabilities + * + * Returns maximum frl bandwidth supported by PCON in GBPS, + * returns 0 if not supported. + */ + int drm_dp_get_pcon_max_frl_bw(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4]) + { + int bw; + u8 buf; + + buf = port_cap[2]; + bw = buf & DP_PCON_MAX_FRL_BW; + + switch (bw) { + case DP_PCON_MAX_9GBPS: + return 9; + case DP_PCON_MAX_18GBPS: + return 18; + case DP_PCON_MAX_24GBPS: + return 24; + case DP_PCON_MAX_32GBPS: + return 32; + case DP_PCON_MAX_40GBPS: + return 40; + case DP_PCON_MAX_48GBPS: + return 48; + case DP_PCON_MAX_0GBPS: + default: + return 0; + } + + return 0; + } + EXPORT_SYMBOL(drm_dp_get_pcon_max_frl_bw); + + /** + * drm_dp_pcon_frl_prepare() - Prepare PCON for FRL. + * @aux: DisplayPort AUX channel + * @enable_frl_ready_hpd: Configure DP_PCON_ENABLE_HPD_READY. + * + * Returns 0 if success, else returns negative error code. + */ + int drm_dp_pcon_frl_prepare(struct drm_dp_aux *aux, bool enable_frl_ready_hpd) + { + int ret; + u8 buf = DP_PCON_ENABLE_SOURCE_CTL_MODE | + DP_PCON_ENABLE_LINK_FRL_MODE; + + if (enable_frl_ready_hpd) + buf |= DP_PCON_ENABLE_HPD_READY; + + ret = drm_dp_dpcd_writeb(aux, DP_PCON_HDMI_LINK_CONFIG_1, buf); + + return ret; + } + EXPORT_SYMBOL(drm_dp_pcon_frl_prepare); + + /** + * drm_dp_pcon_is_frl_ready() - Is PCON ready for FRL + * @aux: DisplayPort AUX channel + * + * Returns true if success, else returns false. + */ + bool drm_dp_pcon_is_frl_ready(struct drm_dp_aux *aux) + { + int ret; + u8 buf; + + ret = drm_dp_dpcd_readb(aux, DP_PCON_HDMI_TX_LINK_STATUS, &buf); + if (ret < 0) + return false; + + if (buf & DP_PCON_FRL_READY) + return true; + + return false; + } + EXPORT_SYMBOL(drm_dp_pcon_is_frl_ready); + + /** + * drm_dp_pcon_frl_configure_1() - Set HDMI LINK Configuration-Step1 + * @aux: DisplayPort AUX channel + * @max_frl_gbps: maximum frl bw to be configured between PCON and HDMI sink + * @frl_mode: FRL Training mode, it can be either Concurrent or Sequential. + * In Concurrent Mode, the FRL link bring up can be done along with + * DP Link training. In Sequential mode, the FRL link bring up is done prior to + * the DP Link training. + * + * Returns 0 if success, else returns negative error code. + */ + + int drm_dp_pcon_frl_configure_1(struct drm_dp_aux *aux, int max_frl_gbps, + u8 frl_mode) + { + int ret; + u8 buf; + + ret = drm_dp_dpcd_readb(aux, DP_PCON_HDMI_LINK_CONFIG_1, &buf); + if (ret < 0) + return ret; + + if (frl_mode == DP_PCON_ENABLE_CONCURRENT_LINK) + buf |= DP_PCON_ENABLE_CONCURRENT_LINK; + else + buf &= ~DP_PCON_ENABLE_CONCURRENT_LINK; + + switch (max_frl_gbps) { + case 9: + buf |= DP_PCON_ENABLE_MAX_BW_9GBPS; + break; + case 18: + buf |= DP_PCON_ENABLE_MAX_BW_18GBPS; + break; + case 24: + buf |= DP_PCON_ENABLE_MAX_BW_24GBPS; + break; + case 32: + buf |= DP_PCON_ENABLE_MAX_BW_32GBPS; + break; + case 40: + buf |= DP_PCON_ENABLE_MAX_BW_40GBPS; + break; + case 48: + buf |= DP_PCON_ENABLE_MAX_BW_48GBPS; + break; + case 0: + buf |= DP_PCON_ENABLE_MAX_BW_0GBPS; + break; + default: + return -EINVAL; + } + + ret = drm_dp_dpcd_writeb(aux, DP_PCON_HDMI_LINK_CONFIG_1, buf); + if (ret < 0) + return ret; + + return 0; + } + EXPORT_SYMBOL(drm_dp_pcon_frl_configure_1); + + /** + * drm_dp_pcon_frl_configure_2() - Set HDMI Link configuration Step-2 + * @aux: DisplayPort AUX channel + * @max_frl_mask : Max FRL BW to be tried by the PCON with HDMI Sink + * @frl_type : FRL training type, can be Extended, or Normal. + * In Normal FRL training, the PCON tries each frl bw from the max_frl_mask + * starting from min, and stops when link training is successful. In Extended + * FRL training, all frl bw selected in the mask are trained by the PCON. + * + * Returns 0 if success, else returns negative error code. + */ + int drm_dp_pcon_frl_configure_2(struct drm_dp_aux *aux, int max_frl_mask, + u8 frl_type) + { + int ret; + u8 buf = max_frl_mask; + + if (frl_type == DP_PCON_FRL_LINK_TRAIN_EXTENDED) + buf |= DP_PCON_FRL_LINK_TRAIN_EXTENDED; + else + buf &= ~DP_PCON_FRL_LINK_TRAIN_EXTENDED; + + ret = drm_dp_dpcd_writeb(aux, DP_PCON_HDMI_LINK_CONFIG_2, buf); + if (ret < 0) + return ret; + + return 0; + } + EXPORT_SYMBOL(drm_dp_pcon_frl_configure_2); + + /** + * drm_dp_pcon_reset_frl_config() - Re-Set HDMI Link configuration. + * @aux: DisplayPort AUX channel + * + * Returns 0 if success, else returns negative error code. + */ + int drm_dp_pcon_reset_frl_config(struct drm_dp_aux *aux) + { + int ret; + + ret = drm_dp_dpcd_writeb(aux, DP_PCON_HDMI_LINK_CONFIG_1, 0x0); + if (ret < 0) + return ret; + + return 0; + } + EXPORT_SYMBOL(drm_dp_pcon_reset_frl_config); + + /** + * drm_dp_pcon_frl_enable() - Enable HDMI link through FRL + * @aux: DisplayPort AUX channel + * + * Returns 0 if success, else returns negative error code. + */ + int drm_dp_pcon_frl_enable(struct drm_dp_aux *aux) + { + int ret; + u8 buf = 0; + + ret = drm_dp_dpcd_readb(aux, DP_PCON_HDMI_LINK_CONFIG_1, &buf); + if (ret < 0) + return ret; + if (!(buf & DP_PCON_ENABLE_SOURCE_CTL_MODE)) { + drm_dbg_kms(aux->drm_dev, "%s: PCON in Autonomous mode, can't enable FRL\n", + aux->name); + return -EINVAL; + } + buf |= DP_PCON_ENABLE_HDMI_LINK; + ret = drm_dp_dpcd_writeb(aux, DP_PCON_HDMI_LINK_CONFIG_1, buf); + if (ret < 0) + return ret; + + return 0; + } + EXPORT_SYMBOL(drm_dp_pcon_frl_enable); + + /** + * drm_dp_pcon_hdmi_link_active() - check if the PCON HDMI LINK status is active. + * @aux: DisplayPort AUX channel + * + * Returns true if link is active else returns false. + */ + bool drm_dp_pcon_hdmi_link_active(struct drm_dp_aux *aux) + { + u8 buf; + int ret; + + ret = drm_dp_dpcd_readb(aux, DP_PCON_HDMI_TX_LINK_STATUS, &buf); + if (ret < 0) + return false; + + return buf & DP_PCON_HDMI_TX_LINK_ACTIVE; + } + EXPORT_SYMBOL(drm_dp_pcon_hdmi_link_active); + + /** + * drm_dp_pcon_hdmi_link_mode() - get the PCON HDMI LINK MODE + * @aux: DisplayPort AUX channel + * @frl_trained_mask: pointer to store bitmask of the trained bw configuration. + * Valid only if the MODE returned is FRL. For Normal Link training mode + * only 1 of the bits will be set, but in case of Extended mode, more than + * one bits can be set. + * + * Returns the link mode : TMDS or FRL on success, else returns negative error + * code. + */ + int drm_dp_pcon_hdmi_link_mode(struct drm_dp_aux *aux, u8 *frl_trained_mask) + { + u8 buf; + int mode; + int ret; + + ret = drm_dp_dpcd_readb(aux, DP_PCON_HDMI_POST_FRL_STATUS, &buf); + if (ret < 0) + return ret; + + mode = buf & DP_PCON_HDMI_LINK_MODE; + + if (frl_trained_mask && DP_PCON_HDMI_MODE_FRL == mode) + *frl_trained_mask = (buf & DP_PCON_HDMI_FRL_TRAINED_BW) >> 1; + + return mode; + } + EXPORT_SYMBOL(drm_dp_pcon_hdmi_link_mode); + + /** + * drm_dp_pcon_hdmi_frl_link_error_count() - print the error count per lane + * during link failure between PCON and HDMI sink + * @aux: DisplayPort AUX channel + * @connector: DRM connector + * code. + **/ + + void drm_dp_pcon_hdmi_frl_link_error_count(struct drm_dp_aux *aux, + struct drm_connector *connector) + { + u8 buf, error_count; + int i, num_error; + struct drm_hdmi_info *hdmi = &connector->display_info.hdmi; + + for (i = 0; i < hdmi->max_lanes; i++) { + if (drm_dp_dpcd_readb(aux, DP_PCON_HDMI_ERROR_STATUS_LN0 + i, &buf) < 0) + return; + + error_count = buf & DP_PCON_HDMI_ERROR_COUNT_MASK; + switch (error_count) { + case DP_PCON_HDMI_ERROR_COUNT_HUNDRED_PLUS: + num_error = 100; + break; + case DP_PCON_HDMI_ERROR_COUNT_TEN_PLUS: + num_error = 10; + break; + case DP_PCON_HDMI_ERROR_COUNT_THREE_PLUS: + num_error = 3; + break; + default: + num_error = 0; + } + + drm_err(aux->drm_dev, "%s: More than %d errors since the last read for lane %d", + aux->name, num_error, i); + } + } + EXPORT_SYMBOL(drm_dp_pcon_hdmi_frl_link_error_count); + + /* + * drm_dp_pcon_enc_is_dsc_1_2 - Does PCON Encoder supports DSC 1.2 + * @pcon_dsc_dpcd: DSC capabilities of the PCON DSC Encoder + * + * Returns true is PCON encoder is DSC 1.2 else returns false. + */ + bool drm_dp_pcon_enc_is_dsc_1_2(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]) + { + u8 buf; + u8 major_v, minor_v; + + buf = pcon_dsc_dpcd[DP_PCON_DSC_VERSION - DP_PCON_DSC_ENCODER]; + major_v = (buf & DP_PCON_DSC_MAJOR_MASK) >> DP_PCON_DSC_MAJOR_SHIFT; + minor_v = (buf & DP_PCON_DSC_MINOR_MASK) >> DP_PCON_DSC_MINOR_SHIFT; + + if (major_v == 1 && minor_v == 2) + return true; + + return false; + } + EXPORT_SYMBOL(drm_dp_pcon_enc_is_dsc_1_2); + + /* + * drm_dp_pcon_dsc_max_slices - Get max slices supported by PCON DSC Encoder + * @pcon_dsc_dpcd: DSC capabilities of the PCON DSC Encoder + * + * Returns maximum no. of slices supported by the PCON DSC Encoder. + */ + int drm_dp_pcon_dsc_max_slices(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]) + { + u8 slice_cap1, slice_cap2; + + slice_cap1 = pcon_dsc_dpcd[DP_PCON_DSC_SLICE_CAP_1 - DP_PCON_DSC_ENCODER]; + slice_cap2 = pcon_dsc_dpcd[DP_PCON_DSC_SLICE_CAP_2 - DP_PCON_DSC_ENCODER]; + + if (slice_cap2 & DP_PCON_DSC_24_PER_DSC_ENC) + return 24; + if (slice_cap2 & DP_PCON_DSC_20_PER_DSC_ENC) + return 20; + if (slice_cap2 & DP_PCON_DSC_16_PER_DSC_ENC) + return 16; + if (slice_cap1 & DP_PCON_DSC_12_PER_DSC_ENC) + return 12; + if (slice_cap1 & DP_PCON_DSC_10_PER_DSC_ENC) + return 10; + if (slice_cap1 & DP_PCON_DSC_8_PER_DSC_ENC) + return 8; + if (slice_cap1 & DP_PCON_DSC_6_PER_DSC_ENC) + return 6; + if (slice_cap1 & DP_PCON_DSC_4_PER_DSC_ENC) + return 4; + if (slice_cap1 & DP_PCON_DSC_2_PER_DSC_ENC) + return 2; + if (slice_cap1 & DP_PCON_DSC_1_PER_DSC_ENC) + return 1; + + return 0; + } + EXPORT_SYMBOL(drm_dp_pcon_dsc_max_slices); + + /* + * drm_dp_pcon_dsc_max_slice_width() - Get max slice width for Pcon DSC encoder + * @pcon_dsc_dpcd: DSC capabilities of the PCON DSC Encoder + * + * Returns maximum width of the slices in pixel width i.e. no. of pixels x 320. + */ + int drm_dp_pcon_dsc_max_slice_width(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]) + { + u8 buf; + + buf = pcon_dsc_dpcd[DP_PCON_DSC_MAX_SLICE_WIDTH - DP_PCON_DSC_ENCODER]; + + return buf * DP_DSC_SLICE_WIDTH_MULTIPLIER; + } + EXPORT_SYMBOL(drm_dp_pcon_dsc_max_slice_width); + + /* + * drm_dp_pcon_dsc_bpp_incr() - Get bits per pixel increment for PCON DSC encoder + * @pcon_dsc_dpcd: DSC capabilities of the PCON DSC Encoder + * + * Returns the bpp precision supported by the PCON encoder. + */ + int drm_dp_pcon_dsc_bpp_incr(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]) + { + u8 buf; + + buf = pcon_dsc_dpcd[DP_PCON_DSC_BPP_INCR - DP_PCON_DSC_ENCODER]; + + switch (buf & DP_PCON_DSC_BPP_INCR_MASK) { + case DP_PCON_DSC_ONE_16TH_BPP: + return 16; + case DP_PCON_DSC_ONE_8TH_BPP: + return 8; + case DP_PCON_DSC_ONE_4TH_BPP: + return 4; + case DP_PCON_DSC_ONE_HALF_BPP: + return 2; + case DP_PCON_DSC_ONE_BPP: + return 1; + } + + return 0; + } + EXPORT_SYMBOL(drm_dp_pcon_dsc_bpp_incr); + + static + int drm_dp_pcon_configure_dsc_enc(struct drm_dp_aux *aux, u8 pps_buf_config) + { + u8 buf; + int ret; + + ret = drm_dp_dpcd_readb(aux, DP_PROTOCOL_CONVERTER_CONTROL_2, &buf); + if (ret < 0) + return ret; + + buf |= DP_PCON_ENABLE_DSC_ENCODER; + + if (pps_buf_config <= DP_PCON_ENC_PPS_OVERRIDE_EN_BUFFER) { + buf &= ~DP_PCON_ENCODER_PPS_OVERRIDE_MASK; + buf |= pps_buf_config << 2; + } + + ret = drm_dp_dpcd_writeb(aux, DP_PROTOCOL_CONVERTER_CONTROL_2, buf); + if (ret < 0) + return ret; + + return 0; + } + + /** + * drm_dp_pcon_pps_default() - Let PCON fill the default pps parameters + * for DSC1.2 between PCON & HDMI2.1 sink + * @aux: DisplayPort AUX channel + * + * Returns 0 on success, else returns negative error code. + */ + int drm_dp_pcon_pps_default(struct drm_dp_aux *aux) + { + int ret; + + ret = drm_dp_pcon_configure_dsc_enc(aux, DP_PCON_ENC_PPS_OVERRIDE_DISABLED); + if (ret < 0) + return ret; + + return 0; + } + EXPORT_SYMBOL(drm_dp_pcon_pps_default); + + /** + * drm_dp_pcon_pps_override_buf() - Configure PPS encoder override buffer for + * HDMI sink + * @aux: DisplayPort AUX channel + * @pps_buf: 128 bytes to be written into PPS buffer for HDMI sink by PCON. + * + * Returns 0 on success, else returns negative error code. + */ + int drm_dp_pcon_pps_override_buf(struct drm_dp_aux *aux, u8 pps_buf[128]) + { + int ret; + + ret = drm_dp_dpcd_write(aux, DP_PCON_HDMI_PPS_OVERRIDE_BASE, &pps_buf, 128); + if (ret < 0) + return ret; + + ret = drm_dp_pcon_configure_dsc_enc(aux, DP_PCON_ENC_PPS_OVERRIDE_EN_BUFFER); + if (ret < 0) + return ret; + + return 0; + } + EXPORT_SYMBOL(drm_dp_pcon_pps_override_buf); + + /* + * drm_dp_pcon_pps_override_param() - Write PPS parameters to DSC encoder + * override registers + * @aux: DisplayPort AUX channel + * @pps_param: 3 Parameters (2 Bytes each) : Slice Width, Slice Height, + * bits_per_pixel. + * + * Returns 0 on success, else returns negative error code. + */ + int drm_dp_pcon_pps_override_param(struct drm_dp_aux *aux, u8 pps_param[6]) + { + int ret; + + ret = drm_dp_dpcd_write(aux, DP_PCON_HDMI_PPS_OVRD_SLICE_HEIGHT, &pps_param[0], 2); + if (ret < 0) + return ret; + ret = drm_dp_dpcd_write(aux, DP_PCON_HDMI_PPS_OVRD_SLICE_WIDTH, &pps_param[2], 2); + if (ret < 0) + return ret; + ret = drm_dp_dpcd_write(aux, DP_PCON_HDMI_PPS_OVRD_BPP, &pps_param[4], 2); + if (ret < 0) + return ret; + + ret = drm_dp_pcon_configure_dsc_enc(aux, DP_PCON_ENC_PPS_OVERRIDE_EN_BUFFER); + if (ret < 0) + return ret; + + return 0; + } + EXPORT_SYMBOL(drm_dp_pcon_pps_override_param); + + /* + * drm_dp_pcon_convert_rgb_to_ycbcr() - Configure the PCon to convert RGB to Ycbcr + * @aux: displayPort AUX channel + * @color_spc: Color-space/s for which conversion is to be enabled, 0 for disable. + * + * Returns 0 on success, else returns negative error code. + */ + int drm_dp_pcon_convert_rgb_to_ycbcr(struct drm_dp_aux *aux, u8 color_spc) + { + int ret; + u8 buf; + + ret = drm_dp_dpcd_readb(aux, DP_PROTOCOL_CONVERTER_CONTROL_2, &buf); + if (ret < 0) + return ret; + + if (color_spc & DP_CONVERSION_RGB_YCBCR_MASK) + buf |= (color_spc & DP_CONVERSION_RGB_YCBCR_MASK); + else + buf &= ~DP_CONVERSION_RGB_YCBCR_MASK; + + ret = drm_dp_dpcd_writeb(aux, DP_PROTOCOL_CONVERTER_CONTROL_2, buf); + if (ret < 0) + return ret; + + return 0; + } + EXPORT_SYMBOL(drm_dp_pcon_convert_rgb_to_ycbcr); + + /** + * drm_edp_backlight_set_level() - Set the backlight level of an eDP panel via AUX + * @aux: The DP AUX channel to use + * @bl: Backlight capability info from drm_edp_backlight_init() + * @level: The brightness level to set + * + * Sets the brightness level of an eDP panel's backlight. Note that the panel's backlight must + * already have been enabled by the driver by calling drm_edp_backlight_enable(). + * + * Returns: %0 on success, negative error code on failure + */ + int drm_edp_backlight_set_level(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl, + u16 level) + { + int ret; + u8 buf[2] = { 0 }; + + /* The panel uses the PWM for controlling brightness levels */ + if (!bl->aux_set) + return 0; + + if (bl->lsb_reg_used) { + buf[0] = (level & 0xff00) >> 8; + buf[1] = (level & 0x00ff); + } else { + buf[0] = level; + } + + ret = drm_dp_dpcd_write(aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB, buf, sizeof(buf)); + if (ret != sizeof(buf)) { + drm_err(aux->drm_dev, + "%s: Failed to write aux backlight level: %d\n", + aux->name, ret); + return ret < 0 ? ret : -EIO; + } + + return 0; + } + EXPORT_SYMBOL(drm_edp_backlight_set_level); + + static int + drm_edp_backlight_set_enable(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl, + bool enable) + { + int ret; + u8 buf; + + /* This panel uses the EDP_BL_PWR GPIO for enablement */ + if (!bl->aux_enable) + return 0; + + ret = drm_dp_dpcd_readb(aux, DP_EDP_DISPLAY_CONTROL_REGISTER, &buf); + if (ret != 1) { + drm_err(aux->drm_dev, "%s: Failed to read eDP display control register: %d\n", + aux->name, ret); + return ret < 0 ? ret : -EIO; + } + if (enable) + buf |= DP_EDP_BACKLIGHT_ENABLE; + else + buf &= ~DP_EDP_BACKLIGHT_ENABLE; + + ret = drm_dp_dpcd_writeb(aux, DP_EDP_DISPLAY_CONTROL_REGISTER, buf); + if (ret != 1) { + drm_err(aux->drm_dev, "%s: Failed to write eDP display control register: %d\n", + aux->name, ret); + return ret < 0 ? ret : -EIO; + } + + return 0; + } + + /** + * drm_edp_backlight_enable() - Enable an eDP panel's backlight using DPCD + * @aux: The DP AUX channel to use + * @bl: Backlight capability info from drm_edp_backlight_init() + * @level: The initial backlight level to set via AUX, if there is one + * + * This function handles enabling DPCD backlight controls on a panel over DPCD, while additionally + * restoring any important backlight state such as the given backlight level, the brightness byte + * count, backlight frequency, etc. + * + * Note that certain panels do not support being enabled or disabled via DPCD, but instead require + * that the driver handle enabling/disabling the panel through implementation-specific means using + * the EDP_BL_PWR GPIO. For such panels, &drm_edp_backlight_info.aux_enable will be set to %false, + * this function becomes a no-op, and the driver is expected to handle powering the panel on using + * the EDP_BL_PWR GPIO. + * + * Returns: %0 on success, negative error code on failure. + */ + int drm_edp_backlight_enable(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl, + const u16 level) + { + int ret; + u8 dpcd_buf; + + if (bl->aux_set) + dpcd_buf = DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD; + else + dpcd_buf = DP_EDP_BACKLIGHT_CONTROL_MODE_PWM; + + if (bl->pwmgen_bit_count) { + ret = drm_dp_dpcd_writeb(aux, DP_EDP_PWMGEN_BIT_COUNT, bl->pwmgen_bit_count); + if (ret != 1) + drm_dbg_kms(aux->drm_dev, "%s: Failed to write aux pwmgen bit count: %d\n", + aux->name, ret); + } + + if (bl->pwm_freq_pre_divider) { + ret = drm_dp_dpcd_writeb(aux, DP_EDP_BACKLIGHT_FREQ_SET, bl->pwm_freq_pre_divider); + if (ret != 1) + drm_dbg_kms(aux->drm_dev, + "%s: Failed to write aux backlight frequency: %d\n", + aux->name, ret); + else + dpcd_buf |= DP_EDP_BACKLIGHT_FREQ_AUX_SET_ENABLE; + } + + ret = drm_dp_dpcd_writeb(aux, DP_EDP_BACKLIGHT_MODE_SET_REGISTER, dpcd_buf); + if (ret != 1) { + drm_dbg_kms(aux->drm_dev, "%s: Failed to write aux backlight mode: %d\n", + aux->name, ret); + return ret < 0 ? ret : -EIO; + } + + ret = drm_edp_backlight_set_level(aux, bl, level); + if (ret < 0) + return ret; + ret = drm_edp_backlight_set_enable(aux, bl, true); + if (ret < 0) + return ret; + + return 0; + } + EXPORT_SYMBOL(drm_edp_backlight_enable); + + /** + * drm_edp_backlight_disable() - Disable an eDP backlight using DPCD, if supported + * @aux: The DP AUX channel to use + * @bl: Backlight capability info from drm_edp_backlight_init() + * + * This function handles disabling DPCD backlight controls on a panel over AUX. + * + * Note that certain panels do not support being enabled or disabled via DPCD, but instead require + * that the driver handle enabling/disabling the panel through implementation-specific means using + * the EDP_BL_PWR GPIO. For such panels, &drm_edp_backlight_info.aux_enable will be set to %false, + * this function becomes a no-op, and the driver is expected to handle powering the panel off using + * the EDP_BL_PWR GPIO. + * + * Returns: %0 on success or no-op, negative error code on failure. + */ + int drm_edp_backlight_disable(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl) + { + int ret; + + ret = drm_edp_backlight_set_enable(aux, bl, false); + if (ret < 0) + return ret; + + return 0; + } + EXPORT_SYMBOL(drm_edp_backlight_disable); + + static inline int + drm_edp_backlight_probe_max(struct drm_dp_aux *aux, struct drm_edp_backlight_info *bl, + u16 driver_pwm_freq_hz, const u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE]) + { + int fxp, fxp_min, fxp_max, fxp_actual, f = 1; + int ret; + u8 pn, pn_min, pn_max; + + if (!bl->aux_set) + return 0; + + ret = drm_dp_dpcd_readb(aux, DP_EDP_PWMGEN_BIT_COUNT, &pn); + if (ret != 1) { + drm_dbg_kms(aux->drm_dev, "%s: Failed to read pwmgen bit count cap: %d\n", + aux->name, ret); + return -ENODEV; + } + + pn &= DP_EDP_PWMGEN_BIT_COUNT_MASK; + bl->max = (1 << pn) - 1; + if (!driver_pwm_freq_hz) + return 0; + + /* + * Set PWM Frequency divider to match desired frequency provided by the driver. + * The PWM Frequency is calculated as 27Mhz / (F x P). + * - Where F = PWM Frequency Pre-Divider value programmed by field 7:0 of the + * EDP_BACKLIGHT_FREQ_SET register (DPCD Address 00728h) + * - Where P = 2^Pn, where Pn is the value programmed by field 4:0 of the + * EDP_PWMGEN_BIT_COUNT register (DPCD Address 00724h) + */ + + /* Find desired value of (F x P) + * Note that, if F x P is out of supported range, the maximum value or minimum value will + * applied automatically. So no need to check that. + */ + fxp = DIV_ROUND_CLOSEST(1000 * DP_EDP_BACKLIGHT_FREQ_BASE_KHZ, driver_pwm_freq_hz); + + /* Use highest possible value of Pn for more granularity of brightness adjustment while + * satisfying the conditions below. + * - Pn is in the range of Pn_min and Pn_max + * - F is in the range of 1 and 255 + * - FxP is within 25% of desired value. + * Note: 25% is arbitrary value and may need some tweak. + */ + ret = drm_dp_dpcd_readb(aux, DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN, &pn_min); + if (ret != 1) { + drm_dbg_kms(aux->drm_dev, "%s: Failed to read pwmgen bit count cap min: %d\n", + aux->name, ret); + return 0; + } + ret = drm_dp_dpcd_readb(aux, DP_EDP_PWMGEN_BIT_COUNT_CAP_MAX, &pn_max); + if (ret != 1) { + drm_dbg_kms(aux->drm_dev, "%s: Failed to read pwmgen bit count cap max: %d\n", + aux->name, ret); + return 0; + } + pn_min &= DP_EDP_PWMGEN_BIT_COUNT_MASK; + pn_max &= DP_EDP_PWMGEN_BIT_COUNT_MASK; + + /* Ensure frequency is within 25% of desired value */ + fxp_min = DIV_ROUND_CLOSEST(fxp * 3, 4); + fxp_max = DIV_ROUND_CLOSEST(fxp * 5, 4); + if (fxp_min < (1 << pn_min) || (255 << pn_max) < fxp_max) { + drm_dbg_kms(aux->drm_dev, + "%s: Driver defined backlight frequency (%d) out of range\n", + aux->name, driver_pwm_freq_hz); + return 0; + } + + for (pn = pn_max; pn >= pn_min; pn--) { + f = clamp(DIV_ROUND_CLOSEST(fxp, 1 << pn), 1, 255); + fxp_actual = f << pn; + if (fxp_min <= fxp_actual && fxp_actual <= fxp_max) + break; + } + + ret = drm_dp_dpcd_writeb(aux, DP_EDP_PWMGEN_BIT_COUNT, pn); + if (ret != 1) { + drm_dbg_kms(aux->drm_dev, "%s: Failed to write aux pwmgen bit count: %d\n", + aux->name, ret); + return 0; + } + bl->pwmgen_bit_count = pn; + bl->max = (1 << pn) - 1; + + if (edp_dpcd[2] & DP_EDP_BACKLIGHT_FREQ_AUX_SET_CAP) { + bl->pwm_freq_pre_divider = f; + drm_dbg_kms(aux->drm_dev, "%s: Using backlight frequency from driver (%dHz)\n", + aux->name, driver_pwm_freq_hz); + } + + return 0; + } + + static inline int + drm_edp_backlight_probe_state(struct drm_dp_aux *aux, struct drm_edp_backlight_info *bl, + u8 *current_mode) + { + int ret; + u8 buf[2]; + u8 mode_reg; + + ret = drm_dp_dpcd_readb(aux, DP_EDP_BACKLIGHT_MODE_SET_REGISTER, &mode_reg); + if (ret != 1) { + drm_dbg_kms(aux->drm_dev, "%s: Failed to read backlight mode: %d\n", + aux->name, ret); + return ret < 0 ? ret : -EIO; + } + + *current_mode = (mode_reg & DP_EDP_BACKLIGHT_CONTROL_MODE_MASK); + if (!bl->aux_set) + return 0; + + if (*current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) { + int size = 1 + bl->lsb_reg_used; + + ret = drm_dp_dpcd_read(aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB, buf, size); + if (ret != size) { + drm_dbg_kms(aux->drm_dev, "%s: Failed to read backlight level: %d\n", + aux->name, ret); + return ret < 0 ? ret : -EIO; + } + + if (bl->lsb_reg_used) + return (buf[0] << 8) | buf[1]; + else + return buf[0]; + } + + /* + * If we're not in DPCD control mode yet, the programmed brightness value is meaningless and + * the driver should assume max brightness + */ + return bl->max; + } + + /** + * drm_edp_backlight_init() - Probe a display panel's TCON using the standard VESA eDP backlight + * interface. + * @aux: The DP aux device to use for probing + * @bl: The &drm_edp_backlight_info struct to fill out with information on the backlight + * @driver_pwm_freq_hz: Optional PWM frequency from the driver in hz + * @edp_dpcd: A cached copy of the eDP DPCD + * @current_level: Where to store the probed brightness level, if any + * @current_mode: Where to store the currently set backlight control mode + * + * Initializes a &drm_edp_backlight_info struct by probing @aux for it's backlight capabilities, + * along with also probing the current and maximum supported brightness levels. + * + * If @driver_pwm_freq_hz is non-zero, this will be used as the backlight frequency. Otherwise, the + * default frequency from the panel is used. + * + * Returns: %0 on success, negative error code on failure. + */ + int + drm_edp_backlight_init(struct drm_dp_aux *aux, struct drm_edp_backlight_info *bl, + u16 driver_pwm_freq_hz, const u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE], + u16 *current_level, u8 *current_mode) + { + int ret; + + if (edp_dpcd[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP) + bl->aux_enable = true; + if (edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP) + bl->aux_set = true; + if (edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT) + bl->lsb_reg_used = true; + + /* Sanity check caps */ + if (!bl->aux_set && !(edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP)) { + drm_dbg_kms(aux->drm_dev, + "%s: Panel supports neither AUX or PWM brightness control? Aborting\n", + aux->name); + return -EINVAL; + } + + ret = drm_edp_backlight_probe_max(aux, bl, driver_pwm_freq_hz, edp_dpcd); + if (ret < 0) + return ret; + + ret = drm_edp_backlight_probe_state(aux, bl, current_mode); + if (ret < 0) + return ret; + *current_level = ret; + + drm_dbg_kms(aux->drm_dev, + "%s: Found backlight: aux_set=%d aux_enable=%d mode=%d\n", + aux->name, bl->aux_set, bl->aux_enable, *current_mode); + if (bl->aux_set) { + drm_dbg_kms(aux->drm_dev, + "%s: Backlight caps: level=%d/%d pwm_freq_pre_divider=%d lsb_reg_used=%d\n", + aux->name, *current_level, bl->max, bl->pwm_freq_pre_divider, + bl->lsb_reg_used); + } + + return 0; + } + EXPORT_SYMBOL(drm_edp_backlight_init); + + #if IS_BUILTIN(CONFIG_BACKLIGHT_CLASS_DEVICE) || \ + (IS_MODULE(CONFIG_DRM_KMS_HELPER) && IS_MODULE(CONFIG_BACKLIGHT_CLASS_DEVICE)) + + static int dp_aux_backlight_update_status(struct backlight_device *bd) + { + struct dp_aux_backlight *bl = bl_get_data(bd); + u16 brightness = backlight_get_brightness(bd); + int ret = 0; + + if (!backlight_is_blank(bd)) { + if (!bl->enabled) { + drm_edp_backlight_enable(bl->aux, &bl->info, brightness); + bl->enabled = true; + return 0; + } + ret = drm_edp_backlight_set_level(bl->aux, &bl->info, brightness); + } else { + if (bl->enabled) { + drm_edp_backlight_disable(bl->aux, &bl->info); + bl->enabled = false; + } + } + + return ret; + } + + static const struct backlight_ops dp_aux_bl_ops = { + .update_status = dp_aux_backlight_update_status, + }; + + /** + * drm_panel_dp_aux_backlight - create and use DP AUX backlight + * @panel: DRM panel + * @aux: The DP AUX channel to use + * + * Use this function to create and handle backlight if your panel + * supports backlight control over DP AUX channel using DPCD + * registers as per VESA's standard backlight control interface. + * + * When the panel is enabled backlight will be enabled after a + * successful call to &drm_panel_funcs.enable() + * + * When the panel is disabled backlight will be disabled before the + * call to &drm_panel_funcs.disable(). + * + * A typical implementation for a panel driver supporting backlight + * control over DP AUX will call this function at probe time. + * Backlight will then be handled transparently without requiring + * any intervention from the driver. + * + * drm_panel_dp_aux_backlight() must be called after the call to drm_panel_init(). + * + * Return: 0 on success or a negative error code on failure. + */ + int drm_panel_dp_aux_backlight(struct drm_panel *panel, struct drm_dp_aux *aux) + { + struct dp_aux_backlight *bl; + struct backlight_properties props = { 0 }; + u16 current_level; + u8 current_mode; + u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE]; + int ret; + + if (!panel || !panel->dev || !aux) + return -EINVAL; + + ret = drm_dp_dpcd_read(aux, DP_EDP_DPCD_REV, edp_dpcd, + EDP_DISPLAY_CTL_CAP_SIZE); + if (ret < 0) + return ret; + + if (!drm_edp_backlight_supported(edp_dpcd)) { + DRM_DEV_INFO(panel->dev, "DP AUX backlight is not supported\n"); + return 0; + } + + bl = devm_kzalloc(panel->dev, sizeof(*bl), GFP_KERNEL); + if (!bl) + return -ENOMEM; + + bl->aux = aux; + + ret = drm_edp_backlight_init(aux, &bl->info, 0, edp_dpcd, + ¤t_level, ¤t_mode); + if (ret < 0) + return ret; + + props.type = BACKLIGHT_RAW; + props.brightness = current_level; + props.max_brightness = bl->info.max; + + bl->base = devm_backlight_device_register(panel->dev, "dp_aux_backlight", + panel->dev, bl, + &dp_aux_bl_ops, &props); + if (IS_ERR(bl->base)) + return PTR_ERR(bl->base); + + backlight_disable(bl->base); + + panel->backlight = bl->base; + + return 0; + } + EXPORT_SYMBOL(drm_panel_dp_aux_backlight); + + #endif diff --cc drivers/gpu/drm/i915/display/intel_display_types.h index b98115418ec5e,41e3dd25a78f2..b50d0e6efe211 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@@ -31,12 -32,13 +31,12 @@@ #include #include + #include + #include #include #include - #include - #include #include #include -#include #include #include #include diff --cc drivers/gpu/drm/i915/display/intel_fbc.c index 3ec34de354605,c0a973eeb4059..87f4af3fd523e --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@@ -605,10 -595,10 +605,10 @@@ static void ivb_fbc_activate(struct int else if (DISPLAY_VER(i915) == 9) skl_fbc_program_cfb_stride(fbc); - if (i915->ggtt.num_fences) + if (to_gt(i915)->ggtt->num_fences) snb_fbc_program_fence(fbc); - intel_de_write(i915, ILK_DPFC_CONTROL, + intel_de_write(i915, ILK_DPFC_CONTROL(fbc->id), DPFC_CTL_EN | ivb_dpfc_ctl(fbc)); } diff --cc drivers/gpu/drm/i915/gem/i915_gem_mman.c index a3b60e1ede90e,4afad1604a6ac..efe69d6b86f43 --- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c @@@ -15,6 -13,6 +15,7 @@@ #include "gt/intel_gt_requests.h" #include "i915_drv.h" ++#include "i915_gem_evict.h" #include "i915_gem_gtt.h" #include "i915_gem_ioctls.h" #include "i915_gem_object.h" diff --cc drivers/gpu/drm/i915/gt/intel_gt.c index 545a2b1f18349,3a355b50082de..e8403fa539097 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@@ -3,15 -3,14 +3,16 @@@ * Copyright © 2019 Intel Corporation */ + #include #include -#include "intel_gt_debugfs.h" - +#include "gem/i915_gem_internal.h" #include "gem/i915_gem_lmem.h" +#include "pxp/intel_pxp.h" + #include "i915_drv.h" #include "intel_context.h" +#include "intel_engine_regs.h" #include "intel_gt.h" #include "intel_gt_buffer_pool.h" #include "intel_gt_clock_utils.h" diff --cc drivers/gpu/drm/i915/gt/intel_gt_regs.h index e8143fa4b5a81,0000000000000..18d158d77aba6 mode 100644,000000..100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@@ -1,1522 -1,0 +1,1526 @@@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2022 Intel Corporation + */ + +#ifndef __INTEL_GT_REGS__ +#define __INTEL_GT_REGS__ + +#include "i915_reg_defs.h" + +/* RPM unit config (Gen8+) */ +#define RPM_CONFIG0 _MMIO(0xd00) +#define GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_SHIFT 3 +#define GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_MASK (1 << GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_SHIFT) +#define GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_19_2_MHZ 0 +#define GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_24_MHZ 1 +#define GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_SHIFT 3 +#define GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_MASK (0x7 << GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_SHIFT) +#define GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_24_MHZ 0 +#define GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_19_2_MHZ 1 +#define GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_38_4_MHZ 2 +#define GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_25_MHZ 3 +#define GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_SHIFT 1 +#define GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_MASK (0x3 << GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_SHIFT) + +#define RPM_CONFIG1 _MMIO(0xd04) +#define GEN10_GT_NOA_ENABLE (1 << 9) + +/* RCP unit config (Gen8+) */ +#define RCP_CONFIG _MMIO(0xd08) + +#define RC6_LOCATION _MMIO(0xd40) +#define RC6_CTX_IN_DRAM (1 << 0) +#define RC6_CTX_BASE _MMIO(0xd48) +#define RC6_CTX_BASE_MASK 0xFFFFFFF0 + +#define FORCEWAKE_ACK_MEDIA_VDBOX_GEN11(n) _MMIO(0xd50 + (n) * 4) +#define FORCEWAKE_ACK_MEDIA_VEBOX_GEN11(n) _MMIO(0xd70 + (n) * 4) +#define FORCEWAKE_ACK_RENDER_GEN9 _MMIO(0xd84) +#define FORCEWAKE_ACK_MEDIA_GEN9 _MMIO(0xd88) + +#define MCFG_MCR_SELECTOR _MMIO(0xfd0) +#define SF_MCR_SELECTOR _MMIO(0xfd8) +#define GEN8_MCR_SELECTOR _MMIO(0xfdc) +#define GEN8_MCR_SLICE(slice) (((slice) & 3) << 26) +#define GEN8_MCR_SLICE_MASK GEN8_MCR_SLICE(3) +#define GEN8_MCR_SUBSLICE(subslice) (((subslice) & 3) << 24) +#define GEN8_MCR_SUBSLICE_MASK GEN8_MCR_SUBSLICE(3) +#define GEN11_MCR_SLICE(slice) (((slice) & 0xf) << 27) +#define GEN11_MCR_SLICE_MASK GEN11_MCR_SLICE(0xf) +#define GEN11_MCR_SUBSLICE(subslice) (((subslice) & 0x7) << 24) +#define GEN11_MCR_SUBSLICE_MASK GEN11_MCR_SUBSLICE(0x7) + +#define IPEIR_I965 _MMIO(0x2064) +#define IPEHR_I965 _MMIO(0x2068) + +/* + * On GEN4, only the render ring INSTDONE exists and has a different + * layout than the GEN7+ version. + * The GEN2 counterpart of this register is GEN2_INSTDONE. + */ +#define INSTPS _MMIO(0x2070) /* 965+ only */ +#define GEN4_INSTDONE1 _MMIO(0x207c) /* 965+ only, aka INSTDONE_2 on SNB */ +#define ACTHD_I965 _MMIO(0x2074) +#define HWS_PGA _MMIO(0x2080) +#define HWS_ADDRESS_MASK 0xfffff000 +#define HWS_START_ADDRESS_SHIFT 4 + +#define _3D_CHICKEN _MMIO(0x2084) +#define _3D_CHICKEN_HIZ_PLANE_DISABLE_MSAA_4X_SNB (1 << 10) + +#define PWRCTXA _MMIO(0x2088) /* 965GM+ only */ +#define PWRCTX_EN (1 << 0) + +#define FF_SLICE_CHICKEN _MMIO(0x2088) +#define FF_SLICE_CHICKEN_CL_PROVOKING_VERTEX_FIX (1 << 1) + +/* GM45+ chicken bits -- debug workaround bits that may be required + * for various sorts of correct behavior. The top 16 bits of each are + * the enables for writing to the corresponding low bit. + */ +#define _3D_CHICKEN2 _MMIO(0x208c) +/* Disables pipelining of read flushes past the SF-WIZ interface. + * Required on all Ironlake steppings according to the B-Spec, but the + * particular danger of not doing so is not specified. + */ +#define _3D_CHICKEN2_WM_READ_PIPELINED (1 << 14) + +#define _3D_CHICKEN3 _MMIO(0x2090) +#define _3D_CHICKEN_SF_PROVOKING_VERTEX_FIX (1 << 12) +#define _3D_CHICKEN_SF_DISABLE_OBJEND_CULL (1 << 10) +#define _3D_CHICKEN3_AA_LINE_QUALITY_FIX_ENABLE (1 << 5) +#define _3D_CHICKEN3_SF_DISABLE_FASTCLIP_CULL (1 << 5) +#define _3D_CHICKEN_SDE_LIMIT_FIFO_POLY_DEPTH(x) ((x) << 1) /* gen8+ */ +#define _3D_CHICKEN3_SF_DISABLE_PIPELINED_ATTR_FETCH (1 << 1) /* gen6 */ + +#define GEN2_INSTDONE _MMIO(0x2090) +#define NOPID _MMIO(0x2094) +#define HWSTAM _MMIO(0x2098) + +#define WAIT_FOR_RC6_EXIT _MMIO(0x20cc) +/* HSW only */ +#define HSW_SELECTIVE_READ_ADDRESSING_SHIFT 2 +#define HSW_SELECTIVE_READ_ADDRESSING_MASK (0x3 << HSW_SLECTIVE_READ_ADDRESSING_SHIFT) +#define HSW_SELECTIVE_WRITE_ADDRESS_SHIFT 4 +#define HSW_SELECTIVE_WRITE_ADDRESS_MASK (0x7 << HSW_SELECTIVE_WRITE_ADDRESS_SHIFT) +/* HSW+ */ +#define HSW_WAIT_FOR_RC6_EXIT_ENABLE (1 << 0) +#define HSW_RCS_CONTEXT_ENABLE (1 << 7) +#define HSW_RCS_INHIBIT (1 << 8) +/* Gen8 */ +#define GEN8_SELECTIVE_WRITE_ADDRESS_SHIFT 4 +#define GEN8_SELECTIVE_WRITE_ADDRESS_MASK (0x3 << GEN8_SELECTIVE_WRITE_ADDRESS_SHIFT) +#define GEN8_SELECTIVE_WRITE_ADDRESS_SHIFT 4 +#define GEN8_SELECTIVE_WRITE_ADDRESS_MASK (0x3 << GEN8_SELECTIVE_WRITE_ADDRESS_SHIFT) +#define GEN8_SELECTIVE_WRITE_ADDRESSING_ENABLE (1 << 6) +#define GEN8_SELECTIVE_READ_SUBSLICE_SELECT_SHIFT 9 +#define GEN8_SELECTIVE_READ_SUBSLICE_SELECT_MASK (0x3 << GEN8_SELECTIVE_READ_SUBSLICE_SELECT_SHIFT) +#define GEN8_SELECTIVE_READ_SLICE_SELECT_SHIFT 11 +#define GEN8_SELECTIVE_READ_SLICE_SELECT_MASK (0x3 << GEN8_SELECTIVE_READ_SLICE_SELECT_SHIFT) +#define GEN8_SELECTIVE_READ_ADDRESSING_ENABLE (1 << 13) + +#define GEN6_GT_MODE _MMIO(0x20d0) +#define GEN6_WIZ_HASHING(hi, lo) (((hi) << 9) | ((lo) << 7)) +#define GEN6_WIZ_HASHING_8x8 GEN6_WIZ_HASHING(0, 0) +#define GEN6_WIZ_HASHING_8x4 GEN6_WIZ_HASHING(0, 1) +#define GEN6_WIZ_HASHING_16x4 GEN6_WIZ_HASHING(1, 0) +#define GEN6_WIZ_HASHING_MASK GEN6_WIZ_HASHING(1, 1) +#define GEN6_TD_FOUR_ROW_DISPATCH_DISABLE (1 << 5) + +/* chicken reg for WaConextSwitchWithConcurrentTLBInvalidate */ +#define GEN9_CSFE_CHICKEN1_RCS _MMIO(0x20d4) +#define GEN9_PREEMPT_GPGPU_SYNC_SWITCH_DISABLE (1 << 2) +#define GEN11_ENABLE_32_PLANE_MODE (1 << 7) + +#define GEN7_FF_SLICE_CS_CHICKEN1 _MMIO(0x20e0) +#define GEN9_FFSC_PERCTX_PREEMPT_CTRL (1 << 14) + +#define FF_SLICE_CS_CHICKEN2 _MMIO(0x20e4) +#define GEN9_TSG_BARRIER_ACK_DISABLE (1 << 8) +#define GEN9_POOLED_EU_LOAD_BALANCING_FIX_DISABLE (1 << 10) + +#define GEN9_CS_DEBUG_MODE1 _MMIO(0x20ec) +#define FF_DOP_CLOCK_GATE_DISABLE REG_BIT(1) +#define GEN12_CS_DEBUG_MODE1_CCCSUNIT_BE_COMMON _MMIO(0x20ec) +#define GEN12_REPLAY_MODE_GRANULARITY REG_BIT(0) + +/* WaClearTdlStateAckDirtyBits */ +#define GEN8_STATE_ACK _MMIO(0x20f0) +#define GEN9_STATE_ACK_SLICE1 _MMIO(0x20f8) +#define GEN9_STATE_ACK_SLICE2 _MMIO(0x2100) +#define GEN9_STATE_ACK_TDL0 (1 << 12) +#define GEN9_STATE_ACK_TDL1 (1 << 13) +#define GEN9_STATE_ACK_TDL2 (1 << 14) +#define GEN9_STATE_ACK_TDL3 (1 << 15) +#define GEN9_SUBSLICE_TDL_ACK_BITS \ + (GEN9_STATE_ACK_TDL3 | GEN9_STATE_ACK_TDL2 | \ + GEN9_STATE_ACK_TDL1 | GEN9_STATE_ACK_TDL0) + +#define CACHE_MODE_0 _MMIO(0x2120) /* 915+ only */ +#define CM0_PIPELINED_RENDER_FLUSH_DISABLE (1 << 8) +#define CM0_IZ_OPT_DISABLE (1 << 6) +#define CM0_ZR_OPT_DISABLE (1 << 5) +#define CM0_STC_EVICT_DISABLE_LRA_SNB (1 << 5) +#define CM0_DEPTH_EVICT_DISABLE (1 << 4) +#define CM0_COLOR_EVICT_DISABLE (1 << 3) +#define CM0_DEPTH_WRITE_DISABLE (1 << 1) +#define CM0_RC_OP_FLUSH_DISABLE (1 << 0) + +#define GFX_FLSH_CNTL _MMIO(0x2170) /* 915+ only */ + +/* + * Logical Context regs + */ +/* + * Notes on SNB/IVB/VLV context size: + * - Power context is saved elsewhere (LLC or stolen) + * - Ring/execlist context is saved on SNB, not on IVB + * - Extended context size already includes render context size + * - We always need to follow the extended context size. + * SNB BSpec has comments indicating that we should use the + * render context size instead if execlists are disabled, but + * based on empirical testing that's just nonsense. + * - Pipelined/VF state is saved on SNB/IVB respectively + * - GT1 size just indicates how much of render context + * doesn't need saving on GT1 + */ +#define CXT_SIZE _MMIO(0x21a0) +#define GEN6_CXT_POWER_SIZE(cxt_reg) (((cxt_reg) >> 24) & 0x3f) +#define GEN6_CXT_RING_SIZE(cxt_reg) (((cxt_reg) >> 18) & 0x3f) +#define GEN6_CXT_RENDER_SIZE(cxt_reg) (((cxt_reg) >> 12) & 0x3f) +#define GEN6_CXT_EXTENDED_SIZE(cxt_reg) (((cxt_reg) >> 6) & 0x3f) +#define GEN6_CXT_PIPELINE_SIZE(cxt_reg) (((cxt_reg) >> 0) & 0x3f) +#define GEN6_CXT_TOTAL_SIZE(cxt_reg) (GEN6_CXT_RING_SIZE(cxt_reg) + \ + GEN6_CXT_EXTENDED_SIZE(cxt_reg) + \ + GEN6_CXT_PIPELINE_SIZE(cxt_reg)) +#define GEN7_CXT_SIZE _MMIO(0x21a8) +#define GEN7_CXT_POWER_SIZE(ctx_reg) (((ctx_reg) >> 25) & 0x7f) +#define GEN7_CXT_RING_SIZE(ctx_reg) (((ctx_reg) >> 22) & 0x7) +#define GEN7_CXT_RENDER_SIZE(ctx_reg) (((ctx_reg) >> 16) & 0x3f) +#define GEN7_CXT_EXTENDED_SIZE(ctx_reg) (((ctx_reg) >> 9) & 0x7f) +#define GEN7_CXT_GT1_SIZE(ctx_reg) (((ctx_reg) >> 6) & 0x7) +#define GEN7_CXT_VFSTATE_SIZE(ctx_reg) (((ctx_reg) >> 0) & 0x3f) +#define GEN7_CXT_TOTAL_SIZE(ctx_reg) (GEN7_CXT_EXTENDED_SIZE(ctx_reg) + \ + GEN7_CXT_VFSTATE_SIZE(ctx_reg)) + +#define HSW_MI_PREDICATE_RESULT_2 _MMIO(0x2214) + +#define GEN9_CTX_PREEMPT_REG _MMIO(0x2248) +#define GEN12_DISABLE_POSH_BUSY_FF_DOP_CG REG_BIT(11) + +#define GPGPU_THREADS_DISPATCHED _MMIO(0x2290) +#define GPGPU_THREADS_DISPATCHED_UDW _MMIO(0x2290 + 4) + +#define GEN9_RCS_FE_FSM2 _MMIO(0x22a4) +#define GEN6_RCS_PWR_FSM _MMIO(0x22ac) + +#define HS_INVOCATION_COUNT _MMIO(0x2300) +#define HS_INVOCATION_COUNT_UDW _MMIO(0x2300 + 4) +#define DS_INVOCATION_COUNT _MMIO(0x2308) +#define DS_INVOCATION_COUNT_UDW _MMIO(0x2308 + 4) +#define IA_VERTICES_COUNT _MMIO(0x2310) +#define IA_VERTICES_COUNT_UDW _MMIO(0x2310 + 4) +#define IA_PRIMITIVES_COUNT _MMIO(0x2318) +#define IA_PRIMITIVES_COUNT_UDW _MMIO(0x2318 + 4) +#define VS_INVOCATION_COUNT _MMIO(0x2320) +#define VS_INVOCATION_COUNT_UDW _MMIO(0x2320 + 4) +#define GS_INVOCATION_COUNT _MMIO(0x2328) +#define GS_INVOCATION_COUNT_UDW _MMIO(0x2328 + 4) +#define GS_PRIMITIVES_COUNT _MMIO(0x2330) +#define GS_PRIMITIVES_COUNT_UDW _MMIO(0x2330 + 4) +#define CL_INVOCATION_COUNT _MMIO(0x2338) +#define CL_INVOCATION_COUNT_UDW _MMIO(0x2338 + 4) +#define CL_PRIMITIVES_COUNT _MMIO(0x2340) +#define CL_PRIMITIVES_COUNT_UDW _MMIO(0x2340 + 4) +#define PS_INVOCATION_COUNT _MMIO(0x2348) +#define PS_INVOCATION_COUNT_UDW _MMIO(0x2348 + 4) +#define PS_DEPTH_COUNT _MMIO(0x2350) +#define PS_DEPTH_COUNT_UDW _MMIO(0x2350 + 4) +#define GEN7_3DPRIM_END_OFFSET _MMIO(0x2420) +#define GEN7_3DPRIM_START_VERTEX _MMIO(0x2430) +#define GEN7_3DPRIM_VERTEX_COUNT _MMIO(0x2434) +#define GEN7_3DPRIM_INSTANCE_COUNT _MMIO(0x2438) +#define GEN7_3DPRIM_START_INSTANCE _MMIO(0x243c) +#define GEN7_3DPRIM_BASE_VERTEX _MMIO(0x2440) +#define GEN7_GPGPU_DISPATCHDIMX _MMIO(0x2500) +#define GEN7_GPGPU_DISPATCHDIMY _MMIO(0x2504) +#define GEN7_GPGPU_DISPATCHDIMZ _MMIO(0x2508) + +#define GFX_MODE _MMIO(0x2520) + +#define GEN8_CS_CHICKEN1 _MMIO(0x2580) +#define GEN9_PREEMPT_3D_OBJECT_LEVEL (1 << 0) +#define GEN9_PREEMPT_GPGPU_LEVEL(hi, lo) (((hi) << 2) | ((lo) << 1)) +#define GEN9_PREEMPT_GPGPU_MID_THREAD_LEVEL GEN9_PREEMPT_GPGPU_LEVEL(0, 0) +#define GEN9_PREEMPT_GPGPU_THREAD_GROUP_LEVEL GEN9_PREEMPT_GPGPU_LEVEL(0, 1) +#define GEN9_PREEMPT_GPGPU_COMMAND_LEVEL GEN9_PREEMPT_GPGPU_LEVEL(1, 0) +#define GEN9_PREEMPT_GPGPU_LEVEL_MASK GEN9_PREEMPT_GPGPU_LEVEL(1, 1) + +#define GEN12_GLOBAL_MOCS(i) _MMIO(0x4000 + (i) * 4) /* Global MOCS regs */ + +#define RENDER_HWS_PGA_GEN7 _MMIO(0x4080) + +#define GEN8_GAMW_ECO_DEV_RW_IA _MMIO(0x4080) +#define GAMW_ECO_ENABLE_64K_IPS_FIELD 0xF +#define GAMW_ECO_DEV_CTX_RELOAD_DISABLE (1 << 7) + +#define GAM_ECOCHK _MMIO(0x4090) +#define BDW_DISABLE_HDC_INVALIDATION (1 << 25) +#define ECOCHK_SNB_BIT (1 << 10) +#define ECOCHK_DIS_TLB (1 << 8) +#define HSW_ECOCHK_ARB_PRIO_SOL (1 << 6) +#define ECOCHK_PPGTT_CACHE64B (0x3 << 3) +#define ECOCHK_PPGTT_CACHE4B (0x0 << 3) +#define ECOCHK_PPGTT_GFDT_IVB (0x1 << 4) +#define ECOCHK_PPGTT_LLC_IVB (0x1 << 3) +#define ECOCHK_PPGTT_UC_HSW (0x1 << 3) +#define ECOCHK_PPGTT_WT_HSW (0x2 << 3) +#define ECOCHK_PPGTT_WB_HSW (0x3 << 3) + +#define GEN8_RING_FAULT_REG _MMIO(0x4094) +#define _RING_FAULT_REG_RCS 0x4094 +#define _RING_FAULT_REG_VCS 0x4194 +#define _RING_FAULT_REG_BCS 0x4294 +#define _RING_FAULT_REG_VECS 0x4394 +#define RING_FAULT_REG(engine) _MMIO(_PICK((engine)->class, \ + _RING_FAULT_REG_RCS, \ + _RING_FAULT_REG_VCS, \ + _RING_FAULT_REG_VECS, \ + _RING_FAULT_REG_BCS)) + +#define ERROR_GEN6 _MMIO(0x40a0) + +#define DONE_REG _MMIO(0x40b0) +#define GEN8_PRIVATE_PAT_LO _MMIO(0x40e0) +#define GEN8_PRIVATE_PAT_HI _MMIO(0x40e0 + 4) +#define GEN10_PAT_INDEX(index) _MMIO(0x40e0 + (index) * 4) +#define BSD_HWS_PGA_GEN7 _MMIO(0x4180) +#define GEN12_GFX_CCS_AUX_NV _MMIO(0x4208) +#define GEN12_VD0_AUX_NV _MMIO(0x4218) +#define GEN12_VD1_AUX_NV _MMIO(0x4228) + +#define GEN8_RTCR _MMIO(0x4260) +#define GEN8_M1TCR _MMIO(0x4264) +#define GEN8_M2TCR _MMIO(0x4268) +#define GEN8_BTCR _MMIO(0x426c) +#define GEN8_VTCR _MMIO(0x4270) + +#define GEN12_VD2_AUX_NV _MMIO(0x4298) +#define GEN12_VD3_AUX_NV _MMIO(0x42a8) +#define GEN12_VE0_AUX_NV _MMIO(0x4238) + +#define BLT_HWS_PGA_GEN7 _MMIO(0x4280) + +#define GEN12_VE1_AUX_NV _MMIO(0x42b8) +#define AUX_INV REG_BIT(0) +#define VEBOX_HWS_PGA_GEN7 _MMIO(0x4380) + +#define GEN12_AUX_ERR_DBG _MMIO(0x43f4) + +#define GEN7_TLB_RD_ADDR _MMIO(0x4700) + +#define GEN12_PAT_INDEX(index) _MMIO(0x4800 + (index) * 4) + ++#define XEHPSDV_FLAT_CCS_BASE_ADDR _MMIO(0x4910) ++#define XEHPSDV_CCS_BASE_SHIFT 8 ++ +#define GAMTARBMODE _MMIO(0x4a08) +#define ARB_MODE_BWGTLB_DISABLE (1 << 9) +#define ARB_MODE_SWIZZLE_BDW (1 << 1) + +#define GEN9_GAMT_ECO_REG_RW_IA _MMIO(0x4ab0) +#define GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS (1 << 18) + +#define GAMT_CHKN_BIT_REG _MMIO(0x4ab8) +#define GAMT_CHKN_DISABLE_L3_COH_PIPE (1 << 31) +#define GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING (1 << 28) +#define GAMT_CHKN_DISABLE_I2M_CYCLE_ON_WR_PORT (1 << 24) + +#define GEN8_FAULT_TLB_DATA0 _MMIO(0x4b10) +#define GEN8_FAULT_TLB_DATA1 _MMIO(0x4b14) + +#define GEN11_GACB_PERF_CTRL _MMIO(0x4b80) +#define GEN11_HASH_CTRL_MASK (0x3 << 12 | 0xf << 0) +#define GEN11_HASH_CTRL_BIT0 (1 << 0) +#define GEN11_HASH_CTRL_BIT4 (1 << 12) + +/* gamt regs */ +#define GEN8_L3_LRA_1_GPGPU _MMIO(0x4dd4) +#define GEN8_L3_LRA_1_GPGPU_DEFAULT_VALUE_BDW 0x67F1427F /* max/min for LRA1/2 */ +#define GEN8_L3_LRA_1_GPGPU_DEFAULT_VALUE_CHV 0x5FF101FF /* max/min for LRA1/2 */ +#define GEN9_L3_LRA_1_GPGPU_DEFAULT_VALUE_SKL 0x67F1427F /* " " */ +#define GEN9_L3_LRA_1_GPGPU_DEFAULT_VALUE_BXT 0x5FF101FF /* " " */ + +#define MMCD_MISC_CTRL _MMIO(0x4ddc) /* skl+ */ +#define MMCD_PCLA (1 << 31) +#define MMCD_HOTSPOT_EN (1 << 27) + +/* There are the 4 64-bit counter registers, one for each stream output */ +#define GEN7_SO_NUM_PRIMS_WRITTEN(n) _MMIO(0x5200 + (n) * 8) +#define GEN7_SO_NUM_PRIMS_WRITTEN_UDW(n) _MMIO(0x5200 + (n) * 8 + 4) + +#define GEN7_SO_PRIM_STORAGE_NEEDED(n) _MMIO(0x5240 + (n) * 8) +#define GEN7_SO_PRIM_STORAGE_NEEDED_UDW(n) _MMIO(0x5240 + (n) * 8 + 4) + +#define GEN9_WM_CHICKEN3 _MMIO(0x5588) +#define GEN9_FACTOR_IN_CLR_VAL_HIZ (1 << 9) + +#define VFLSKPD _MMIO(0x62a8) +#define DIS_OVER_FETCH_CACHE REG_BIT(1) +#define DIS_MULT_MISS_RD_SQUASH REG_BIT(0) + +#define FF_MODE2 _MMIO(0x6604) +#define FF_MODE2_GS_TIMER_MASK REG_GENMASK(31, 24) +#define FF_MODE2_GS_TIMER_224 REG_FIELD_PREP(FF_MODE2_GS_TIMER_MASK, 224) +#define FF_MODE2_TDS_TIMER_MASK REG_GENMASK(23, 16) +#define FF_MODE2_TDS_TIMER_128 REG_FIELD_PREP(FF_MODE2_TDS_TIMER_MASK, 4) + +#define XEHPG_INSTDONE_GEOM_SVG _MMIO(0x666c) + +#define CACHE_MODE_0_GEN7 _MMIO(0x7000) /* IVB+ */ +#define RC_OP_FLUSH_ENABLE (1 << 0) +#define HIZ_RAW_STALL_OPT_DISABLE (1 << 2) +#define CACHE_MODE_1 _MMIO(0x7004) /* IVB+ */ +#define PIXEL_SUBSPAN_COLLECT_OPT_DISABLE (1 << 6) +#define GEN8_4x4_STC_OPTIMIZATION_DISABLE (1 << 6) +#define GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE (1 << 1) + +#define GEN7_GT_MODE _MMIO(0x7008) +#define GEN9_IZ_HASHING_MASK(slice) (0x3 << ((slice) * 2)) +#define GEN9_IZ_HASHING(slice, val) ((val) << ((slice) * 2)) + +/* GEN7 chicken */ +#define GEN7_COMMON_SLICE_CHICKEN1 _MMIO(0x7010) +#define GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC (1 << 10) +#define GEN9_RHWO_OPTIMIZATION_DISABLE (1 << 14) + +#define COMMON_SLICE_CHICKEN2 _MMIO(0x7014) +#define GEN9_PBE_COMPRESSED_HASH_SELECTION (1 << 13) +#define GEN9_DISABLE_GATHER_AT_SET_SHADER_COMMON_SLICE (1 << 12) +#define GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION (1 << 8) +#define GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE (1 << 0) + +#define HIZ_CHICKEN _MMIO(0x7018) +#define CHV_HZ_8X8_MODE_IN_1X REG_BIT(15) +#define DG1_HZ_READ_SUPPRESSION_OPTIMIZATION_DISABLE REG_BIT(14) +#define BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE REG_BIT(3) + +#define GEN8_L3CNTLREG _MMIO(0x7034) +#define GEN8_ERRDETBCTRL (1 << 9) + +#define GEN7_SC_INSTDONE _MMIO(0x7100) +#define GEN12_SC_INSTDONE_EXTRA _MMIO(0x7104) +#define GEN12_SC_INSTDONE_EXTRA2 _MMIO(0x7108) + +/* GEN8 chicken */ +#define HDC_CHICKEN0 _MMIO(0x7300) +#define HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE (1 << 15) +#define HDC_FENCE_DEST_SLM_DISABLE (1 << 14) +#define HDC_DONOT_FETCH_MEM_WHEN_MASKED (1 << 11) +#define HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT (1 << 5) +#define HDC_FORCE_NON_COHERENT (1 << 4) +#define HDC_BARRIER_PERFORMANCE_DISABLE (1 << 10) + +#define GEN8_HDC_CHICKEN1 _MMIO(0x7304) + +#define GEN11_COMMON_SLICE_CHICKEN3 _MMIO(0x7304) +#define DG1_FLOAT_POINT_BLEND_OPT_STRICT_MODE_EN REG_BIT(12) +#define XEHP_DUAL_SIMD8_SEQ_MERGE_DISABLE REG_BIT(12) +#define GEN11_BLEND_EMB_FIX_DISABLE_IN_RCC REG_BIT(11) +#define GEN12_DISABLE_CPS_AWARE_COLOR_PIPE REG_BIT(9) + +/* GEN9 chicken */ +#define SLICE_ECO_CHICKEN0 _MMIO(0x7308) +#define PIXEL_MASK_CAMMING_DISABLE (1 << 14) + +#define GEN9_SLICE_COMMON_ECO_CHICKEN0 _MMIO(0x7308) +#define DISABLE_PIXEL_MASK_CAMMING (1 << 14) + +#define GEN9_SLICE_COMMON_ECO_CHICKEN1 _MMIO(0x731c) +#define GEN11_STATE_CACHE_REDIRECT_TO_CS (1 << 11) + +#define SLICE_COMMON_ECO_CHICKEN1 _MMIO(0x731c) +#define MSC_MSAA_REODER_BUF_BYPASS_DISABLE REG_BIT(14) + +#define GEN9_SLICE_PGCTL_ACK(slice) _MMIO(0x804c + (slice) * 0x4) +#define GEN10_SLICE_PGCTL_ACK(slice) _MMIO(0x804c + ((slice) / 3) * 0x34 + \ + ((slice) % 3) * 0x4) +#define GEN9_PGCTL_SLICE_ACK (1 << 0) +#define GEN9_PGCTL_SS_ACK(subslice) (1 << (2 + (subslice) * 2)) +#define GEN10_PGCTL_VALID_SS_MASK(slice) ((slice) == 0 ? 0x7F : 0x1F) + +#define GEN9_SS01_EU_PGCTL_ACK(slice) _MMIO(0x805c + (slice) * 0x8) +#define GEN10_SS01_EU_PGCTL_ACK(slice) _MMIO(0x805c + ((slice) / 3) * 0x30 + \ + ((slice) % 3) * 0x8) +#define GEN9_SS23_EU_PGCTL_ACK(slice) _MMIO(0x8060 + (slice) * 0x8) +#define GEN10_SS23_EU_PGCTL_ACK(slice) _MMIO(0x8060 + ((slice) / 3) * 0x30 + \ + ((slice) % 3) * 0x8) +#define GEN9_PGCTL_SSA_EU08_ACK (1 << 0) +#define GEN9_PGCTL_SSA_EU19_ACK (1 << 2) +#define GEN9_PGCTL_SSA_EU210_ACK (1 << 4) +#define GEN9_PGCTL_SSA_EU311_ACK (1 << 6) +#define GEN9_PGCTL_SSB_EU08_ACK (1 << 8) +#define GEN9_PGCTL_SSB_EU19_ACK (1 << 10) +#define GEN9_PGCTL_SSB_EU210_ACK (1 << 12) +#define GEN9_PGCTL_SSB_EU311_ACK (1 << 14) + +#define GEN8_RC6_CTX_INFO _MMIO(0x8504) + +#define GEN12_SQCM _MMIO(0x8724) +#define EN_32B_ACCESS REG_BIT(30) + +#define HSW_IDICR _MMIO(0x9008) +#define IDIHASHMSK(x) (((x) & 0x3f) << 16) + +#define GEN6_MBCUNIT_SNPCR _MMIO(0x900c) /* for LLC config */ +#define GEN6_MBC_SNPCR_SHIFT 21 +#define GEN6_MBC_SNPCR_MASK (3 << 21) +#define GEN6_MBC_SNPCR_MAX (0 << 21) +#define GEN6_MBC_SNPCR_MED (1 << 21) +#define GEN6_MBC_SNPCR_LOW (2 << 21) +#define GEN6_MBC_SNPCR_MIN (3 << 21) /* only 1/16th of the cache is shared */ + +#define VLV_G3DCTL _MMIO(0x9024) +#define VLV_GSCKGCTL _MMIO(0x9028) + +/* WaCatErrorRejectionIssue */ +#define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG _MMIO(0x9030) +#define GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB (1 << 11) + +#define FBC_LLC_READ_CTRL _MMIO(0x9044) +#define FBC_LLC_FULLY_OPEN REG_BIT(30) + +#define GEN6_MBCTL _MMIO(0x907c) +#define GEN6_MBCTL_ENABLE_BOOT_FETCH (1 << 4) +#define GEN6_MBCTL_CTX_FETCH_NEEDED (1 << 3) +#define GEN6_MBCTL_BME_UPDATE_ENABLE (1 << 2) +#define GEN6_MBCTL_MAE_UPDATE_ENABLE (1 << 1) +#define GEN6_MBCTL_BOOT_FETCH_MECH (1 << 0) + +/* Fuse readout registers for GT */ +#define GEN10_MIRROR_FUSE3 _MMIO(0x9118) +#define GEN10_L3BANK_PAIR_COUNT 4 +#define GEN10_L3BANK_MASK 0x0F +/* on Xe_HP the same fuses indicates mslices instead of L3 banks */ +#define GEN12_MAX_MSLICES 4 +#define GEN12_MEML3_EN_MASK 0x0F + +#define HSW_PAVP_FUSE1 _MMIO(0x911c) +#define XEHP_SFC_ENABLE_MASK REG_GENMASK(27, 24) +#define HSW_F1_EU_DIS_MASK REG_GENMASK(17, 16) +#define HSW_F1_EU_DIS_10EUS 0 +#define HSW_F1_EU_DIS_8EUS 1 +#define HSW_F1_EU_DIS_6EUS 2 + +#define GEN8_FUSE2 _MMIO(0x9120) +#define GEN8_F2_SS_DIS_SHIFT 21 +#define GEN8_F2_SS_DIS_MASK (0x7 << GEN8_F2_SS_DIS_SHIFT) +#define GEN8_F2_S_ENA_SHIFT 25 +#define GEN8_F2_S_ENA_MASK (0x7 << GEN8_F2_S_ENA_SHIFT) +#define GEN9_F2_SS_DIS_SHIFT 20 +#define GEN9_F2_SS_DIS_MASK (0xf << GEN9_F2_SS_DIS_SHIFT) +#define GEN10_F2_S_ENA_SHIFT 22 +#define GEN10_F2_S_ENA_MASK (0x3f << GEN10_F2_S_ENA_SHIFT) +#define GEN10_F2_SS_DIS_SHIFT 18 +#define GEN10_F2_SS_DIS_MASK (0xf << GEN10_F2_SS_DIS_SHIFT) + +#define GEN8_EU_DISABLE0 _MMIO(0x9134) +#define GEN9_EU_DISABLE(slice) _MMIO(0x9134 + (slice) * 0x4) +#define GEN11_EU_DISABLE _MMIO(0x9134) +#define GEN8_EU_DIS0_S0_MASK 0xffffff +#define GEN8_EU_DIS0_S1_SHIFT 24 +#define GEN8_EU_DIS0_S1_MASK (0xff << GEN8_EU_DIS0_S1_SHIFT) +#define GEN11_EU_DIS_MASK 0xFF +#define XEHP_EU_ENABLE _MMIO(0x9134) +#define XEHP_EU_ENA_MASK 0xFF + +#define GEN8_EU_DISABLE1 _MMIO(0x9138) +#define GEN8_EU_DIS1_S1_MASK 0xffff +#define GEN8_EU_DIS1_S2_SHIFT 16 +#define GEN8_EU_DIS1_S2_MASK (0xffff << GEN8_EU_DIS1_S2_SHIFT) + +#define GEN11_GT_SLICE_ENABLE _MMIO(0x9138) +#define GEN11_GT_S_ENA_MASK 0xFF + +#define GEN8_EU_DISABLE2 _MMIO(0x913c) +#define GEN8_EU_DIS2_S2_MASK 0xff + +#define GEN11_GT_SUBSLICE_DISABLE _MMIO(0x913c) +#define GEN12_GT_GEOMETRY_DSS_ENABLE _MMIO(0x913c) + +#define GEN10_EU_DISABLE3 _MMIO(0x9140) +#define GEN10_EU_DIS_SS_MASK 0xff +#define GEN11_GT_VEBOX_VDBOX_DISABLE _MMIO(0x9140) +#define GEN11_GT_VDBOX_DISABLE_MASK 0xff +#define GEN11_GT_VEBOX_DISABLE_SHIFT 16 +#define GEN11_GT_VEBOX_DISABLE_MASK (0x0f << GEN11_GT_VEBOX_DISABLE_SHIFT) + +#define GEN12_GT_COMPUTE_DSS_ENABLE _MMIO(0x9144) + +#define GEN6_UCGCTL1 _MMIO(0x9400) +#define GEN6_GAMUNIT_CLOCK_GATE_DISABLE (1 << 22) +#define GEN6_EU_TCUNIT_CLOCK_GATE_DISABLE (1 << 16) +#define GEN6_BLBUNIT_CLOCK_GATE_DISABLE (1 << 5) +#define GEN6_CSUNIT_CLOCK_GATE_DISABLE (1 << 7) + +#define GEN6_UCGCTL2 _MMIO(0x9404) +#define GEN6_VFUNIT_CLOCK_GATE_DISABLE (1 << 31) +#define GEN7_VDSUNIT_CLOCK_GATE_DISABLE (1 << 30) +#define GEN7_TDLUNIT_CLOCK_GATE_DISABLE (1 << 22) +#define GEN6_RCZUNIT_CLOCK_GATE_DISABLE (1 << 13) +#define GEN6_RCPBUNIT_CLOCK_GATE_DISABLE (1 << 12) +#define GEN6_RCCUNIT_CLOCK_GATE_DISABLE (1 << 11) + +#define GEN6_UCGCTL3 _MMIO(0x9408) +#define GEN6_OACSUNIT_CLOCK_GATE_DISABLE (1 << 20) + +#define GEN7_UCGCTL4 _MMIO(0x940c) +#define GEN7_L3BANK2X_CLOCK_GATE_DISABLE (1 << 25) +#define GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE (1 << 14) + +#define GEN6_RCGCTL1 _MMIO(0x9410) +#define GEN6_RCGCTL2 _MMIO(0x9414) + +#define GEN6_GDRST _MMIO(0x941c) +#define GEN6_GRDOM_FULL (1 << 0) +#define GEN6_GRDOM_RENDER (1 << 1) +#define GEN6_GRDOM_MEDIA (1 << 2) +#define GEN6_GRDOM_BLT (1 << 3) +#define GEN6_GRDOM_VECS (1 << 4) +#define GEN9_GRDOM_GUC (1 << 5) +#define GEN8_GRDOM_MEDIA2 (1 << 7) +/* GEN11 changed all bit defs except for FULL & RENDER */ +#define GEN11_GRDOM_FULL GEN6_GRDOM_FULL +#define GEN11_GRDOM_RENDER GEN6_GRDOM_RENDER +#define GEN11_GRDOM_BLT (1 << 2) +#define GEN11_GRDOM_GUC (1 << 3) +#define GEN11_GRDOM_MEDIA (1 << 5) +#define GEN11_GRDOM_MEDIA2 (1 << 6) +#define GEN11_GRDOM_MEDIA3 (1 << 7) +#define GEN11_GRDOM_MEDIA4 (1 << 8) +#define GEN11_GRDOM_MEDIA5 (1 << 9) +#define GEN11_GRDOM_MEDIA6 (1 << 10) +#define GEN11_GRDOM_MEDIA7 (1 << 11) +#define GEN11_GRDOM_MEDIA8 (1 << 12) +#define GEN11_GRDOM_VECS (1 << 13) +#define GEN11_GRDOM_VECS2 (1 << 14) +#define GEN11_GRDOM_VECS3 (1 << 15) +#define GEN11_GRDOM_VECS4 (1 << 16) +#define GEN11_GRDOM_SFC0 (1 << 17) +#define GEN11_GRDOM_SFC1 (1 << 18) +#define GEN11_GRDOM_SFC2 (1 << 19) +#define GEN11_GRDOM_SFC3 (1 << 20) +#define GEN11_VCS_SFC_RESET_BIT(instance) (GEN11_GRDOM_SFC0 << ((instance) >> 1)) +#define GEN11_VECS_SFC_RESET_BIT(instance) (GEN11_GRDOM_SFC0 << (instance)) + +#define GEN6_RSTCTL _MMIO(0x9420) + +#define GEN7_MISCCPCTL _MMIO(0x9424) +#define GEN7_DOP_CLOCK_GATE_ENABLE (1 << 0) +#define GEN8_DOP_CLOCK_GATE_CFCLK_ENABLE (1 << 2) +#define GEN8_DOP_CLOCK_GATE_GUC_ENABLE (1 << 4) +#define GEN8_DOP_CLOCK_GATE_MEDIA_ENABLE (1 << 6) + +#define GEN8_UCGCTL6 _MMIO(0x9430) +#define GEN8_GAPSUNIT_CLOCK_GATE_DISABLE (1 << 24) +#define GEN8_SDEUNIT_CLOCK_GATE_DISABLE (1 << 14) +#define GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ (1 << 28) + +#define UNSLCGCTL9430 _MMIO(0x9430) +#define MSQDUNIT_CLKGATE_DIS REG_BIT(3) + +#define UNSLICE_UNIT_LEVEL_CLKGATE _MMIO(0x9434) +#define VFUNIT_CLKGATE_DIS REG_BIT(20) +#define TSGUNIT_CLKGATE_DIS REG_BIT(17) /* XEHPSDV */ +#define CG3DDISCFEG_CLKGATE_DIS REG_BIT(17) /* DG2 */ +#define GAMEDIA_CLKGATE_DIS REG_BIT(11) +#define HSUNIT_CLKGATE_DIS REG_BIT(8) +#define VSUNIT_CLKGATE_DIS REG_BIT(3) + +#define UNSLCGCTL9440 _MMIO(0x9440) +#define GAMTLBOACS_CLKGATE_DIS REG_BIT(28) +#define GAMTLBVDBOX5_CLKGATE_DIS REG_BIT(27) +#define GAMTLBVDBOX6_CLKGATE_DIS REG_BIT(26) +#define GAMTLBVDBOX3_CLKGATE_DIS REG_BIT(24) +#define GAMTLBVDBOX4_CLKGATE_DIS REG_BIT(23) +#define GAMTLBVDBOX7_CLKGATE_DIS REG_BIT(22) +#define GAMTLBVDBOX2_CLKGATE_DIS REG_BIT(21) +#define GAMTLBVDBOX0_CLKGATE_DIS REG_BIT(17) +#define GAMTLBKCR_CLKGATE_DIS REG_BIT(16) +#define GAMTLBGUC_CLKGATE_DIS REG_BIT(15) +#define GAMTLBBLT_CLKGATE_DIS REG_BIT(14) +#define GAMTLBVDBOX1_CLKGATE_DIS REG_BIT(6) + +#define UNSLCGCTL9444 _MMIO(0x9444) +#define GAMTLBGFXA0_CLKGATE_DIS REG_BIT(30) +#define GAMTLBGFXA1_CLKGATE_DIS REG_BIT(29) +#define GAMTLBCOMPA0_CLKGATE_DIS REG_BIT(28) +#define GAMTLBCOMPA1_CLKGATE_DIS REG_BIT(27) +#define GAMTLBCOMPB0_CLKGATE_DIS REG_BIT(26) +#define GAMTLBCOMPB1_CLKGATE_DIS REG_BIT(25) +#define GAMTLBCOMPC0_CLKGATE_DIS REG_BIT(24) +#define GAMTLBCOMPC1_CLKGATE_DIS REG_BIT(23) +#define GAMTLBCOMPD0_CLKGATE_DIS REG_BIT(22) +#define GAMTLBCOMPD1_CLKGATE_DIS REG_BIT(21) +#define GAMTLBMERT_CLKGATE_DIS REG_BIT(20) +#define GAMTLBVEBOX3_CLKGATE_DIS REG_BIT(19) +#define GAMTLBVEBOX2_CLKGATE_DIS REG_BIT(18) +#define GAMTLBVEBOX1_CLKGATE_DIS REG_BIT(17) +#define GAMTLBVEBOX0_CLKGATE_DIS REG_BIT(16) +#define LTCDD_CLKGATE_DIS REG_BIT(10) + +#define SLICE_UNIT_LEVEL_CLKGATE _MMIO(0x94d4) +#define SARBUNIT_CLKGATE_DIS (1 << 5) +#define RCCUNIT_CLKGATE_DIS (1 << 7) +#define MSCUNIT_CLKGATE_DIS (1 << 10) +#define NODEDSS_CLKGATE_DIS REG_BIT(12) +#define L3_CLKGATE_DIS REG_BIT(16) +#define L3_CR2X_CLKGATE_DIS REG_BIT(17) + +#define SCCGCTL94DC _MMIO(0x94dc) +#define CG3DDISURB REG_BIT(14) + +#define UNSLICE_UNIT_LEVEL_CLKGATE2 _MMIO(0x94e4) +#define VSUNIT_CLKGATE_DIS_TGL REG_BIT(19) +#define PSDUNIT_CLKGATE_DIS REG_BIT(5) + +#define SUBSLICE_UNIT_LEVEL_CLKGATE _MMIO(0x9524) +#define DSS_ROUTER_CLKGATE_DIS REG_BIT(28) +#define GWUNIT_CLKGATE_DIS REG_BIT(16) + +#define SUBSLICE_UNIT_LEVEL_CLKGATE2 _MMIO(0x9528) +#define CPSSUNIT_CLKGATE_DIS REG_BIT(9) + +#define SSMCGCTL9530 _MMIO(0x9530) +#define RTFUNIT_CLKGATE_DIS REG_BIT(18) + +#define GEN10_DFR_RATIO_EN_AND_CHICKEN _MMIO(0x9550) +#define DFR_DISABLE (1 << 9) + +#define INF_UNIT_LEVEL_CLKGATE _MMIO(0x9560) +#define CGPSF_CLKGATE_DIS (1 << 3) + +#define MICRO_BP0_0 _MMIO(0x9800) +#define MICRO_BP0_2 _MMIO(0x9804) +#define MICRO_BP0_1 _MMIO(0x9808) +#define MICRO_BP1_0 _MMIO(0x980c) +#define MICRO_BP1_2 _MMIO(0x9810) +#define MICRO_BP1_1 _MMIO(0x9814) +#define MICRO_BP2_0 _MMIO(0x9818) +#define MICRO_BP2_2 _MMIO(0x981c) +#define MICRO_BP2_1 _MMIO(0x9820) +#define MICRO_BP3_0 _MMIO(0x9824) +#define MICRO_BP3_2 _MMIO(0x9828) +#define MICRO_BP3_1 _MMIO(0x982c) +#define MICRO_BP_TRIGGER _MMIO(0x9830) +#define MICRO_BP3_COUNT_STATUS01 _MMIO(0x9834) +#define MICRO_BP3_COUNT_STATUS23 _MMIO(0x9838) +#define MICRO_BP_FIRED_ARMED _MMIO(0x983c) + +#define GEN6_GFXPAUSE _MMIO(0xa000) +#define GEN6_RPNSWREQ _MMIO(0xa008) +#define GEN6_TURBO_DISABLE (1 << 31) +#define GEN6_FREQUENCY(x) ((x) << 25) +#define HSW_FREQUENCY(x) ((x) << 24) +#define GEN9_FREQUENCY(x) ((x) << 23) +#define GEN6_OFFSET(x) ((x) << 19) +#define GEN6_AGGRESSIVE_TURBO (0 << 15) +#define GEN9_SW_REQ_UNSLICE_RATIO_SHIFT 23 +#define GEN9_IGNORE_SLICE_RATIO (0 << 0) + +#define GEN6_RC_VIDEO_FREQ _MMIO(0xa00c) +#define GEN6_RC_CTL_RC6pp_ENABLE (1 << 16) +#define GEN6_RC_CTL_RC6p_ENABLE (1 << 17) +#define GEN6_RC_CTL_RC6_ENABLE (1 << 18) +#define GEN6_RC_CTL_RC1e_ENABLE (1 << 20) +#define GEN6_RC_CTL_RC7_ENABLE (1 << 22) +#define VLV_RC_CTL_CTX_RST_PARALLEL (1 << 24) +#define GEN7_RC_CTL_TO_MODE (1 << 28) +#define GEN6_RC_CTL_EI_MODE(x) ((x) << 27) +#define GEN6_RC_CTL_HW_ENABLE (1 << 31) +#define GEN6_RP_DOWN_TIMEOUT _MMIO(0xa010) +#define GEN6_RP_INTERRUPT_LIMITS _MMIO(0xa014) +#define GEN6_RPSTAT1 _MMIO(0xa01c) +#define GEN6_CAGF_SHIFT 8 +#define HSW_CAGF_SHIFT 7 +#define GEN9_CAGF_SHIFT 23 +#define GEN6_CAGF_MASK (0x7f << GEN6_CAGF_SHIFT) +#define HSW_CAGF_MASK (0x7f << HSW_CAGF_SHIFT) +#define GEN9_CAGF_MASK (0x1ff << GEN9_CAGF_SHIFT) +#define GEN6_RP_CONTROL _MMIO(0xa024) +#define GEN6_RP_MEDIA_TURBO (1 << 11) +#define GEN6_RP_MEDIA_MODE_MASK (3 << 9) +#define GEN6_RP_MEDIA_HW_TURBO_MODE (3 << 9) +#define GEN6_RP_MEDIA_HW_NORMAL_MODE (2 << 9) +#define GEN6_RP_MEDIA_HW_MODE (1 << 9) +#define GEN6_RP_MEDIA_SW_MODE (0 << 9) +#define GEN6_RP_MEDIA_IS_GFX (1 << 8) +#define GEN6_RP_ENABLE (1 << 7) +#define GEN6_RP_UP_IDLE_MIN (0x1 << 3) +#define GEN6_RP_UP_BUSY_AVG (0x2 << 3) +#define GEN6_RP_UP_BUSY_CONT (0x4 << 3) +#define GEN6_RP_DOWN_IDLE_AVG (0x2 << 0) +#define GEN6_RP_DOWN_IDLE_CONT (0x1 << 0) +#define GEN6_RPSWCTL_SHIFT 9 +#define GEN9_RPSWCTL_ENABLE (0x2 << GEN6_RPSWCTL_SHIFT) +#define GEN9_RPSWCTL_DISABLE (0x0 << GEN6_RPSWCTL_SHIFT) +#define GEN6_RP_UP_THRESHOLD _MMIO(0xa02c) +#define GEN6_RP_DOWN_THRESHOLD _MMIO(0xa030) +#define GEN6_RP_CUR_UP_EI _MMIO(0xa050) +#define GEN6_RP_EI_MASK 0xffffff +#define GEN6_CURICONT_MASK GEN6_RP_EI_MASK +#define GEN6_RP_CUR_UP _MMIO(0xa054) +#define GEN6_CURBSYTAVG_MASK GEN6_RP_EI_MASK +#define GEN6_RP_PREV_UP _MMIO(0xa058) +#define GEN6_RP_CUR_DOWN_EI _MMIO(0xa05c) +#define GEN6_CURIAVG_MASK GEN6_RP_EI_MASK +#define GEN6_RP_CUR_DOWN _MMIO(0xa060) +#define GEN6_RP_PREV_DOWN _MMIO(0xa064) +#define GEN6_RP_UP_EI _MMIO(0xa068) +#define GEN6_RP_DOWN_EI _MMIO(0xa06c) +#define GEN6_RP_IDLE_HYSTERSIS _MMIO(0xa070) +#define GEN6_RPDEUHWTC _MMIO(0xa080) +#define GEN6_RPDEUC _MMIO(0xa084) +#define GEN6_RPDEUCSW _MMIO(0xa088) +#define GEN6_RC_CONTROL _MMIO(0xa090) +#define GEN6_RC_STATE _MMIO(0xa094) +#define RC_SW_TARGET_STATE_SHIFT 16 +#define RC_SW_TARGET_STATE_MASK (7 << RC_SW_TARGET_STATE_SHIFT) +#define GEN6_RC1_WAKE_RATE_LIMIT _MMIO(0xa098) +#define GEN6_RC6_WAKE_RATE_LIMIT _MMIO(0xa09c) +#define GEN6_RC6pp_WAKE_RATE_LIMIT _MMIO(0xa0a0) +#define GEN10_MEDIA_WAKE_RATE_LIMIT _MMIO(0xa0a0) +#define GEN6_RC_EVALUATION_INTERVAL _MMIO(0xa0a8) +#define GEN6_RC_IDLE_HYSTERSIS _MMIO(0xa0ac) +#define GEN6_RC_SLEEP _MMIO(0xa0b0) +#define GEN6_RCUBMABDTMR _MMIO(0xa0b0) +#define GEN6_RC1e_THRESHOLD _MMIO(0xa0b4) +#define GEN6_RC6_THRESHOLD _MMIO(0xa0b8) +#define GEN6_RC6p_THRESHOLD _MMIO(0xa0bc) +#define VLV_RCEDATA _MMIO(0xa0bc) +#define GEN6_RC6pp_THRESHOLD _MMIO(0xa0c0) +#define GEN9_MEDIA_PG_IDLE_HYSTERESIS _MMIO(0xa0c4) +#define GEN9_RENDER_PG_IDLE_HYSTERESIS _MMIO(0xa0c8) + +#define GEN6_PMINTRMSK _MMIO(0xa168) +#define GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC (1 << 31) +#define ARAT_EXPIRED_INTRMSK (1 << 9) + +#define GEN8_MISC_CTRL0 _MMIO(0xa180) + +#define ECOBUS _MMIO(0xa180) +#define FORCEWAKE_MT_ENABLE (1 << 5) + +#define FORCEWAKE_MT _MMIO(0xa188) /* multi-threaded */ +#define FORCEWAKE_GT_GEN9 _MMIO(0xa188) +#define FORCEWAKE _MMIO(0xa18c) + +#define VLV_SPAREG2H _MMIO(0xa194) + +#define GEN9_PG_ENABLE _MMIO(0xa210) +#define GEN9_RENDER_PG_ENABLE REG_BIT(0) +#define GEN9_MEDIA_PG_ENABLE REG_BIT(1) +#define GEN11_MEDIA_SAMPLER_PG_ENABLE REG_BIT(2) +#define VDN_HCP_POWERGATE_ENABLE(n) REG_BIT(3 + 2 * (n)) +#define VDN_MFX_POWERGATE_ENABLE(n) REG_BIT(4 + 2 * (n)) + +#define GEN8_PUSHBUS_CONTROL _MMIO(0xa248) +#define GEN8_PUSHBUS_ENABLE _MMIO(0xa250) +#define GEN8_PUSHBUS_SHIFT _MMIO(0xa25c) + +/* GPM unit config (Gen9+) */ +#define CTC_MODE _MMIO(0xa26c) +#define CTC_SOURCE_PARAMETER_MASK 1 +#define CTC_SOURCE_CRYSTAL_CLOCK 0 +#define CTC_SOURCE_DIVIDE_LOGIC 1 +#define CTC_SHIFT_PARAMETER_SHIFT 1 +#define CTC_SHIFT_PARAMETER_MASK (0x3 << CTC_SHIFT_PARAMETER_SHIFT) + +#define FORCEWAKE_MEDIA_GEN9 _MMIO(0xa270) +#define FORCEWAKE_RENDER_GEN9 _MMIO(0xa278) + +#define VLV_PWRDWNUPCTL _MMIO(0xa294) + +#define GEN9_PWRGT_DOMAIN_STATUS _MMIO(0xa2a0) +#define GEN9_PWRGT_MEDIA_STATUS_MASK (1 << 0) +#define GEN9_PWRGT_RENDER_STATUS_MASK (1 << 1) + +#define MISC_STATUS0 _MMIO(0xa500) +#define MISC_STATUS1 _MMIO(0xa504) + +#define FORCEWAKE_MEDIA_VDBOX_GEN11(n) _MMIO(0xa540 + (n) * 4) +#define FORCEWAKE_MEDIA_VEBOX_GEN11(n) _MMIO(0xa560 + (n) * 4) + +#define CHV_POWER_SS0_SIG1 _MMIO(0xa720) +#define CHV_POWER_SS0_SIG2 _MMIO(0xa724) +#define CHV_POWER_SS1_SIG1 _MMIO(0xa728) +#define CHV_SS_PG_ENABLE (1 << 1) +#define CHV_EU08_PG_ENABLE (1 << 9) +#define CHV_EU19_PG_ENABLE (1 << 17) +#define CHV_EU210_PG_ENABLE (1 << 25) +#define CHV_POWER_SS1_SIG2 _MMIO(0xa72c) +#define CHV_EU311_PG_ENABLE (1 << 1) + +#define GEN7_SARCHKMD _MMIO(0xb000) +#define GEN7_DISABLE_DEMAND_PREFETCH (1 << 31) +#define GEN7_DISABLE_SAMPLER_PREFETCH (1 << 30) + +#define GEN8_GARBCNTL _MMIO(0xb004) +#define GEN9_GAPS_TSV_CREDIT_DISABLE (1 << 7) +#define GEN11_ARBITRATION_PRIO_ORDER_MASK (0x3f << 22) +#define GEN11_HASH_CTRL_EXCL_MASK (0x7f << 0) +#define GEN11_HASH_CTRL_EXCL_BIT0 (1 << 0) + +#define GEN9_SCRATCH_LNCF1 _MMIO(0xb008) +#define GEN9_LNCF_NONIA_COHERENT_ATOMICS_ENABLE REG_BIT(0) + +#define GEN7_L3SQCREG1 _MMIO(0xb010) +#define VLV_B0_WA_L3SQCREG1_VALUE 0x00D30000 + +#define GEN7_L3CNTLREG1 _MMIO(0xb01c) +#define GEN7_WA_FOR_GEN7_L3_CONTROL 0x3C47FF8C +#define GEN7_L3AGDIS (1 << 19) +#define GEN7_L3CNTLREG2 _MMIO(0xb020) + +/* MOCS (Memory Object Control State) registers */ +#define GEN9_LNCFCMOCS(i) _MMIO(0xb020 + (i) * 4) /* L3 Cache Control */ +#define GEN9_LNCFCMOCS_REG_COUNT 32 + +#define GEN7_L3CNTLREG3 _MMIO(0xb024) + +#define GEN7_L3_CHICKEN_MODE_REGISTER _MMIO(0xb030) +#define GEN7_WA_L3_CHICKEN_MODE 0x20000000 + +#define GEN7_L3SQCREG4 _MMIO(0xb034) +#define L3SQ_URB_READ_CAM_MATCH_DISABLE (1 << 27) + +#define HSW_SCRATCH1 _MMIO(0xb038) +#define HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE (1 << 27) + +#define GEN7_L3LOG(slice, i) _MMIO(0xb070 + (slice) * 0x200 + (i) * 4) +#define GEN7_L3LOG_SIZE 0x80 + +#define GEN10_SCRATCH_LNCF2 _MMIO(0xb0a0) +#define PMFLUSHDONE_LNICRSDROP (1 << 20) +#define PMFLUSH_GAPL3UNBLOCK (1 << 21) +#define PMFLUSHDONE_LNEBLK (1 << 22) + +#define XEHP_L3NODEARBCFG _MMIO(0xb0b4) +#define XEHP_LNESPARE REG_BIT(19) + +#define GEN8_L3SQCREG1 _MMIO(0xb100) +/* + * Note that on CHV the following has an off-by-one error wrt. to BSpec. + * Using the formula in BSpec leads to a hang, while the formula here works + * fine and matches the formulas for all other platforms. A BSpec change + * request has been filed to clarify this. + */ +#define L3_GENERAL_PRIO_CREDITS(x) (((x) >> 1) << 19) +#define L3_HIGH_PRIO_CREDITS(x) (((x) >> 1) << 14) +#define L3_PRIO_CREDITS_MASK ((0x1f << 19) | (0x1f << 14)) + +#define GEN10_L3_CHICKEN_MODE_REGISTER _MMIO(0xb114) +#define GEN11_I2M_WRITE_DISABLE (1 << 28) + +#define GEN8_L3SQCREG4 _MMIO(0xb118) +#define GEN11_LQSC_CLEAN_EVICT_DISABLE (1 << 6) +#define GEN8_LQSC_RO_PERF_DIS (1 << 27) +#define GEN8_LQSC_FLUSH_COHERENT_LINES (1 << 21) +#define GEN8_LQSQ_NONIA_COHERENT_ATOMICS_ENABLE REG_BIT(22) + +#define GEN9_SCRATCH1 _MMIO(0xb11c) +#define EVICTION_PERF_FIX_ENABLE REG_BIT(8) + +#define BDW_SCRATCH1 _MMIO(0xb11c) +#define GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE (1 << 2) + +#define GEN11_SCRATCH2 _MMIO(0xb140) +#define GEN11_COHERENT_PARTIAL_WRITE_MERGE_ENABLE (1 << 19) + +#define GEN11_L3SQCREG5 _MMIO(0xb158) +#define L3_PWM_TIMER_INIT_VAL_MASK REG_GENMASK(9, 0) + +#define MLTICTXCTL _MMIO(0xb170) +#define TDONRENDER REG_BIT(2) + +#define XEHP_L3SCQREG7 _MMIO(0xb188) +#define BLEND_FILL_CACHING_OPT_DIS REG_BIT(3) + +#define L3SQCREG1_CCS0 _MMIO(0xb200) +#define FLUSHALLNONCOH REG_BIT(5) + +#define GEN11_GLBLINVL _MMIO(0xb404) +#define GEN11_BANK_HASH_ADDR_EXCL_MASK (0x7f << 5) +#define GEN11_BANK_HASH_ADDR_EXCL_BIT0 (1 << 5) + +#define GEN11_LSN_UNSLCVC _MMIO(0xb43c) +#define GEN11_LSN_UNSLCVC_GAFS_HALF_CL2_MAXALLOC (1 << 9) +#define GEN11_LSN_UNSLCVC_GAFS_HALF_SF_MAXALLOC (1 << 7) + +#define __GEN9_RCS0_MOCS0 0xc800 +#define GEN9_GFX_MOCS(i) _MMIO(__GEN9_RCS0_MOCS0 + (i) * 4) +#define __GEN9_VCS0_MOCS0 0xc900 +#define GEN9_MFX0_MOCS(i) _MMIO(__GEN9_VCS0_MOCS0 + (i) * 4) +#define __GEN9_VCS1_MOCS0 0xca00 +#define GEN9_MFX1_MOCS(i) _MMIO(__GEN9_VCS1_MOCS0 + (i) * 4) +#define __GEN9_VECS0_MOCS0 0xcb00 +#define GEN9_VEBOX_MOCS(i) _MMIO(__GEN9_VECS0_MOCS0 + (i) * 4) +#define __GEN9_BCS0_MOCS0 0xcc00 +#define GEN9_BLT_MOCS(i) _MMIO(__GEN9_BCS0_MOCS0 + (i) * 4) + +#define GEN12_FAULT_TLB_DATA0 _MMIO(0xceb8) +#define GEN12_FAULT_TLB_DATA1 _MMIO(0xcebc) +#define FAULT_VA_HIGH_BITS (0xf << 0) +#define FAULT_GTT_SEL (1 << 4) + +#define GEN12_RING_FAULT_REG _MMIO(0xcec4) +#define GEN8_RING_FAULT_ENGINE_ID(x) (((x) >> 12) & 0x7) +#define RING_FAULT_GTTSEL_MASK (1 << 11) +#define RING_FAULT_SRCID(x) (((x) >> 3) & 0xff) +#define RING_FAULT_FAULT_TYPE(x) (((x) >> 1) & 0x3) +#define RING_FAULT_VALID (1 << 0) + +#define GEN12_GFX_TLB_INV_CR _MMIO(0xced8) +#define GEN12_VD_TLB_INV_CR _MMIO(0xcedc) +#define GEN12_VE_TLB_INV_CR _MMIO(0xcee0) +#define GEN12_BLT_TLB_INV_CR _MMIO(0xcee4) + +#define GEN12_MERT_MOD_CTRL _MMIO(0xcf28) +#define RENDER_MOD_CTRL _MMIO(0xcf2c) +#define COMP_MOD_CTRL _MMIO(0xcf30) +#define VDBX_MOD_CTRL _MMIO(0xcf34) +#define VEBX_MOD_CTRL _MMIO(0xcf38) +#define FORCE_MISS_FTLB REG_BIT(3) + +#define GEN12_GAMSTLB_CTRL _MMIO(0xcf4c) +#define CONTROL_BLOCK_CLKGATE_DIS REG_BIT(12) +#define EGRESS_BLOCK_CLKGATE_DIS REG_BIT(11) +#define TAG_BLOCK_CLKGATE_DIS REG_BIT(7) + +#define GEN12_GAMCNTRL_CTRL _MMIO(0xcf54) +#define INVALIDATION_BROADCAST_MODE_DIS REG_BIT(12) +#define GLOBAL_INVALIDATION_MODE REG_BIT(2) + +#define GEN12_GAM_DONE _MMIO(0xcf68) + +#define GEN7_HALF_SLICE_CHICKEN1 _MMIO(0xe100) /* IVB GT1 + VLV */ +#define GEN7_MAX_PS_THREAD_DEP (8 << 12) +#define GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE (1 << 10) +#define GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE (1 << 4) +#define GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE (1 << 3) + +#define GEN7_SAMPLER_INSTDONE _MMIO(0xe160) +#define GEN7_ROW_INSTDONE _MMIO(0xe164) + +#define HALF_SLICE_CHICKEN2 _MMIO(0xe180) +#define GEN8_ST_PO_DISABLE (1 << 13) + +#define HALF_SLICE_CHICKEN3 _MMIO(0xe184) +#define HSW_SAMPLE_C_PERFORMANCE (1 << 9) +#define GEN8_CENTROID_PIXEL_OPT_DIS (1 << 8) +#define GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC (1 << 5) +#define GEN8_SAMPLER_POWER_BYPASS_DIS (1 << 1) + +#define GEN9_HALF_SLICE_CHICKEN5 _MMIO(0xe188) +#define GEN9_DG_MIRROR_FIX_ENABLE (1 << 5) +#define GEN9_CCS_TLB_PREFETCH_ENABLE (1 << 3) + +#define GEN10_SAMPLER_MODE _MMIO(0xe18c) +#define ENABLE_SMALLPL REG_BIT(15) +#define GEN11_SAMPLER_ENABLE_HEADLESS_MSG REG_BIT(5) + +#define GEN9_HALF_SLICE_CHICKEN7 _MMIO(0xe194) +#define DG2_DISABLE_ROUND_ENABLE_ALLOW_FOR_SSLA REG_BIT(15) +#define GEN9_SAMPLER_HASH_COMPRESSED_READ_ADDR REG_BIT(8) +#define GEN9_ENABLE_YV12_BUGFIX REG_BIT(4) +#define GEN9_ENABLE_GPGPU_PREEMPTION REG_BIT(2) + +#define GEN10_CACHE_MODE_SS _MMIO(0xe420) +#define ENABLE_PREFETCH_INTO_IC REG_BIT(3) +#define FLOAT_BLEND_OPTIMIZATION_ENABLE REG_BIT(4) + +#define EU_PERF_CNTL0 _MMIO(0xe458) +#define EU_PERF_CNTL4 _MMIO(0xe45c) + +#define GEN9_ROW_CHICKEN4 _MMIO(0xe48c) +#define GEN12_DISABLE_GRF_CLEAR REG_BIT(13) ++#define XEHP_DIS_BBL_SYSPIPE REG_BIT(11) +#define GEN12_DISABLE_TDL_PUSH REG_BIT(9) +#define GEN11_DIS_PICK_2ND_EU REG_BIT(7) +#define GEN12_DISABLE_HDR_PAST_PAYLOAD_HOLD_FIX REG_BIT(4) + +#define HSW_ROW_CHICKEN3 _MMIO(0xe49c) +#define HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE (1 << 6) + +#define GEN8_ROW_CHICKEN _MMIO(0xe4f0) +#define FLOW_CONTROL_ENABLE REG_BIT(15) +#define UGM_BACKUP_MODE REG_BIT(13) +#define MDQ_ARBITRATION_MODE REG_BIT(12) +#define PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE REG_BIT(8) +#define STALL_DOP_GATING_DISABLE REG_BIT(5) +#define THROTTLE_12_5 REG_GENMASK(4, 2) +#define DISABLE_EARLY_EOT REG_BIT(1) + +#define GEN7_ROW_CHICKEN2 _MMIO(0xe4f4) +#define GEN12_DISABLE_READ_SUPPRESSION REG_BIT(15) +#define GEN12_DISABLE_EARLY_READ REG_BIT(14) +#define GEN12_ENABLE_LARGE_GRF_MODE REG_BIT(12) +#define GEN12_PUSH_CONST_DEREF_HOLD_DIS REG_BIT(8) + +#define RT_CTRL _MMIO(0xe530) +#define DIS_NULL_QUERY REG_BIT(10) + +#define EU_PERF_CNTL1 _MMIO(0xe558) +#define EU_PERF_CNTL5 _MMIO(0xe55c) + +#define GEN12_HDC_CHICKEN0 _MMIO(0xe5f0) +#define LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK REG_GENMASK(13, 11) +#define ICL_HDC_MODE _MMIO(0xe5f4) + +#define EU_PERF_CNTL2 _MMIO(0xe658) +#define EU_PERF_CNTL6 _MMIO(0xe65c) +#define EU_PERF_CNTL3 _MMIO(0xe758) + +#define LSC_CHICKEN_BIT_0 _MMIO(0xe7c8) +#define FORCE_1_SUB_MESSAGE_PER_FRAGMENT REG_BIT(15) +#define LSC_CHICKEN_BIT_0_UDW _MMIO(0xe7c8 + 4) +#define DIS_CHAIN_2XSIMD8 REG_BIT(55 - 32) +#define FORCE_SLM_FENCE_SCOPE_TO_TILE REG_BIT(42 - 32) +#define FORCE_UGM_FENCE_SCOPE_TO_TILE REG_BIT(41 - 32) +#define MAXREQS_PER_BANK REG_GENMASK(39 - 32, 37 - 32) +#define DISABLE_128B_EVICTION_COMMAND_UDW REG_BIT(36 - 32) + +#define SARB_CHICKEN1 _MMIO(0xe90c) +#define COMP_CKN_IN REG_GENMASK(30, 29) + +#define GEN7_HALF_SLICE_CHICKEN1_GT2 _MMIO(0xf100) + +#define GEN7_ROW_CHICKEN2_GT2 _MMIO(0xf4f4) +#define DOP_CLOCK_GATING_DISABLE (1 << 0) +#define PUSH_CONSTANT_DEREF_DISABLE (1 << 8) +#define GEN11_TDL_CLOCK_GATING_FIX_DISABLE (1 << 1) + +#define __GEN11_VCS2_MOCS0 0x10000 +#define GEN11_MFX2_MOCS(i) _MMIO(__GEN11_VCS2_MOCS0 + (i) * 4) + +#define CRSTANDVID _MMIO(0x11100) +#define PXVFREQ(fstart) _MMIO(0x11110 + (fstart) * 4) /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */ +#define PXVFREQ_PX_MASK 0x7f000000 +#define PXVFREQ_PX_SHIFT 24 +#define VIDFREQ_BASE _MMIO(0x11110) +#define VIDFREQ1 _MMIO(0x11110) /* VIDFREQ1-4 (0x1111c) (Cantiga) */ +#define VIDFREQ2 _MMIO(0x11114) +#define VIDFREQ3 _MMIO(0x11118) +#define VIDFREQ4 _MMIO(0x1111c) +#define VIDFREQ_P0_MASK 0x1f000000 +#define VIDFREQ_P0_SHIFT 24 +#define VIDFREQ_P0_CSCLK_MASK 0x00f00000 +#define VIDFREQ_P0_CSCLK_SHIFT 20 +#define VIDFREQ_P0_CRCLK_MASK 0x000f0000 +#define VIDFREQ_P0_CRCLK_SHIFT 16 +#define VIDFREQ_P1_MASK 0x00001f00 +#define VIDFREQ_P1_SHIFT 8 +#define VIDFREQ_P1_CSCLK_MASK 0x000000f0 +#define VIDFREQ_P1_CSCLK_SHIFT 4 +#define VIDFREQ_P1_CRCLK_MASK 0x0000000f +#define INTTOEXT_BASE _MMIO(0x11120) /* INTTOEXT1-8 (0x1113c) */ +#define INTTOEXT_MAP3_SHIFT 24 +#define INTTOEXT_MAP3_MASK (0x1f << INTTOEXT_MAP3_SHIFT) +#define INTTOEXT_MAP2_SHIFT 16 +#define INTTOEXT_MAP2_MASK (0x1f << INTTOEXT_MAP2_SHIFT) +#define INTTOEXT_MAP1_SHIFT 8 +#define INTTOEXT_MAP1_MASK (0x1f << INTTOEXT_MAP1_SHIFT) +#define INTTOEXT_MAP0_SHIFT 0 +#define INTTOEXT_MAP0_MASK (0x1f << INTTOEXT_MAP0_SHIFT) +#define MEMSWCTL _MMIO(0x11170) /* Ironlake only */ +#define MEMCTL_CMD_MASK 0xe000 +#define MEMCTL_CMD_SHIFT 13 +#define MEMCTL_CMD_RCLK_OFF 0 +#define MEMCTL_CMD_RCLK_ON 1 +#define MEMCTL_CMD_CHFREQ 2 +#define MEMCTL_CMD_CHVID 3 +#define MEMCTL_CMD_VMMOFF 4 +#define MEMCTL_CMD_VMMON 5 +#define MEMCTL_CMD_STS (1 << 12) /* write 1 triggers command, clears + when command complete */ +#define MEMCTL_FREQ_MASK 0x0f00 /* jitter, from 0-15 */ +#define MEMCTL_FREQ_SHIFT 8 +#define MEMCTL_SFCAVM (1 << 7) +#define MEMCTL_TGT_VID_MASK 0x007f +#define MEMIHYST _MMIO(0x1117c) +#define MEMINTREN _MMIO(0x11180) /* 16 bits */ +#define MEMINT_RSEXIT_EN (1 << 8) +#define MEMINT_CX_SUPR_EN (1 << 7) +#define MEMINT_CONT_BUSY_EN (1 << 6) +#define MEMINT_AVG_BUSY_EN (1 << 5) +#define MEMINT_EVAL_CHG_EN (1 << 4) +#define MEMINT_MON_IDLE_EN (1 << 3) +#define MEMINT_UP_EVAL_EN (1 << 2) +#define MEMINT_DOWN_EVAL_EN (1 << 1) +#define MEMINT_SW_CMD_EN (1 << 0) +#define MEMINTRSTR _MMIO(0x11182) /* 16 bits */ +#define MEM_RSEXIT_MASK 0xc000 +#define MEM_RSEXIT_SHIFT 14 +#define MEM_CONT_BUSY_MASK 0x3000 +#define MEM_CONT_BUSY_SHIFT 12 +#define MEM_AVG_BUSY_MASK 0x0c00 +#define MEM_AVG_BUSY_SHIFT 10 +#define MEM_EVAL_CHG_MASK 0x0300 +#define MEM_EVAL_BUSY_SHIFT 8 +#define MEM_MON_IDLE_MASK 0x00c0 +#define MEM_MON_IDLE_SHIFT 6 +#define MEM_UP_EVAL_MASK 0x0030 +#define MEM_UP_EVAL_SHIFT 4 +#define MEM_DOWN_EVAL_MASK 0x000c +#define MEM_DOWN_EVAL_SHIFT 2 +#define MEM_SW_CMD_MASK 0x0003 +#define MEM_INT_STEER_GFX 0 +#define MEM_INT_STEER_CMR 1 +#define MEM_INT_STEER_SMI 2 +#define MEM_INT_STEER_SCI 3 +#define MEMINTRSTS _MMIO(0x11184) +#define MEMINT_RSEXIT (1 << 7) +#define MEMINT_CONT_BUSY (1 << 6) +#define MEMINT_AVG_BUSY (1 << 5) +#define MEMINT_EVAL_CHG (1 << 4) +#define MEMINT_MON_IDLE (1 << 3) +#define MEMINT_UP_EVAL (1 << 2) +#define MEMINT_DOWN_EVAL (1 << 1) +#define MEMINT_SW_CMD (1 << 0) +#define MEMMODECTL _MMIO(0x11190) +#define MEMMODE_BOOST_EN (1 << 31) +#define MEMMODE_BOOST_FREQ_MASK 0x0f000000 /* jitter for boost, 0-15 */ +#define MEMMODE_BOOST_FREQ_SHIFT 24 +#define MEMMODE_IDLE_MODE_MASK 0x00030000 +#define MEMMODE_IDLE_MODE_SHIFT 16 +#define MEMMODE_IDLE_MODE_EVAL 0 +#define MEMMODE_IDLE_MODE_CONT 1 +#define MEMMODE_HWIDLE_EN (1 << 15) +#define MEMMODE_SWMODE_EN (1 << 14) +#define MEMMODE_RCLK_GATE (1 << 13) +#define MEMMODE_HW_UPDATE (1 << 12) +#define MEMMODE_FSTART_MASK 0x00000f00 /* starting jitter, 0-15 */ +#define MEMMODE_FSTART_SHIFT 8 +#define MEMMODE_FMAX_MASK 0x000000f0 /* max jitter, 0-15 */ +#define MEMMODE_FMAX_SHIFT 4 +#define MEMMODE_FMIN_MASK 0x0000000f /* min jitter, 0-15 */ +#define RCBMAXAVG _MMIO(0x1119c) +#define MEMSWCTL2 _MMIO(0x1119e) /* Cantiga only */ +#define SWMEMCMD_RENDER_OFF (0 << 13) +#define SWMEMCMD_RENDER_ON (1 << 13) +#define SWMEMCMD_SWFREQ (2 << 13) +#define SWMEMCMD_TARVID (3 << 13) +#define SWMEMCMD_VRM_OFF (4 << 13) +#define SWMEMCMD_VRM_ON (5 << 13) +#define CMDSTS (1 << 12) +#define SFCAVM (1 << 11) +#define SWFREQ_MASK 0x0380 /* P0-7 */ +#define SWFREQ_SHIFT 7 +#define TARVID_MASK 0x001f +#define MEMSTAT_CTG _MMIO(0x111a0) +#define RCBMINAVG _MMIO(0x111a0) +#define RCUPEI _MMIO(0x111b0) +#define RCDNEI _MMIO(0x111b4) +#define RSTDBYCTL _MMIO(0x111b8) +#define RS1EN (1 << 31) +#define RS2EN (1 << 30) +#define RS3EN (1 << 29) +#define D3RS3EN (1 << 28) /* Display D3 imlies RS3 */ +#define SWPROMORSX (1 << 27) /* RSx promotion timers ignored */ +#define RCWAKERW (1 << 26) /* Resetwarn from PCH causes wakeup */ +#define DPRSLPVREN (1 << 25) /* Fast voltage ramp enable */ +#define GFXTGHYST (1 << 24) /* Hysteresis to allow trunk gating */ +#define RCX_SW_EXIT (1 << 23) /* Leave RSx and prevent re-entry */ +#define RSX_STATUS_MASK (7 << 20) +#define RSX_STATUS_ON (0 << 20) +#define RSX_STATUS_RC1 (1 << 20) +#define RSX_STATUS_RC1E (2 << 20) +#define RSX_STATUS_RS1 (3 << 20) +#define RSX_STATUS_RS2 (4 << 20) /* aka rc6 */ +#define RSX_STATUS_RSVD (5 << 20) /* deep rc6 unsupported on ilk */ +#define RSX_STATUS_RS3 (6 << 20) /* rs3 unsupported on ilk */ +#define RSX_STATUS_RSVD2 (7 << 20) +#define UWRCRSXE (1 << 19) /* wake counter limit prevents rsx */ +#define RSCRP (1 << 18) /* rs requests control on rs1/2 reqs */ +#define JRSC (1 << 17) /* rsx coupled to cpu c-state */ +#define RS2INC0 (1 << 16) /* allow rs2 in cpu c0 */ +#define RS1CONTSAV_MASK (3 << 14) +#define RS1CONTSAV_NO_RS1 (0 << 14) /* rs1 doesn't save/restore context */ +#define RS1CONTSAV_RSVD (1 << 14) +#define RS1CONTSAV_SAVE_RS1 (2 << 14) /* rs1 saves context */ +#define RS1CONTSAV_FULL_RS1 (3 << 14) /* rs1 saves and restores context */ +#define NORMSLEXLAT_MASK (3 << 12) +#define SLOW_RS123 (0 << 12) +#define SLOW_RS23 (1 << 12) +#define SLOW_RS3 (2 << 12) +#define NORMAL_RS123 (3 << 12) +#define RCMODE_TIMEOUT (1 << 11) /* 0 is eval interval method */ +#define IMPROMOEN (1 << 10) /* promo is immediate or delayed until next idle interval (only for timeout method above) */ +#define RCENTSYNC (1 << 9) /* rs coupled to cpu c-state (3/6/7) */ +#define STATELOCK (1 << 7) /* locked to rs_cstate if 0 */ +#define RS_CSTATE_MASK (3 << 4) +#define RS_CSTATE_C367_RS1 (0 << 4) +#define RS_CSTATE_C36_RS1_C7_RS2 (1 << 4) +#define RS_CSTATE_RSVD (2 << 4) +#define RS_CSTATE_C367_RS2 (3 << 4) +#define REDSAVES (1 << 3) /* no context save if was idle during rs0 */ +#define REDRESTORES (1 << 2) /* no restore if was idle during rs0 */ +#define VIDCTL _MMIO(0x111c0) +#define VIDSTS _MMIO(0x111c8) +#define VIDSTART _MMIO(0x111cc) /* 8 bits */ +#define MEMSTAT_ILK _MMIO(0x111f8) +#define MEMSTAT_VID_MASK 0x7f00 +#define MEMSTAT_VID_SHIFT 8 +#define MEMSTAT_PSTATE_MASK 0x00f8 +#define MEMSTAT_PSTATE_SHIFT 3 +#define MEMSTAT_MON_ACTV (1 << 2) +#define MEMSTAT_SRC_CTL_MASK 0x0003 +#define MEMSTAT_SRC_CTL_CORE 0 +#define MEMSTAT_SRC_CTL_TRB 1 +#define MEMSTAT_SRC_CTL_THM 2 +#define MEMSTAT_SRC_CTL_STDBY 3 +#define PMMISC _MMIO(0x11214) +#define MCPPCE_EN (1 << 0) /* enable PM_MSG from PCH->MPC */ +#define SDEW _MMIO(0x1124c) +#define CSIEW0 _MMIO(0x11250) +#define CSIEW1 _MMIO(0x11254) +#define CSIEW2 _MMIO(0x11258) +#define PEW(i) _MMIO(0x1125c + (i) * 4) /* 5 registers */ +#define DEW(i) _MMIO(0x11270 + (i) * 4) /* 3 registers */ +#define MCHAFE _MMIO(0x112c0) +#define CSIEC _MMIO(0x112e0) +#define DMIEC _MMIO(0x112e4) +#define DDREC _MMIO(0x112e8) +#define PEG0EC _MMIO(0x112ec) +#define PEG1EC _MMIO(0x112f0) +#define GFXEC _MMIO(0x112f4) +#define INTTOEXT_BASE_ILK _MMIO(0x11300) +#define RPPREVBSYTUPAVG _MMIO(0x113b8) +#define RCPREVBSYTUPAVG _MMIO(0x113b8) +#define RCPREVBSYTDNAVG _MMIO(0x113bc) +#define RPPREVBSYTDNAVG _MMIO(0x113bc) +#define ECR _MMIO(0x11600) +#define ECR_GPFE (1 << 31) +#define ECR_IMONE (1 << 30) +#define ECR_CAP_MASK 0x0000001f /* Event range, 0-31 */ +#define OGW0 _MMIO(0x11608) +#define OGW1 _MMIO(0x1160c) +#define EG0 _MMIO(0x11610) +#define EG1 _MMIO(0x11614) +#define EG2 _MMIO(0x11618) +#define EG3 _MMIO(0x1161c) +#define EG4 _MMIO(0x11620) +#define EG5 _MMIO(0x11624) +#define EG6 _MMIO(0x11628) +#define EG7 _MMIO(0x1162c) +#define PXW(i) _MMIO(0x11664 + (i) * 4) /* 4 registers */ +#define PXWL(i) _MMIO(0x11680 + (i) * 8) /* 8 registers */ +#define LCFUSE02 _MMIO(0x116c0) +#define LCFUSE_HIV_MASK 0x000000ff + +#define GAC_ECO_BITS _MMIO(0x14090) +#define ECOBITS_SNB_BIT (1 << 13) +#define ECOBITS_PPGTT_CACHE64B (3 << 8) +#define ECOBITS_PPGTT_CACHE4B (0 << 8) + +#define CHV_FUSE_GT _MMIO(VLV_DISPLAY_BASE + 0x2168) +#define CHV_FGT_DISABLE_SS0 (1 << 10) +#define CHV_FGT_DISABLE_SS1 (1 << 11) +#define CHV_FGT_EU_DIS_SS0_R0_SHIFT 16 +#define CHV_FGT_EU_DIS_SS0_R0_MASK (0xf << CHV_FGT_EU_DIS_SS0_R0_SHIFT) +#define CHV_FGT_EU_DIS_SS0_R1_SHIFT 20 +#define CHV_FGT_EU_DIS_SS0_R1_MASK (0xf << CHV_FGT_EU_DIS_SS0_R1_SHIFT) +#define CHV_FGT_EU_DIS_SS1_R0_SHIFT 24 +#define CHV_FGT_EU_DIS_SS1_R0_MASK (0xf << CHV_FGT_EU_DIS_SS1_R0_SHIFT) +#define CHV_FGT_EU_DIS_SS1_R1_SHIFT 28 +#define CHV_FGT_EU_DIS_SS1_R1_MASK (0xf << CHV_FGT_EU_DIS_SS1_R1_SHIFT) + +#define BCS_SWCTRL _MMIO(0x22200) +#define BCS_SRC_Y REG_BIT(0) +#define BCS_DST_Y REG_BIT(1) + +#define GAB_CTL _MMIO(0x24000) +#define GAB_CTL_CONT_AFTER_PAGEFAULT (1 << 8) + +#define GEN6_PMISR _MMIO(0x44020) +#define GEN6_PMIMR _MMIO(0x44024) /* rps_lock */ +#define GEN6_PMIIR _MMIO(0x44028) +#define GEN6_PMIER _MMIO(0x4402c) +#define GEN6_PM_MBOX_EVENT (1 << 25) +#define GEN6_PM_THERMAL_EVENT (1 << 24) +/* + * For Gen11 these are in the upper word of the GPM_WGBOXPERF + * registers. Shifting is handled on accessing the imr and ier. + */ +#define GEN6_PM_RP_DOWN_TIMEOUT (1 << 6) +#define GEN6_PM_RP_UP_THRESHOLD (1 << 5) +#define GEN6_PM_RP_DOWN_THRESHOLD (1 << 4) +#define GEN6_PM_RP_UP_EI_EXPIRED (1 << 2) +#define GEN6_PM_RP_DOWN_EI_EXPIRED (1 << 1) +#define GEN6_PM_RPS_EVENTS (GEN6_PM_RP_UP_EI_EXPIRED | \ + GEN6_PM_RP_UP_THRESHOLD | \ + GEN6_PM_RP_DOWN_EI_EXPIRED | \ + GEN6_PM_RP_DOWN_THRESHOLD | \ + GEN6_PM_RP_DOWN_TIMEOUT) + +#define GEN7_GT_SCRATCH(i) _MMIO(0x4f100 + (i) * 4) +#define GEN7_GT_SCRATCH_REG_NUM 8 + +#define GFX_FLSH_CNTL_GEN6 _MMIO(0x101008) +#define GFX_FLSH_CNTL_EN (1 << 0) + +#define GTFIFODBG _MMIO(0x120000) +#define GT_FIFO_SBDEDICATE_FREE_ENTRY_CHV (0x1f << 20) +#define GT_FIFO_FREE_ENTRIES_CHV (0x7f << 13) +#define GT_FIFO_SBDROPERR (1 << 6) +#define GT_FIFO_BLOBDROPERR (1 << 5) +#define GT_FIFO_SB_READ_ABORTERR (1 << 4) +#define GT_FIFO_DROPERR (1 << 3) +#define GT_FIFO_OVFERR (1 << 2) +#define GT_FIFO_IAWRERR (1 << 1) +#define GT_FIFO_IARDERR (1 << 0) + +#define GTFIFOCTL _MMIO(0x120008) +#define GT_FIFO_FREE_ENTRIES_MASK 0x7f +#define GT_FIFO_NUM_RESERVED_ENTRIES 20 +#define GT_FIFO_CTL_BLOCK_ALL_POLICY_STALL (1 << 12) +#define GT_FIFO_CTL_RC6_POLICY_STALL (1 << 11) + +#define FORCEWAKE_MT_ACK _MMIO(0x130040) +#define FORCEWAKE_ACK_HSW _MMIO(0x130044) +#define FORCEWAKE_ACK_GT_GEN9 _MMIO(0x130044) +#define FORCEWAKE_KERNEL BIT(0) +#define FORCEWAKE_USER BIT(1) +#define FORCEWAKE_KERNEL_FALLBACK BIT(15) +#define FORCEWAKE_ACK _MMIO(0x130090) +#define VLV_GTLC_WAKE_CTRL _MMIO(0x130090) +#define VLV_GTLC_RENDER_CTX_EXISTS (1 << 25) +#define VLV_GTLC_MEDIA_CTX_EXISTS (1 << 24) +#define VLV_GTLC_ALLOWWAKEREQ (1 << 0) +#define VLV_GTLC_PW_STATUS _MMIO(0x130094) +#define VLV_GTLC_ALLOWWAKEACK (1 << 0) +#define VLV_GTLC_ALLOWWAKEERR (1 << 1) +#define VLV_GTLC_PW_MEDIA_STATUS_MASK (1 << 5) +#define VLV_GTLC_PW_RENDER_STATUS_MASK (1 << 7) +#define VLV_GTLC_SURVIVABILITY_REG _MMIO(0x130098) +#define VLV_GFX_CLK_STATUS_BIT (1 << 3) +#define VLV_GFX_CLK_FORCE_ON_BIT (1 << 2) +#define FORCEWAKE_VLV _MMIO(0x1300b0) +#define FORCEWAKE_ACK_VLV _MMIO(0x1300b4) +#define FORCEWAKE_MEDIA_VLV _MMIO(0x1300b8) +#define FORCEWAKE_ACK_MEDIA_VLV _MMIO(0x1300bc) + +#define GEN6_GT_THREAD_STATUS_REG _MMIO(0x13805c) +#define GEN6_GT_THREAD_STATUS_CORE_MASK 0x7 + +#define GEN6_GT_CORE_STATUS _MMIO(0x138060) +#define GEN6_CORE_CPD_STATE_MASK (7 << 4) +#define GEN6_RCn_MASK 7 +#define GEN6_RC0 0 +#define GEN6_RC3 2 +#define GEN6_RC6 3 +#define GEN6_RC7 4 + +#define GEN8_GT_SLICE_INFO _MMIO(0x138064) +#define GEN8_LSLICESTAT_MASK 0x7 + +#define GEN6_GT_GFX_RC6_LOCKED _MMIO(0x138104) +#define VLV_COUNTER_CONTROL _MMIO(0x138104) +#define VLV_COUNT_RANGE_HIGH (1 << 15) +#define VLV_MEDIA_RC0_COUNT_EN (1 << 5) +#define VLV_RENDER_RC0_COUNT_EN (1 << 4) +#define VLV_MEDIA_RC6_COUNT_EN (1 << 1) +#define VLV_RENDER_RC6_COUNT_EN (1 << 0) +#define GEN6_GT_GFX_RC6 _MMIO(0x138108) +#define VLV_GT_RENDER_RC6 _MMIO(0x138108) +#define VLV_GT_MEDIA_RC6 _MMIO(0x13810c) + +#define GEN6_GT_GFX_RC6p _MMIO(0x13810c) +#define GEN6_GT_GFX_RC6pp _MMIO(0x138110) +#define VLV_RENDER_C0_COUNT _MMIO(0x138118) +#define VLV_MEDIA_C0_COUNT _MMIO(0x13811c) + +#define GEN11_GT_INTR_DW(x) _MMIO(0x190018 + ((x) * 4)) +#define GEN11_CSME (31) +#define GEN11_GUNIT (28) +#define GEN11_GUC (25) +#define GEN11_WDPERF (20) +#define GEN11_KCR (19) +#define GEN11_GTPM (16) +#define GEN11_BCS (15) +#define GEN11_RCS0 (0) +#define GEN11_VECS(x) (31 - (x)) +#define GEN11_VCS(x) (x) + +#define GEN11_RENDER_COPY_INTR_ENABLE _MMIO(0x190030) +#define GEN11_VCS_VECS_INTR_ENABLE _MMIO(0x190034) +#define GEN11_GUC_SG_INTR_ENABLE _MMIO(0x190038) +#define ENGINE1_MASK REG_GENMASK(31, 16) +#define ENGINE0_MASK REG_GENMASK(15, 0) +#define GEN11_GPM_WGBOXPERF_INTR_ENABLE _MMIO(0x19003c) +#define GEN11_CRYPTO_RSVD_INTR_ENABLE _MMIO(0x190040) +#define GEN11_GUNIT_CSME_INTR_ENABLE _MMIO(0x190044) + +#define GEN11_INTR_IDENTITY_REG(x) _MMIO(0x190060 + ((x) * 4)) +#define GEN11_INTR_DATA_VALID (1 << 31) +#define GEN11_INTR_ENGINE_CLASS(x) (((x) & GENMASK(18, 16)) >> 16) +#define GEN11_INTR_ENGINE_INSTANCE(x) (((x) & GENMASK(25, 20)) >> 20) +#define GEN11_INTR_ENGINE_INTR(x) ((x) & 0xffff) +/* irq instances for OTHER_CLASS */ +#define OTHER_GUC_INSTANCE 0 +#define OTHER_GTPM_INSTANCE 1 +#define OTHER_KCR_INSTANCE 4 + +#define GEN11_IIR_REG_SELECTOR(x) _MMIO(0x190070 + ((x) * 4)) + +#define GEN11_RCS0_RSVD_INTR_MASK _MMIO(0x190090) +#define GEN11_BCS_RSVD_INTR_MASK _MMIO(0x1900a0) +#define GEN11_VCS0_VCS1_INTR_MASK _MMIO(0x1900a8) +#define GEN11_VCS2_VCS3_INTR_MASK _MMIO(0x1900ac) +#define GEN12_VCS4_VCS5_INTR_MASK _MMIO(0x1900b0) +#define GEN12_VCS6_VCS7_INTR_MASK _MMIO(0x1900b4) +#define GEN11_VECS0_VECS1_INTR_MASK _MMIO(0x1900d0) +#define GEN12_VECS2_VECS3_INTR_MASK _MMIO(0x1900d4) +#define GEN11_GUC_SG_INTR_MASK _MMIO(0x1900e8) +#define GEN11_GPM_WGBOXPERF_INTR_MASK _MMIO(0x1900ec) +#define GEN11_CRYPTO_RSVD_INTR_MASK _MMIO(0x1900f0) +#define GEN11_GUNIT_CSME_INTR_MASK _MMIO(0x1900f4) + +#define GEN12_SFC_DONE(n) _MMIO(0x1cc000 + (n) * 0x1000) + +enum { + INTEL_ADVANCED_CONTEXT = 0, + INTEL_LEGACY_32B_CONTEXT, + INTEL_ADVANCED_AD_CONTEXT, + INTEL_LEGACY_64B_CONTEXT +}; + +enum { + FAULT_AND_HANG = 0, + FAULT_AND_HALT, /* Debug only */ + FAULT_AND_STREAM, + FAULT_AND_CONTINUE /* Unsupported */ +}; + +#define CTX_GTT_ADDRESS_MASK GENMASK(31, 12) +#define GEN8_CTX_VALID (1 << 0) +#define GEN8_CTX_FORCE_PD_RESTORE (1 << 1) +#define GEN8_CTX_FORCE_RESTORE (1 << 2) +#define GEN8_CTX_L3LLC_COHERENT (1 << 5) +#define GEN8_CTX_PRIVILEGE (1 << 8) +#define GEN8_CTX_ADDRESSING_MODE_SHIFT 3 +#define GEN8_CTX_ID_SHIFT 32 +#define GEN8_CTX_ID_WIDTH 21 +#define GEN11_SW_CTX_ID_SHIFT 37 +#define GEN11_SW_CTX_ID_WIDTH 11 +#define GEN11_ENGINE_CLASS_SHIFT 61 +#define GEN11_ENGINE_CLASS_WIDTH 3 +#define GEN11_ENGINE_INSTANCE_SHIFT 48 +#define GEN11_ENGINE_INSTANCE_WIDTH 6 +#define XEHP_SW_CTX_ID_SHIFT 39 +#define XEHP_SW_CTX_ID_WIDTH 16 +#define XEHP_SW_COUNTER_SHIFT 58 +#define XEHP_SW_COUNTER_WIDTH 6 + +#endif /* __INTEL_GT_REGS__ */ diff --cc drivers/gpu/drm/i915/gt/intel_region_lmem.c index cb5a67c98f300,21215a0800886..a04e0cf4a94b9 --- a/drivers/gpu/drm/i915/gt/intel_region_lmem.c +++ b/drivers/gpu/drm/i915/gt/intel_region_lmem.c @@@ -12,6 -11,6 +12,7 @@@ #include "gem/i915_gem_region.h" #include "gem/i915_gem_ttm.h" #include "gt/intel_gt.h" ++#include "gt/intel_gt_regs.h" static int init_fake_lmem_bar(struct intel_memory_region *mem) { diff --cc drivers/gpu/drm/i915/i915_drv.h index ffde71b6b3f1f,9b48dd9ccacd2..f600d1cb01b34 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@@ -1089,10 -1284,10 +1087,12 @@@ IS_SUBPLATFORM(const struct drm_i915_pr IS_SUBPLATFORM(dev_priv, INTEL_DG2, INTEL_SUBPLATFORM_G10) #define IS_DG2_G11(dev_priv) \ IS_SUBPLATFORM(dev_priv, INTEL_DG2, INTEL_SUBPLATFORM_G11) + #define IS_DG2_G12(dev_priv) \ + IS_SUBPLATFORM(dev_priv, INTEL_DG2, INTEL_SUBPLATFORM_G12) #define IS_ADLS_RPLS(dev_priv) \ IS_SUBPLATFORM(dev_priv, INTEL_ALDERLAKE_S, INTEL_SUBPLATFORM_RPL_S) +#define IS_ADLP_N(dev_priv) \ + IS_SUBPLATFORM(dev_priv, INTEL_ALDERLAKE_P, INTEL_SUBPLATFORM_N) #define IS_HSW_EARLY_SDV(dev_priv) (IS_HASWELL(dev_priv) && \ (INTEL_DEVID(dev_priv) & 0xFF00) == 0x0C00) #define IS_BDW_ULT(dev_priv) \ diff --cc drivers/gpu/drm/i915/i915_gem_evict.h index d4478b6ad11bb,0000000000000..e593c530f9bd7 mode 100644,000000..100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.h +++ b/drivers/gpu/drm/i915/i915_gem_evict.h @@@ -1,24 -1,0 +1,28 @@@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2021 Intel Corporation + */ + +#ifndef __I915_GEM_EVICT_H__ +#define __I915_GEM_EVICT_H__ + +#include + +struct drm_mm_node; +struct i915_address_space; ++struct i915_gem_ww_ctx; + +int __must_check i915_gem_evict_something(struct i915_address_space *vm, ++ struct i915_gem_ww_ctx *ww, + u64 min_size, u64 alignment, + unsigned long color, + u64 start, u64 end, + unsigned flags); +int __must_check i915_gem_evict_for_node(struct i915_address_space *vm, ++ struct i915_gem_ww_ctx *ww, + struct drm_mm_node *node, + unsigned int flags); - int i915_gem_evict_vm(struct i915_address_space *vm); ++int i915_gem_evict_vm(struct i915_address_space *vm, ++ struct i915_gem_ww_ctx *ww); + +#endif /* __I915_GEM_EVICT_H__ */ diff --cc drivers/gpu/drm/i915/i915_module.c index 5d6fdf37fb5af,4d324638aba56..65acd7bf75d08 --- a/drivers/gpu/drm/i915/i915_module.c +++ b/drivers/gpu/drm/i915/i915_module.c @@@ -9,8 -9,6 +9,7 @@@ #include "gem/i915_gem_context.h" #include "gem/i915_gem_object.h" #include "i915_active.h" - #include "i915_buddy.h" +#include "i915_driver.h" #include "i915_params.h" #include "i915_pci.h" #include "i915_perf.h" diff --cc drivers/gpu/drm/i915/i915_reg.h index b9783584841b3,f95bbb10b6f41..2b8a3086ed35a --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@@ -8835,4 -13021,11 +8835,8 @@@ enum skl_power_gate #define CLKGATE_DIS_MISC _MMIO(0x46534) #define CLKGATE_DIS_MISC_DMASC_GATING_DIS REG_BIT(21) -#define SLICE_COMMON_ECO_CHICKEN1 _MMIO(0x731C) -#define MSC_MSAA_REODER_BUF_BYPASS_DISABLE REG_BIT(14) - + #define GEN12_CULLBIT1 _MMIO(0x6100) + #define GEN12_CULLBIT2 _MMIO(0x7030) + #define GEN12_STATE_ACK_DEBUG _MMIO(0x20BC) + #endif /* _I915_REG_H_ */ diff --cc drivers/gpu/drm/i915/i915_vma.c index 68cf1d3922503,30307e34d2dcb..845cd88f8313c --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@@ -913,30 -967,30 +968,39 @@@ err_st_alloc } static struct scatterlist * --remap_pages(struct drm_i915_gem_object *obj, -- unsigned int offset, unsigned int alignment_pad, -- unsigned int width, unsigned int height, -- unsigned int src_stride, unsigned int dst_stride, -- struct sg_table *st, struct scatterlist *sg) ++add_padding_pages(unsigned int count, ++ struct sg_table *st, struct scatterlist *sg) ++{ ++ st->nents++; ++ ++ /* ++ * The DE ignores the PTEs for the padding tiles, the sg entry ++ * here is just a convenience to indicate how many padding PTEs ++ * to insert at this spot. ++ */ ++ sg_set_page(sg, NULL, count * I915_GTT_PAGE_SIZE, 0); ++ sg_dma_address(sg) = 0; ++ sg_dma_len(sg) = count * I915_GTT_PAGE_SIZE; ++ sg = sg_next(sg); ++ ++ return sg; ++} ++ ++static struct scatterlist * ++remap_tiled_color_plane_pages(struct drm_i915_gem_object *obj, ++ unsigned int offset, unsigned int alignment_pad, ++ unsigned int width, unsigned int height, ++ unsigned int src_stride, unsigned int dst_stride, ++ struct sg_table *st, struct scatterlist *sg, ++ unsigned int *gtt_offset) { unsigned int row; if (!width || !height) return sg; -- if (alignment_pad) { -- st->nents++; -- -- /* -- * The DE ignores the PTEs for the padding tiles, the sg entry -- * here is just a convenience to indicate how many padding PTEs -- * to insert at this spot. -- */ -- sg_set_page(sg, NULL, alignment_pad * 4096, 0); -- sg_dma_address(sg) = 0; -- sg_dma_len(sg) = alignment_pad * 4096; -- sg = sg_next(sg); -- } ++ if (alignment_pad) ++ sg = add_padding_pages(alignment_pad, st, sg); for (row = 0; row < height; row++) { unsigned int left = width * I915_GTT_PAGE_SIZE; @@@ -973,18 -1027,18 +1037,98 @@@ if (!left) continue; ++ sg = add_padding_pages(left >> PAGE_SHIFT, st, sg); ++ } ++ ++ *gtt_offset += alignment_pad + dst_stride * height; ++ ++ return sg; ++} ++ ++static struct scatterlist * ++remap_contiguous_pages(struct drm_i915_gem_object *obj, ++ unsigned int obj_offset, ++ unsigned int count, ++ struct sg_table *st, struct scatterlist *sg) ++{ ++ struct scatterlist *iter; ++ unsigned int offset; ++ ++ iter = i915_gem_object_get_sg_dma(obj, obj_offset, &offset); ++ GEM_BUG_ON(!iter); ++ ++ do { ++ unsigned int len; ++ ++ len = min(sg_dma_len(iter) - (offset << PAGE_SHIFT), ++ count << PAGE_SHIFT); ++ sg_set_page(sg, NULL, len, 0); ++ sg_dma_address(sg) = ++ sg_dma_address(iter) + (offset << PAGE_SHIFT); ++ sg_dma_len(sg) = len; ++ st->nents++; ++ count -= len >> PAGE_SHIFT; ++ if (count == 0) ++ return sg; -- /* -- * The DE ignores the PTEs for the padding tiles, the sg entry -- * here is just a conenience to indicate how many padding PTEs -- * to insert at this spot. -- */ -- sg_set_page(sg, NULL, left, 0); -- sg_dma_address(sg) = 0; -- sg_dma_len(sg) = left; -- sg = sg_next(sg); -- } ++ sg = __sg_next(sg); ++ iter = __sg_next(iter); ++ offset = 0; ++ } while (1); ++} ++ ++static struct scatterlist * ++remap_linear_color_plane_pages(struct drm_i915_gem_object *obj, ++ unsigned int obj_offset, unsigned int alignment_pad, ++ unsigned int size, ++ struct sg_table *st, struct scatterlist *sg, ++ unsigned int *gtt_offset) ++{ ++ if (!size) ++ return sg; ++ ++ if (alignment_pad) ++ sg = add_padding_pages(alignment_pad, st, sg); ++ ++ sg = remap_contiguous_pages(obj, obj_offset, size, st, sg); ++ sg = sg_next(sg); ++ ++ *gtt_offset += alignment_pad + size; ++ ++ return sg; ++} ++ ++static struct scatterlist * ++remap_color_plane_pages(const struct intel_remapped_info *rem_info, ++ struct drm_i915_gem_object *obj, ++ int color_plane, ++ struct sg_table *st, struct scatterlist *sg, ++ unsigned int *gtt_offset) ++{ ++ unsigned int alignment_pad = 0; ++ ++ if (rem_info->plane_alignment) ++ alignment_pad = ALIGN(*gtt_offset, rem_info->plane_alignment) - *gtt_offset; ++ ++ if (rem_info->plane[color_plane].linear) ++ sg = remap_linear_color_plane_pages(obj, ++ rem_info->plane[color_plane].offset, ++ alignment_pad, ++ rem_info->plane[color_plane].size, ++ st, sg, ++ gtt_offset); ++ ++ else ++ sg = remap_tiled_color_plane_pages(obj, ++ rem_info->plane[color_plane].offset, ++ alignment_pad, ++ rem_info->plane[color_plane].width, ++ rem_info->plane[color_plane].height, ++ rem_info->plane[color_plane].src_stride, ++ rem_info->plane[color_plane].dst_stride, ++ st, sg, ++ gtt_offset); return sg; } @@@ -1013,21 -1067,21 +1157,8 @@@ intel_remap_pages(struct intel_remapped st->nents = 0; sg = st->sgl; -- for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++) { -- unsigned int alignment_pad = 0; -- -- if (rem_info->plane_alignment) -- alignment_pad = ALIGN(gtt_offset, rem_info->plane_alignment) - gtt_offset; -- -- sg = remap_pages(obj, -- rem_info->plane[i].offset, alignment_pad, -- rem_info->plane[i].width, rem_info->plane[i].height, -- rem_info->plane[i].src_stride, rem_info->plane[i].dst_stride, -- st, sg); -- -- gtt_offset += alignment_pad + -- rem_info->plane[i].dst_stride * rem_info->plane[i].height; -- } ++ for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++) ++ sg = remap_color_plane_pages(rem_info, obj, i, st, sg, >t_offset); i915_sg_trim(st); @@@ -1049,9 -1103,9 +1180,8 @@@ intel_partial_pages(const struct i915_g struct drm_i915_gem_object *obj) { struct sg_table *st; -- struct scatterlist *sg, *iter; ++ struct scatterlist *sg; unsigned int count = view->partial.size; -- unsigned int offset; int ret = -ENOMEM; st = kmalloc(sizeof(*st), GFP_KERNEL); @@@ -1062,34 -1116,34 +1192,14 @@@ if (ret) goto err_sg_alloc; -- iter = i915_gem_object_get_sg_dma(obj, view->partial.offset, &offset); -- GEM_BUG_ON(!iter); -- -- sg = st->sgl; st->nents = 0; -- do { -- unsigned int len; - - len = min(sg_dma_len(iter) - (offset << PAGE_SHIFT), - count << PAGE_SHIFT); - sg_set_page(sg, NULL, len, 0); - sg_dma_address(sg) = - sg_dma_address(iter) + (offset << PAGE_SHIFT); - sg_dma_len(sg) = len; - len = min(sg_dma_len(iter) - (offset << PAGE_SHIFT), - count << PAGE_SHIFT); - sg_set_page(sg, NULL, len, 0); - sg_dma_address(sg) = - sg_dma_address(iter) + (offset << PAGE_SHIFT); - sg_dma_len(sg) = len; - -- st->nents++; -- count -= len >> PAGE_SHIFT; -- if (count == 0) { -- sg_mark_end(sg); -- i915_sg_trim(st); /* Drop any unused tail entries. */ ++ sg = remap_contiguous_pages(obj, view->partial.offset, count, st, st->sgl); -- return st; -- } ++ sg_mark_end(sg); ++ i915_sg_trim(st); /* Drop any unused tail entries. */ -- sg = __sg_next(sg); -- iter = __sg_next(iter); -- offset = 0; -- } while (1); ++ return st; err_sg_alloc: kfree(st); diff --cc drivers/gpu/drm/vkms/vkms_drv.h index 18d944c578838,9496fdc900b8c..91e63b12f60fe --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@@ -20,9 -20,11 +20,11 @@@ #define XRES_MAX 8192 #define YRES_MAX 8192 + #define NUM_OVERLAY_PLANES 8 + struct vkms_writeback_job { - struct dma_buf_map map[DRM_FORMAT_MAX_PLANES]; - struct dma_buf_map data[DRM_FORMAT_MAX_PLANES]; + struct iosys_map map[DRM_FORMAT_MAX_PLANES]; + struct iosys_map data[DRM_FORMAT_MAX_PLANES]; }; struct vkms_composer { diff --cc include/drm/dp/drm_dp_helper.h index 0000000000000,98d020835b49c..69487bd8ed561 mode 000000,100644..100644 --- a/include/drm/dp/drm_dp_helper.h +++ b/include/drm/dp/drm_dp_helper.h @@@ -1,0 -1,2365 +1,2379 @@@ + /* + * Copyright © 2008 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + + #ifndef _DRM_DP_HELPER_H_ + #define _DRM_DP_HELPER_H_ + + #include + #include + #include + #include + + struct drm_device; + struct drm_dp_aux; + struct drm_panel; + + /* + * Unless otherwise noted, all values are from the DP 1.1a spec. Note that + * DP and DPCD versions are independent. Differences from 1.0 are not noted, + * 1.0 devices basically don't exist in the wild. + * + * Abbreviations, in chronological order: + * + * eDP: Embedded DisplayPort version 1 + * DPI: DisplayPort Interoperability Guideline v1.1a + * 1.2: DisplayPort 1.2 + * MST: Multistream Transport - part of DP 1.2a + * + * 1.2 formally includes both eDP and DPI definitions. + */ + + /* MSA (Main Stream Attribute) MISC bits (as MISC1<<8|MISC0) */ + #define DP_MSA_MISC_SYNC_CLOCK (1 << 0) + #define DP_MSA_MISC_INTERLACE_VTOTAL_EVEN (1 << 8) + #define DP_MSA_MISC_STEREO_NO_3D (0 << 9) + #define DP_MSA_MISC_STEREO_PROG_RIGHT_EYE (1 << 9) + #define DP_MSA_MISC_STEREO_PROG_LEFT_EYE (3 << 9) + /* bits per component for non-RAW */ + #define DP_MSA_MISC_6_BPC (0 << 5) + #define DP_MSA_MISC_8_BPC (1 << 5) + #define DP_MSA_MISC_10_BPC (2 << 5) + #define DP_MSA_MISC_12_BPC (3 << 5) + #define DP_MSA_MISC_16_BPC (4 << 5) + /* bits per component for RAW */ + #define DP_MSA_MISC_RAW_6_BPC (1 << 5) + #define DP_MSA_MISC_RAW_7_BPC (2 << 5) + #define DP_MSA_MISC_RAW_8_BPC (3 << 5) + #define DP_MSA_MISC_RAW_10_BPC (4 << 5) + #define DP_MSA_MISC_RAW_12_BPC (5 << 5) + #define DP_MSA_MISC_RAW_14_BPC (6 << 5) + #define DP_MSA_MISC_RAW_16_BPC (7 << 5) + /* pixel encoding/colorimetry format */ + #define _DP_MSA_MISC_COLOR(misc1_7, misc0_21, misc0_3, misc0_4) \ + ((misc1_7) << 15 | (misc0_4) << 4 | (misc0_3) << 3 | ((misc0_21) << 1)) + #define DP_MSA_MISC_COLOR_RGB _DP_MSA_MISC_COLOR(0, 0, 0, 0) + #define DP_MSA_MISC_COLOR_CEA_RGB _DP_MSA_MISC_COLOR(0, 0, 1, 0) + #define DP_MSA_MISC_COLOR_RGB_WIDE_FIXED _DP_MSA_MISC_COLOR(0, 3, 0, 0) + #define DP_MSA_MISC_COLOR_RGB_WIDE_FLOAT _DP_MSA_MISC_COLOR(0, 3, 0, 1) + #define DP_MSA_MISC_COLOR_Y_ONLY _DP_MSA_MISC_COLOR(1, 0, 0, 0) + #define DP_MSA_MISC_COLOR_RAW _DP_MSA_MISC_COLOR(1, 1, 0, 0) + #define DP_MSA_MISC_COLOR_YCBCR_422_BT601 _DP_MSA_MISC_COLOR(0, 1, 1, 0) + #define DP_MSA_MISC_COLOR_YCBCR_422_BT709 _DP_MSA_MISC_COLOR(0, 1, 1, 1) + #define DP_MSA_MISC_COLOR_YCBCR_444_BT601 _DP_MSA_MISC_COLOR(0, 2, 1, 0) + #define DP_MSA_MISC_COLOR_YCBCR_444_BT709 _DP_MSA_MISC_COLOR(0, 2, 1, 1) + #define DP_MSA_MISC_COLOR_XVYCC_422_BT601 _DP_MSA_MISC_COLOR(0, 1, 0, 0) + #define DP_MSA_MISC_COLOR_XVYCC_422_BT709 _DP_MSA_MISC_COLOR(0, 1, 0, 1) + #define DP_MSA_MISC_COLOR_XVYCC_444_BT601 _DP_MSA_MISC_COLOR(0, 2, 0, 0) + #define DP_MSA_MISC_COLOR_XVYCC_444_BT709 _DP_MSA_MISC_COLOR(0, 2, 0, 1) + #define DP_MSA_MISC_COLOR_OPRGB _DP_MSA_MISC_COLOR(0, 0, 1, 1) + #define DP_MSA_MISC_COLOR_DCI_P3 _DP_MSA_MISC_COLOR(0, 3, 1, 0) + #define DP_MSA_MISC_COLOR_COLOR_PROFILE _DP_MSA_MISC_COLOR(0, 3, 1, 1) + #define DP_MSA_MISC_COLOR_VSC_SDP (1 << 14) + + #define DP_AUX_MAX_PAYLOAD_BYTES 16 + + #define DP_AUX_I2C_WRITE 0x0 + #define DP_AUX_I2C_READ 0x1 + #define DP_AUX_I2C_WRITE_STATUS_UPDATE 0x2 + #define DP_AUX_I2C_MOT 0x4 + #define DP_AUX_NATIVE_WRITE 0x8 + #define DP_AUX_NATIVE_READ 0x9 + + #define DP_AUX_NATIVE_REPLY_ACK (0x0 << 0) + #define DP_AUX_NATIVE_REPLY_NACK (0x1 << 0) + #define DP_AUX_NATIVE_REPLY_DEFER (0x2 << 0) + #define DP_AUX_NATIVE_REPLY_MASK (0x3 << 0) + + #define DP_AUX_I2C_REPLY_ACK (0x0 << 2) + #define DP_AUX_I2C_REPLY_NACK (0x1 << 2) + #define DP_AUX_I2C_REPLY_DEFER (0x2 << 2) + #define DP_AUX_I2C_REPLY_MASK (0x3 << 2) + + /* DPCD Field Address Mapping */ + + /* Receiver Capability */ + #define DP_DPCD_REV 0x000 + # define DP_DPCD_REV_10 0x10 + # define DP_DPCD_REV_11 0x11 + # define DP_DPCD_REV_12 0x12 + # define DP_DPCD_REV_13 0x13 + # define DP_DPCD_REV_14 0x14 + + #define DP_MAX_LINK_RATE 0x001 + + #define DP_MAX_LANE_COUNT 0x002 + # define DP_MAX_LANE_COUNT_MASK 0x1f + # define DP_TPS3_SUPPORTED (1 << 6) /* 1.2 */ + # define DP_ENHANCED_FRAME_CAP (1 << 7) + + #define DP_MAX_DOWNSPREAD 0x003 + # define DP_MAX_DOWNSPREAD_0_5 (1 << 0) + # define DP_STREAM_REGENERATION_STATUS_CAP (1 << 1) /* 2.0 */ + # define DP_NO_AUX_HANDSHAKE_LINK_TRAINING (1 << 6) + # define DP_TPS4_SUPPORTED (1 << 7) + + #define DP_NORP 0x004 + + #define DP_DOWNSTREAMPORT_PRESENT 0x005 + # define DP_DWN_STRM_PORT_PRESENT (1 << 0) + # define DP_DWN_STRM_PORT_TYPE_MASK 0x06 + # define DP_DWN_STRM_PORT_TYPE_DP (0 << 1) + # define DP_DWN_STRM_PORT_TYPE_ANALOG (1 << 1) + # define DP_DWN_STRM_PORT_TYPE_TMDS (2 << 1) + # define DP_DWN_STRM_PORT_TYPE_OTHER (3 << 1) + # define DP_FORMAT_CONVERSION (1 << 3) + # define DP_DETAILED_CAP_INFO_AVAILABLE (1 << 4) /* DPI */ + + #define DP_MAIN_LINK_CHANNEL_CODING 0x006 + # define DP_CAP_ANSI_8B10B (1 << 0) + # define DP_CAP_ANSI_128B132B (1 << 1) /* 2.0 */ + + #define DP_DOWN_STREAM_PORT_COUNT 0x007 + # define DP_PORT_COUNT_MASK 0x0f + # define DP_MSA_TIMING_PAR_IGNORED (1 << 6) /* eDP */ + # define DP_OUI_SUPPORT (1 << 7) + + #define DP_RECEIVE_PORT_0_CAP_0 0x008 + # define DP_LOCAL_EDID_PRESENT (1 << 1) + # define DP_ASSOCIATED_TO_PRECEDING_PORT (1 << 2) + + #define DP_RECEIVE_PORT_0_BUFFER_SIZE 0x009 + + #define DP_RECEIVE_PORT_1_CAP_0 0x00a + #define DP_RECEIVE_PORT_1_BUFFER_SIZE 0x00b + + #define DP_I2C_SPEED_CAP 0x00c /* DPI */ + # define DP_I2C_SPEED_1K 0x01 + # define DP_I2C_SPEED_5K 0x02 + # define DP_I2C_SPEED_10K 0x04 + # define DP_I2C_SPEED_100K 0x08 + # define DP_I2C_SPEED_400K 0x10 + # define DP_I2C_SPEED_1M 0x20 + + #define DP_EDP_CONFIGURATION_CAP 0x00d /* XXX 1.2? */ + # define DP_ALTERNATE_SCRAMBLER_RESET_CAP (1 << 0) + # define DP_FRAMING_CHANGE_CAP (1 << 1) + # define DP_DPCD_DISPLAY_CONTROL_CAPABLE (1 << 3) /* edp v1.2 or higher */ + + #define DP_TRAINING_AUX_RD_INTERVAL 0x00e /* XXX 1.2? */ + # define DP_TRAINING_AUX_RD_MASK 0x7F /* DP 1.3 */ + # define DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT (1 << 7) /* DP 1.3 */ + + #define DP_ADAPTER_CAP 0x00f /* 1.2 */ + # define DP_FORCE_LOAD_SENSE_CAP (1 << 0) + # define DP_ALTERNATE_I2C_PATTERN_CAP (1 << 1) + + #define DP_SUPPORTED_LINK_RATES 0x010 /* eDP 1.4 */ + # define DP_MAX_SUPPORTED_RATES 8 /* 16-bit little-endian */ + + /* Multiple stream transport */ + #define DP_FAUX_CAP 0x020 /* 1.2 */ + # define DP_FAUX_CAP_1 (1 << 0) + + #define DP_SINK_VIDEO_FALLBACK_FORMATS 0x020 /* 2.0 */ + # define DP_FALLBACK_1024x768_60HZ_24BPP (1 << 0) + # define DP_FALLBACK_1280x720_60HZ_24BPP (1 << 1) + # define DP_FALLBACK_1920x1080_60HZ_24BPP (1 << 2) + + #define DP_MSTM_CAP 0x021 /* 1.2 */ + # define DP_MST_CAP (1 << 0) + # define DP_SINGLE_STREAM_SIDEBAND_MSG (1 << 1) /* 2.0 */ + + #define DP_NUMBER_OF_AUDIO_ENDPOINTS 0x022 /* 1.2 */ + + /* AV_SYNC_DATA_BLOCK 1.2 */ + #define DP_AV_GRANULARITY 0x023 + # define DP_AG_FACTOR_MASK (0xf << 0) + # define DP_AG_FACTOR_3MS (0 << 0) + # define DP_AG_FACTOR_2MS (1 << 0) + # define DP_AG_FACTOR_1MS (2 << 0) + # define DP_AG_FACTOR_500US (3 << 0) + # define DP_AG_FACTOR_200US (4 << 0) + # define DP_AG_FACTOR_100US (5 << 0) + # define DP_AG_FACTOR_10US (6 << 0) + # define DP_AG_FACTOR_1US (7 << 0) + # define DP_VG_FACTOR_MASK (0xf << 4) + # define DP_VG_FACTOR_3MS (0 << 4) + # define DP_VG_FACTOR_2MS (1 << 4) + # define DP_VG_FACTOR_1MS (2 << 4) + # define DP_VG_FACTOR_500US (3 << 4) + # define DP_VG_FACTOR_200US (4 << 4) + # define DP_VG_FACTOR_100US (5 << 4) + + #define DP_AUD_DEC_LAT0 0x024 + #define DP_AUD_DEC_LAT1 0x025 + + #define DP_AUD_PP_LAT0 0x026 + #define DP_AUD_PP_LAT1 0x027 + + #define DP_VID_INTER_LAT 0x028 + + #define DP_VID_PROG_LAT 0x029 + + #define DP_REP_LAT 0x02a + + #define DP_AUD_DEL_INS0 0x02b + #define DP_AUD_DEL_INS1 0x02c + #define DP_AUD_DEL_INS2 0x02d + /* End of AV_SYNC_DATA_BLOCK */ + + #define DP_RECEIVER_ALPM_CAP 0x02e /* eDP 1.4 */ + # define DP_ALPM_CAP (1 << 0) + + #define DP_SINK_DEVICE_AUX_FRAME_SYNC_CAP 0x02f /* eDP 1.4 */ + # define DP_AUX_FRAME_SYNC_CAP (1 << 0) + + #define DP_GUID 0x030 /* 1.2 */ + + #define DP_DSC_SUPPORT 0x060 /* DP 1.4 */ + # define DP_DSC_DECOMPRESSION_IS_SUPPORTED (1 << 0) + + #define DP_DSC_REV 0x061 + # define DP_DSC_MAJOR_MASK (0xf << 0) + # define DP_DSC_MINOR_MASK (0xf << 4) + # define DP_DSC_MAJOR_SHIFT 0 + # define DP_DSC_MINOR_SHIFT 4 + + #define DP_DSC_RC_BUF_BLK_SIZE 0x062 + # define DP_DSC_RC_BUF_BLK_SIZE_1 0x0 + # define DP_DSC_RC_BUF_BLK_SIZE_4 0x1 + # define DP_DSC_RC_BUF_BLK_SIZE_16 0x2 + # define DP_DSC_RC_BUF_BLK_SIZE_64 0x3 + + #define DP_DSC_RC_BUF_SIZE 0x063 + + #define DP_DSC_SLICE_CAP_1 0x064 + # define DP_DSC_1_PER_DP_DSC_SINK (1 << 0) + # define DP_DSC_2_PER_DP_DSC_SINK (1 << 1) + # define DP_DSC_4_PER_DP_DSC_SINK (1 << 3) + # define DP_DSC_6_PER_DP_DSC_SINK (1 << 4) + # define DP_DSC_8_PER_DP_DSC_SINK (1 << 5) + # define DP_DSC_10_PER_DP_DSC_SINK (1 << 6) + # define DP_DSC_12_PER_DP_DSC_SINK (1 << 7) + + #define DP_DSC_LINE_BUF_BIT_DEPTH 0x065 + # define DP_DSC_LINE_BUF_BIT_DEPTH_MASK (0xf << 0) + # define DP_DSC_LINE_BUF_BIT_DEPTH_9 0x0 + # define DP_DSC_LINE_BUF_BIT_DEPTH_10 0x1 + # define DP_DSC_LINE_BUF_BIT_DEPTH_11 0x2 + # define DP_DSC_LINE_BUF_BIT_DEPTH_12 0x3 + # define DP_DSC_LINE_BUF_BIT_DEPTH_13 0x4 + # define DP_DSC_LINE_BUF_BIT_DEPTH_14 0x5 + # define DP_DSC_LINE_BUF_BIT_DEPTH_15 0x6 + # define DP_DSC_LINE_BUF_BIT_DEPTH_16 0x7 + # define DP_DSC_LINE_BUF_BIT_DEPTH_8 0x8 + + #define DP_DSC_BLK_PREDICTION_SUPPORT 0x066 + # define DP_DSC_BLK_PREDICTION_IS_SUPPORTED (1 << 0) + + #define DP_DSC_MAX_BITS_PER_PIXEL_LOW 0x067 /* eDP 1.4 */ + + #define DP_DSC_MAX_BITS_PER_PIXEL_HI 0x068 /* eDP 1.4 */ + # define DP_DSC_MAX_BITS_PER_PIXEL_HI_MASK (0x3 << 0) + # define DP_DSC_MAX_BITS_PER_PIXEL_HI_SHIFT 8 + + #define DP_DSC_DEC_COLOR_FORMAT_CAP 0x069 + # define DP_DSC_RGB (1 << 0) + # define DP_DSC_YCbCr444 (1 << 1) + # define DP_DSC_YCbCr422_Simple (1 << 2) + # define DP_DSC_YCbCr422_Native (1 << 3) + # define DP_DSC_YCbCr420_Native (1 << 4) + + #define DP_DSC_DEC_COLOR_DEPTH_CAP 0x06A + # define DP_DSC_8_BPC (1 << 1) + # define DP_DSC_10_BPC (1 << 2) + # define DP_DSC_12_BPC (1 << 3) + + #define DP_DSC_PEAK_THROUGHPUT 0x06B + # define DP_DSC_THROUGHPUT_MODE_0_MASK (0xf << 0) + # define DP_DSC_THROUGHPUT_MODE_0_SHIFT 0 + # define DP_DSC_THROUGHPUT_MODE_0_UNSUPPORTED 0 + # define DP_DSC_THROUGHPUT_MODE_0_340 (1 << 0) + # define DP_DSC_THROUGHPUT_MODE_0_400 (2 << 0) + # define DP_DSC_THROUGHPUT_MODE_0_450 (3 << 0) + # define DP_DSC_THROUGHPUT_MODE_0_500 (4 << 0) + # define DP_DSC_THROUGHPUT_MODE_0_550 (5 << 0) + # define DP_DSC_THROUGHPUT_MODE_0_600 (6 << 0) + # define DP_DSC_THROUGHPUT_MODE_0_650 (7 << 0) + # define DP_DSC_THROUGHPUT_MODE_0_700 (8 << 0) + # define DP_DSC_THROUGHPUT_MODE_0_750 (9 << 0) + # define DP_DSC_THROUGHPUT_MODE_0_800 (10 << 0) + # define DP_DSC_THROUGHPUT_MODE_0_850 (11 << 0) + # define DP_DSC_THROUGHPUT_MODE_0_900 (12 << 0) + # define DP_DSC_THROUGHPUT_MODE_0_950 (13 << 0) + # define DP_DSC_THROUGHPUT_MODE_0_1000 (14 << 0) + # define DP_DSC_THROUGHPUT_MODE_0_170 (15 << 0) /* 1.4a */ + # define DP_DSC_THROUGHPUT_MODE_1_MASK (0xf << 4) + # define DP_DSC_THROUGHPUT_MODE_1_SHIFT 4 + # define DP_DSC_THROUGHPUT_MODE_1_UNSUPPORTED 0 + # define DP_DSC_THROUGHPUT_MODE_1_340 (1 << 4) + # define DP_DSC_THROUGHPUT_MODE_1_400 (2 << 4) + # define DP_DSC_THROUGHPUT_MODE_1_450 (3 << 4) + # define DP_DSC_THROUGHPUT_MODE_1_500 (4 << 4) + # define DP_DSC_THROUGHPUT_MODE_1_550 (5 << 4) + # define DP_DSC_THROUGHPUT_MODE_1_600 (6 << 4) + # define DP_DSC_THROUGHPUT_MODE_1_650 (7 << 4) + # define DP_DSC_THROUGHPUT_MODE_1_700 (8 << 4) + # define DP_DSC_THROUGHPUT_MODE_1_750 (9 << 4) + # define DP_DSC_THROUGHPUT_MODE_1_800 (10 << 4) + # define DP_DSC_THROUGHPUT_MODE_1_850 (11 << 4) + # define DP_DSC_THROUGHPUT_MODE_1_900 (12 << 4) + # define DP_DSC_THROUGHPUT_MODE_1_950 (13 << 4) + # define DP_DSC_THROUGHPUT_MODE_1_1000 (14 << 4) + # define DP_DSC_THROUGHPUT_MODE_1_170 (15 << 4) + + #define DP_DSC_MAX_SLICE_WIDTH 0x06C + #define DP_DSC_MIN_SLICE_WIDTH_VALUE 2560 + #define DP_DSC_SLICE_WIDTH_MULTIPLIER 320 + + #define DP_DSC_SLICE_CAP_2 0x06D + # define DP_DSC_16_PER_DP_DSC_SINK (1 << 0) + # define DP_DSC_20_PER_DP_DSC_SINK (1 << 1) + # define DP_DSC_24_PER_DP_DSC_SINK (1 << 2) + + #define DP_DSC_BITS_PER_PIXEL_INC 0x06F + # define DP_DSC_BITS_PER_PIXEL_1_16 0x0 + # define DP_DSC_BITS_PER_PIXEL_1_8 0x1 + # define DP_DSC_BITS_PER_PIXEL_1_4 0x2 + # define DP_DSC_BITS_PER_PIXEL_1_2 0x3 + # define DP_DSC_BITS_PER_PIXEL_1 0x4 + + #define DP_PSR_SUPPORT 0x070 /* XXX 1.2? */ + # define DP_PSR_IS_SUPPORTED 1 + # define DP_PSR2_IS_SUPPORTED 2 /* eDP 1.4 */ + # define DP_PSR2_WITH_Y_COORD_IS_SUPPORTED 3 /* eDP 1.4a */ + + #define DP_PSR_CAPS 0x071 /* XXX 1.2? */ + # define DP_PSR_NO_TRAIN_ON_EXIT 1 + # define DP_PSR_SETUP_TIME_330 (0 << 1) + # define DP_PSR_SETUP_TIME_275 (1 << 1) + # define DP_PSR_SETUP_TIME_220 (2 << 1) + # define DP_PSR_SETUP_TIME_165 (3 << 1) + # define DP_PSR_SETUP_TIME_110 (4 << 1) + # define DP_PSR_SETUP_TIME_55 (5 << 1) + # define DP_PSR_SETUP_TIME_0 (6 << 1) + # define DP_PSR_SETUP_TIME_MASK (7 << 1) + # define DP_PSR_SETUP_TIME_SHIFT 1 + # define DP_PSR2_SU_Y_COORDINATE_REQUIRED (1 << 4) /* eDP 1.4a */ + # define DP_PSR2_SU_GRANULARITY_REQUIRED (1 << 5) /* eDP 1.4b */ + + #define DP_PSR2_SU_X_GRANULARITY 0x072 /* eDP 1.4b */ + #define DP_PSR2_SU_Y_GRANULARITY 0x074 /* eDP 1.4b */ + + /* + * 0x80-0x8f describe downstream port capabilities, but there are two layouts + * based on whether DP_DETAILED_CAP_INFO_AVAILABLE was set. If it was not, + * each port's descriptor is one byte wide. If it was set, each port's is + * four bytes wide, starting with the one byte from the base info. As of + * DP interop v1.1a only VGA defines additional detail. + */ + + /* offset 0 */ + #define DP_DOWNSTREAM_PORT_0 0x80 + # define DP_DS_PORT_TYPE_MASK (7 << 0) + # define DP_DS_PORT_TYPE_DP 0 + # define DP_DS_PORT_TYPE_VGA 1 + # define DP_DS_PORT_TYPE_DVI 2 + # define DP_DS_PORT_TYPE_HDMI 3 + # define DP_DS_PORT_TYPE_NON_EDID 4 + # define DP_DS_PORT_TYPE_DP_DUALMODE 5 + # define DP_DS_PORT_TYPE_WIRELESS 6 + # define DP_DS_PORT_HPD (1 << 3) + # define DP_DS_NON_EDID_MASK (0xf << 4) + # define DP_DS_NON_EDID_720x480i_60 (1 << 4) + # define DP_DS_NON_EDID_720x480i_50 (2 << 4) + # define DP_DS_NON_EDID_1920x1080i_60 (3 << 4) + # define DP_DS_NON_EDID_1920x1080i_50 (4 << 4) + # define DP_DS_NON_EDID_1280x720_60 (5 << 4) + # define DP_DS_NON_EDID_1280x720_50 (7 << 4) + /* offset 1 for VGA is maximum megapixels per second / 8 */ + /* offset 1 for DVI/HDMI is maximum TMDS clock in Mbps / 2.5 */ + /* offset 2 for VGA/DVI/HDMI */ + # define DP_DS_MAX_BPC_MASK (3 << 0) + # define DP_DS_8BPC 0 + # define DP_DS_10BPC 1 + # define DP_DS_12BPC 2 + # define DP_DS_16BPC 3 + /* HDMI2.1 PCON FRL CONFIGURATION */ + # define DP_PCON_MAX_FRL_BW (7 << 2) + # define DP_PCON_MAX_0GBPS (0 << 2) + # define DP_PCON_MAX_9GBPS (1 << 2) + # define DP_PCON_MAX_18GBPS (2 << 2) + # define DP_PCON_MAX_24GBPS (3 << 2) + # define DP_PCON_MAX_32GBPS (4 << 2) + # define DP_PCON_MAX_40GBPS (5 << 2) + # define DP_PCON_MAX_48GBPS (6 << 2) + # define DP_PCON_SOURCE_CTL_MODE (1 << 5) + + /* offset 3 for DVI */ + # define DP_DS_DVI_DUAL_LINK (1 << 1) + # define DP_DS_DVI_HIGH_COLOR_DEPTH (1 << 2) + /* offset 3 for HDMI */ + # define DP_DS_HDMI_FRAME_SEQ_TO_FRAME_PACK (1 << 0) + # define DP_DS_HDMI_YCBCR422_PASS_THROUGH (1 << 1) + # define DP_DS_HDMI_YCBCR420_PASS_THROUGH (1 << 2) + # define DP_DS_HDMI_YCBCR444_TO_422_CONV (1 << 3) + # define DP_DS_HDMI_YCBCR444_TO_420_CONV (1 << 4) + + /* + * VESA DP-to-HDMI PCON Specification adds caps for colorspace + * conversion in DFP cap DPCD 83h. Sec6.1 Table-3. + * Based on the available support the source can enable + * color conversion by writing into PROTOCOL_COVERTER_CONTROL_2 + * DPCD 3052h. + */ + # define DP_DS_HDMI_BT601_RGB_YCBCR_CONV (1 << 5) + # define DP_DS_HDMI_BT709_RGB_YCBCR_CONV (1 << 6) + # define DP_DS_HDMI_BT2020_RGB_YCBCR_CONV (1 << 7) + + #define DP_MAX_DOWNSTREAM_PORTS 0x10 + + /* DP Forward error Correction Registers */ + #define DP_FEC_CAPABILITY 0x090 /* 1.4 */ + # define DP_FEC_CAPABLE (1 << 0) + # define DP_FEC_UNCORR_BLK_ERROR_COUNT_CAP (1 << 1) + # define DP_FEC_CORR_BLK_ERROR_COUNT_CAP (1 << 2) + # define DP_FEC_BIT_ERROR_COUNT_CAP (1 << 3) + #define DP_FEC_CAPABILITY_1 0x091 /* 2.0 */ + + /* DP-HDMI2.1 PCON DSC ENCODER SUPPORT */ + #define DP_PCON_DSC_ENCODER_CAP_SIZE 0xC /* 0x9E - 0x92 */ + #define DP_PCON_DSC_ENCODER 0x092 + # define DP_PCON_DSC_ENCODER_SUPPORTED (1 << 0) + # define DP_PCON_DSC_PPS_ENC_OVERRIDE (1 << 1) + + /* DP-HDMI2.1 PCON DSC Version */ + #define DP_PCON_DSC_VERSION 0x093 + # define DP_PCON_DSC_MAJOR_MASK (0xF << 0) + # define DP_PCON_DSC_MINOR_MASK (0xF << 4) + # define DP_PCON_DSC_MAJOR_SHIFT 0 + # define DP_PCON_DSC_MINOR_SHIFT 4 + + /* DP-HDMI2.1 PCON DSC RC Buffer block size */ + #define DP_PCON_DSC_RC_BUF_BLK_INFO 0x094 + # define DP_PCON_DSC_RC_BUF_BLK_SIZE (0x3 << 0) + # define DP_PCON_DSC_RC_BUF_BLK_1KB 0 + # define DP_PCON_DSC_RC_BUF_BLK_4KB 1 + # define DP_PCON_DSC_RC_BUF_BLK_16KB 2 + # define DP_PCON_DSC_RC_BUF_BLK_64KB 3 + + /* DP-HDMI2.1 PCON DSC RC Buffer size */ + #define DP_PCON_DSC_RC_BUF_SIZE 0x095 + + /* DP-HDMI2.1 PCON DSC Slice capabilities-1 */ + #define DP_PCON_DSC_SLICE_CAP_1 0x096 + # define DP_PCON_DSC_1_PER_DSC_ENC (0x1 << 0) + # define DP_PCON_DSC_2_PER_DSC_ENC (0x1 << 1) + # define DP_PCON_DSC_4_PER_DSC_ENC (0x1 << 3) + # define DP_PCON_DSC_6_PER_DSC_ENC (0x1 << 4) + # define DP_PCON_DSC_8_PER_DSC_ENC (0x1 << 5) + # define DP_PCON_DSC_10_PER_DSC_ENC (0x1 << 6) + # define DP_PCON_DSC_12_PER_DSC_ENC (0x1 << 7) + + #define DP_PCON_DSC_BUF_BIT_DEPTH 0x097 + # define DP_PCON_DSC_BIT_DEPTH_MASK (0xF << 0) + # define DP_PCON_DSC_DEPTH_9_BITS 0 + # define DP_PCON_DSC_DEPTH_10_BITS 1 + # define DP_PCON_DSC_DEPTH_11_BITS 2 + # define DP_PCON_DSC_DEPTH_12_BITS 3 + # define DP_PCON_DSC_DEPTH_13_BITS 4 + # define DP_PCON_DSC_DEPTH_14_BITS 5 + # define DP_PCON_DSC_DEPTH_15_BITS 6 + # define DP_PCON_DSC_DEPTH_16_BITS 7 + # define DP_PCON_DSC_DEPTH_8_BITS 8 + + #define DP_PCON_DSC_BLOCK_PREDICTION 0x098 + # define DP_PCON_DSC_BLOCK_PRED_SUPPORT (0x1 << 0) + + #define DP_PCON_DSC_ENC_COLOR_FMT_CAP 0x099 + # define DP_PCON_DSC_ENC_RGB (0x1 << 0) + # define DP_PCON_DSC_ENC_YUV444 (0x1 << 1) + # define DP_PCON_DSC_ENC_YUV422_S (0x1 << 2) + # define DP_PCON_DSC_ENC_YUV422_N (0x1 << 3) + # define DP_PCON_DSC_ENC_YUV420_N (0x1 << 4) + + #define DP_PCON_DSC_ENC_COLOR_DEPTH_CAP 0x09A + # define DP_PCON_DSC_ENC_8BPC (0x1 << 1) + # define DP_PCON_DSC_ENC_10BPC (0x1 << 2) + # define DP_PCON_DSC_ENC_12BPC (0x1 << 3) + + #define DP_PCON_DSC_MAX_SLICE_WIDTH 0x09B + + /* DP-HDMI2.1 PCON DSC Slice capabilities-2 */ + #define DP_PCON_DSC_SLICE_CAP_2 0x09C + # define DP_PCON_DSC_16_PER_DSC_ENC (0x1 << 0) + # define DP_PCON_DSC_20_PER_DSC_ENC (0x1 << 1) + # define DP_PCON_DSC_24_PER_DSC_ENC (0x1 << 2) + + /* DP-HDMI2.1 PCON HDMI TX Encoder Bits/pixel increment */ + #define DP_PCON_DSC_BPP_INCR 0x09E + # define DP_PCON_DSC_BPP_INCR_MASK (0x7 << 0) + # define DP_PCON_DSC_ONE_16TH_BPP 0 + # define DP_PCON_DSC_ONE_8TH_BPP 1 + # define DP_PCON_DSC_ONE_4TH_BPP 2 + # define DP_PCON_DSC_ONE_HALF_BPP 3 + # define DP_PCON_DSC_ONE_BPP 4 + + /* DP Extended DSC Capabilities */ + #define DP_DSC_BRANCH_OVERALL_THROUGHPUT_0 0x0a0 /* DP 1.4a SCR */ + #define DP_DSC_BRANCH_OVERALL_THROUGHPUT_1 0x0a1 + #define DP_DSC_BRANCH_MAX_LINE_WIDTH 0x0a2 + + /* DFP Capability Extension */ + #define DP_DFP_CAPABILITY_EXTENSION_SUPPORT 0x0a3 /* 2.0 */ + + /* Link Configuration */ + #define DP_LINK_BW_SET 0x100 + # define DP_LINK_RATE_TABLE 0x00 /* eDP 1.4 */ + # define DP_LINK_BW_1_62 0x06 + # define DP_LINK_BW_2_7 0x0a + # define DP_LINK_BW_5_4 0x14 /* 1.2 */ + # define DP_LINK_BW_8_1 0x1e /* 1.4 */ + # define DP_LINK_BW_10 0x01 /* 2.0 128b/132b Link Layer */ + # define DP_LINK_BW_13_5 0x04 /* 2.0 128b/132b Link Layer */ + # define DP_LINK_BW_20 0x02 /* 2.0 128b/132b Link Layer */ + + #define DP_LANE_COUNT_SET 0x101 + # define DP_LANE_COUNT_MASK 0x0f + # define DP_LANE_COUNT_ENHANCED_FRAME_EN (1 << 7) + + #define DP_TRAINING_PATTERN_SET 0x102 + # define DP_TRAINING_PATTERN_DISABLE 0 + # define DP_TRAINING_PATTERN_1 1 + # define DP_TRAINING_PATTERN_2 2 ++# define DP_TRAINING_PATTERN_2_CDS 3 /* 2.0 E11 */ + # define DP_TRAINING_PATTERN_3 3 /* 1.2 */ + # define DP_TRAINING_PATTERN_4 7 /* 1.4 */ + # define DP_TRAINING_PATTERN_MASK 0x3 + # define DP_TRAINING_PATTERN_MASK_1_4 0xf + + /* DPCD 1.1 only. For DPCD >= 1.2 see per-lane DP_LINK_QUAL_LANEn_SET */ + # define DP_LINK_QUAL_PATTERN_11_DISABLE (0 << 2) + # define DP_LINK_QUAL_PATTERN_11_D10_2 (1 << 2) + # define DP_LINK_QUAL_PATTERN_11_ERROR_RATE (2 << 2) + # define DP_LINK_QUAL_PATTERN_11_PRBS7 (3 << 2) + # define DP_LINK_QUAL_PATTERN_11_MASK (3 << 2) + + # define DP_RECOVERED_CLOCK_OUT_EN (1 << 4) + # define DP_LINK_SCRAMBLING_DISABLE (1 << 5) + + # define DP_SYMBOL_ERROR_COUNT_BOTH (0 << 6) + # define DP_SYMBOL_ERROR_COUNT_DISPARITY (1 << 6) + # define DP_SYMBOL_ERROR_COUNT_SYMBOL (2 << 6) + # define DP_SYMBOL_ERROR_COUNT_MASK (3 << 6) + + #define DP_TRAINING_LANE0_SET 0x103 + #define DP_TRAINING_LANE1_SET 0x104 + #define DP_TRAINING_LANE2_SET 0x105 + #define DP_TRAINING_LANE3_SET 0x106 + + # define DP_TRAIN_VOLTAGE_SWING_MASK 0x3 + # define DP_TRAIN_VOLTAGE_SWING_SHIFT 0 + # define DP_TRAIN_MAX_SWING_REACHED (1 << 2) + # define DP_TRAIN_VOLTAGE_SWING_LEVEL_0 (0 << 0) + # define DP_TRAIN_VOLTAGE_SWING_LEVEL_1 (1 << 0) + # define DP_TRAIN_VOLTAGE_SWING_LEVEL_2 (2 << 0) + # define DP_TRAIN_VOLTAGE_SWING_LEVEL_3 (3 << 0) + + # define DP_TRAIN_PRE_EMPHASIS_MASK (3 << 3) + # define DP_TRAIN_PRE_EMPH_LEVEL_0 (0 << 3) + # define DP_TRAIN_PRE_EMPH_LEVEL_1 (1 << 3) + # define DP_TRAIN_PRE_EMPH_LEVEL_2 (2 << 3) + # define DP_TRAIN_PRE_EMPH_LEVEL_3 (3 << 3) + + # define DP_TRAIN_PRE_EMPHASIS_SHIFT 3 + # define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED (1 << 5) + + # define DP_TX_FFE_PRESET_VALUE_MASK (0xf << 0) /* 2.0 128b/132b Link Layer */ + + #define DP_DOWNSPREAD_CTRL 0x107 + # define DP_SPREAD_AMP_0_5 (1 << 4) + # define DP_MSA_TIMING_PAR_IGNORE_EN (1 << 7) /* eDP */ + + #define DP_MAIN_LINK_CHANNEL_CODING_SET 0x108 + # define DP_SET_ANSI_8B10B (1 << 0) + # define DP_SET_ANSI_128B132B (1 << 1) + + #define DP_I2C_SPEED_CONTROL_STATUS 0x109 /* DPI */ + /* bitmask as for DP_I2C_SPEED_CAP */ + + #define DP_EDP_CONFIGURATION_SET 0x10a /* XXX 1.2? */ + # define DP_ALTERNATE_SCRAMBLER_RESET_ENABLE (1 << 0) + # define DP_FRAMING_CHANGE_ENABLE (1 << 1) + # define DP_PANEL_SELF_TEST_ENABLE (1 << 7) + + #define DP_LINK_QUAL_LANE0_SET 0x10b /* DPCD >= 1.2 */ + #define DP_LINK_QUAL_LANE1_SET 0x10c + #define DP_LINK_QUAL_LANE2_SET 0x10d + #define DP_LINK_QUAL_LANE3_SET 0x10e + # define DP_LINK_QUAL_PATTERN_DISABLE 0 + # define DP_LINK_QUAL_PATTERN_D10_2 1 + # define DP_LINK_QUAL_PATTERN_ERROR_RATE 2 + # define DP_LINK_QUAL_PATTERN_PRBS7 3 + # define DP_LINK_QUAL_PATTERN_80BIT_CUSTOM 4 + # define DP_LINK_QUAL_PATTERN_CP2520_PAT_1 5 + # define DP_LINK_QUAL_PATTERN_CP2520_PAT_2 6 + # define DP_LINK_QUAL_PATTERN_CP2520_PAT_3 7 + /* DP 2.0 UHBR10, UHBR13.5, UHBR20 */ + # define DP_LINK_QUAL_PATTERN_128B132B_TPS1 0x08 + # define DP_LINK_QUAL_PATTERN_128B132B_TPS2 0x10 + # define DP_LINK_QUAL_PATTERN_PRSBS9 0x18 + # define DP_LINK_QUAL_PATTERN_PRSBS11 0x20 + # define DP_LINK_QUAL_PATTERN_PRSBS15 0x28 + # define DP_LINK_QUAL_PATTERN_PRSBS23 0x30 + # define DP_LINK_QUAL_PATTERN_PRSBS31 0x38 + # define DP_LINK_QUAL_PATTERN_CUSTOM 0x40 + # define DP_LINK_QUAL_PATTERN_SQUARE 0x48 + + #define DP_TRAINING_LANE0_1_SET2 0x10f + #define DP_TRAINING_LANE2_3_SET2 0x110 + # define DP_LANE02_POST_CURSOR2_SET_MASK (3 << 0) + # define DP_LANE02_MAX_POST_CURSOR2_REACHED (1 << 2) + # define DP_LANE13_POST_CURSOR2_SET_MASK (3 << 4) + # define DP_LANE13_MAX_POST_CURSOR2_REACHED (1 << 6) + + #define DP_MSTM_CTRL 0x111 /* 1.2 */ + # define DP_MST_EN (1 << 0) + # define DP_UP_REQ_EN (1 << 1) + # define DP_UPSTREAM_IS_SRC (1 << 2) + + #define DP_AUDIO_DELAY0 0x112 /* 1.2 */ + #define DP_AUDIO_DELAY1 0x113 + #define DP_AUDIO_DELAY2 0x114 + + #define DP_LINK_RATE_SET 0x115 /* eDP 1.4 */ + # define DP_LINK_RATE_SET_SHIFT 0 + # define DP_LINK_RATE_SET_MASK (7 << 0) + + #define DP_RECEIVER_ALPM_CONFIG 0x116 /* eDP 1.4 */ + # define DP_ALPM_ENABLE (1 << 0) + # define DP_ALPM_LOCK_ERROR_IRQ_HPD_ENABLE (1 << 1) + + #define DP_SINK_DEVICE_AUX_FRAME_SYNC_CONF 0x117 /* eDP 1.4 */ + # define DP_AUX_FRAME_SYNC_ENABLE (1 << 0) + # define DP_IRQ_HPD_ENABLE (1 << 1) + + #define DP_UPSTREAM_DEVICE_DP_PWR_NEED 0x118 /* 1.2 */ + # define DP_PWR_NOT_NEEDED (1 << 0) + + #define DP_FEC_CONFIGURATION 0x120 /* 1.4 */ + # define DP_FEC_READY (1 << 0) + # define DP_FEC_ERR_COUNT_SEL_MASK (7 << 1) + # define DP_FEC_ERR_COUNT_DIS (0 << 1) + # define DP_FEC_UNCORR_BLK_ERROR_COUNT (1 << 1) + # define DP_FEC_CORR_BLK_ERROR_COUNT (2 << 1) + # define DP_FEC_BIT_ERROR_COUNT (3 << 1) + # define DP_FEC_LANE_SELECT_MASK (3 << 4) + # define DP_FEC_LANE_0_SELECT (0 << 4) + # define DP_FEC_LANE_1_SELECT (1 << 4) + # define DP_FEC_LANE_2_SELECT (2 << 4) + # define DP_FEC_LANE_3_SELECT (3 << 4) + + #define DP_AUX_FRAME_SYNC_VALUE 0x15c /* eDP 1.4 */ + # define DP_AUX_FRAME_SYNC_VALID (1 << 0) + + #define DP_DSC_ENABLE 0x160 /* DP 1.4 */ + # define DP_DECOMPRESSION_EN (1 << 0) + #define DP_DSC_CONFIGURATION 0x161 /* DP 2.0 */ + + #define DP_PSR_EN_CFG 0x170 /* XXX 1.2? */ + # define DP_PSR_ENABLE BIT(0) + # define DP_PSR_MAIN_LINK_ACTIVE BIT(1) + # define DP_PSR_CRC_VERIFICATION BIT(2) + # define DP_PSR_FRAME_CAPTURE BIT(3) + # define DP_PSR_SU_REGION_SCANLINE_CAPTURE BIT(4) /* eDP 1.4a */ + # define DP_PSR_IRQ_HPD_WITH_CRC_ERRORS BIT(5) /* eDP 1.4a */ + # define DP_PSR_ENABLE_PSR2 BIT(6) /* eDP 1.4a */ + + #define DP_ADAPTER_CTRL 0x1a0 + # define DP_ADAPTER_CTRL_FORCE_LOAD_SENSE (1 << 0) + + #define DP_BRANCH_DEVICE_CTRL 0x1a1 + # define DP_BRANCH_DEVICE_IRQ_HPD (1 << 0) + + #define DP_PAYLOAD_ALLOCATE_SET 0x1c0 + #define DP_PAYLOAD_ALLOCATE_START_TIME_SLOT 0x1c1 + #define DP_PAYLOAD_ALLOCATE_TIME_SLOT_COUNT 0x1c2 + + /* Link/Sink Device Status */ + #define DP_SINK_COUNT 0x200 + /* prior to 1.2 bit 7 was reserved mbz */ + # define DP_GET_SINK_COUNT(x) ((((x) & 0x80) >> 1) | ((x) & 0x3f)) + # define DP_SINK_CP_READY (1 << 6) + + #define DP_DEVICE_SERVICE_IRQ_VECTOR 0x201 + # define DP_REMOTE_CONTROL_COMMAND_PENDING (1 << 0) + # define DP_AUTOMATED_TEST_REQUEST (1 << 1) + # define DP_CP_IRQ (1 << 2) + # define DP_MCCS_IRQ (1 << 3) + # define DP_DOWN_REP_MSG_RDY (1 << 4) /* 1.2 MST */ + # define DP_UP_REQ_MSG_RDY (1 << 5) /* 1.2 MST */ + # define DP_SINK_SPECIFIC_IRQ (1 << 6) + + #define DP_LANE0_1_STATUS 0x202 + #define DP_LANE2_3_STATUS 0x203 + # define DP_LANE_CR_DONE (1 << 0) + # define DP_LANE_CHANNEL_EQ_DONE (1 << 1) + # define DP_LANE_SYMBOL_LOCKED (1 << 2) + + #define DP_CHANNEL_EQ_BITS (DP_LANE_CR_DONE | \ + DP_LANE_CHANNEL_EQ_DONE | \ + DP_LANE_SYMBOL_LOCKED) + -#define DP_LANE_ALIGN_STATUS_UPDATED 0x204 - -#define DP_INTERLANE_ALIGN_DONE (1 << 0) -#define DP_DOWNSTREAM_PORT_STATUS_CHANGED (1 << 6) -#define DP_LINK_STATUS_UPDATED (1 << 7) ++#define DP_LANE_ALIGN_STATUS_UPDATED 0x204 ++#define DP_INTERLANE_ALIGN_DONE (1 << 0) ++#define DP_128B132B_DPRX_EQ_INTERLANE_ALIGN_DONE (1 << 2) /* 2.0 E11 */ ++#define DP_128B132B_DPRX_CDS_INTERLANE_ALIGN_DONE (1 << 3) /* 2.0 E11 */ ++#define DP_128B132B_LT_FAILED (1 << 4) /* 2.0 E11 */ ++#define DP_DOWNSTREAM_PORT_STATUS_CHANGED (1 << 6) ++#define DP_LINK_STATUS_UPDATED (1 << 7) + + #define DP_SINK_STATUS 0x205 + # define DP_RECEIVE_PORT_0_STATUS (1 << 0) + # define DP_RECEIVE_PORT_1_STATUS (1 << 1) + # define DP_STREAM_REGENERATION_STATUS (1 << 2) /* 2.0 */ + # define DP_INTRA_HOP_AUX_REPLY_INDICATION (1 << 3) /* 2.0 */ + + #define DP_ADJUST_REQUEST_LANE0_1 0x206 + #define DP_ADJUST_REQUEST_LANE2_3 0x207 + # define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK 0x03 + # define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0 + # define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK 0x0c + # define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT 2 + # define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK 0x30 + # define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4 + # define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK 0xc0 + # define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6 + + /* DP 2.0 128b/132b Link Layer */ + # define DP_ADJUST_TX_FFE_PRESET_LANE0_MASK (0xf << 0) + # define DP_ADJUST_TX_FFE_PRESET_LANE0_SHIFT 0 + # define DP_ADJUST_TX_FFE_PRESET_LANE1_MASK (0xf << 4) + # define DP_ADJUST_TX_FFE_PRESET_LANE1_SHIFT 4 + + #define DP_ADJUST_REQUEST_POST_CURSOR2 0x20c + # define DP_ADJUST_POST_CURSOR2_LANE0_MASK 0x03 + # define DP_ADJUST_POST_CURSOR2_LANE0_SHIFT 0 + # define DP_ADJUST_POST_CURSOR2_LANE1_MASK 0x0c + # define DP_ADJUST_POST_CURSOR2_LANE1_SHIFT 2 + # define DP_ADJUST_POST_CURSOR2_LANE2_MASK 0x30 + # define DP_ADJUST_POST_CURSOR2_LANE2_SHIFT 4 + # define DP_ADJUST_POST_CURSOR2_LANE3_MASK 0xc0 + # define DP_ADJUST_POST_CURSOR2_LANE3_SHIFT 6 + + #define DP_TEST_REQUEST 0x218 + # define DP_TEST_LINK_TRAINING (1 << 0) + # define DP_TEST_LINK_VIDEO_PATTERN (1 << 1) + # define DP_TEST_LINK_EDID_READ (1 << 2) + # define DP_TEST_LINK_PHY_TEST_PATTERN (1 << 3) /* DPCD >= 1.1 */ + # define DP_TEST_LINK_FAUX_PATTERN (1 << 4) /* DPCD >= 1.2 */ + # define DP_TEST_LINK_AUDIO_PATTERN (1 << 5) /* DPCD >= 1.2 */ + # define DP_TEST_LINK_AUDIO_DISABLED_VIDEO (1 << 6) /* DPCD >= 1.2 */ + + #define DP_TEST_LINK_RATE 0x219 + # define DP_LINK_RATE_162 (0x6) + # define DP_LINK_RATE_27 (0xa) + + #define DP_TEST_LANE_COUNT 0x220 + + #define DP_TEST_PATTERN 0x221 + # define DP_NO_TEST_PATTERN 0x0 + # define DP_COLOR_RAMP 0x1 + # define DP_BLACK_AND_WHITE_VERTICAL_LINES 0x2 + # define DP_COLOR_SQUARE 0x3 + + #define DP_TEST_H_TOTAL_HI 0x222 + #define DP_TEST_H_TOTAL_LO 0x223 + + #define DP_TEST_V_TOTAL_HI 0x224 + #define DP_TEST_V_TOTAL_LO 0x225 + + #define DP_TEST_H_START_HI 0x226 + #define DP_TEST_H_START_LO 0x227 + + #define DP_TEST_V_START_HI 0x228 + #define DP_TEST_V_START_LO 0x229 + + #define DP_TEST_HSYNC_HI 0x22A + # define DP_TEST_HSYNC_POLARITY (1 << 7) + # define DP_TEST_HSYNC_WIDTH_HI_MASK (127 << 0) + #define DP_TEST_HSYNC_WIDTH_LO 0x22B + + #define DP_TEST_VSYNC_HI 0x22C + # define DP_TEST_VSYNC_POLARITY (1 << 7) + # define DP_TEST_VSYNC_WIDTH_HI_MASK (127 << 0) + #define DP_TEST_VSYNC_WIDTH_LO 0x22D + + #define DP_TEST_H_WIDTH_HI 0x22E + #define DP_TEST_H_WIDTH_LO 0x22F + + #define DP_TEST_V_HEIGHT_HI 0x230 + #define DP_TEST_V_HEIGHT_LO 0x231 + + #define DP_TEST_MISC0 0x232 + # define DP_TEST_SYNC_CLOCK (1 << 0) + # define DP_TEST_COLOR_FORMAT_MASK (3 << 1) + # define DP_TEST_COLOR_FORMAT_SHIFT 1 + # define DP_COLOR_FORMAT_RGB (0 << 1) + # define DP_COLOR_FORMAT_YCbCr422 (1 << 1) + # define DP_COLOR_FORMAT_YCbCr444 (2 << 1) + # define DP_TEST_DYNAMIC_RANGE_VESA (0 << 3) + # define DP_TEST_DYNAMIC_RANGE_CEA (1 << 3) + # define DP_TEST_YCBCR_COEFFICIENTS (1 << 4) + # define DP_YCBCR_COEFFICIENTS_ITU601 (0 << 4) + # define DP_YCBCR_COEFFICIENTS_ITU709 (1 << 4) + # define DP_TEST_BIT_DEPTH_MASK (7 << 5) + # define DP_TEST_BIT_DEPTH_SHIFT 5 + # define DP_TEST_BIT_DEPTH_6 (0 << 5) + # define DP_TEST_BIT_DEPTH_8 (1 << 5) + # define DP_TEST_BIT_DEPTH_10 (2 << 5) + # define DP_TEST_BIT_DEPTH_12 (3 << 5) + # define DP_TEST_BIT_DEPTH_16 (4 << 5) + + #define DP_TEST_MISC1 0x233 + # define DP_TEST_REFRESH_DENOMINATOR (1 << 0) + # define DP_TEST_INTERLACED (1 << 1) + + #define DP_TEST_REFRESH_RATE_NUMERATOR 0x234 + + #define DP_TEST_MISC0 0x232 + + #define DP_TEST_CRC_R_CR 0x240 + #define DP_TEST_CRC_G_Y 0x242 + #define DP_TEST_CRC_B_CB 0x244 + + #define DP_TEST_SINK_MISC 0x246 + # define DP_TEST_CRC_SUPPORTED (1 << 5) + # define DP_TEST_COUNT_MASK 0xf + + #define DP_PHY_TEST_PATTERN 0x248 + # define DP_PHY_TEST_PATTERN_SEL_MASK 0x7 + # define DP_PHY_TEST_PATTERN_NONE 0x0 + # define DP_PHY_TEST_PATTERN_D10_2 0x1 + # define DP_PHY_TEST_PATTERN_ERROR_COUNT 0x2 + # define DP_PHY_TEST_PATTERN_PRBS7 0x3 + # define DP_PHY_TEST_PATTERN_80BIT_CUSTOM 0x4 + # define DP_PHY_TEST_PATTERN_CP2520 0x5 + + #define DP_PHY_SQUARE_PATTERN 0x249 + + #define DP_TEST_HBR2_SCRAMBLER_RESET 0x24A + #define DP_TEST_80BIT_CUSTOM_PATTERN_7_0 0x250 + #define DP_TEST_80BIT_CUSTOM_PATTERN_15_8 0x251 + #define DP_TEST_80BIT_CUSTOM_PATTERN_23_16 0x252 + #define DP_TEST_80BIT_CUSTOM_PATTERN_31_24 0x253 + #define DP_TEST_80BIT_CUSTOM_PATTERN_39_32 0x254 + #define DP_TEST_80BIT_CUSTOM_PATTERN_47_40 0x255 + #define DP_TEST_80BIT_CUSTOM_PATTERN_55_48 0x256 + #define DP_TEST_80BIT_CUSTOM_PATTERN_63_56 0x257 + #define DP_TEST_80BIT_CUSTOM_PATTERN_71_64 0x258 + #define DP_TEST_80BIT_CUSTOM_PATTERN_79_72 0x259 + + #define DP_TEST_RESPONSE 0x260 + # define DP_TEST_ACK (1 << 0) + # define DP_TEST_NAK (1 << 1) + # define DP_TEST_EDID_CHECKSUM_WRITE (1 << 2) + + #define DP_TEST_EDID_CHECKSUM 0x261 + + #define DP_TEST_SINK 0x270 + # define DP_TEST_SINK_START (1 << 0) + #define DP_TEST_AUDIO_MODE 0x271 + #define DP_TEST_AUDIO_PATTERN_TYPE 0x272 + #define DP_TEST_AUDIO_PERIOD_CH1 0x273 + #define DP_TEST_AUDIO_PERIOD_CH2 0x274 + #define DP_TEST_AUDIO_PERIOD_CH3 0x275 + #define DP_TEST_AUDIO_PERIOD_CH4 0x276 + #define DP_TEST_AUDIO_PERIOD_CH5 0x277 + #define DP_TEST_AUDIO_PERIOD_CH6 0x278 + #define DP_TEST_AUDIO_PERIOD_CH7 0x279 + #define DP_TEST_AUDIO_PERIOD_CH8 0x27A + + #define DP_FEC_STATUS 0x280 /* 1.4 */ + # define DP_FEC_DECODE_EN_DETECTED (1 << 0) + # define DP_FEC_DECODE_DIS_DETECTED (1 << 1) + + #define DP_FEC_ERROR_COUNT_LSB 0x0281 /* 1.4 */ + + #define DP_FEC_ERROR_COUNT_MSB 0x0282 /* 1.4 */ + # define DP_FEC_ERROR_COUNT_MASK 0x7F + # define DP_FEC_ERR_COUNT_VALID (1 << 7) + + #define DP_PAYLOAD_TABLE_UPDATE_STATUS 0x2c0 /* 1.2 MST */ + # define DP_PAYLOAD_TABLE_UPDATED (1 << 0) + # define DP_PAYLOAD_ACT_HANDLED (1 << 1) + + #define DP_VC_PAYLOAD_ID_SLOT_1 0x2c1 /* 1.2 MST */ + /* up to ID_SLOT_63 at 0x2ff */ + + /* Source Device-specific */ + #define DP_SOURCE_OUI 0x300 + + /* Sink Device-specific */ + #define DP_SINK_OUI 0x400 + + /* Branch Device-specific */ + #define DP_BRANCH_OUI 0x500 + #define DP_BRANCH_ID 0x503 + #define DP_BRANCH_REVISION_START 0x509 + #define DP_BRANCH_HW_REV 0x509 + #define DP_BRANCH_SW_REV 0x50A + + /* Link/Sink Device Power Control */ + #define DP_SET_POWER 0x600 + # define DP_SET_POWER_D0 0x1 + # define DP_SET_POWER_D3 0x2 + # define DP_SET_POWER_MASK 0x3 + # define DP_SET_POWER_D3_AUX_ON 0x5 + + /* eDP-specific */ + #define DP_EDP_DPCD_REV 0x700 /* eDP 1.2 */ + # define DP_EDP_11 0x00 + # define DP_EDP_12 0x01 + # define DP_EDP_13 0x02 + # define DP_EDP_14 0x03 + # define DP_EDP_14a 0x04 /* eDP 1.4a */ + # define DP_EDP_14b 0x05 /* eDP 1.4b */ + + #define DP_EDP_GENERAL_CAP_1 0x701 + # define DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP (1 << 0) + # define DP_EDP_BACKLIGHT_PIN_ENABLE_CAP (1 << 1) + # define DP_EDP_BACKLIGHT_AUX_ENABLE_CAP (1 << 2) + # define DP_EDP_PANEL_SELF_TEST_PIN_ENABLE_CAP (1 << 3) + # define DP_EDP_PANEL_SELF_TEST_AUX_ENABLE_CAP (1 << 4) + # define DP_EDP_FRC_ENABLE_CAP (1 << 5) + # define DP_EDP_COLOR_ENGINE_CAP (1 << 6) + # define DP_EDP_SET_POWER_CAP (1 << 7) + + #define DP_EDP_BACKLIGHT_ADJUSTMENT_CAP 0x702 + # define DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP (1 << 0) + # define DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP (1 << 1) + # define DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT (1 << 2) + # define DP_EDP_BACKLIGHT_AUX_PWM_PRODUCT_CAP (1 << 3) + # define DP_EDP_BACKLIGHT_FREQ_PWM_PIN_PASSTHRU_CAP (1 << 4) + # define DP_EDP_BACKLIGHT_FREQ_AUX_SET_CAP (1 << 5) + # define DP_EDP_DYNAMIC_BACKLIGHT_CAP (1 << 6) + # define DP_EDP_VBLANK_BACKLIGHT_UPDATE_CAP (1 << 7) + + #define DP_EDP_GENERAL_CAP_2 0x703 + # define DP_EDP_OVERDRIVE_ENGINE_ENABLED (1 << 0) + + #define DP_EDP_GENERAL_CAP_3 0x704 /* eDP 1.4 */ + # define DP_EDP_X_REGION_CAP_MASK (0xf << 0) + # define DP_EDP_X_REGION_CAP_SHIFT 0 + # define DP_EDP_Y_REGION_CAP_MASK (0xf << 4) + # define DP_EDP_Y_REGION_CAP_SHIFT 4 + + #define DP_EDP_DISPLAY_CONTROL_REGISTER 0x720 + # define DP_EDP_BACKLIGHT_ENABLE (1 << 0) + # define DP_EDP_BLACK_VIDEO_ENABLE (1 << 1) + # define DP_EDP_FRC_ENABLE (1 << 2) + # define DP_EDP_COLOR_ENGINE_ENABLE (1 << 3) + # define DP_EDP_VBLANK_BACKLIGHT_UPDATE_ENABLE (1 << 7) + + #define DP_EDP_BACKLIGHT_MODE_SET_REGISTER 0x721 + # define DP_EDP_BACKLIGHT_CONTROL_MODE_MASK (3 << 0) + # define DP_EDP_BACKLIGHT_CONTROL_MODE_PWM (0 << 0) + # define DP_EDP_BACKLIGHT_CONTROL_MODE_PRESET (1 << 0) + # define DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD (2 << 0) + # define DP_EDP_BACKLIGHT_CONTROL_MODE_PRODUCT (3 << 0) + # define DP_EDP_BACKLIGHT_FREQ_PWM_PIN_PASSTHRU_ENABLE (1 << 2) + # define DP_EDP_BACKLIGHT_FREQ_AUX_SET_ENABLE (1 << 3) + # define DP_EDP_DYNAMIC_BACKLIGHT_ENABLE (1 << 4) + # define DP_EDP_REGIONAL_BACKLIGHT_ENABLE (1 << 5) + # define DP_EDP_UPDATE_REGION_BRIGHTNESS (1 << 6) /* eDP 1.4 */ + + #define DP_EDP_BACKLIGHT_BRIGHTNESS_MSB 0x722 + #define DP_EDP_BACKLIGHT_BRIGHTNESS_LSB 0x723 + + #define DP_EDP_PWMGEN_BIT_COUNT 0x724 + #define DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN 0x725 + #define DP_EDP_PWMGEN_BIT_COUNT_CAP_MAX 0x726 + # define DP_EDP_PWMGEN_BIT_COUNT_MASK (0x1f << 0) + + #define DP_EDP_BACKLIGHT_CONTROL_STATUS 0x727 + + #define DP_EDP_BACKLIGHT_FREQ_SET 0x728 + # define DP_EDP_BACKLIGHT_FREQ_BASE_KHZ 27000 + + #define DP_EDP_BACKLIGHT_FREQ_CAP_MIN_MSB 0x72a + #define DP_EDP_BACKLIGHT_FREQ_CAP_MIN_MID 0x72b + #define DP_EDP_BACKLIGHT_FREQ_CAP_MIN_LSB 0x72c + + #define DP_EDP_BACKLIGHT_FREQ_CAP_MAX_MSB 0x72d + #define DP_EDP_BACKLIGHT_FREQ_CAP_MAX_MID 0x72e + #define DP_EDP_BACKLIGHT_FREQ_CAP_MAX_LSB 0x72f + + #define DP_EDP_DBC_MINIMUM_BRIGHTNESS_SET 0x732 + #define DP_EDP_DBC_MAXIMUM_BRIGHTNESS_SET 0x733 + + #define DP_EDP_REGIONAL_BACKLIGHT_BASE 0x740 /* eDP 1.4 */ + #define DP_EDP_REGIONAL_BACKLIGHT_0 0x741 /* eDP 1.4 */ + + #define DP_EDP_MSO_LINK_CAPABILITIES 0x7a4 /* eDP 1.4 */ + # define DP_EDP_MSO_NUMBER_OF_LINKS_MASK (7 << 0) + # define DP_EDP_MSO_NUMBER_OF_LINKS_SHIFT 0 + # define DP_EDP_MSO_INDEPENDENT_LINK_BIT (1 << 3) + + /* Sideband MSG Buffers */ + #define DP_SIDEBAND_MSG_DOWN_REQ_BASE 0x1000 /* 1.2 MST */ + #define DP_SIDEBAND_MSG_UP_REP_BASE 0x1200 /* 1.2 MST */ + #define DP_SIDEBAND_MSG_DOWN_REP_BASE 0x1400 /* 1.2 MST */ + #define DP_SIDEBAND_MSG_UP_REQ_BASE 0x1600 /* 1.2 MST */ + + /* DPRX Event Status Indicator */ + #define DP_SINK_COUNT_ESI 0x2002 /* same as 0x200 */ + #define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 0x2003 /* same as 0x201 */ + + #define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1 0x2004 /* 1.2 */ + # define DP_RX_GTC_MSTR_REQ_STATUS_CHANGE (1 << 0) + # define DP_LOCK_ACQUISITION_REQUEST (1 << 1) + # define DP_CEC_IRQ (1 << 2) + + #define DP_LINK_SERVICE_IRQ_VECTOR_ESI0 0x2005 /* 1.2 */ + # define RX_CAP_CHANGED (1 << 0) + # define LINK_STATUS_CHANGED (1 << 1) + # define STREAM_STATUS_CHANGED (1 << 2) + # define HDMI_LINK_STATUS_CHANGED (1 << 3) + # define CONNECTED_OFF_ENTRY_REQUESTED (1 << 4) + + #define DP_PSR_ERROR_STATUS 0x2006 /* XXX 1.2? */ + # define DP_PSR_LINK_CRC_ERROR (1 << 0) + # define DP_PSR_RFB_STORAGE_ERROR (1 << 1) + # define DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR (1 << 2) /* eDP 1.4 */ + + #define DP_PSR_ESI 0x2007 /* XXX 1.2? */ + # define DP_PSR_CAPS_CHANGE (1 << 0) + + #define DP_PSR_STATUS 0x2008 /* XXX 1.2? */ + # define DP_PSR_SINK_INACTIVE 0 + # define DP_PSR_SINK_ACTIVE_SRC_SYNCED 1 + # define DP_PSR_SINK_ACTIVE_RFB 2 + # define DP_PSR_SINK_ACTIVE_SINK_SYNCED 3 + # define DP_PSR_SINK_ACTIVE_RESYNC 4 + # define DP_PSR_SINK_INTERNAL_ERROR 7 + # define DP_PSR_SINK_STATE_MASK 0x07 + + #define DP_SYNCHRONIZATION_LATENCY_IN_SINK 0x2009 /* edp 1.4 */ + # define DP_MAX_RESYNC_FRAME_COUNT_MASK (0xf << 0) + # define DP_MAX_RESYNC_FRAME_COUNT_SHIFT 0 + # define DP_LAST_ACTUAL_SYNCHRONIZATION_LATENCY_MASK (0xf << 4) + # define DP_LAST_ACTUAL_SYNCHRONIZATION_LATENCY_SHIFT 4 + + #define DP_LAST_RECEIVED_PSR_SDP 0x200a /* eDP 1.2 */ + # define DP_PSR_STATE_BIT (1 << 0) /* eDP 1.2 */ + # define DP_UPDATE_RFB_BIT (1 << 1) /* eDP 1.2 */ + # define DP_CRC_VALID_BIT (1 << 2) /* eDP 1.2 */ + # define DP_SU_VALID (1 << 3) /* eDP 1.4 */ + # define DP_FIRST_SCAN_LINE_SU_REGION (1 << 4) /* eDP 1.4 */ + # define DP_LAST_SCAN_LINE_SU_REGION (1 << 5) /* eDP 1.4 */ + # define DP_Y_COORDINATE_VALID (1 << 6) /* eDP 1.4a */ + + #define DP_RECEIVER_ALPM_STATUS 0x200b /* eDP 1.4 */ + # define DP_ALPM_LOCK_TIMEOUT_ERROR (1 << 0) + + #define DP_LANE0_1_STATUS_ESI 0x200c /* status same as 0x202 */ + #define DP_LANE2_3_STATUS_ESI 0x200d /* status same as 0x203 */ + #define DP_LANE_ALIGN_STATUS_UPDATED_ESI 0x200e /* status same as 0x204 */ + #define DP_SINK_STATUS_ESI 0x200f /* status same as 0x205 */ + + /* Extended Receiver Capability: See DP_DPCD_REV for definitions */ + #define DP_DP13_DPCD_REV 0x2200 + + #define DP_DPRX_FEATURE_ENUMERATION_LIST 0x2210 /* DP 1.3 */ + # define DP_GTC_CAP (1 << 0) /* DP 1.3 */ + # define DP_SST_SPLIT_SDP_CAP (1 << 1) /* DP 1.4 */ + # define DP_AV_SYNC_CAP (1 << 2) /* DP 1.3 */ + # define DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED (1 << 3) /* DP 1.3 */ + # define DP_VSC_EXT_VESA_SDP_SUPPORTED (1 << 4) /* DP 1.4 */ + # define DP_VSC_EXT_VESA_SDP_CHAINING_SUPPORTED (1 << 5) /* DP 1.4 */ + # define DP_VSC_EXT_CEA_SDP_SUPPORTED (1 << 6) /* DP 1.4 */ + # define DP_VSC_EXT_CEA_SDP_CHAINING_SUPPORTED (1 << 7) /* DP 1.4 */ + + #define DP_128B132B_SUPPORTED_LINK_RATES 0x2215 /* 2.0 */ + # define DP_UHBR10 (1 << 0) + # define DP_UHBR20 (1 << 1) + # define DP_UHBR13_5 (1 << 2) + + #define DP_128B132B_TRAINING_AUX_RD_INTERVAL 0x2216 /* 2.0 */ ++# define DP_128B132B_TRAINING_AUX_RD_INTERVAL_1MS_UNIT (1 << 7) + # define DP_128B132B_TRAINING_AUX_RD_INTERVAL_MASK 0x7f + # define DP_128B132B_TRAINING_AUX_RD_INTERVAL_400_US 0x00 + # define DP_128B132B_TRAINING_AUX_RD_INTERVAL_4_MS 0x01 + # define DP_128B132B_TRAINING_AUX_RD_INTERVAL_8_MS 0x02 + # define DP_128B132B_TRAINING_AUX_RD_INTERVAL_12_MS 0x03 + # define DP_128B132B_TRAINING_AUX_RD_INTERVAL_16_MS 0x04 + # define DP_128B132B_TRAINING_AUX_RD_INTERVAL_32_MS 0x05 + # define DP_128B132B_TRAINING_AUX_RD_INTERVAL_64_MS 0x06 + + #define DP_TEST_264BIT_CUSTOM_PATTERN_7_0 0x2230 + #define DP_TEST_264BIT_CUSTOM_PATTERN_263_256 0x2250 + + /* DSC Extended Capability Branch Total DSC Resources */ + #define DP_DSC_SUPPORT_AND_DSC_DECODER_COUNT 0x2260 /* 2.0 */ + # define DP_DSC_DECODER_COUNT_MASK (0b111 << 5) + # define DP_DSC_DECODER_COUNT_SHIFT 5 + #define DP_DSC_MAX_SLICE_COUNT_AND_AGGREGATION_0 0x2270 /* 2.0 */ + # define DP_DSC_DECODER_0_MAXIMUM_SLICE_COUNT_MASK (1 << 0) + # define DP_DSC_DECODER_0_AGGREGATION_SUPPORT_MASK (0b111 << 1) + # define DP_DSC_DECODER_0_AGGREGATION_SUPPORT_SHIFT 1 + + /* Protocol Converter Extension */ + /* HDMI CEC tunneling over AUX DP 1.3 section 5.3.3.3.1 DPCD 1.4+ */ + #define DP_CEC_TUNNELING_CAPABILITY 0x3000 + # define DP_CEC_TUNNELING_CAPABLE (1 << 0) + # define DP_CEC_SNOOPING_CAPABLE (1 << 1) + # define DP_CEC_MULTIPLE_LA_CAPABLE (1 << 2) + + #define DP_CEC_TUNNELING_CONTROL 0x3001 + # define DP_CEC_TUNNELING_ENABLE (1 << 0) + # define DP_CEC_SNOOPING_ENABLE (1 << 1) + + #define DP_CEC_RX_MESSAGE_INFO 0x3002 + # define DP_CEC_RX_MESSAGE_LEN_MASK (0xf << 0) + # define DP_CEC_RX_MESSAGE_LEN_SHIFT 0 + # define DP_CEC_RX_MESSAGE_HPD_STATE (1 << 4) + # define DP_CEC_RX_MESSAGE_HPD_LOST (1 << 5) + # define DP_CEC_RX_MESSAGE_ACKED (1 << 6) + # define DP_CEC_RX_MESSAGE_ENDED (1 << 7) + + #define DP_CEC_TX_MESSAGE_INFO 0x3003 + # define DP_CEC_TX_MESSAGE_LEN_MASK (0xf << 0) + # define DP_CEC_TX_MESSAGE_LEN_SHIFT 0 + # define DP_CEC_TX_RETRY_COUNT_MASK (0x7 << 4) + # define DP_CEC_TX_RETRY_COUNT_SHIFT 4 + # define DP_CEC_TX_MESSAGE_SEND (1 << 7) + + #define DP_CEC_TUNNELING_IRQ_FLAGS 0x3004 + # define DP_CEC_RX_MESSAGE_INFO_VALID (1 << 0) + # define DP_CEC_RX_MESSAGE_OVERFLOW (1 << 1) + # define DP_CEC_TX_MESSAGE_SENT (1 << 4) + # define DP_CEC_TX_LINE_ERROR (1 << 5) + # define DP_CEC_TX_ADDRESS_NACK_ERROR (1 << 6) + # define DP_CEC_TX_DATA_NACK_ERROR (1 << 7) + + #define DP_CEC_LOGICAL_ADDRESS_MASK 0x300E /* 0x300F word */ + # define DP_CEC_LOGICAL_ADDRESS_0 (1 << 0) + # define DP_CEC_LOGICAL_ADDRESS_1 (1 << 1) + # define DP_CEC_LOGICAL_ADDRESS_2 (1 << 2) + # define DP_CEC_LOGICAL_ADDRESS_3 (1 << 3) + # define DP_CEC_LOGICAL_ADDRESS_4 (1 << 4) + # define DP_CEC_LOGICAL_ADDRESS_5 (1 << 5) + # define DP_CEC_LOGICAL_ADDRESS_6 (1 << 6) + # define DP_CEC_LOGICAL_ADDRESS_7 (1 << 7) + #define DP_CEC_LOGICAL_ADDRESS_MASK_2 0x300F /* 0x300E word */ + # define DP_CEC_LOGICAL_ADDRESS_8 (1 << 0) + # define DP_CEC_LOGICAL_ADDRESS_9 (1 << 1) + # define DP_CEC_LOGICAL_ADDRESS_10 (1 << 2) + # define DP_CEC_LOGICAL_ADDRESS_11 (1 << 3) + # define DP_CEC_LOGICAL_ADDRESS_12 (1 << 4) + # define DP_CEC_LOGICAL_ADDRESS_13 (1 << 5) + # define DP_CEC_LOGICAL_ADDRESS_14 (1 << 6) + # define DP_CEC_LOGICAL_ADDRESS_15 (1 << 7) + + #define DP_CEC_RX_MESSAGE_BUFFER 0x3010 + #define DP_CEC_TX_MESSAGE_BUFFER 0x3020 + #define DP_CEC_MESSAGE_BUFFER_LENGTH 0x10 + + /* PCON CONFIGURE-1 FRL FOR HDMI SINK */ + #define DP_PCON_HDMI_LINK_CONFIG_1 0x305A + # define DP_PCON_ENABLE_MAX_FRL_BW (7 << 0) + # define DP_PCON_ENABLE_MAX_BW_0GBPS 0 + # define DP_PCON_ENABLE_MAX_BW_9GBPS 1 + # define DP_PCON_ENABLE_MAX_BW_18GBPS 2 + # define DP_PCON_ENABLE_MAX_BW_24GBPS 3 + # define DP_PCON_ENABLE_MAX_BW_32GBPS 4 + # define DP_PCON_ENABLE_MAX_BW_40GBPS 5 + # define DP_PCON_ENABLE_MAX_BW_48GBPS 6 + # define DP_PCON_ENABLE_SOURCE_CTL_MODE (1 << 3) + # define DP_PCON_ENABLE_CONCURRENT_LINK (1 << 4) + # define DP_PCON_ENABLE_SEQUENTIAL_LINK (0 << 4) + # define DP_PCON_ENABLE_LINK_FRL_MODE (1 << 5) + # define DP_PCON_ENABLE_HPD_READY (1 << 6) + # define DP_PCON_ENABLE_HDMI_LINK (1 << 7) + + /* PCON CONFIGURE-2 FRL FOR HDMI SINK */ + #define DP_PCON_HDMI_LINK_CONFIG_2 0x305B + # define DP_PCON_MAX_LINK_BW_MASK (0x3F << 0) + # define DP_PCON_FRL_BW_MASK_9GBPS (1 << 0) + # define DP_PCON_FRL_BW_MASK_18GBPS (1 << 1) + # define DP_PCON_FRL_BW_MASK_24GBPS (1 << 2) + # define DP_PCON_FRL_BW_MASK_32GBPS (1 << 3) + # define DP_PCON_FRL_BW_MASK_40GBPS (1 << 4) + # define DP_PCON_FRL_BW_MASK_48GBPS (1 << 5) + # define DP_PCON_FRL_LINK_TRAIN_EXTENDED (1 << 6) + # define DP_PCON_FRL_LINK_TRAIN_NORMAL (0 << 6) + + /* PCON HDMI LINK STATUS */ + #define DP_PCON_HDMI_TX_LINK_STATUS 0x303B + # define DP_PCON_HDMI_TX_LINK_ACTIVE (1 << 0) + # define DP_PCON_FRL_READY (1 << 1) + + /* PCON HDMI POST FRL STATUS */ + #define DP_PCON_HDMI_POST_FRL_STATUS 0x3036 + # define DP_PCON_HDMI_LINK_MODE (1 << 0) + # define DP_PCON_HDMI_MODE_TMDS 0 + # define DP_PCON_HDMI_MODE_FRL 1 + # define DP_PCON_HDMI_FRL_TRAINED_BW (0x3F << 1) + # define DP_PCON_FRL_TRAINED_BW_9GBPS (1 << 1) + # define DP_PCON_FRL_TRAINED_BW_18GBPS (1 << 2) + # define DP_PCON_FRL_TRAINED_BW_24GBPS (1 << 3) + # define DP_PCON_FRL_TRAINED_BW_32GBPS (1 << 4) + # define DP_PCON_FRL_TRAINED_BW_40GBPS (1 << 5) + # define DP_PCON_FRL_TRAINED_BW_48GBPS (1 << 6) + + #define DP_PROTOCOL_CONVERTER_CONTROL_0 0x3050 /* DP 1.3 */ + # define DP_HDMI_DVI_OUTPUT_CONFIG (1 << 0) /* DP 1.3 */ + #define DP_PROTOCOL_CONVERTER_CONTROL_1 0x3051 /* DP 1.3 */ + # define DP_CONVERSION_TO_YCBCR420_ENABLE (1 << 0) /* DP 1.3 */ + # define DP_HDMI_EDID_PROCESSING_DISABLE (1 << 1) /* DP 1.4 */ + # define DP_HDMI_AUTONOMOUS_SCRAMBLING_DISABLE (1 << 2) /* DP 1.4 */ + # define DP_HDMI_FORCE_SCRAMBLING (1 << 3) /* DP 1.4 */ + #define DP_PROTOCOL_CONVERTER_CONTROL_2 0x3052 /* DP 1.3 */ + # define DP_CONVERSION_TO_YCBCR422_ENABLE (1 << 0) /* DP 1.3 */ + # define DP_PCON_ENABLE_DSC_ENCODER (1 << 1) + # define DP_PCON_ENCODER_PPS_OVERRIDE_MASK (0x3 << 2) + # define DP_PCON_ENC_PPS_OVERRIDE_DISABLED 0 + # define DP_PCON_ENC_PPS_OVERRIDE_EN_PARAMS 1 + # define DP_PCON_ENC_PPS_OVERRIDE_EN_BUFFER 2 + # define DP_CONVERSION_RGB_YCBCR_MASK (7 << 4) + # define DP_CONVERSION_BT601_RGB_YCBCR_ENABLE (1 << 4) + # define DP_CONVERSION_BT709_RGB_YCBCR_ENABLE (1 << 5) + # define DP_CONVERSION_BT2020_RGB_YCBCR_ENABLE (1 << 6) + + /* PCON Downstream HDMI ERROR Status per Lane */ + #define DP_PCON_HDMI_ERROR_STATUS_LN0 0x3037 + #define DP_PCON_HDMI_ERROR_STATUS_LN1 0x3038 + #define DP_PCON_HDMI_ERROR_STATUS_LN2 0x3039 + #define DP_PCON_HDMI_ERROR_STATUS_LN3 0x303A + # define DP_PCON_HDMI_ERROR_COUNT_MASK (0x7 << 0) + # define DP_PCON_HDMI_ERROR_COUNT_THREE_PLUS (1 << 0) + # define DP_PCON_HDMI_ERROR_COUNT_TEN_PLUS (1 << 1) + # define DP_PCON_HDMI_ERROR_COUNT_HUNDRED_PLUS (1 << 2) + + /* PCON HDMI CONFIG PPS Override Buffer + * Valid Offsets to be added to Base : 0-127 + */ + #define DP_PCON_HDMI_PPS_OVERRIDE_BASE 0x3100 + + /* PCON HDMI CONFIG PPS Override Parameter: Slice height + * Offset-0 8LSBs of the Slice height. + * Offset-1 8MSBs of the Slice height. + */ + #define DP_PCON_HDMI_PPS_OVRD_SLICE_HEIGHT 0x3180 + + /* PCON HDMI CONFIG PPS Override Parameter: Slice width + * Offset-0 8LSBs of the Slice width. + * Offset-1 8MSBs of the Slice width. + */ + #define DP_PCON_HDMI_PPS_OVRD_SLICE_WIDTH 0x3182 + + /* PCON HDMI CONFIG PPS Override Parameter: bits_per_pixel + * Offset-0 8LSBs of the bits_per_pixel. + * Offset-1 2MSBs of the bits_per_pixel. + */ + #define DP_PCON_HDMI_PPS_OVRD_BPP 0x3184 + + /* HDCP 1.3 and HDCP 2.2 */ + #define DP_AUX_HDCP_BKSV 0x68000 + #define DP_AUX_HDCP_RI_PRIME 0x68005 + #define DP_AUX_HDCP_AKSV 0x68007 + #define DP_AUX_HDCP_AN 0x6800C + #define DP_AUX_HDCP_V_PRIME(h) (0x68014 + h * 4) + #define DP_AUX_HDCP_BCAPS 0x68028 + # define DP_BCAPS_REPEATER_PRESENT BIT(1) + # define DP_BCAPS_HDCP_CAPABLE BIT(0) + #define DP_AUX_HDCP_BSTATUS 0x68029 + # define DP_BSTATUS_REAUTH_REQ BIT(3) + # define DP_BSTATUS_LINK_FAILURE BIT(2) + # define DP_BSTATUS_R0_PRIME_READY BIT(1) + # define DP_BSTATUS_READY BIT(0) + #define DP_AUX_HDCP_BINFO 0x6802A + #define DP_AUX_HDCP_KSV_FIFO 0x6802C + #define DP_AUX_HDCP_AINFO 0x6803B + + /* DP HDCP2.2 parameter offsets in DPCD address space */ + #define DP_HDCP_2_2_REG_RTX_OFFSET 0x69000 + #define DP_HDCP_2_2_REG_TXCAPS_OFFSET 0x69008 + #define DP_HDCP_2_2_REG_CERT_RX_OFFSET 0x6900B + #define DP_HDCP_2_2_REG_RRX_OFFSET 0x69215 + #define DP_HDCP_2_2_REG_RX_CAPS_OFFSET 0x6921D + #define DP_HDCP_2_2_REG_EKPUB_KM_OFFSET 0x69220 + #define DP_HDCP_2_2_REG_EKH_KM_WR_OFFSET 0x692A0 + #define DP_HDCP_2_2_REG_M_OFFSET 0x692B0 + #define DP_HDCP_2_2_REG_HPRIME_OFFSET 0x692C0 + #define DP_HDCP_2_2_REG_EKH_KM_RD_OFFSET 0x692E0 + #define DP_HDCP_2_2_REG_RN_OFFSET 0x692F0 + #define DP_HDCP_2_2_REG_LPRIME_OFFSET 0x692F8 + #define DP_HDCP_2_2_REG_EDKEY_KS_OFFSET 0x69318 + #define DP_HDCP_2_2_REG_RIV_OFFSET 0x69328 + #define DP_HDCP_2_2_REG_RXINFO_OFFSET 0x69330 + #define DP_HDCP_2_2_REG_SEQ_NUM_V_OFFSET 0x69332 + #define DP_HDCP_2_2_REG_VPRIME_OFFSET 0x69335 + #define DP_HDCP_2_2_REG_RECV_ID_LIST_OFFSET 0x69345 + #define DP_HDCP_2_2_REG_V_OFFSET 0x693E0 + #define DP_HDCP_2_2_REG_SEQ_NUM_M_OFFSET 0x693F0 + #define DP_HDCP_2_2_REG_K_OFFSET 0x693F3 + #define DP_HDCP_2_2_REG_STREAM_ID_TYPE_OFFSET 0x693F5 + #define DP_HDCP_2_2_REG_MPRIME_OFFSET 0x69473 + #define DP_HDCP_2_2_REG_RXSTATUS_OFFSET 0x69493 + #define DP_HDCP_2_2_REG_STREAM_TYPE_OFFSET 0x69494 + #define DP_HDCP_2_2_REG_DBG_OFFSET 0x69518 + + /* LTTPR: Link Training (LT)-tunable PHY Repeaters */ + #define DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV 0xf0000 /* 1.3 */ + #define DP_MAX_LINK_RATE_PHY_REPEATER 0xf0001 /* 1.4a */ + #define DP_PHY_REPEATER_CNT 0xf0002 /* 1.3 */ + #define DP_PHY_REPEATER_MODE 0xf0003 /* 1.3 */ + #define DP_MAX_LANE_COUNT_PHY_REPEATER 0xf0004 /* 1.4a */ + #define DP_Repeater_FEC_CAPABILITY 0xf0004 /* 1.4 */ + #define DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT 0xf0005 /* 1.4a */ + #define DP_MAIN_LINK_CHANNEL_CODING_PHY_REPEATER 0xf0006 /* 2.0 */ + # define DP_PHY_REPEATER_128B132B_SUPPORTED (1 << 0) + /* See DP_128B132B_SUPPORTED_LINK_RATES for values */ + #define DP_PHY_REPEATER_128B132B_RATES 0xf0007 /* 2.0 */ ++#define DP_PHY_REPEATER_EQ_DONE 0xf0008 /* 2.0 E11 */ + + enum drm_dp_phy { + DP_PHY_DPRX, + + DP_PHY_LTTPR1, + DP_PHY_LTTPR2, + DP_PHY_LTTPR3, + DP_PHY_LTTPR4, + DP_PHY_LTTPR5, + DP_PHY_LTTPR6, + DP_PHY_LTTPR7, + DP_PHY_LTTPR8, + + DP_MAX_LTTPR_COUNT = DP_PHY_LTTPR8, + }; + + #define DP_PHY_LTTPR(i) (DP_PHY_LTTPR1 + (i)) + + #define __DP_LTTPR1_BASE 0xf0010 /* 1.3 */ + #define __DP_LTTPR2_BASE 0xf0060 /* 1.3 */ + #define DP_LTTPR_BASE(dp_phy) \ + (__DP_LTTPR1_BASE + (__DP_LTTPR2_BASE - __DP_LTTPR1_BASE) * \ + ((dp_phy) - DP_PHY_LTTPR1)) + + #define DP_LTTPR_REG(dp_phy, lttpr1_reg) \ + (DP_LTTPR_BASE(dp_phy) - DP_LTTPR_BASE(DP_PHY_LTTPR1) + (lttpr1_reg)) + + #define DP_TRAINING_PATTERN_SET_PHY_REPEATER1 0xf0010 /* 1.3 */ + #define DP_TRAINING_PATTERN_SET_PHY_REPEATER(dp_phy) \ + DP_LTTPR_REG(dp_phy, DP_TRAINING_PATTERN_SET_PHY_REPEATER1) + + #define DP_TRAINING_LANE0_SET_PHY_REPEATER1 0xf0011 /* 1.3 */ + #define DP_TRAINING_LANE0_SET_PHY_REPEATER(dp_phy) \ + DP_LTTPR_REG(dp_phy, DP_TRAINING_LANE0_SET_PHY_REPEATER1) + + #define DP_TRAINING_LANE1_SET_PHY_REPEATER1 0xf0012 /* 1.3 */ + #define DP_TRAINING_LANE2_SET_PHY_REPEATER1 0xf0013 /* 1.3 */ + #define DP_TRAINING_LANE3_SET_PHY_REPEATER1 0xf0014 /* 1.3 */ + #define DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 0xf0020 /* 1.4a */ + #define DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy) \ + DP_LTTPR_REG(dp_phy, DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1) + + #define DP_TRANSMITTER_CAPABILITY_PHY_REPEATER1 0xf0021 /* 1.4a */ + # define DP_VOLTAGE_SWING_LEVEL_3_SUPPORTED BIT(0) + # define DP_PRE_EMPHASIS_LEVEL_3_SUPPORTED BIT(1) + + #define DP_128B132B_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 0xf0022 /* 2.0 */ + #define DP_128B132B_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy) \ + DP_LTTPR_REG(dp_phy, DP_128B132B_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1) + /* see DP_128B132B_TRAINING_AUX_RD_INTERVAL for values */ + + #define DP_LANE0_1_STATUS_PHY_REPEATER1 0xf0030 /* 1.3 */ + #define DP_LANE0_1_STATUS_PHY_REPEATER(dp_phy) \ + DP_LTTPR_REG(dp_phy, DP_LANE0_1_STATUS_PHY_REPEATER1) + + #define DP_LANE2_3_STATUS_PHY_REPEATER1 0xf0031 /* 1.3 */ + + #define DP_LANE_ALIGN_STATUS_UPDATED_PHY_REPEATER1 0xf0032 /* 1.3 */ + #define DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1 0xf0033 /* 1.3 */ + #define DP_ADJUST_REQUEST_LANE2_3_PHY_REPEATER1 0xf0034 /* 1.3 */ + #define DP_SYMBOL_ERROR_COUNT_LANE0_PHY_REPEATER1 0xf0035 /* 1.3 */ + #define DP_SYMBOL_ERROR_COUNT_LANE1_PHY_REPEATER1 0xf0037 /* 1.3 */ + #define DP_SYMBOL_ERROR_COUNT_LANE2_PHY_REPEATER1 0xf0039 /* 1.3 */ + #define DP_SYMBOL_ERROR_COUNT_LANE3_PHY_REPEATER1 0xf003b /* 1.3 */ + + #define __DP_FEC1_BASE 0xf0290 /* 1.4 */ + #define __DP_FEC2_BASE 0xf0298 /* 1.4 */ + #define DP_FEC_BASE(dp_phy) \ + (__DP_FEC1_BASE + ((__DP_FEC2_BASE - __DP_FEC1_BASE) * \ + ((dp_phy) - DP_PHY_LTTPR1))) + + #define DP_FEC_REG(dp_phy, fec1_reg) \ + (DP_FEC_BASE(dp_phy) - DP_FEC_BASE(DP_PHY_LTTPR1) + fec1_reg) + + #define DP_FEC_STATUS_PHY_REPEATER1 0xf0290 /* 1.4 */ + #define DP_FEC_STATUS_PHY_REPEATER(dp_phy) \ + DP_FEC_REG(dp_phy, DP_FEC_STATUS_PHY_REPEATER1) + + #define DP_FEC_ERROR_COUNT_PHY_REPEATER1 0xf0291 /* 1.4 */ + #define DP_FEC_CAPABILITY_PHY_REPEATER1 0xf0294 /* 1.4a */ + + #define DP_LTTPR_MAX_ADD 0xf02ff /* 1.4 */ + + #define DP_DPCD_MAX_ADD 0xfffff /* 1.4 */ + + /* Repeater modes */ + #define DP_PHY_REPEATER_MODE_TRANSPARENT 0x55 /* 1.3 */ + #define DP_PHY_REPEATER_MODE_NON_TRANSPARENT 0xaa /* 1.3 */ + + /* DP HDCP message start offsets in DPCD address space */ + #define DP_HDCP_2_2_AKE_INIT_OFFSET DP_HDCP_2_2_REG_RTX_OFFSET + #define DP_HDCP_2_2_AKE_SEND_CERT_OFFSET DP_HDCP_2_2_REG_CERT_RX_OFFSET + #define DP_HDCP_2_2_AKE_NO_STORED_KM_OFFSET DP_HDCP_2_2_REG_EKPUB_KM_OFFSET + #define DP_HDCP_2_2_AKE_STORED_KM_OFFSET DP_HDCP_2_2_REG_EKH_KM_WR_OFFSET + #define DP_HDCP_2_2_AKE_SEND_HPRIME_OFFSET DP_HDCP_2_2_REG_HPRIME_OFFSET + #define DP_HDCP_2_2_AKE_SEND_PAIRING_INFO_OFFSET \ + DP_HDCP_2_2_REG_EKH_KM_RD_OFFSET + #define DP_HDCP_2_2_LC_INIT_OFFSET DP_HDCP_2_2_REG_RN_OFFSET + #define DP_HDCP_2_2_LC_SEND_LPRIME_OFFSET DP_HDCP_2_2_REG_LPRIME_OFFSET + #define DP_HDCP_2_2_SKE_SEND_EKS_OFFSET DP_HDCP_2_2_REG_EDKEY_KS_OFFSET + #define DP_HDCP_2_2_REP_SEND_RECVID_LIST_OFFSET DP_HDCP_2_2_REG_RXINFO_OFFSET + #define DP_HDCP_2_2_REP_SEND_ACK_OFFSET DP_HDCP_2_2_REG_V_OFFSET + #define DP_HDCP_2_2_REP_STREAM_MANAGE_OFFSET DP_HDCP_2_2_REG_SEQ_NUM_M_OFFSET + #define DP_HDCP_2_2_REP_STREAM_READY_OFFSET DP_HDCP_2_2_REG_MPRIME_OFFSET + + #define HDCP_2_2_DP_RXSTATUS_LEN 1 + #define HDCP_2_2_DP_RXSTATUS_READY(x) ((x) & BIT(0)) + #define HDCP_2_2_DP_RXSTATUS_H_PRIME(x) ((x) & BIT(1)) + #define HDCP_2_2_DP_RXSTATUS_PAIRING(x) ((x) & BIT(2)) + #define HDCP_2_2_DP_RXSTATUS_REAUTH_REQ(x) ((x) & BIT(3)) + #define HDCP_2_2_DP_RXSTATUS_LINK_FAILED(x) ((x) & BIT(4)) + + /* DP 1.2 Sideband message defines */ + /* peer device type - DP 1.2a Table 2-92 */ + #define DP_PEER_DEVICE_NONE 0x0 + #define DP_PEER_DEVICE_SOURCE_OR_SST 0x1 + #define DP_PEER_DEVICE_MST_BRANCHING 0x2 + #define DP_PEER_DEVICE_SST_SINK 0x3 + #define DP_PEER_DEVICE_DP_LEGACY_CONV 0x4 + + /* DP 1.2 MST sideband request names DP 1.2a Table 2-80 */ + #define DP_GET_MSG_TRANSACTION_VERSION 0x00 /* DP 1.3 */ + #define DP_LINK_ADDRESS 0x01 + #define DP_CONNECTION_STATUS_NOTIFY 0x02 + #define DP_ENUM_PATH_RESOURCES 0x10 + #define DP_ALLOCATE_PAYLOAD 0x11 + #define DP_QUERY_PAYLOAD 0x12 + #define DP_RESOURCE_STATUS_NOTIFY 0x13 + #define DP_CLEAR_PAYLOAD_ID_TABLE 0x14 + #define DP_REMOTE_DPCD_READ 0x20 + #define DP_REMOTE_DPCD_WRITE 0x21 + #define DP_REMOTE_I2C_READ 0x22 + #define DP_REMOTE_I2C_WRITE 0x23 + #define DP_POWER_UP_PHY 0x24 + #define DP_POWER_DOWN_PHY 0x25 + #define DP_SINK_EVENT_NOTIFY 0x30 + #define DP_QUERY_STREAM_ENC_STATUS 0x38 + #define DP_QUERY_STREAM_ENC_STATUS_STATE_NO_EXIST 0 + #define DP_QUERY_STREAM_ENC_STATUS_STATE_INACTIVE 1 + #define DP_QUERY_STREAM_ENC_STATUS_STATE_ACTIVE 2 + + /* DP 1.2 MST sideband reply types */ + #define DP_SIDEBAND_REPLY_ACK 0x00 + #define DP_SIDEBAND_REPLY_NAK 0x01 + + /* DP 1.2 MST sideband nak reasons - table 2.84 */ + #define DP_NAK_WRITE_FAILURE 0x01 + #define DP_NAK_INVALID_READ 0x02 + #define DP_NAK_CRC_FAILURE 0x03 + #define DP_NAK_BAD_PARAM 0x04 + #define DP_NAK_DEFER 0x05 + #define DP_NAK_LINK_FAILURE 0x06 + #define DP_NAK_NO_RESOURCES 0x07 + #define DP_NAK_DPCD_FAIL 0x08 + #define DP_NAK_I2C_NAK 0x09 + #define DP_NAK_ALLOCATE_FAIL 0x0a + + #define MODE_I2C_START 1 + #define MODE_I2C_WRITE 2 + #define MODE_I2C_READ 4 + #define MODE_I2C_STOP 8 + + /* DP 1.2 MST PORTs - Section 2.5.1 v1.2a spec */ + #define DP_MST_PHYSICAL_PORT_0 0 + #define DP_MST_LOGICAL_PORT_0 8 + + #define DP_LINK_CONSTANT_N_VALUE 0x8000 + #define DP_LINK_STATUS_SIZE 6 + bool drm_dp_channel_eq_ok(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane_count); + bool drm_dp_clock_recovery_ok(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane_count); + u8 drm_dp_get_adjust_request_voltage(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane); + u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane); + u8 drm_dp_get_adjust_tx_ffe_preset(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane); + u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZE], + unsigned int lane); + + #define DP_BRANCH_OUI_HEADER_SIZE 0xc + #define DP_RECEIVER_CAP_SIZE 0xf + #define DP_DSC_RECEIVER_CAP_SIZE 0xf + #define EDP_PSR_RECEIVER_CAP_SIZE 2 + #define EDP_DISPLAY_CTL_CAP_SIZE 3 + #define DP_LTTPR_COMMON_CAP_SIZE 8 + #define DP_LTTPR_PHY_CAP_SIZE 3 + + int drm_dp_read_clock_recovery_delay(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_CAP_SIZE], + enum drm_dp_phy dp_phy, bool uhbr); + int drm_dp_read_channel_eq_delay(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_CAP_SIZE], + enum drm_dp_phy dp_phy, bool uhbr); + + void drm_dp_link_train_clock_recovery_delay(const struct drm_dp_aux *aux, + const u8 dpcd[DP_RECEIVER_CAP_SIZE]); + void drm_dp_lttpr_link_train_clock_recovery_delay(void); + void drm_dp_link_train_channel_eq_delay(const struct drm_dp_aux *aux, + const u8 dpcd[DP_RECEIVER_CAP_SIZE]); + void drm_dp_lttpr_link_train_channel_eq_delay(const struct drm_dp_aux *aux, + const u8 caps[DP_LTTPR_PHY_CAP_SIZE]); + ++int drm_dp_128b132b_read_aux_rd_interval(struct drm_dp_aux *aux); ++bool drm_dp_128b132b_lane_channel_eq_done(const u8 link_status[DP_LINK_STATUS_SIZE], ++ int lane_count); ++bool drm_dp_128b132b_lane_symbol_locked(const u8 link_status[DP_LINK_STATUS_SIZE], ++ int lane_count); ++bool drm_dp_128b132b_eq_interlane_align_done(const u8 link_status[DP_LINK_STATUS_SIZE]); ++bool drm_dp_128b132b_cds_interlane_align_done(const u8 link_status[DP_LINK_STATUS_SIZE]); ++bool drm_dp_128b132b_link_training_failed(const u8 link_status[DP_LINK_STATUS_SIZE]); ++ + u8 drm_dp_link_rate_to_bw_code(int link_rate); + int drm_dp_bw_code_to_link_rate(u8 link_bw); + + #define DP_SDP_AUDIO_TIMESTAMP 0x01 + #define DP_SDP_AUDIO_STREAM 0x02 + #define DP_SDP_EXTENSION 0x04 /* DP 1.1 */ + #define DP_SDP_AUDIO_COPYMANAGEMENT 0x05 /* DP 1.2 */ + #define DP_SDP_ISRC 0x06 /* DP 1.2 */ + #define DP_SDP_VSC 0x07 /* DP 1.2 */ + #define DP_SDP_CAMERA_GENERIC(i) (0x08 + (i)) /* 0-7, DP 1.3 */ + #define DP_SDP_PPS 0x10 /* DP 1.4 */ + #define DP_SDP_VSC_EXT_VESA 0x20 /* DP 1.4 */ + #define DP_SDP_VSC_EXT_CEA 0x21 /* DP 1.4 */ + /* 0x80+ CEA-861 infoframe types */ + + /** + * struct dp_sdp_header - DP secondary data packet header + * @HB0: Secondary Data Packet ID + * @HB1: Secondary Data Packet Type + * @HB2: Secondary Data Packet Specific header, Byte 0 + * @HB3: Secondary Data packet Specific header, Byte 1 + */ + struct dp_sdp_header { + u8 HB0; + u8 HB1; + u8 HB2; + u8 HB3; + } __packed; + + #define EDP_SDP_HEADER_REVISION_MASK 0x1F + #define EDP_SDP_HEADER_VALID_PAYLOAD_BYTES 0x1F + #define DP_SDP_PPS_HEADER_PAYLOAD_BYTES_MINUS_1 0x7F + + /** + * struct dp_sdp - DP secondary data packet + * @sdp_header: DP secondary data packet header + * @db: DP secondaray data packet data blocks + * VSC SDP Payload for PSR + * db[0]: Stereo Interface + * db[1]: 0 - PSR State; 1 - Update RFB; 2 - CRC Valid + * db[2]: CRC value bits 7:0 of the R or Cr component + * db[3]: CRC value bits 15:8 of the R or Cr component + * db[4]: CRC value bits 7:0 of the G or Y component + * db[5]: CRC value bits 15:8 of the G or Y component + * db[6]: CRC value bits 7:0 of the B or Cb component + * db[7]: CRC value bits 15:8 of the B or Cb component + * db[8] - db[31]: Reserved + * VSC SDP Payload for Pixel Encoding/Colorimetry Format + * db[0] - db[15]: Reserved + * db[16]: Pixel Encoding and Colorimetry Formats + * db[17]: Dynamic Range and Component Bit Depth + * db[18]: Content Type + * db[19] - db[31]: Reserved + */ + struct dp_sdp { + struct dp_sdp_header sdp_header; + u8 db[32]; + } __packed; + + #define EDP_VSC_PSR_STATE_ACTIVE (1<<0) + #define EDP_VSC_PSR_UPDATE_RFB (1<<1) + #define EDP_VSC_PSR_CRC_VALUES_VALID (1<<2) + + /** + * enum dp_pixelformat - drm DP Pixel encoding formats + * + * This enum is used to indicate DP VSC SDP Pixel encoding formats. + * It is based on DP 1.4 spec [Table 2-117: VSC SDP Payload for DB16 through + * DB18] + * + * @DP_PIXELFORMAT_RGB: RGB pixel encoding format + * @DP_PIXELFORMAT_YUV444: YCbCr 4:4:4 pixel encoding format + * @DP_PIXELFORMAT_YUV422: YCbCr 4:2:2 pixel encoding format + * @DP_PIXELFORMAT_YUV420: YCbCr 4:2:0 pixel encoding format + * @DP_PIXELFORMAT_Y_ONLY: Y Only pixel encoding format + * @DP_PIXELFORMAT_RAW: RAW pixel encoding format + * @DP_PIXELFORMAT_RESERVED: Reserved pixel encoding format + */ + enum dp_pixelformat { + DP_PIXELFORMAT_RGB = 0, + DP_PIXELFORMAT_YUV444 = 0x1, + DP_PIXELFORMAT_YUV422 = 0x2, + DP_PIXELFORMAT_YUV420 = 0x3, + DP_PIXELFORMAT_Y_ONLY = 0x4, + DP_PIXELFORMAT_RAW = 0x5, + DP_PIXELFORMAT_RESERVED = 0x6, + }; + + /** + * enum dp_colorimetry - drm DP Colorimetry formats + * + * This enum is used to indicate DP VSC SDP Colorimetry formats. + * It is based on DP 1.4 spec [Table 2-117: VSC SDP Payload for DB16 through + * DB18] and a name of enum member follows DRM_MODE_COLORIMETRY definition. + * + * @DP_COLORIMETRY_DEFAULT: sRGB (IEC 61966-2-1) or + * ITU-R BT.601 colorimetry format + * @DP_COLORIMETRY_RGB_WIDE_FIXED: RGB wide gamut fixed point colorimetry format + * @DP_COLORIMETRY_BT709_YCC: ITU-R BT.709 colorimetry format + * @DP_COLORIMETRY_RGB_WIDE_FLOAT: RGB wide gamut floating point + * (scRGB (IEC 61966-2-2)) colorimetry format + * @DP_COLORIMETRY_XVYCC_601: xvYCC601 colorimetry format + * @DP_COLORIMETRY_OPRGB: OpRGB colorimetry format + * @DP_COLORIMETRY_XVYCC_709: xvYCC709 colorimetry format + * @DP_COLORIMETRY_DCI_P3_RGB: DCI-P3 (SMPTE RP 431-2) colorimetry format + * @DP_COLORIMETRY_SYCC_601: sYCC601 colorimetry format + * @DP_COLORIMETRY_RGB_CUSTOM: RGB Custom Color Profile colorimetry format + * @DP_COLORIMETRY_OPYCC_601: opYCC601 colorimetry format + * @DP_COLORIMETRY_BT2020_RGB: ITU-R BT.2020 R' G' B' colorimetry format + * @DP_COLORIMETRY_BT2020_CYCC: ITU-R BT.2020 Y'c C'bc C'rc colorimetry format + * @DP_COLORIMETRY_BT2020_YCC: ITU-R BT.2020 Y' C'b C'r colorimetry format + */ + enum dp_colorimetry { + DP_COLORIMETRY_DEFAULT = 0, + DP_COLORIMETRY_RGB_WIDE_FIXED = 0x1, + DP_COLORIMETRY_BT709_YCC = 0x1, + DP_COLORIMETRY_RGB_WIDE_FLOAT = 0x2, + DP_COLORIMETRY_XVYCC_601 = 0x2, + DP_COLORIMETRY_OPRGB = 0x3, + DP_COLORIMETRY_XVYCC_709 = 0x3, + DP_COLORIMETRY_DCI_P3_RGB = 0x4, + DP_COLORIMETRY_SYCC_601 = 0x4, + DP_COLORIMETRY_RGB_CUSTOM = 0x5, + DP_COLORIMETRY_OPYCC_601 = 0x5, + DP_COLORIMETRY_BT2020_RGB = 0x6, + DP_COLORIMETRY_BT2020_CYCC = 0x6, + DP_COLORIMETRY_BT2020_YCC = 0x7, + }; + + /** + * enum dp_dynamic_range - drm DP Dynamic Range + * + * This enum is used to indicate DP VSC SDP Dynamic Range. + * It is based on DP 1.4 spec [Table 2-117: VSC SDP Payload for DB16 through + * DB18] + * + * @DP_DYNAMIC_RANGE_VESA: VESA range + * @DP_DYNAMIC_RANGE_CTA: CTA range + */ + enum dp_dynamic_range { + DP_DYNAMIC_RANGE_VESA = 0, + DP_DYNAMIC_RANGE_CTA = 1, + }; + + /** + * enum dp_content_type - drm DP Content Type + * + * This enum is used to indicate DP VSC SDP Content Types. + * It is based on DP 1.4 spec [Table 2-117: VSC SDP Payload for DB16 through + * DB18] + * CTA-861-G defines content types and expected processing by a sink device + * + * @DP_CONTENT_TYPE_NOT_DEFINED: Not defined type + * @DP_CONTENT_TYPE_GRAPHICS: Graphics type + * @DP_CONTENT_TYPE_PHOTO: Photo type + * @DP_CONTENT_TYPE_VIDEO: Video type + * @DP_CONTENT_TYPE_GAME: Game type + */ + enum dp_content_type { + DP_CONTENT_TYPE_NOT_DEFINED = 0x00, + DP_CONTENT_TYPE_GRAPHICS = 0x01, + DP_CONTENT_TYPE_PHOTO = 0x02, + DP_CONTENT_TYPE_VIDEO = 0x03, + DP_CONTENT_TYPE_GAME = 0x04, + }; + + /** + * struct drm_dp_vsc_sdp - drm DP VSC SDP + * + * This structure represents a DP VSC SDP of drm + * It is based on DP 1.4 spec [Table 2-116: VSC SDP Header Bytes] and + * [Table 2-117: VSC SDP Payload for DB16 through DB18] + * + * @sdp_type: secondary-data packet type + * @revision: revision number + * @length: number of valid data bytes + * @pixelformat: pixel encoding format + * @colorimetry: colorimetry format + * @bpc: bit per color + * @dynamic_range: dynamic range information + * @content_type: CTA-861-G defines content types and expected processing by a sink device + */ + struct drm_dp_vsc_sdp { + unsigned char sdp_type; + unsigned char revision; + unsigned char length; + enum dp_pixelformat pixelformat; + enum dp_colorimetry colorimetry; + int bpc; + enum dp_dynamic_range dynamic_range; + enum dp_content_type content_type; + }; + + void drm_dp_vsc_sdp_log(const char *level, struct device *dev, + const struct drm_dp_vsc_sdp *vsc); + + int drm_dp_psr_setup_time(const u8 psr_cap[EDP_PSR_RECEIVER_CAP_SIZE]); + + static inline int + drm_dp_max_link_rate(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + return drm_dp_bw_code_to_link_rate(dpcd[DP_MAX_LINK_RATE]); + } + + static inline u8 + drm_dp_max_lane_count(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + return dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK; + } + + static inline bool + drm_dp_enhanced_frame_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + return dpcd[DP_DPCD_REV] >= 0x11 && + (dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP); + } + + static inline bool + drm_dp_fast_training_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + return dpcd[DP_DPCD_REV] >= 0x11 && + (dpcd[DP_MAX_DOWNSPREAD] & DP_NO_AUX_HANDSHAKE_LINK_TRAINING); + } + + static inline bool + drm_dp_tps3_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + return dpcd[DP_DPCD_REV] >= 0x12 && + dpcd[DP_MAX_LANE_COUNT] & DP_TPS3_SUPPORTED; + } + + static inline bool + drm_dp_max_downspread(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + return dpcd[DP_DPCD_REV] >= 0x11 || + dpcd[DP_MAX_DOWNSPREAD] & DP_MAX_DOWNSPREAD_0_5; + } + + static inline bool + drm_dp_tps4_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + return dpcd[DP_DPCD_REV] >= 0x14 && + dpcd[DP_MAX_DOWNSPREAD] & DP_TPS4_SUPPORTED; + } + + static inline u8 + drm_dp_training_pattern_mask(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + return (dpcd[DP_DPCD_REV] >= 0x14) ? DP_TRAINING_PATTERN_MASK_1_4 : + DP_TRAINING_PATTERN_MASK; + } + + static inline bool + drm_dp_is_branch(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + return dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT; + } + + /* DP/eDP DSC support */ + u8 drm_dp_dsc_sink_max_slice_count(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE], + bool is_edp); + u8 drm_dp_dsc_sink_line_buf_depth(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]); + int drm_dp_dsc_sink_supported_input_bpcs(const u8 dsc_dpc[DP_DSC_RECEIVER_CAP_SIZE], + u8 dsc_bpc[3]); + + static inline bool + drm_dp_sink_supports_dsc(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]) + { + return dsc_dpcd[DP_DSC_SUPPORT - DP_DSC_SUPPORT] & + DP_DSC_DECOMPRESSION_IS_SUPPORTED; + } + + static inline u16 + drm_edp_dsc_sink_output_bpp(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]) + { + return dsc_dpcd[DP_DSC_MAX_BITS_PER_PIXEL_LOW - DP_DSC_SUPPORT] | + (dsc_dpcd[DP_DSC_MAX_BITS_PER_PIXEL_HI - DP_DSC_SUPPORT] & + DP_DSC_MAX_BITS_PER_PIXEL_HI_MASK << + DP_DSC_MAX_BITS_PER_PIXEL_HI_SHIFT); + } + + static inline u32 + drm_dp_dsc_sink_max_slice_width(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]) + { + /* Max Slicewidth = Number of Pixels * 320 */ + return dsc_dpcd[DP_DSC_MAX_SLICE_WIDTH - DP_DSC_SUPPORT] * + DP_DSC_SLICE_WIDTH_MULTIPLIER; + } + + /* Forward Error Correction Support on DP 1.4 */ + static inline bool + drm_dp_sink_supports_fec(const u8 fec_capable) + { + return fec_capable & DP_FEC_CAPABLE; + } + + static inline bool + drm_dp_channel_coding_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + return dpcd[DP_MAIN_LINK_CHANNEL_CODING] & DP_CAP_ANSI_8B10B; + } + + static inline bool + drm_dp_alternate_scrambler_reset_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + return dpcd[DP_EDP_CONFIGURATION_CAP] & + DP_ALTERNATE_SCRAMBLER_RESET_CAP; + } + + /* Ignore MSA timing for Adaptive Sync support on DP 1.4 */ + static inline bool + drm_dp_sink_can_do_video_without_timing_msa(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + return dpcd[DP_DOWN_STREAM_PORT_COUNT] & + DP_MSA_TIMING_PAR_IGNORED; + } + + /** + * drm_edp_backlight_supported() - Check an eDP DPCD for VESA backlight support + * @edp_dpcd: The DPCD to check + * + * Note that currently this function will return %false for panels which support various DPCD + * backlight features but which require the brightness be set through PWM, and don't support setting + * the brightness level via the DPCD. + * + * Returns: %True if @edp_dpcd indicates that VESA backlight controls are supported, %false + * otherwise + */ + static inline bool + drm_edp_backlight_supported(const u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE]) + { + return !!(edp_dpcd[1] & DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP); + } + + /* + * DisplayPort AUX channel + */ + + /** + * struct drm_dp_aux_msg - DisplayPort AUX channel transaction + * @address: address of the (first) register to access + * @request: contains the type of transaction (see DP_AUX_* macros) + * @reply: upon completion, contains the reply type of the transaction + * @buffer: pointer to a transmission or reception buffer + * @size: size of @buffer + */ + struct drm_dp_aux_msg { + unsigned int address; + u8 request; + u8 reply; + void *buffer; + size_t size; + }; + + struct cec_adapter; + struct edid; + struct drm_connector; + + /** + * struct drm_dp_aux_cec - DisplayPort CEC-Tunneling-over-AUX + * @lock: mutex protecting this struct + * @adap: the CEC adapter for CEC-Tunneling-over-AUX support. + * @connector: the connector this CEC adapter is associated with + * @unregister_work: unregister the CEC adapter + */ + struct drm_dp_aux_cec { + struct mutex lock; + struct cec_adapter *adap; + struct drm_connector *connector; + struct delayed_work unregister_work; + }; + + /** + * struct drm_dp_aux - DisplayPort AUX channel + * + * An AUX channel can also be used to transport I2C messages to a sink. A + * typical application of that is to access an EDID that's present in the sink + * device. The @transfer() function can also be used to execute such + * transactions. The drm_dp_aux_register() function registers an I2C adapter + * that can be passed to drm_probe_ddc(). Upon removal, drivers should call + * drm_dp_aux_unregister() to remove the I2C adapter. The I2C adapter uses long + * transfers by default; if a partial response is received, the adapter will + * drop down to the size given by the partial response for this transaction + * only. + */ + struct drm_dp_aux { + /** + * @name: user-visible name of this AUX channel and the + * I2C-over-AUX adapter. + * + * It's also used to specify the name of the I2C adapter. If set + * to %NULL, dev_name() of @dev will be used. + */ + const char *name; + + /** + * @ddc: I2C adapter that can be used for I2C-over-AUX + * communication + */ + struct i2c_adapter ddc; + + /** + * @dev: pointer to struct device that is the parent for this + * AUX channel. + */ + struct device *dev; + + /** + * @drm_dev: pointer to the &drm_device that owns this AUX channel. + * Beware, this may be %NULL before drm_dp_aux_register() has been + * called. + * + * It should be set to the &drm_device that will be using this AUX + * channel as early as possible. For many graphics drivers this should + * happen before drm_dp_aux_init(), however it's perfectly fine to set + * this field later so long as it's assigned before calling + * drm_dp_aux_register(). + */ + struct drm_device *drm_dev; + + /** + * @crtc: backpointer to the crtc that is currently using this + * AUX channel + */ + struct drm_crtc *crtc; + + /** + * @hw_mutex: internal mutex used for locking transfers. + * + * Note that if the underlying hardware is shared among multiple + * channels, the driver needs to do additional locking to + * prevent concurrent access. + */ + struct mutex hw_mutex; + + /** + * @crc_work: worker that captures CRCs for each frame + */ + struct work_struct crc_work; + + /** + * @crc_count: counter of captured frame CRCs + */ + u8 crc_count; + + /** + * @transfer: transfers a message representing a single AUX + * transaction. + * + * This is a hardware-specific implementation of how + * transactions are executed that the drivers must provide. + * + * A pointer to a &drm_dp_aux_msg structure describing the + * transaction is passed into this function. Upon success, the + * implementation should return the number of payload bytes that + * were transferred, or a negative error-code on failure. + * + * Helpers will propagate these errors, with the exception of + * the %-EBUSY error, which causes a transaction to be retried. + * On a short, helpers will return %-EPROTO to make it simpler + * to check for failure. + * + * The @transfer() function must only modify the reply field of + * the &drm_dp_aux_msg structure. The retry logic and i2c + * helpers assume this is the case. + * + * Also note that this callback can be called no matter the + * state @dev is in. Drivers that need that device to be powered + * to perform this operation will first need to make sure it's + * been properly enabled. + */ + ssize_t (*transfer)(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg); + + /** + * @i2c_nack_count: Counts I2C NACKs, used for DP validation. + */ + unsigned i2c_nack_count; + /** + * @i2c_defer_count: Counts I2C DEFERs, used for DP validation. + */ + unsigned i2c_defer_count; + /** + * @cec: struct containing fields used for CEC-Tunneling-over-AUX. + */ + struct drm_dp_aux_cec cec; + /** + * @is_remote: Is this AUX CH actually using sideband messaging. + */ + bool is_remote; + }; + + ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset, + void *buffer, size_t size); + ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset, + void *buffer, size_t size); + + /** + * drm_dp_dpcd_readb() - read a single byte from the DPCD + * @aux: DisplayPort AUX channel + * @offset: address of the register to read + * @valuep: location where the value of the register will be stored + * + * Returns the number of bytes transferred (1) on success, or a negative + * error code on failure. + */ + static inline ssize_t drm_dp_dpcd_readb(struct drm_dp_aux *aux, + unsigned int offset, u8 *valuep) + { + return drm_dp_dpcd_read(aux, offset, valuep, 1); + } + + /** + * drm_dp_dpcd_writeb() - write a single byte to the DPCD + * @aux: DisplayPort AUX channel + * @offset: address of the register to write + * @value: value to write to the register + * + * Returns the number of bytes transferred (1) on success, or a negative + * error code on failure. + */ + static inline ssize_t drm_dp_dpcd_writeb(struct drm_dp_aux *aux, + unsigned int offset, u8 value) + { + return drm_dp_dpcd_write(aux, offset, &value, 1); + } + + int drm_dp_read_dpcd_caps(struct drm_dp_aux *aux, + u8 dpcd[DP_RECEIVER_CAP_SIZE]); + + int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux, + u8 status[DP_LINK_STATUS_SIZE]); + + int drm_dp_dpcd_read_phy_link_status(struct drm_dp_aux *aux, + enum drm_dp_phy dp_phy, + u8 link_status[DP_LINK_STATUS_SIZE]); + + bool drm_dp_send_real_edid_checksum(struct drm_dp_aux *aux, + u8 real_edid_checksum); + + int drm_dp_read_downstream_info(struct drm_dp_aux *aux, + const u8 dpcd[DP_RECEIVER_CAP_SIZE], + u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]); + bool drm_dp_downstream_is_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4], u8 type); + bool drm_dp_downstream_is_tmds(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4], + const struct edid *edid); + int drm_dp_downstream_max_dotclock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4]); + int drm_dp_downstream_max_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4], + const struct edid *edid); + int drm_dp_downstream_min_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4], + const struct edid *edid); + int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4], + const struct edid *edid); + bool drm_dp_downstream_420_passthrough(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4]); + bool drm_dp_downstream_444_to_420_conversion(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4]); + struct drm_display_mode *drm_dp_downstream_mode(struct drm_device *dev, + const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4]); + int drm_dp_downstream_id(struct drm_dp_aux *aux, char id[6]); + void drm_dp_downstream_debug(struct seq_file *m, + const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4], + const struct edid *edid, + struct drm_dp_aux *aux); + enum drm_mode_subconnector + drm_dp_subconnector_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4]); + void drm_dp_set_subconnector_property(struct drm_connector *connector, + enum drm_connector_status status, + const u8 *dpcd, + const u8 port_cap[4]); + + struct drm_dp_desc; + bool drm_dp_read_sink_count_cap(struct drm_connector *connector, + const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const struct drm_dp_desc *desc); + int drm_dp_read_sink_count(struct drm_dp_aux *aux); + + int drm_dp_read_lttpr_common_caps(struct drm_dp_aux *aux, + u8 caps[DP_LTTPR_COMMON_CAP_SIZE]); + int drm_dp_read_lttpr_phy_caps(struct drm_dp_aux *aux, + enum drm_dp_phy dp_phy, + u8 caps[DP_LTTPR_PHY_CAP_SIZE]); + int drm_dp_lttpr_count(const u8 cap[DP_LTTPR_COMMON_CAP_SIZE]); + int drm_dp_lttpr_max_link_rate(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE]); + int drm_dp_lttpr_max_lane_count(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE]); + bool drm_dp_lttpr_voltage_swing_level_3_supported(const u8 caps[DP_LTTPR_PHY_CAP_SIZE]); + bool drm_dp_lttpr_pre_emphasis_level_3_supported(const u8 caps[DP_LTTPR_PHY_CAP_SIZE]); + + void drm_dp_remote_aux_init(struct drm_dp_aux *aux); + void drm_dp_aux_init(struct drm_dp_aux *aux); + int drm_dp_aux_register(struct drm_dp_aux *aux); + void drm_dp_aux_unregister(struct drm_dp_aux *aux); + + int drm_dp_start_crc(struct drm_dp_aux *aux, struct drm_crtc *crtc); + int drm_dp_stop_crc(struct drm_dp_aux *aux); + + struct drm_dp_dpcd_ident { + u8 oui[3]; + u8 device_id[6]; + u8 hw_rev; + u8 sw_major_rev; + u8 sw_minor_rev; + } __packed; + + /** + * struct drm_dp_desc - DP branch/sink device descriptor + * @ident: DP device identification from DPCD 0x400 (sink) or 0x500 (branch). + * @quirks: Quirks; use drm_dp_has_quirk() to query for the quirks. + */ + struct drm_dp_desc { + struct drm_dp_dpcd_ident ident; + u32 quirks; + }; + + int drm_dp_read_desc(struct drm_dp_aux *aux, struct drm_dp_desc *desc, + bool is_branch); + + /** + * enum drm_dp_quirk - Display Port sink/branch device specific quirks + * + * Display Port sink and branch devices in the wild have a variety of bugs, try + * to collect them here. The quirks are shared, but it's up to the drivers to + * implement workarounds for them. + */ + enum drm_dp_quirk { + /** + * @DP_DPCD_QUIRK_CONSTANT_N: + * + * The device requires main link attributes Mvid and Nvid to be limited + * to 16 bits. So will give a constant value (0x8000) for compatability. + */ + DP_DPCD_QUIRK_CONSTANT_N, + /** + * @DP_DPCD_QUIRK_NO_PSR: + * + * The device does not support PSR even if reports that it supports or + * driver still need to implement proper handling for such device. + */ + DP_DPCD_QUIRK_NO_PSR, + /** + * @DP_DPCD_QUIRK_NO_SINK_COUNT: + * + * The device does not set SINK_COUNT to a non-zero value. + * The driver should ignore SINK_COUNT during detection. Note that + * drm_dp_read_sink_count_cap() automatically checks for this quirk. + */ + DP_DPCD_QUIRK_NO_SINK_COUNT, + /** + * @DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD: + * + * The device supports MST DSC despite not supporting Virtual DPCD. + * The DSC caps can be read from the physical aux instead. + */ + DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD, + /** + * @DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS: + * + * The device supports a link rate of 3.24 Gbps (multiplier 0xc) despite + * the DP_MAX_LINK_RATE register reporting a lower max multiplier. + */ + DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS, + }; + + /** + * drm_dp_has_quirk() - does the DP device have a specific quirk + * @desc: Device descriptor filled by drm_dp_read_desc() + * @quirk: Quirk to query for + * + * Return true if DP device identified by @desc has @quirk. + */ + static inline bool + drm_dp_has_quirk(const struct drm_dp_desc *desc, enum drm_dp_quirk quirk) + { + return desc->quirks & BIT(quirk); + } + + /** + * struct drm_edp_backlight_info - Probed eDP backlight info struct + * @pwmgen_bit_count: The pwmgen bit count + * @pwm_freq_pre_divider: The PWM frequency pre-divider value being used for this backlight, if any + * @max: The maximum backlight level that may be set + * @lsb_reg_used: Do we also write values to the DP_EDP_BACKLIGHT_BRIGHTNESS_LSB register? + * @aux_enable: Does the panel support the AUX enable cap? + * @aux_set: Does the panel support setting the brightness through AUX? + * + * This structure contains various data about an eDP backlight, which can be populated by using + * drm_edp_backlight_init(). + */ + struct drm_edp_backlight_info { + u8 pwmgen_bit_count; + u8 pwm_freq_pre_divider; + u16 max; + + bool lsb_reg_used : 1; + bool aux_enable : 1; + bool aux_set : 1; + }; + + int + drm_edp_backlight_init(struct drm_dp_aux *aux, struct drm_edp_backlight_info *bl, + u16 driver_pwm_freq_hz, const u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE], + u16 *current_level, u8 *current_mode); + int drm_edp_backlight_set_level(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl, + u16 level); + int drm_edp_backlight_enable(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl, + u16 level); + int drm_edp_backlight_disable(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl); + + #if IS_ENABLED(CONFIG_DRM_KMS_HELPER) && (IS_BUILTIN(CONFIG_BACKLIGHT_CLASS_DEVICE) || \ + (IS_MODULE(CONFIG_DRM_KMS_HELPER) && IS_MODULE(CONFIG_BACKLIGHT_CLASS_DEVICE))) + + int drm_panel_dp_aux_backlight(struct drm_panel *panel, struct drm_dp_aux *aux); + + #else + + static inline int drm_panel_dp_aux_backlight(struct drm_panel *panel, + struct drm_dp_aux *aux) + { + return 0; + } + + #endif + + #ifdef CONFIG_DRM_DP_CEC + void drm_dp_cec_irq(struct drm_dp_aux *aux); + void drm_dp_cec_register_connector(struct drm_dp_aux *aux, + struct drm_connector *connector); + void drm_dp_cec_unregister_connector(struct drm_dp_aux *aux); + void drm_dp_cec_set_edid(struct drm_dp_aux *aux, const struct edid *edid); + void drm_dp_cec_unset_edid(struct drm_dp_aux *aux); + #else + static inline void drm_dp_cec_irq(struct drm_dp_aux *aux) + { + } + + static inline void + drm_dp_cec_register_connector(struct drm_dp_aux *aux, + struct drm_connector *connector) + { + } + + static inline void drm_dp_cec_unregister_connector(struct drm_dp_aux *aux) + { + } + + static inline void drm_dp_cec_set_edid(struct drm_dp_aux *aux, + const struct edid *edid) + { + } + + static inline void drm_dp_cec_unset_edid(struct drm_dp_aux *aux) + { + } + + #endif + + /** + * struct drm_dp_phy_test_params - DP Phy Compliance parameters + * @link_rate: Requested Link rate from DPCD 0x219 + * @num_lanes: Number of lanes requested by sing through DPCD 0x220 + * @phy_pattern: DP Phy test pattern from DPCD 0x248 + * @hbr2_reset: DP HBR2_COMPLIANCE_SCRAMBLER_RESET from DCPD 0x24A and 0x24B + * @custom80: DP Test_80BIT_CUSTOM_PATTERN from DPCDs 0x250 through 0x259 + * @enhanced_frame_cap: flag for enhanced frame capability. + */ + struct drm_dp_phy_test_params { + int link_rate; + u8 num_lanes; + u8 phy_pattern; + u8 hbr2_reset[2]; + u8 custom80[10]; + bool enhanced_frame_cap; + }; + + int drm_dp_get_phy_test_pattern(struct drm_dp_aux *aux, + struct drm_dp_phy_test_params *data); + int drm_dp_set_phy_test_pattern(struct drm_dp_aux *aux, + struct drm_dp_phy_test_params *data, u8 dp_rev); + int drm_dp_get_pcon_max_frl_bw(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4]); + int drm_dp_pcon_frl_prepare(struct drm_dp_aux *aux, bool enable_frl_ready_hpd); + bool drm_dp_pcon_is_frl_ready(struct drm_dp_aux *aux); + int drm_dp_pcon_frl_configure_1(struct drm_dp_aux *aux, int max_frl_gbps, + u8 frl_mode); + int drm_dp_pcon_frl_configure_2(struct drm_dp_aux *aux, int max_frl_mask, + u8 frl_type); + int drm_dp_pcon_reset_frl_config(struct drm_dp_aux *aux); + int drm_dp_pcon_frl_enable(struct drm_dp_aux *aux); + + bool drm_dp_pcon_hdmi_link_active(struct drm_dp_aux *aux); + int drm_dp_pcon_hdmi_link_mode(struct drm_dp_aux *aux, u8 *frl_trained_mask); + void drm_dp_pcon_hdmi_frl_link_error_count(struct drm_dp_aux *aux, + struct drm_connector *connector); + bool drm_dp_pcon_enc_is_dsc_1_2(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]); + int drm_dp_pcon_dsc_max_slices(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]); + int drm_dp_pcon_dsc_max_slice_width(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]); + int drm_dp_pcon_dsc_bpp_incr(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]); + int drm_dp_pcon_pps_default(struct drm_dp_aux *aux); + int drm_dp_pcon_pps_override_buf(struct drm_dp_aux *aux, u8 pps_buf[128]); + int drm_dp_pcon_pps_override_param(struct drm_dp_aux *aux, u8 pps_param[6]); + bool drm_dp_downstream_rgb_to_ycbcr_conversion(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4], u8 color_spc); + int drm_dp_pcon_convert_rgb_to_ycbcr(struct drm_dp_aux *aux, u8 color_spc); + + #endif /* _DRM_DP_HELPER_H_ */