From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932125AbcIJCQe (ORCPT ); Fri, 9 Sep 2016 22:16:34 -0400 Received: from mail-pa0-f65.google.com ([209.85.220.65]:36395 "EHLO mail-pa0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753075AbcIJCP7 (ORCPT ); Fri, 9 Sep 2016 22:15:59 -0400 From: Chris Zhong To: dianders@chromium.org, tfiga@chromium.org, heiko@sntech.de, yzq@rock-chips.com, groeck@chromium.org, myungjoo.ham@samsung.com, cw00.choi@samsung.com, wulf@rock-chips.com, marcheu@chromium.org, briannorris@chromium.org, zhengxing@rock-chips.com, cychiang@chromium.org, hychao@chromium.org, broonie@kernel.org Cc: linux-rockchip@lists.infradead.org, Chris Zhong , Sean Paul , Mark Yao , linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, David Airlie , linux-arm-kernel@lists.infradead.org Subject: [PATCH v15 3/5] drm/rockchip: cdn-dp: add cdn DP support for rk3399 Date: Fri, 9 Sep 2016 19:15:46 -0700 Message-Id: <1473473748-22331-4-git-send-email-zyw@rock-chips.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1473473748-22331-1-git-send-email-zyw@rock-chips.com> References: <1473473748-22331-1-git-send-email-zyw@rock-chips.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add support for cdn DP controller which is embedded in the rk3399 SoCs. The DP is compliant with DisplayPort Specification, Version 1.3, This IP is compatible with the rockchip type-c PHY IP. There is a uCPU in DP controller, it need a firmware to work, please put the firmware file to /lib/firmware/rockchip/dptx.bin. The uCPU in charge of aux communication and link training, the host use mailbox to communicate with the ucpu. The dclk pin_pol of vop must not be invert for DP. Signed-off-by: Chris Zhong Signed-off-by: Sean Paul Reviewed-by: Sean Paul Acked-by: Mark Yao --- Changes in v15: Chris Zhong's changes: - fix disable phy unbalance - support Apple Dock hot-plug in HDMI port - retraining when Apple Dock hpd irq coming Sean Paul's changes: - Restructured the worker - Synchronized between worker & drm hooks - Properly implemented enable/disable - Added error checking - Use devm variant of extcon - Use DRM_DEV_* logging - Refactored code to (hopefully) be more clear Changes in v14: - Modify some grammatical errors - remove the mutex around cdn_dp_audio_get_eld - power on the power domain after clk_enable - retry to read edid - change super speed property name to EXTCON_PROP_USB_SS - do a correct mode_valid check when bpc is 0 Changes in v13: - support suspend/resume - switch power domain dynamically - re-training when hpd signal is triggered Changes in v12: - use EXTCON_PROP_USB_SUPERSPEED to replace EXTCON_USB_HOST Changes in v11: - add best_encoder back, since it required by drm_atomic_helper_check Changes in v10: - remove best_encoder ops - support read sink count from DPCD - control the grf_clk in DP Changes in v9: - do not need reset the phy before power_on - add a orientation information for set_capability - retry to read dpcd in 10 seconds Changes in v8: - optimization the err log Changes in v7: - support firmware standby when no dptx connection - optimization the calculation of tu size and valid symbol Changes in v6: - add a port struct - select SND_SOC_HDMI_CODEC - force reset the phy when hpd detected Changes in v5: - alphabetical order - do not use long, use u32 or u64 - return MODE_CLOCK_HIGH when requested > actual - Optimized Coding Style - add a formula to get better tu size and symbol value. - modify according to Sean Paul's comments - fixed the fw_wait always 0 Changes in v4: - use phy framework to control DP phy - support 2 phys Changes in v3: - use EXTCON_DISP_DP and EXTCON_DISP_DP_ALT cable to get dp port state. - reset spdif before config it - modify the firmware clk to 100Mhz - retry load firmware if fw file is requested too early Changes in v2: - Alphabetic order - remove excess error message - use define clk_rate - check all return value - remove dev_set_name(dp->dev, "cdn-dp"); - use schedule_delayed_work - remove never-called functions - remove some unnecessary () Changes in v1: - use extcon API - use hdmi-codec for the DP Asoc - do not initialize the "ret" - printk a err log when drm_of_encoder_active_endpoint_id - modify the dclk pin_pol to a single line drivers/gpu/drm/rockchip/Kconfig | 10 + drivers/gpu/drm/rockchip/Makefile | 1 + drivers/gpu/drm/rockchip/cdn-dp-core.c | 1161 +++++++++++++++++++++++++++ drivers/gpu/drm/rockchip/cdn-dp-core.h | 108 +++ drivers/gpu/drm/rockchip/cdn-dp-reg.c | 956 ++++++++++++++++++++++ drivers/gpu/drm/rockchip/cdn-dp-reg.h | 482 +++++++++++ drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 13 +- drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 9 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 2 + 9 files changed, 2739 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-core.c create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-core.h create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.c create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.h diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index d30bdc3..20aaafe 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -25,6 +25,16 @@ config ROCKCHIP_ANALOGIX_DP for the Analogix Core DP driver. If you want to enable DP on RK3288 based SoC, you should selet this option. +config ROCKCHIP_CDN_DP + tristate "Rockchip cdn DP" + depends on DRM_ROCKCHIP + select SND_SOC_HDMI_CODEC if SND_SOC + help + This selects support for Rockchip SoC specific extensions + for the cdn DP driver. If you want to enable Dp on + RK3399 based SoC, you should select this + option. + config ROCKCHIP_DW_HDMI tristate "Rockchip specific extensions for Synopsys DW HDMI" depends on DRM_ROCKCHIP diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 9746365..6a07809 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -7,6 +7,7 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o +obj-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o obj-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c new file mode 100644 index 0000000..8d708d3 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -0,0 +1,1161 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" +#include "rockchip_drm_vop.h" + +#define connector_to_dp(c) \ + container_of(c, struct cdn_dp_device, connector) + +#define encoder_to_dp(c) \ + container_of(c, struct cdn_dp_device, encoder) + +#define GRF_SOC_CON9 0x6224 +#define DP_SEL_VOP_LIT BIT(12) +#define GRF_SOC_CON26 0x6268 +#define UPHY_SEL_BIT 3 +#define UPHY_SEL_MASK BIT(19) +#define DPTX_HPD_SEL (3 << 12) +#define DPTX_HPD_DEL (2 << 12) +#define DPTX_HPD_SEL_MASK (3 << 28) + +#define CDN_FW_TIMEOUT_MS (64 * 1000) +#define CDN_DPCD_TIMEOUT_MS 5000 +#define CDN_DP_FIRMWARE "rockchip/dptx.bin" + +struct cdn_dp_data { + u8 max_phy; +}; + +struct cdn_dp_data rk3399_cdn_dp = { + .max_phy = 2, +}; + +static const struct of_device_id cdn_dp_dt_ids[] = { + { .compatible = "rockchip,rk3399-cdn-dp", + .data = (void *)&rk3399_cdn_dp }, + {} +}; + +MODULE_DEVICE_TABLE(of, cdn_dp_dt_ids); + +static int cdn_dp_grf_write(struct cdn_dp_device *dp, + unsigned int reg, unsigned int val) +{ + int ret; + + ret = clk_prepare_enable(dp->grf_clk); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Failed to prepare_enable grf clock\n"); + return ret; + } + + ret = regmap_write(dp->grf, reg, val); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Could not write to GRF: %d\n", ret); + return ret; + } + + clk_disable_unprepare(dp->grf_clk); + + return 0; +} + +static int cdn_dp_clk_enable(struct cdn_dp_device *dp) +{ + int ret; + u32 rate; + + ret = clk_prepare_enable(dp->pclk); + if (ret < 0) { + DRM_DEV_ERROR(dp->dev, "cannot enable dp pclk %d\n", ret); + goto err_pclk; + } + + ret = clk_prepare_enable(dp->core_clk); + if (ret < 0) { + DRM_DEV_ERROR(dp->dev, "cannot enable core_clk %d\n", ret); + goto err_core_clk; + } + + ret = pm_runtime_get_sync(dp->dev); + if (ret < 0) { + DRM_DEV_ERROR(dp->dev, "cannot get pm runtime %d\n", ret); + goto err_pclk; + } + + reset_control_assert(dp->dptx_rst); + reset_control_assert(dp->apb_rst); + reset_control_deassert(dp->dptx_rst); + reset_control_deassert(dp->apb_rst); + + rate = clk_get_rate(dp->core_clk); + if (rate < 0) { + DRM_DEV_ERROR(dp->dev, "get clk rate failed: %d\n", rate); + goto err_set_rate; + } + + cdn_dp_set_fw_clk(dp, rate); + cdn_dp_clock_reset(dp); + + return 0; + +err_set_rate: + clk_disable_unprepare(dp->core_clk); +err_core_clk: + clk_disable_unprepare(dp->pclk); +err_pclk: + return ret; +} + +static void cdn_dp_clk_disable(struct cdn_dp_device *dp) +{ + pm_runtime_put_sync(dp->dev); + clk_disable_unprepare(dp->pclk); + clk_disable_unprepare(dp->core_clk); +} + +static int cdn_dp_get_port_lanes(struct cdn_dp_port *port) +{ + struct extcon_dev *edev = port->extcon; + union extcon_property_value property; + u8 lanes = 0; + int dptx; + + dptx = extcon_get_state(edev, EXTCON_DISP_DP); + if (dptx > 0) { + extcon_get_property(edev, EXTCON_DISP_DP, + EXTCON_PROP_USB_SS, &property); + if (property.intval) + lanes = 2; + else + lanes = 4; + } + + return lanes; +} + +static struct cdn_dp_port *cdn_dp_connected_port(struct cdn_dp_device *dp) +{ + struct cdn_dp_port *port; + int i, lanes; + + if (dp->no_sink) + return NULL; + + for (i = 0; i < dp->ports; i++) { + port = dp->port[i]; + lanes = cdn_dp_get_port_lanes(port); + if (lanes) + return port; + } + return NULL; +} + +static enum drm_connector_status +cdn_dp_connector_detect(struct drm_connector *connector, bool force) +{ + struct cdn_dp_device *dp = connector_to_dp(connector); + enum drm_connector_status status = connector_status_disconnected; + + mutex_lock(&dp->lock); + if (dp->active && dp->enabled) + status = connector_status_connected; + mutex_unlock(&dp->lock); + + return status; +} + +static void cdn_dp_connector_destroy(struct drm_connector *connector) +{ + drm_connector_unregister(connector); + drm_connector_cleanup(connector); +} + +static struct drm_connector_funcs cdn_dp_atomic_connector_funcs = { + .dpms = drm_atomic_helper_connector_dpms, + .detect = cdn_dp_connector_detect, + .destroy = cdn_dp_connector_destroy, + .fill_modes = drm_helper_probe_single_connector_modes, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int cdn_dp_connector_get_modes(struct drm_connector *connector) +{ + struct cdn_dp_device *dp = connector_to_dp(connector); + struct edid *edid; + int ret = 0; + + mutex_lock(&dp->lock); + if (WARN_ON(!dp->fw_loaded)) + goto out; + + edid = drm_do_get_edid(connector, cdn_dp_get_edid_block, dp); + if (edid) { + DRM_DEV_DEBUG_KMS(dp->dev, "got edid: width[%d] x height[%d]\n", + edid->width_cm, edid->height_cm); + + dp->sink_has_audio = drm_detect_monitor_audio(edid); + ret = drm_add_edid_modes(connector, edid); + if (ret) { + drm_mode_connector_update_edid_property(connector, + edid); + drm_edid_to_eld(connector, edid); + } + kfree(edid); + } + +out: + mutex_unlock(&dp->lock); + return ret; +} + +static struct drm_encoder * +cdn_dp_connector_best_encoder(struct drm_connector *connector) +{ + struct cdn_dp_device *dp = connector_to_dp(connector); + + return &dp->encoder; +} + +static int cdn_dp_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct cdn_dp_device *dp = connector_to_dp(connector); + struct drm_display_info *display_info = &dp->connector.display_info; + u32 requested, actual, rate, sink_max, source_max = 0; + u8 lanes, bpc, i; + + switch (display_info->bpc) { + case 16: + case 12: + case 10: + bpc = 10; + break; + case 6: + bpc = 6; + break; + default: + bpc = 8; + break; + } + + requested = mode->clock * bpc * 3 / 1000; + + /* find the running port */ + for (i = 0; i < dp->ports; i++) { + if (dp->port[i]->phy_enabled) { + source_max = dp->port[i]->lanes; + break; + } + } + + sink_max = drm_dp_max_lane_count(dp->dpcd); + lanes = min(source_max, sink_max); + + source_max = drm_dp_bw_code_to_link_rate(CDN_DP_MAX_LINK_RATE); + sink_max = drm_dp_max_link_rate(dp->dpcd); + rate = min(source_max, sink_max); + + actual = rate * lanes / 100; + + /* efficiency is about 0.8 */ + actual = actual * 8 / 10; + + if (requested > actual) { + DRM_DEV_DEBUG_KMS(dp->dev, + "requested=%d, actual=%d, clock=%d\n", + requested, actual, mode->clock); + return MODE_CLOCK_HIGH; + } + + return MODE_OK; +} + +static struct drm_connector_helper_funcs cdn_dp_connector_helper_funcs = { + .get_modes = cdn_dp_connector_get_modes, + .best_encoder = cdn_dp_connector_best_encoder, + .mode_valid = cdn_dp_connector_mode_valid, +}; + +static int cdn_dp_firmware_init(struct cdn_dp_device *dp) +{ + int ret; + const u32 *iram_data, *dram_data; + const struct firmware *fw = dp->fw; + const struct cdn_firmware_header *hdr; + + hdr = (struct cdn_firmware_header *)fw->data; + if (fw->size != le32_to_cpu(hdr->size_bytes)) { + DRM_DEV_ERROR(dp->dev, "firmware is invalid\n"); + return -EINVAL; + } + + iram_data = (const u32 *)(fw->data + hdr->header_size); + dram_data = (const u32 *)(fw->data + hdr->header_size + hdr->iram_size); + + ret = cdn_dp_load_firmware(dp, iram_data, hdr->iram_size, + dram_data, hdr->dram_size); + if (ret) + return ret; + + ret = cdn_dp_set_firmware_active(dp, true); + if (ret) { + DRM_DEV_ERROR(dp->dev, "active ucpu failed: %d\n", ret); + return ret; + } + + return cdn_dp_event_config(dp); +} + +static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp, + struct cdn_dp_port *port) +{ + u8 sink_count; + int ret; + unsigned long timeout = jiffies + msecs_to_jiffies(CDN_DPCD_TIMEOUT_MS); + + /* + * Attempt to read sink count & sink capability, retry in case the sink + * may not be ready. + * + * Sinks are *supposed* to come up within 1ms from an off state, but + * some docks need more time to power up. + */ + while (time_before(jiffies, timeout)) { + ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, &sink_count, 1); + if (!ret) { + DRM_DEV_DEBUG_KMS(dp->dev, "get dpcd success!\n"); + + sink_count = DP_GET_SINK_COUNT(sink_count); + if (!sink_count) { + DRM_DEV_ERROR(dp->dev, "Sink count is 0\n"); + return -ENODEV; + } + + ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, + DP_RECEIVER_CAP_SIZE); + if (ret) + continue; + + return 0; + + } else if (!extcon_get_state(port->extcon, EXTCON_DISP_DP)) { + break; + } + usleep_range(5000, 10000); + } + + dev_err(dp->dev, "get dpcd failed!\n"); + return -ETIMEDOUT; +} + +static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port) +{ + union extcon_property_value property; + int ret; + + ret = cdn_dp_grf_write(dp, GRF_SOC_CON26, + (port->id << UPHY_SEL_BIT) | UPHY_SEL_MASK); + if (ret) + return ret; + + if (!port->phy_enabled) { + ret = phy_power_on(port->phy); + if (ret) { + DRM_DEV_ERROR(dp->dev, "phy power on failed: %d\n", + ret); + goto err_phy; + } + port->phy_enabled = true; + } + + ret = cdn_dp_grf_write(dp, GRF_SOC_CON26, + DPTX_HPD_SEL_MASK | DPTX_HPD_SEL); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Failed to write HPD_SEL %d\n", ret); + goto err_power_on; + } + + ret = cdn_dp_get_hpd_status(dp); + if (ret <= 0) { + if (!ret) + DRM_DEV_ERROR(dp->dev, "hpd does not exist\n"); + goto err_power_on; + } + + ret = extcon_get_property(port->extcon, EXTCON_DISP_DP, + EXTCON_PROP_USB_TYPEC_POLARITY, &property); + if (ret) { + DRM_DEV_ERROR(dp->dev, "get property failed\n"); + goto err_power_on; + } + + port->lanes = cdn_dp_get_port_lanes(port); + ret = cdn_dp_set_host_cap(dp, port->lanes, property.intval); + if (ret) { + DRM_DEV_ERROR(dp->dev, "set host capabilities failed: %d\n", + ret); + goto err_power_on; + } + + return 0; + +err_power_on: + if (phy_power_off(port->phy)) + DRM_DEV_ERROR(dp->dev, "phy power off failed: %d", ret); + else + port->phy_enabled = false; + +err_phy: + cdn_dp_grf_write(dp, GRF_SOC_CON26, + DPTX_HPD_SEL_MASK | DPTX_HPD_DEL); + return ret; +} + +static int cdn_dp_disable_phy(struct cdn_dp_device *dp, + struct cdn_dp_port *port) +{ + int ret; + + if (port->phy_enabled) { + ret = phy_power_off(port->phy); + if (ret) { + DRM_DEV_ERROR(dp->dev, "phy power off failed: %d", ret); + return ret; + } + } + + port->phy_enabled = false; + port->lanes = 0; + return 0; +} + +static int cdn_dp_enable(struct cdn_dp_device *dp) +{ + int ret; + struct cdn_dp_port *port; + + if (dp->active) + return 0; + + port = cdn_dp_connected_port(dp); + if (!port) { + DRM_DEV_ERROR(dp->dev, "Can't enable without connection\n"); + return -ENODEV; + } + + ret = cdn_dp_clk_enable(dp); + if (ret) + return ret; + + ret = cdn_dp_firmware_init(dp); + if (ret) { + DRM_DEV_ERROR(dp->dev, "firmware init failed: %d", ret); + goto err_clk_disable; + } + + ret = cdn_dp_enable_phy(dp, port); + if (ret) + goto err_clk_disable; + + ret = cdn_dp_get_sink_capability(dp, port); + if (ret) + goto err_phy_disable; + + dp->active = true; + return 0; + +err_phy_disable: + cdn_dp_disable_phy(dp, port); +err_clk_disable: + cdn_dp_clk_disable(dp); + return ret; +} + +static int cdn_dp_disable(struct cdn_dp_device *dp) +{ + int ret, i; + + if (!dp->active) + return 0; + + for (i = 0; i < dp->ports; i++) { + if (cdn_dp_get_port_lanes(dp->port[i])) + cdn_dp_disable_phy(dp, dp->port[i]); + } + + ret = cdn_dp_grf_write(dp, GRF_SOC_CON26, + DPTX_HPD_SEL_MASK | DPTX_HPD_DEL); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Failed to clear hpd sel %d\n", + ret); + return ret; + } + + cdn_dp_set_firmware_active(dp, false); + cdn_dp_clk_disable(dp); + dp->active = false; + dp->no_sink = false; + return 0; +} + +static void cdn_dp_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted) +{ + struct cdn_dp_device *dp = encoder_to_dp(encoder); + struct drm_display_info *display_info = &dp->connector.display_info; + struct rockchip_crtc_state *state; + struct video_info *video = &dp->video_info; + int ret, val; + + switch (display_info->bpc) { + case 16: + case 12: + case 10: + video->color_depth = 10; + break; + case 6: + video->color_depth = 6; + break; + default: + video->color_depth = 8; + break; + } + + video->color_fmt = PXL_RGB; + + video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); + video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); + + ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder); + if (ret < 0) { + DRM_DEV_ERROR(dp->dev, "Could not get vop id, %d", ret); + return; + } + + DRM_DEV_DEBUG_KMS(dp->dev, "vop %s output to cdn-dp\n", + (ret) ? "LIT" : "BIG"); + state = to_rockchip_crtc_state(encoder->crtc->state); + if (ret) { + val = DP_SEL_VOP_LIT | (DP_SEL_VOP_LIT << 16); + state->output_mode = ROCKCHIP_OUT_MODE_P888; + } else { + val = DP_SEL_VOP_LIT << 16; + state->output_mode = ROCKCHIP_OUT_MODE_AAAA; + } + + ret = cdn_dp_grf_write(dp, GRF_SOC_CON9, val); + if (ret) + return; + + memcpy(&dp->mode, adjusted, sizeof(*mode)); +} + +static void cdn_dp_encoder_enable(struct drm_encoder *encoder) +{ + struct cdn_dp_device *dp = encoder_to_dp(encoder); + int ret; + + mutex_lock(&dp->lock); + if (!dp->active) { + ret = cdn_dp_enable(dp); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Failed to enable encoder %d\n", + ret); + } + } + + ret = cdn_dp_training_start(dp); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Failed to start training %d\n", ret); + goto out; + } + + ret = cdn_dp_get_training_status(dp); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Failed to get training stat %d\n", ret); + goto out; + } + + DRM_DEV_INFO(dp->dev, "rate:0x%x, lanes:%d\n", dp->link.rate, + dp->link.num_lanes); + + if (cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE)) { + DRM_DEV_ERROR(dp->dev, "Failed to idle video\n"); + goto out; + } + + if (cdn_dp_config_video(dp)) { + DRM_DEV_ERROR(dp->dev, "Failed to config video\n"); + goto out; + } + + if (cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID)) { + DRM_DEV_ERROR(dp->dev, "Failed to valid video\n"); + goto out; + } + +out: + mutex_unlock(&dp->lock); +} + +static void cdn_dp_encoder_disable(struct drm_encoder *encoder) +{ + struct cdn_dp_device *dp = encoder_to_dp(encoder); + int ret; + + mutex_lock(&dp->lock); + if (dp->active) { + ret = cdn_dp_disable(dp); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Failed to disable encoder %d\n", + ret); + } + } + mutex_unlock(&dp->lock); +} + +static int cdn_dp_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + + s->output_mode = ROCKCHIP_OUT_MODE_AAAA; + s->output_type = DRM_MODE_CONNECTOR_DisplayPort; + + return 0; +} + +static struct drm_encoder_helper_funcs cdn_dp_encoder_helper_funcs = { + .mode_set = cdn_dp_encoder_mode_set, + .enable = cdn_dp_encoder_enable, + .disable = cdn_dp_encoder_disable, + .atomic_check = cdn_dp_encoder_atomic_check, +}; + +static struct drm_encoder_funcs cdn_dp_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static int cdn_dp_parse_dt(struct cdn_dp_device *dp) +{ + struct device *dev = dp->dev; + struct device_node *np = dev->of_node; + struct platform_device *pdev = to_platform_device(dev); + struct resource *res; + + dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); + if (IS_ERR(dp->grf)) { + DRM_DEV_ERROR(dev, "cdn-dp needs rockchip,grf property\n"); + return PTR_ERR(dp->grf); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dp->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(dp->regs)) { + DRM_DEV_ERROR(dev, "ioremap reg failed\n"); + return PTR_ERR(dp->regs); + } + + dp->core_clk = devm_clk_get(dev, "core-clk"); + if (IS_ERR(dp->core_clk)) { + DRM_DEV_ERROR(dev, "cannot get core_clk_dp\n"); + return PTR_ERR(dp->core_clk); + } + + dp->pclk = devm_clk_get(dev, "pclk"); + if (IS_ERR(dp->pclk)) { + DRM_DEV_ERROR(dev, "cannot get pclk\n"); + return PTR_ERR(dp->pclk); + } + + dp->spdif_clk = devm_clk_get(dev, "spdif"); + if (IS_ERR(dp->spdif_clk)) { + DRM_DEV_ERROR(dev, "cannot get spdif_clk\n"); + return PTR_ERR(dp->spdif_clk); + } + + dp->grf_clk = devm_clk_get(dev, "grf"); + if (IS_ERR(dp->grf_clk)) { + DRM_DEV_ERROR(dev, "cannot get grf clk\n"); + return PTR_ERR(dp->grf_clk); + } + + dp->spdif_rst = devm_reset_control_get(dev, "spdif"); + if (IS_ERR(dp->spdif_rst)) { + DRM_DEV_ERROR(dev, "no spdif reset control found\n"); + return PTR_ERR(dp->spdif_rst); + } + + dp->dptx_rst = devm_reset_control_get(dev, "dptx"); + if (IS_ERR(dp->dptx_rst)) { + DRM_DEV_ERROR(dev, "no uphy reset control found\n"); + return PTR_ERR(dp->dptx_rst); + } + + dp->apb_rst = devm_reset_control_get(dev, "apb"); + if (IS_ERR(dp->apb_rst)) { + DRM_DEV_ERROR(dev, "no apb reset control found\n"); + return PTR_ERR(dp->apb_rst); + } + + return 0; +} + +static int cdn_dp_audio_hw_params(struct device *dev, void *data, + struct hdmi_codec_daifmt *daifmt, + struct hdmi_codec_params *params) +{ + struct cdn_dp_device *dp = dev_get_drvdata(dev); + struct audio_info audio = { + .sample_width = params->sample_width, + .sample_rate = params->sample_rate, + .channels = params->channels, + }; + int ret; + + if (!dp->encoder.crtc) + return -ENODEV; + + switch (daifmt->fmt) { + case HDMI_I2S: + audio.format = AFMT_I2S; + break; + case HDMI_SPDIF: + audio.format = AFMT_SPDIF; + break; + default: + DRM_DEV_ERROR(dev, "Invalid format %d\n", daifmt->fmt); + return -EINVAL; + } + + ret = cdn_dp_audio_config(dp, &audio); + if (!ret) + dp->audio_info = audio; + + return ret; +} + +static void cdn_dp_audio_shutdown(struct device *dev, void *data) +{ + struct cdn_dp_device *dp = dev_get_drvdata(dev); + int ret; + + if (!dp->encoder.crtc) + return; + + ret = cdn_dp_audio_stop(dp, &dp->audio_info); + if (!ret) + dp->audio_info.format = AFMT_UNUSED; +} + +static int cdn_dp_audio_digital_mute(struct device *dev, void *data, + bool enable) +{ + struct cdn_dp_device *dp = dev_get_drvdata(dev); + + if (!dp->encoder.crtc) + return -ENODEV; + + return cdn_dp_audio_mute(dp, enable); +} + +static int cdn_dp_audio_get_eld(struct device *dev, void *data, + u8 *buf, size_t len) +{ + struct cdn_dp_device *dp = dev_get_drvdata(dev); + + memcpy(buf, dp->connector.eld, min(sizeof(dp->connector.eld), len)); + + return 0; +} + +static const struct hdmi_codec_ops audio_codec_ops = { + .hw_params = cdn_dp_audio_hw_params, + .audio_shutdown = cdn_dp_audio_shutdown, + .digital_mute = cdn_dp_audio_digital_mute, + .get_eld = cdn_dp_audio_get_eld, +}; + +static int cdn_dp_audio_codec_init(struct cdn_dp_device *dp, + struct device *dev) +{ + struct hdmi_codec_pdata codec_data = { + .i2s = 1, + .spdif = 1, + .ops = &audio_codec_ops, + .max_i2s_channels = 8, + }; + + dp->audio_pdev = platform_device_register_data( + dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, + &codec_data, sizeof(codec_data)); + + return PTR_ERR_OR_ZERO(dp->audio_pdev); +} + +static int cdn_dp_request_firmware(struct cdn_dp_device *dp) +{ + int ret; + unsigned long timeout = jiffies + msecs_to_jiffies(CDN_FW_TIMEOUT_MS); + unsigned long sleep = 1000; + + WARN_ON(!mutex_is_locked(&dp->lock)); + + if (dp->fw_loaded) + return 0; + + /* Drop the lock before getting the firmware to avoid blocking boot */ + mutex_unlock(&dp->lock); + + while (time_before(jiffies, timeout)) { + ret = request_firmware(&dp->fw, CDN_DP_FIRMWARE, dp->dev); + if (ret == -ENOENT) { + msleep(sleep); + sleep *= 2; + continue; + } else if (ret) { + DRM_DEV_ERROR(dp->dev, + "failed to request firmware: %d\n", ret); + goto out; + } + + dp->fw_loaded = true; + ret = 0; + goto out; + } + + DRM_DEV_ERROR(dp->dev, "Timed out trying to load firmware\n"); + ret = -ETIMEDOUT; +out: + mutex_lock(&dp->lock); + return ret; +} + +static void cdn_dp_pd_event_work(struct work_struct *work) +{ + struct cdn_dp_device *dp = container_of(work, struct cdn_dp_device, + event_work); + union extcon_property_value property; + struct cdn_dp_port *port; + int ret, i, lanes; + bool hpd_event = false; + bool re_training = false; + u8 sink_count; + + DRM_DEV_INFO(dp->dev, "Received DP hotplug event\n"); + + mutex_lock(&dp->lock); + if (!dp->enabled) + goto out; + + ret = cdn_dp_request_firmware(dp); + if (ret) + goto out; + + /* We might need to notify userspace for everything below here */ + hpd_event = true; + + /* Disable any ports that have just become inactive */ + for (i = 0; i < dp->ports; i++) { + port = dp->port[i]; + lanes = cdn_dp_get_port_lanes(port); + if (lanes && dp->active) { + extcon_get_property(port->extcon, EXTCON_DISP_DP, + EXTCON_PROP_DISP_HPD, &property); + + ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, + &sink_count, 1); + if (ret || !sink_count) { + dp->no_sink = true; + lanes = 0; + } else if (property.intval) { + re_training = true; + goto out; + } + } + + if (!lanes && port->lanes) + cdn_dp_disable_phy(dp, port); + } + + /* Power on/off the block and ports */ + if (!cdn_dp_connected_port(dp)) { + ret = cdn_dp_disable(dp); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Disable dp failed %d\n", ret); + goto out; + } + + } else if (!dp->active) { + ret = cdn_dp_enable(dp); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Failed to enable dp %d\n", ret); + goto out; + } + } + +out: + mutex_unlock(&dp->lock); + + if (hpd_event) + drm_helper_hpd_irq_event(dp->drm_dev); + + if (re_training) + cdn_dp_encoder_enable(&dp->encoder); +} + +static int cdn_dp_pd_event(struct notifier_block *nb, + unsigned long event, void *priv) +{ + struct cdn_dp_port *port = container_of(nb, struct cdn_dp_port, + event_nb); + struct cdn_dp_device *dp = port->dp; + + /* + * It would be nice to be able to just do the work inline right here. + * However, we need to make a bunch of calls that might sleep in order + * to turn on the block/phy, so use a worker instead. + */ + schedule_work(&dp->event_work); + + return NOTIFY_DONE; +} + +static int cdn_dp_bind(struct device *dev, struct device *master, void *data) +{ + struct cdn_dp_device *dp = dev_get_drvdata(dev); + struct drm_encoder *encoder; + struct drm_connector *connector; + struct cdn_dp_port *port; + struct drm_device *drm_dev = data; + int ret, i; + + pm_runtime_enable(dev); + + ret = cdn_dp_parse_dt(dp); + if (ret < 0) + return ret; + + dp->drm_dev = drm_dev; + dp->enabled = true; + dp->active = false; + + mutex_init(&dp->lock); + INIT_WORK(&dp->event_work, cdn_dp_pd_event_work); + + encoder = &dp->encoder; + + encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev, + dev->of_node); + DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); + + ret = drm_encoder_init(drm_dev, encoder, &cdn_dp_encoder_funcs, + DRM_MODE_ENCODER_TMDS, NULL); + if (ret) { + DRM_ERROR("failed to initialize encoder with drm\n"); + return ret; + } + + drm_encoder_helper_add(encoder, &cdn_dp_encoder_helper_funcs); + + connector = &dp->connector; + connector->polled = DRM_CONNECTOR_POLL_HPD; + connector->dpms = DRM_MODE_DPMS_OFF; + + ret = drm_connector_init(drm_dev, connector, + &cdn_dp_atomic_connector_funcs, + DRM_MODE_CONNECTOR_DisplayPort); + if (ret) { + DRM_ERROR("failed to initialize connector with drm\n"); + goto err_free_encoder; + } + + drm_connector_helper_add(connector, &cdn_dp_connector_helper_funcs); + + ret = drm_mode_connector_attach_encoder(connector, encoder); + if (ret) { + DRM_ERROR("failed to attach connector and encoder\n"); + goto err_free_connector; + } + + cdn_dp_audio_codec_init(dp, dev); + + for (i = 0; i < dp->ports; i++) { + port = dp->port[i]; + + port->event_nb.notifier_call = cdn_dp_pd_event; + ret = devm_extcon_register_notifier(dp->dev, port->extcon, + EXTCON_DISP_DP, + &port->event_nb); + if (ret) { + DRM_DEV_ERROR(dev, + "register EXTCON_DISP_DP notifier err\n"); + goto err_free_connector; + } + + if (extcon_get_state(port->extcon, EXTCON_DISP_DP)) + schedule_work(&dp->event_work); + } + + return 0; + +err_free_connector: + drm_connector_cleanup(connector); +err_free_encoder: + drm_encoder_cleanup(encoder); + return ret; +} + +static void cdn_dp_unbind(struct device *dev, struct device *master, void *data) +{ + struct cdn_dp_device *dp = dev_get_drvdata(dev); + struct drm_encoder *encoder = &dp->encoder; + struct drm_connector *connector = &dp->connector; + + platform_device_unregister(dp->audio_pdev); + cdn_dp_encoder_disable(encoder); + encoder->funcs->destroy(encoder); + connector->funcs->destroy(connector); + + pm_runtime_disable(dev); + release_firmware(dp->fw); +} + +static const struct component_ops cdn_dp_component_ops = { + .bind = cdn_dp_bind, + .unbind = cdn_dp_unbind, +}; + +int cdn_dp_suspend(struct device *dev) +{ + struct cdn_dp_device *dp = dev_get_drvdata(dev); + + if (dp->active) + return cdn_dp_disable(dp); + + return 0; +} + +int cdn_dp_resume(struct device *dev) +{ + struct cdn_dp_device *dp = dev_get_drvdata(dev); + + schedule_work(&dp->event_work); + return 0; +} + +static int cdn_dp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *match; + struct cdn_dp_data *dp_data; + struct cdn_dp_port *port; + struct cdn_dp_device *dp; + struct extcon_dev *extcon; + struct phy *phy; + int i; + + dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); + if (!dp) + return -ENOMEM; + dp->dev = dev; + + match = of_match_node(cdn_dp_dt_ids, pdev->dev.of_node); + dp_data = (struct cdn_dp_data *)match->data; + + for (i = 0; i < dp_data->max_phy; i++) { + extcon = extcon_get_edev_by_phandle(dev, i); + phy = devm_of_phy_get_by_index(dev, dev->of_node, i); + + if (PTR_ERR(extcon) == -EPROBE_DEFER || + PTR_ERR(phy) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + if (IS_ERR(extcon) || IS_ERR(phy)) + continue; + + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!dp) + return -ENOMEM; + + port->extcon = extcon; + port->phy = phy; + port->dp = dp; + port->id = i; + dp->port[dp->ports++] = port; + } + + if (!dp->ports) { + DRM_DEV_ERROR(dev, "missing extcon or phy\n"); + return -EINVAL; + } + + dev_set_drvdata(dev, dp); + + return component_add(dev, &cdn_dp_component_ops); +} + +static int cdn_dp_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &cdn_dp_component_ops); + + return 0; +} + +static const struct dev_pm_ops cdn_dp_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(cdn_dp_suspend, + cdn_dp_resume) +}; + +static struct platform_driver cdn_dp_driver = { + .probe = cdn_dp_probe, + .remove = cdn_dp_remove, + .driver = { + .name = "cdn-dp", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(cdn_dp_dt_ids), + .pm = &cdn_dp_pm_ops, + }, +}; + +module_platform_driver(cdn_dp_driver); + +MODULE_AUTHOR("Chris Zhong "); +MODULE_DESCRIPTION("cdn DP Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h new file mode 100644 index 0000000..c0f7d04 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2016 Chris Zhong + * Copyright (C) 2016 ROCKCHIP, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CDN_DP_CORE_H +#define _CDN_DP_CORE_H + +#include +#include +#include +#include +#include "rockchip_drm_drv.h" + +#define MAX_PHY 2 + +enum audio_format { + AFMT_I2S = 0, + AFMT_SPDIF = 1, + AFMT_UNUSED, +}; + +struct audio_info { + enum audio_format format; + int sample_rate; + int channels; + int sample_width; +}; + +enum vic_pxl_encoding_format { + PXL_RGB = 0x1, + YCBCR_4_4_4 = 0x2, + YCBCR_4_2_2 = 0x4, + YCBCR_4_2_0 = 0x8, + Y_ONLY = 0x10, +}; + +struct video_info { + bool h_sync_polarity; + bool v_sync_polarity; + bool interlaced; + int color_depth; + enum vic_pxl_encoding_format color_fmt; +}; + +struct cdn_firmware_header { + u32 size_bytes; /* size of the entire header+image(s) in bytes */ + u32 header_size; /* size of just the header in bytes */ + u32 iram_size; /* size of iram */ + u32 dram_size; /* size of dram */ +}; + +struct cdn_dp_port { + struct cdn_dp_device *dp; + struct notifier_block event_nb; + struct extcon_dev *extcon; + struct phy *phy; + u8 lanes; + bool phy_enabled; + u8 id; +}; + +struct cdn_dp_device { + struct device *dev; + struct drm_device *drm_dev; + struct drm_connector connector; + struct drm_encoder encoder; + struct drm_display_mode mode; + struct platform_device *audio_pdev; + struct work_struct event_work; + + struct mutex lock; + bool enabled; + bool active; + + const struct firmware *fw; /* cdn dp firmware */ + unsigned int fw_version; /* cdn fw version */ + bool fw_loaded; + + void __iomem *regs; + struct regmap *grf; + struct clk *core_clk; + struct clk *pclk; + struct clk *spdif_clk; + struct clk *grf_clk; + struct reset_control *spdif_rst; + struct reset_control *dptx_rst; + struct reset_control *apb_rst; + struct audio_info audio_info; + struct video_info video_info; + struct drm_dp_link link; + struct cdn_dp_port *port[MAX_PHY]; + u8 ports; + + u8 dpcd[DP_RECEIVER_CAP_SIZE]; + bool sink_has_audio; + bool no_sink; +}; +#endif /* _CDN_DP_CORE_H */ diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c new file mode 100644 index 0000000..8d7d1c9 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -0,0 +1,956 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" + +#define CDN_DP_SPDIF_CLK 200000000 +#define FW_ALIVE_TIMEOUT_US 1000000 +#define MAILBOX_RETRY_US 1000 +#define MAILBOX_TIMEOUT_US 5000000 +#define LINK_TRAINING_RETRY_MS 20 +#define LINK_TRAINING_TIMEOUT_MS 500 + +void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, u32 clk) +{ + writel(clk / 1000000, dp->regs + SW_CLK_H); +} + +void cdn_dp_clock_reset(struct cdn_dp_device *dp) +{ + u32 val; + + val = DPTX_FRMR_DATA_CLK_RSTN_EN | + DPTX_FRMR_DATA_CLK_EN | + DPTX_PHY_DATA_RSTN_EN | + DPTX_PHY_DATA_CLK_EN | + DPTX_PHY_CHAR_RSTN_EN | + DPTX_PHY_CHAR_CLK_EN | + SOURCE_AUX_SYS_CLK_RSTN_EN | + SOURCE_AUX_SYS_CLK_EN | + DPTX_SYS_CLK_RSTN_EN | + DPTX_SYS_CLK_EN | + CFG_DPTX_VIF_CLK_RSTN_EN | + CFG_DPTX_VIF_CLK_EN; + writel(val, dp->regs + SOURCE_DPTX_CAR); + + val = SOURCE_PHY_RSTN_EN | SOURCE_PHY_CLK_EN; + writel(val, dp->regs + SOURCE_PHY_CAR); + + val = SOURCE_PKT_SYS_RSTN_EN | + SOURCE_PKT_SYS_CLK_EN | + SOURCE_PKT_DATA_RSTN_EN | + SOURCE_PKT_DATA_CLK_EN; + writel(val, dp->regs + SOURCE_PKT_CAR); + + val = SPDIF_CDR_CLK_RSTN_EN | + SPDIF_CDR_CLK_EN | + SOURCE_AIF_SYS_RSTN_EN | + SOURCE_AIF_SYS_CLK_EN | + SOURCE_AIF_CLK_RSTN_EN | + SOURCE_AIF_CLK_EN; + writel(val, dp->regs + SOURCE_AIF_CAR); + + val = SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN | + SOURCE_CIPHER_SYS_CLK_EN | + SOURCE_CIPHER_CHAR_CLK_RSTN_EN | + SOURCE_CIPHER_CHAR_CLK_EN; + writel(val, dp->regs + SOURCE_CIPHER_CAR); + + val = SOURCE_CRYPTO_SYS_CLK_RSTN_EN | + SOURCE_CRYPTO_SYS_CLK_EN; + writel(val, dp->regs + SOURCE_CRYPTO_CAR); + + val = ~(MAILBOX_INT_MASK_BIT | PIF_INT_MASK_BIT) & ALL_INT_MASK; + writel(val, dp->regs + APB_INT_MASK); +} + +static int cdn_dp_mailbox_read(struct cdn_dp_device *dp, bool force) +{ + int val, ret; + + ret = readx_poll_timeout(readl, dp->regs + MAILBOX_EMPTY_ADDR, + val, !val, MAILBOX_RETRY_US, + MAILBOX_TIMEOUT_US); + if (ret < 0) + return ret; + + return readl(dp->regs + MAILBOX0_RD_DATA) & 0xff; +} + +static int cdp_dp_mailbox_write(struct cdn_dp_device *dp, u8 val, bool force) +{ + int ret, full; + + ret = readx_poll_timeout(readl, dp->regs + MAILBOX_FULL_ADDR, + full, !full, MAILBOX_RETRY_US, + MAILBOX_TIMEOUT_US); + if (ret < 0) + return ret; + + writel(val, dp->regs + MAILBOX0_WR_DATA); + + return 0; +} + +static int cdn_dp_mailbox_validate_receive(struct cdn_dp_device *dp, + u8 module_id, u8 opcode, + u8 req_size) +{ + u32 mbox_size, i; + u8 header[4]; + int ret; + + /* read the header of the message */ + for (i = 0; i < 4; i++) { + ret = cdn_dp_mailbox_read(dp, 0); + if (ret < 0) + return ret; + + header[i] = ret; + } + + mbox_size = (header[2] << 8) | header[3]; + + if (opcode != header[0] || module_id != header[1] || + req_size != mbox_size) { + /* + * If the message in mailbox is not what we want, we need to + * clear the mailbox by reading its contents. + */ + for (i = 0; i < mbox_size; i++) + if (cdn_dp_mailbox_read(dp, 0) < 0) + break; + + return -EINVAL; + } + + return 0; +} + +static int cdn_dp_mailbox_read_receive(struct cdn_dp_device *dp, + u8 *buff, u8 buff_size) +{ + u32 i; + int ret; + + for (i = 0; i < buff_size; i++) { + ret = cdn_dp_mailbox_read(dp, 0); + if (ret < 0) + return ret; + + buff[i] = ret; + } + + return 0; +} + +static int cdn_dp_mailbox_send(struct cdn_dp_device *dp, u8 module_id, + u8 opcode, u16 size, u8 *message) +{ + u8 header[4]; + int ret, i; + + header[0] = opcode; + header[1] = module_id; + header[2] = (size >> 8) & 0xff; + header[3] = size & 0xff; + + for (i = 0; i < 4; i++) { + ret = cdp_dp_mailbox_write(dp, header[i], 0); + if (ret) + return ret; + } + + for (i = 0; i < size; i++) { + ret = cdp_dp_mailbox_write(dp, message[i], 0); + if (ret) + return ret; + } + + return 0; +} + +static int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val) +{ + u8 msg[6]; + + msg[0] = (addr >> 8) & 0xff; + msg[1] = addr & 0xff; + msg[2] = (val >> 24) & 0xff; + msg[3] = (val >> 16) & 0xff; + msg[4] = (val >> 8) & 0xff; + msg[5] = val & 0xff; + return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_REGISTER, + sizeof(msg), msg); +} + +static int cdn_dp_reg_write_bit(struct cdn_dp_device *dp, u16 addr, + u8 start_bit, u8 bits_no, u32 val) +{ + u8 field[8]; + + field[0] = (addr >> 8) & 0xff; + field[1] = addr & 0xff; + field[2] = start_bit; + field[3] = bits_no; + field[4] = (val >> 24) & 0xff; + field[5] = (val >> 16) & 0xff; + field[6] = (val >> 8) & 0xff; + field[7] = val & 0xff; + + return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_FIELD, + sizeof(field), field); +} + +int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len) +{ + u8 msg[5], reg[5]; + int ret; + + msg[0] = (len >> 8) & 0xff; + msg[1] = len & 0xff; + msg[2] = (addr >> 16) & 0xff; + msg[3] = (addr >> 8) & 0xff; + msg[4] = addr & 0xff; + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_DPCD, + sizeof(msg), msg); + if (ret) + goto err_dpcd_read; + + ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, + DPTX_READ_DPCD, + sizeof(reg) + len); + if (ret) + goto err_dpcd_read; + + ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg)); + if (ret) + goto err_dpcd_read; + + ret = cdn_dp_mailbox_read_receive(dp, data, len); + +err_dpcd_read: + return ret; +} + +int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value) +{ + u8 msg[6], reg[5]; + int ret; + + msg[0] = 0; + msg[1] = 1; + msg[2] = (addr >> 16) & 0xff; + msg[3] = (addr >> 8) & 0xff; + msg[4] = addr & 0xff; + msg[5] = value; + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_DPCD, + sizeof(msg), msg); + if (ret) + goto err_dpcd_write; + + ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, + DPTX_WRITE_DPCD, sizeof(reg)); + if (ret) + goto err_dpcd_write; + + ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg)); + if (ret) + goto err_dpcd_write; + + if (addr != (reg[2] << 16 | reg[3] << 8 | reg[4])) + ret = -EINVAL; + +err_dpcd_write: + if (ret) + DRM_DEV_ERROR(dp->dev, "dpcd write failed: %d\n", ret); + return ret; +} + +int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem, + u32 i_size, const u32 *d_mem, u32 d_size) +{ + u32 reg; + int i, ret; + + /* reset ucpu before load firmware*/ + writel(APB_IRAM_PATH | APB_DRAM_PATH | APB_XT_RESET, + dp->regs + APB_CTRL); + + for (i = 0; i < i_size; i += 4) + writel(*i_mem++, dp->regs + ADDR_IMEM + i); + + for (i = 0; i < d_size; i += 4) + writel(*d_mem++, dp->regs + ADDR_DMEM + i); + + /* un-reset ucpu */ + writel(0, dp->regs + APB_CTRL); + + /* check the keep alive register to make sure fw working */ + ret = readx_poll_timeout(readl, dp->regs + KEEP_ALIVE, + reg, reg, 2000, FW_ALIVE_TIMEOUT_US); + if (ret < 0) { + DRM_DEV_ERROR(dp->dev, "failed to loaded the FW reg = %x\n", + reg); + return -EINVAL; + } + + reg = readl(dp->regs + VER_L) & 0xff; + dp->fw_version = reg; + reg = readl(dp->regs + VER_H) & 0xff; + dp->fw_version |= reg << 8; + reg = readl(dp->regs + VER_LIB_L_ADDR) & 0xff; + dp->fw_version |= reg << 16; + reg = readl(dp->regs + VER_LIB_H_ADDR) & 0xff; + dp->fw_version |= reg << 24; + + dev_dbg(dp->dev, "firmware version: %x\n", dp->fw_version); + + return 0; +} + +int cdn_dp_set_firmware_active(struct cdn_dp_device *dp, bool enable) +{ + u8 msg[5]; + int ret, i; + + msg[0] = GENERAL_MAIN_CONTROL; + msg[1] = MB_MODULE_ID_GENERAL; + msg[2] = 0; + msg[3] = 1; + msg[4] = enable ? FW_ACTIVE : FW_STANDBY; + + for (i = 0; i < sizeof(msg); i++) { + ret = cdp_dp_mailbox_write(dp, msg[i], 1); + if (ret) + goto err_set_firmware_active; + } + + /* read the firmware state */ + for (i = 0; i < sizeof(msg); i++) { + ret = cdn_dp_mailbox_read(dp, 1); + if (ret < 0) + goto err_set_firmware_active; + + msg[i] = ret; + } + + ret = 0; + +err_set_firmware_active: + if (ret < 0) + DRM_DEV_ERROR(dp->dev, "set firmware active failed\n"); + return ret; +} + +int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip) +{ + u8 msg[8]; + int ret; + + msg[0] = CDN_DP_MAX_LINK_RATE; + msg[1] = lanes; + msg[2] = VOLTAGE_LEVEL_2; + msg[3] = PRE_EMPHASIS_LEVEL_3; + msg[4] = PTS1 | PTS2 | PTS3 | PTS4; + msg[5] = FAST_LT_NOT_SUPPORT; + msg[6] = flip ? LANE_MAPPING_FLIPPED : LANE_MAPPING_NORMAL; + msg[7] = ENHANCED; + + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, + DPTX_SET_HOST_CAPABILITIES, + sizeof(msg), msg); + if (ret) + goto err_set_host_cap; + + ret = cdn_dp_reg_write(dp, DP_AUX_SWAP_INVERSION_CONTROL, + AUX_HOST_INVERT); + +err_set_host_cap: + if (ret) + DRM_DEV_ERROR(dp->dev, "set host cap failed: %d\n", ret); + return ret; +} + +int cdn_dp_event_config(struct cdn_dp_device *dp) +{ + u8 msg[5]; + int ret; + + memset(msg, 0, sizeof(msg)); + + msg[0] = DPTX_EVENT_ENABLE_HPD | DPTX_EVENT_ENABLE_TRAINING; + + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_ENABLE_EVENT, + sizeof(msg), msg); + if (ret) + DRM_DEV_ERROR(dp->dev, "set event config failed: %d\n", ret); + + return ret; +} + +u32 cdn_dp_get_event(struct cdn_dp_device *dp) +{ + return readl(dp->regs + SW_EVENTS0); +} + +int cdn_dp_get_hpd_status(struct cdn_dp_device *dp) +{ + u8 status; + int ret; + + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_HPD_STATE, + 0, NULL); + if (ret) + goto err_get_hpd; + + ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, + DPTX_HPD_STATE, sizeof(status)); + if (ret) + goto err_get_hpd; + + ret = cdn_dp_mailbox_read_receive(dp, &status, sizeof(status)); + if (ret) + goto err_get_hpd; + + return status; + +err_get_hpd: + DRM_DEV_ERROR(dp->dev, "get hpd status failed: %d\n", ret); + return ret; +} + +int cdn_dp_get_edid_block(void *data, u8 *edid, + unsigned int block, size_t length) +{ + struct cdn_dp_device *dp = data; + u8 msg[2], reg[2], i; + int ret; + + for (i = 0; i < 4; i++) { + msg[0] = block / 2; + msg[1] = block % 2; + + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_GET_EDID, + sizeof(msg), msg); + if (ret) + continue; + + ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, + DPTX_GET_EDID, + sizeof(reg) + length); + if (ret) + continue; + + ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg)); + if (ret) + continue; + + ret = cdn_dp_mailbox_read_receive(dp, edid, length); + if (ret) + continue; + + if (reg[0] == length && reg[1] == block / 2) + break; + } + + if (ret) + DRM_DEV_ERROR(dp->dev, "get block[%d] edid failed: %d\n", block, + ret); + + return ret; +} + +int cdn_dp_training_start(struct cdn_dp_device *dp) +{ + unsigned long timeout; + u8 msg, event[2]; + int ret; + + msg = LINK_TRAINING_RUN; + + /* start training */ + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_TRAINING_CONTROL, + sizeof(msg), &msg); + if (ret) + goto err_training_start; + + timeout = jiffies + msecs_to_jiffies(LINK_TRAINING_TIMEOUT_MS); + while (time_before(jiffies, timeout)) { + msleep(LINK_TRAINING_RETRY_MS); + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, + DPTX_READ_EVENT, 0, NULL); + if (ret) + goto err_training_start; + + ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, + DPTX_READ_EVENT, + sizeof(event)); + if (ret) + goto err_training_start; + + ret = cdn_dp_mailbox_read_receive(dp, event, sizeof(event)); + if (ret) + goto err_training_start; + + if (event[1] & EQ_PHASE_FINISHED) + return 0; + } + + ret = -ETIMEDOUT; + +err_training_start: + DRM_DEV_ERROR(dp->dev, "training failed: %d\n", ret); + return ret; +} + +int cdn_dp_get_training_status(struct cdn_dp_device *dp) +{ + u8 status[10]; + int ret; + + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_LINK_STAT, + 0, NULL); + if (ret) + goto err_get_training_status; + + ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, + DPTX_READ_LINK_STAT, + sizeof(status)); + if (ret) + goto err_get_training_status; + + ret = cdn_dp_mailbox_read_receive(dp, status, sizeof(status)); + if (ret) + goto err_get_training_status; + + dp->link.rate = status[0]; + dp->link.num_lanes = status[1]; + +err_get_training_status: + if (ret) + DRM_DEV_ERROR(dp->dev, "get training status failed: %d\n", ret); + return ret; +} + +int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active) +{ + u8 msg; + int ret; + + msg = !!active; + + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_SET_VIDEO, + sizeof(msg), &msg); + if (ret) + DRM_DEV_ERROR(dp->dev, "set video status failed: %d\n", ret); + + return ret; +} + +static int cdn_dp_get_msa_misc(struct video_info *video, + struct drm_display_mode *mode) +{ + u32 msa_misc; + u8 val[2]; + + switch (video->color_fmt) { + case PXL_RGB: + case Y_ONLY: + val[0] = 0; + break; + /* set YUV default color space conversion to BT601 */ + case YCBCR_4_4_4: + val[0] = 6 + BT_601 * 8; + break; + case YCBCR_4_2_2: + val[0] = 5 + BT_601 * 8; + break; + case YCBCR_4_2_0: + val[0] = 5; + break; + }; + + switch (video->color_depth) { + case 6: + val[1] = 0; + break; + case 8: + val[1] = 1; + break; + case 10: + val[1] = 2; + break; + case 12: + val[1] = 3; + break; + case 16: + val[1] = 4; + break; + }; + + msa_misc = 2 * val[0] + 32 * val[1] + + ((video->color_fmt == Y_ONLY) ? (1 << 14) : 0); + + return msa_misc; +} + +int cdn_dp_config_video(struct cdn_dp_device *dp) +{ + struct video_info *video = &dp->video_info; + struct drm_display_mode *mode = &dp->mode; + u64 symbol, tmp; + u32 val, link_rate; + u8 bit_per_pix, tu_size_reg = TU_SIZE; + int ret; + + bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ? + (video->color_depth * 2) : (video->color_depth * 3); + + link_rate = drm_dp_bw_code_to_link_rate(dp->link.rate) / 1000; + + val = VIF_BYPASS_INTERLACE; + ret = cdn_dp_reg_write(dp, BND_HSYNC2VSYNC, val); + if (ret) + goto err_config_video; + + ret = cdn_dp_reg_write(dp, HSYNC2VSYNC_POL_CTRL, 0); + if (ret) + goto err_config_video; + + /* + * get a best tu_size and valid symbol: + * 1. chose Lclk freq(162Mhz, 270Mhz, 540Mhz), set TU to 32 + * 2. calculate VS(valid symbol) = TU * Pclk * Bpp / (Lclk * Lanes) + * 3. if VS > *.85 or VS < *.1 or VS < 2 or TU < VS + 4, then set + * TU += 2 and repeat 2nd step. + */ + do { + tu_size_reg += 2; + tmp = tu_size_reg * mode->clock * bit_per_pix; + tmp /= dp->link.num_lanes * link_rate * 8; + symbol = tmp / 1000; + } while ((symbol <= 1) || (tu_size_reg - symbol < 4) || + (tmp % 1000 > 850) || (tmp % 1000 < 100)); + + val = symbol + (tu_size_reg << 8); + ret = cdn_dp_reg_write(dp, DP_FRAMER_TU, val); + if (ret) + goto err_config_video; + + /* set the FIFO Buffer size */ + val = ((mode->clock * (symbol + 1) / 1000) + link_rate); + val /= (dp->link.num_lanes * link_rate); + val = 8 * (symbol + 1) / bit_per_pix - val; + val += 2; + ret = cdn_dp_reg_write(dp, DP_VC_TABLE(15), val); + + switch (video->color_depth) { + case 6: + val = BCS_6; + break; + case 8: + val = BCS_8; + break; + case 10: + val = BCS_10; + break; + case 12: + val = BCS_12; + break; + case 16: + val = BCS_16; + break; + }; + + val += video->color_fmt << 8; + ret = cdn_dp_reg_write(dp, DP_FRAMER_PXL_REPR, val); + if (ret) + goto err_config_video; + + val = video->h_sync_polarity ? DP_FRAMER_SP_HSP : 0; + val |= video->v_sync_polarity ? DP_FRAMER_SP_VSP : 0; + ret = cdn_dp_reg_write(dp, DP_FRAMER_SP, val); + if (ret) + goto err_config_video; + + val = (mode->hsync_start - mode->hdisplay) << 16; + val |= mode->htotal - mode->hsync_end; + ret = cdn_dp_reg_write(dp, DP_FRONT_BACK_PORCH, val); + if (ret) + goto err_config_video; + + val = mode->hdisplay * bit_per_pix / 8; + ret = cdn_dp_reg_write(dp, DP_BYTE_COUNT, val); + if (ret) + goto err_config_video; + + val = mode->htotal | ((mode->htotal - mode->hsync_start) << 16); + ret = cdn_dp_reg_write(dp, MSA_HORIZONTAL_0, val); + if (ret) + goto err_config_video; + + val = mode->hsync_end - mode->hsync_start; + val |= (mode->hdisplay << 16) | (video->h_sync_polarity << 15); + ret = cdn_dp_reg_write(dp, MSA_HORIZONTAL_1, val); + if (ret) + goto err_config_video; + + val = mode->vtotal; + val |= ((mode->vtotal - mode->vsync_start) << 16); + ret = cdn_dp_reg_write(dp, MSA_VERTICAL_0, val); + if (ret) + goto err_config_video; + + val = mode->vsync_end - mode->vsync_start; + val |= mode->vdisplay << 16 | (video->v_sync_polarity << 15); + ret = cdn_dp_reg_write(dp, MSA_VERTICAL_1, val); + if (ret) + goto err_config_video; + + val = cdn_dp_get_msa_misc(video, mode); + ret = cdn_dp_reg_write(dp, MSA_MISC, val); + if (ret) + goto err_config_video; + + ret = cdn_dp_reg_write(dp, STREAM_CONFIG, 1); + if (ret) + goto err_config_video; + + val = mode->hsync_end - mode->hsync_start; + val |= (mode->hdisplay << 16); + ret = cdn_dp_reg_write(dp, DP_HORIZONTAL, val); + if (ret) + goto err_config_video; + + val = mode->vtotal; + val -= (mode->vtotal - mode->vdisplay); + val |= (mode->vtotal - mode->vsync_start) << 16; + ret = cdn_dp_reg_write(dp, DP_VERTICAL_0, val); + if (ret) + goto err_config_video; + + val = mode->vtotal; + ret = cdn_dp_reg_write(dp, DP_VERTICAL_1, val); + if (ret) + goto err_config_video; + + val = 0; + ret = cdn_dp_reg_write_bit(dp, DP_VB_ID, 2, 1, val); + +err_config_video: + if (ret) + DRM_DEV_ERROR(dp->dev, "config video failed: %d\n", ret); + return ret; +} + +int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio) +{ + u32 val; + int ret; + + ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, 0); + if (ret) { + DRM_DEV_ERROR(dp->dev, "audio stop failed: %d\n", ret); + return ret; + } + + val = SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; + val |= SPDIF_FIFO_MID_RANGE(0xe0); + val |= SPDIF_JITTER_THRSH(0xe0); + val |= SPDIF_JITTER_AVG_WIN(7); + writel(val, dp->regs + SPDIF_CTRL_ADDR); + + /* clearn the audio config and reset */ + writel(0, dp->regs + AUDIO_SRC_CNTL); + writel(0, dp->regs + AUDIO_SRC_CNFG); + writel(AUDIO_SW_RST, dp->regs + AUDIO_SRC_CNTL); + writel(0, dp->regs + AUDIO_SRC_CNTL); + + /* reset smpl2pckt component */ + writel(0, dp->regs + SMPL2PKT_CNTL); + writel(AUDIO_SW_RST, dp->regs + SMPL2PKT_CNTL); + writel(0, dp->regs + SMPL2PKT_CNTL); + + /* reset FIFO */ + writel(AUDIO_SW_RST, dp->regs + FIFO_CNTL); + writel(0, dp->regs + FIFO_CNTL); + + if (audio->format == AFMT_SPDIF) + clk_disable_unprepare(dp->spdif_clk); + + return 0; +} + +int cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable) +{ + int ret; + + ret = cdn_dp_reg_write_bit(dp, DP_VB_ID, 4, 1, enable); + if (ret) + DRM_DEV_ERROR(dp->dev, "audio mute failed: %d\n", ret); + + return ret; +} + +static void cdn_dp_audio_config_i2s(struct cdn_dp_device *dp, + struct audio_info *audio) +{ + int sub_pckt_num = 1, i2s_port_en_val = 0xf, i; + u32 val; + + if (audio->channels == 2) { + if (dp->link.num_lanes == 1) + sub_pckt_num = 2; + else + sub_pckt_num = 4; + + i2s_port_en_val = 1; + } else if (audio->channels == 4) { + i2s_port_en_val = 3; + } + + writel(0x0, dp->regs + SPDIF_CTRL_ADDR); + + writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL); + + val = MAX_NUM_CH(audio->channels); + val |= NUM_OF_I2S_PORTS(audio->channels); + val |= AUDIO_TYPE_LPCM; + val |= CFG_SUB_PCKT_NUM(sub_pckt_num); + writel(val, dp->regs + SMPL2PKT_CNFG); + + if (audio->sample_width == 16) + val = 0; + else if (audio->sample_width == 24) + val = 1 << 9; + else + val = 2 << 9; + + val |= AUDIO_CH_NUM(audio->channels); + val |= I2S_DEC_PORT_EN(i2s_port_en_val); + val |= TRANS_SMPL_WIDTH_32; + writel(val, dp->regs + AUDIO_SRC_CNFG); + + for (i = 0; i < (audio->channels + 1) / 2; i++) { + if (audio->sample_width == 16) + val = (0x08 << 8) | (0x08 << 20); + else if (audio->sample_width == 24) + val = (0x0b << 8) | (0x0b << 20); + + val |= ((2 * i) << 4) | ((2 * i + 1) << 16); + writel(val, dp->regs + STTS_BIT_CH(i)); + } + + switch (audio->sample_rate) { + case 32000: + val = SAMPLING_FREQ(3) | + ORIGINAL_SAMP_FREQ(0xc); + break; + case 44100: + val = SAMPLING_FREQ(0) | + ORIGINAL_SAMP_FREQ(0xf); + break; + case 48000: + val = SAMPLING_FREQ(2) | + ORIGINAL_SAMP_FREQ(0xd); + break; + case 88200: + val = SAMPLING_FREQ(8) | + ORIGINAL_SAMP_FREQ(0x7); + break; + case 96000: + val = SAMPLING_FREQ(0xa) | + ORIGINAL_SAMP_FREQ(5); + break; + case 176400: + val = SAMPLING_FREQ(0xc) | + ORIGINAL_SAMP_FREQ(3); + break; + case 192000: + val = SAMPLING_FREQ(0xe) | + ORIGINAL_SAMP_FREQ(1); + break; + } + val |= 4; + writel(val, dp->regs + COM_CH_STTS_BITS); + + writel(SMPL2PKT_EN, dp->regs + SMPL2PKT_CNTL); + writel(I2S_DEC_START, dp->regs + AUDIO_SRC_CNTL); +} + +static void cdn_dp_audio_config_spdif(struct cdn_dp_device *dp) +{ + u32 val; + + val = SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; + val |= SPDIF_FIFO_MID_RANGE(0xe0); + val |= SPDIF_JITTER_THRSH(0xe0); + val |= SPDIF_JITTER_AVG_WIN(7); + writel(val, dp->regs + SPDIF_CTRL_ADDR); + + writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL); + + val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4); + writel(val, dp->regs + SMPL2PKT_CNFG); + writel(SMPL2PKT_EN, dp->regs + SMPL2PKT_CNTL); + + val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; + val |= SPDIF_FIFO_MID_RANGE(0xe0); + val |= SPDIF_JITTER_THRSH(0xe0); + val |= SPDIF_JITTER_AVG_WIN(7); + writel(val, dp->regs + SPDIF_CTRL_ADDR); + + clk_prepare_enable(dp->spdif_clk); + clk_set_rate(dp->spdif_clk, CDN_DP_SPDIF_CLK); +} + +int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio) +{ + int ret; + + /* reset the spdif clk before config */ + if (audio->format == AFMT_SPDIF) { + reset_control_assert(dp->spdif_rst); + reset_control_deassert(dp->spdif_rst); + } + + ret = cdn_dp_reg_write(dp, CM_LANE_CTRL, LANE_REF_CYC); + if (ret) + goto err_audio_config; + + ret = cdn_dp_reg_write(dp, CM_CTRL, 0); + if (ret) + goto err_audio_config; + + if (audio->format == AFMT_I2S) + cdn_dp_audio_config_i2s(dp, audio); + else if (audio->format == AFMT_SPDIF) + cdn_dp_audio_config_spdif(dp); + + ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN); + +err_audio_config: + if (ret) + DRM_DEV_ERROR(dp->dev, "audio config failed: %d\n", ret); + return ret; +} diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/drivers/gpu/drm/rockchip/cdn-dp-reg.h new file mode 100644 index 0000000..6ac3674 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.h @@ -0,0 +1,482 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CDN_DP_REG_H +#define _CDN_DP_REG_H + +#include + +#define ADDR_IMEM 0x10000 +#define ADDR_DMEM 0x20000 + +/* APB CFG addr */ +#define APB_CTRL 0 +#define XT_INT_CTRL 0x04 +#define MAILBOX_FULL_ADDR 0x08 +#define MAILBOX_EMPTY_ADDR 0x0c +#define MAILBOX0_WR_DATA 0x10 +#define MAILBOX0_RD_DATA 0x14 +#define KEEP_ALIVE 0x18 +#define VER_L 0x1c +#define VER_H 0x20 +#define VER_LIB_L_ADDR 0x24 +#define VER_LIB_H_ADDR 0x28 +#define SW_DEBUG_L 0x2c +#define SW_DEBUG_H 0x30 +#define MAILBOX_INT_MASK 0x34 +#define MAILBOX_INT_STATUS 0x38 +#define SW_CLK_L 0x3c +#define SW_CLK_H 0x40 +#define SW_EVENTS0 0x44 +#define SW_EVENTS1 0x48 +#define SW_EVENTS2 0x4c +#define SW_EVENTS3 0x50 +#define XT_OCD_CTRL 0x60 +#define APB_INT_MASK 0x6c +#define APB_STATUS_MASK 0x70 + +/* audio decoder addr */ +#define AUDIO_SRC_CNTL 0x30000 +#define AUDIO_SRC_CNFG 0x30004 +#define COM_CH_STTS_BITS 0x30008 +#define STTS_BIT_CH(x) (0x3000c + ((x) << 2)) +#define SPDIF_CTRL_ADDR 0x3004c +#define SPDIF_CH1_CS_3100_ADDR 0x30050 +#define SPDIF_CH1_CS_6332_ADDR 0x30054 +#define SPDIF_CH1_CS_9564_ADDR 0x30058 +#define SPDIF_CH1_CS_12796_ADDR 0x3005c +#define SPDIF_CH1_CS_159128_ADDR 0x30060 +#define SPDIF_CH1_CS_191160_ADDR 0x30064 +#define SPDIF_CH2_CS_3100_ADDR 0x30068 +#define SPDIF_CH2_CS_6332_ADDR 0x3006c +#define SPDIF_CH2_CS_9564_ADDR 0x30070 +#define SPDIF_CH2_CS_12796_ADDR 0x30074 +#define SPDIF_CH2_CS_159128_ADDR 0x30078 +#define SPDIF_CH2_CS_191160_ADDR 0x3007c +#define SMPL2PKT_CNTL 0x30080 +#define SMPL2PKT_CNFG 0x30084 +#define FIFO_CNTL 0x30088 +#define FIFO_STTS 0x3008c + +/* source pif addr */ +#define SOURCE_PIF_WR_ADDR 0x30800 +#define SOURCE_PIF_WR_REQ 0x30804 +#define SOURCE_PIF_RD_ADDR 0x30808 +#define SOURCE_PIF_RD_REQ 0x3080c +#define SOURCE_PIF_DATA_WR 0x30810 +#define SOURCE_PIF_DATA_RD 0x30814 +#define SOURCE_PIF_FIFO1_FLUSH 0x30818 +#define SOURCE_PIF_FIFO2_FLUSH 0x3081c +#define SOURCE_PIF_STATUS 0x30820 +#define SOURCE_PIF_INTERRUPT_SOURCE 0x30824 +#define SOURCE_PIF_INTERRUPT_MASK 0x30828 +#define SOURCE_PIF_PKT_ALLOC_REG 0x3082c +#define SOURCE_PIF_PKT_ALLOC_WR_EN 0x30830 +#define SOURCE_PIF_SW_RESET 0x30834 + +/* bellow registers need access by mailbox */ +/* source car addr */ +#define SOURCE_HDTX_CAR 0x0900 +#define SOURCE_DPTX_CAR 0x0904 +#define SOURCE_PHY_CAR 0x0908 +#define SOURCE_CEC_CAR 0x090c +#define SOURCE_CBUS_CAR 0x0910 +#define SOURCE_PKT_CAR 0x0918 +#define SOURCE_AIF_CAR 0x091c +#define SOURCE_CIPHER_CAR 0x0920 +#define SOURCE_CRYPTO_CAR 0x0924 + +/* clock meters addr */ +#define CM_CTRL 0x0a00 +#define CM_I2S_CTRL 0x0a04 +#define CM_SPDIF_CTRL 0x0a08 +#define CM_VID_CTRL 0x0a0c +#define CM_LANE_CTRL 0x0a10 +#define I2S_NM_STABLE 0x0a14 +#define I2S_NCTS_STABLE 0x0a18 +#define SPDIF_NM_STABLE 0x0a1c +#define SPDIF_NCTS_STABLE 0x0a20 +#define NMVID_MEAS_STABLE 0x0a24 +#define I2S_MEAS 0x0a40 +#define SPDIF_MEAS 0x0a80 +#define NMVID_MEAS 0x0ac0 + +/* source vif addr */ +#define BND_HSYNC2VSYNC 0x0b00 +#define HSYNC2VSYNC_F1_L1 0x0b04 +#define HSYNC2VSYNC_F2_L1 0x0b08 +#define HSYNC2VSYNC_STATUS 0x0b0c +#define HSYNC2VSYNC_POL_CTRL 0x0b10 + +/* dptx phy addr */ +#define DP_TX_PHY_CONFIG_REG 0x2000 +#define DP_TX_PHY_STATUS_REG 0x2004 +#define DP_TX_PHY_SW_RESET 0x2008 +#define DP_TX_PHY_SCRAMBLER_SEED 0x200c +#define DP_TX_PHY_TRAINING_01_04 0x2010 +#define DP_TX_PHY_TRAINING_05_08 0x2014 +#define DP_TX_PHY_TRAINING_09_10 0x2018 +#define TEST_COR 0x23fc + +/* dptx hpd addr */ +#define HPD_IRQ_DET_MIN_TIMER 0x2100 +#define HPD_IRQ_DET_MAX_TIMER 0x2104 +#define HPD_UNPLGED_DET_MIN_TIMER 0x2108 +#define HPD_STABLE_TIMER 0x210c +#define HPD_FILTER_TIMER 0x2110 +#define HPD_EVENT_MASK 0x211c +#define HPD_EVENT_DET 0x2120 + +/* dpyx framer addr */ +#define DP_FRAMER_GLOBAL_CONFIG 0x2200 +#define DP_SW_RESET 0x2204 +#define DP_FRAMER_TU 0x2208 +#define DP_FRAMER_PXL_REPR 0x220c +#define DP_FRAMER_SP 0x2210 +#define AUDIO_PACK_CONTROL 0x2214 +#define DP_VC_TABLE(x) (0x2218 + ((x) << 2)) +#define DP_VB_ID 0x2258 +#define DP_MTPH_LVP_CONTROL 0x225c +#define DP_MTPH_SYMBOL_VALUES 0x2260 +#define DP_MTPH_ECF_CONTROL 0x2264 +#define DP_MTPH_ACT_CONTROL 0x2268 +#define DP_MTPH_STATUS 0x226c +#define DP_INTERRUPT_SOURCE 0x2270 +#define DP_INTERRUPT_MASK 0x2274 +#define DP_FRONT_BACK_PORCH 0x2278 +#define DP_BYTE_COUNT 0x227c + +/* dptx stream addr */ +#define MSA_HORIZONTAL_0 0x2280 +#define MSA_HORIZONTAL_1 0x2284 +#define MSA_VERTICAL_0 0x2288 +#define MSA_VERTICAL_1 0x228c +#define MSA_MISC 0x2290 +#define STREAM_CONFIG 0x2294 +#define AUDIO_PACK_STATUS 0x2298 +#define VIF_STATUS 0x229c +#define PCK_STUFF_STATUS_0 0x22a0 +#define PCK_STUFF_STATUS_1 0x22a4 +#define INFO_PACK_STATUS 0x22a8 +#define RATE_GOVERNOR_STATUS 0x22ac +#define DP_HORIZONTAL 0x22b0 +#define DP_VERTICAL_0 0x22b4 +#define DP_VERTICAL_1 0x22b8 +#define DP_BLOCK_SDP 0x22bc + +/* dptx glbl addr */ +#define DPTX_LANE_EN 0x2300 +#define DPTX_ENHNCD 0x2304 +#define DPTX_INT_MASK 0x2308 +#define DPTX_INT_STATUS 0x230c + +/* dp aux addr */ +#define DP_AUX_HOST_CONTROL 0x2800 +#define DP_AUX_INTERRUPT_SOURCE 0x2804 +#define DP_AUX_INTERRUPT_MASK 0x2808 +#define DP_AUX_SWAP_INVERSION_CONTROL 0x280c +#define DP_AUX_SEND_NACK_TRANSACTION 0x2810 +#define DP_AUX_CLEAR_RX 0x2814 +#define DP_AUX_CLEAR_TX 0x2818 +#define DP_AUX_TIMER_STOP 0x281c +#define DP_AUX_TIMER_CLEAR 0x2820 +#define DP_AUX_RESET_SW 0x2824 +#define DP_AUX_DIVIDE_2M 0x2828 +#define DP_AUX_TX_PREACHARGE_LENGTH 0x282c +#define DP_AUX_FREQUENCY_1M_MAX 0x2830 +#define DP_AUX_FREQUENCY_1M_MIN 0x2834 +#define DP_AUX_RX_PRE_MIN 0x2838 +#define DP_AUX_RX_PRE_MAX 0x283c +#define DP_AUX_TIMER_PRESET 0x2840 +#define DP_AUX_NACK_FORMAT 0x2844 +#define DP_AUX_TX_DATA 0x2848 +#define DP_AUX_RX_DATA 0x284c +#define DP_AUX_TX_STATUS 0x2850 +#define DP_AUX_RX_STATUS 0x2854 +#define DP_AUX_RX_CYCLE_COUNTER 0x2858 +#define DP_AUX_MAIN_STATES 0x285c +#define DP_AUX_MAIN_TIMER 0x2860 +#define DP_AUX_AFE_OUT 0x2864 + +/* crypto addr */ +#define CRYPTO_HDCP_REVISION 0x5800 +#define HDCP_CRYPTO_CONFIG 0x5804 +#define CRYPTO_INTERRUPT_SOURCE 0x5808 +#define CRYPTO_INTERRUPT_MASK 0x580c +#define CRYPTO22_CONFIG 0x5818 +#define CRYPTO22_STATUS 0x581c +#define SHA_256_DATA_IN 0x583c +#define SHA_256_DATA_OUT_(x) (0x5850 + ((x) << 2)) +#define AES_32_KEY_(x) (0x5870 + ((x) << 2)) +#define AES_32_DATA_IN 0x5880 +#define AES_32_DATA_OUT_(x) (0x5884 + ((x) << 2)) +#define CRYPTO14_CONFIG 0x58a0 +#define CRYPTO14_STATUS 0x58a4 +#define CRYPTO14_PRNM_OUT 0x58a8 +#define CRYPTO14_KM_0 0x58ac +#define CRYPTO14_KM_1 0x58b0 +#define CRYPTO14_AN_0 0x58b4 +#define CRYPTO14_AN_1 0x58b8 +#define CRYPTO14_YOUR_KSV_0 0x58bc +#define CRYPTO14_YOUR_KSV_1 0x58c0 +#define CRYPTO14_MI_0 0x58c4 +#define CRYPTO14_MI_1 0x58c8 +#define CRYPTO14_TI_0 0x58cc +#define CRYPTO14_KI_0 0x58d0 +#define CRYPTO14_KI_1 0x58d4 +#define CRYPTO14_BLOCKS_NUM 0x58d8 +#define CRYPTO14_KEY_MEM_DATA_0 0x58dc +#define CRYPTO14_KEY_MEM_DATA_1 0x58e0 +#define CRYPTO14_SHA1_MSG_DATA 0x58e4 +#define CRYPTO14_SHA1_V_VALUE_(x) (0x58e8 + ((x) << 2)) +#define TRNG_CTRL 0x58fc +#define TRNG_DATA_RDY 0x5900 +#define TRNG_DATA 0x5904 + +/* cipher addr */ +#define HDCP_REVISION 0x60000 +#define INTERRUPT_SOURCE 0x60004 +#define INTERRUPT_MASK 0x60008 +#define HDCP_CIPHER_CONFIG 0x6000c +#define AES_128_KEY_0 0x60010 +#define AES_128_KEY_1 0x60014 +#define AES_128_KEY_2 0x60018 +#define AES_128_KEY_3 0x6001c +#define AES_128_RANDOM_0 0x60020 +#define AES_128_RANDOM_1 0x60024 +#define CIPHER14_KM_0 0x60028 +#define CIPHER14_KM_1 0x6002c +#define CIPHER14_STATUS 0x60030 +#define CIPHER14_RI_PJ_STATUS 0x60034 +#define CIPHER_MODE 0x60038 +#define CIPHER14_AN_0 0x6003c +#define CIPHER14_AN_1 0x60040 +#define CIPHER22_AUTH 0x60044 +#define CIPHER14_R0_DP_STATUS 0x60048 +#define CIPHER14_BOOTSTRAP 0x6004c + +#define DPTX_FRMR_DATA_CLK_RSTN_EN BIT(11) +#define DPTX_FRMR_DATA_CLK_EN BIT(10) +#define DPTX_PHY_DATA_RSTN_EN BIT(9) +#define DPTX_PHY_DATA_CLK_EN BIT(8) +#define DPTX_PHY_CHAR_RSTN_EN BIT(7) +#define DPTX_PHY_CHAR_CLK_EN BIT(6) +#define SOURCE_AUX_SYS_CLK_RSTN_EN BIT(5) +#define SOURCE_AUX_SYS_CLK_EN BIT(4) +#define DPTX_SYS_CLK_RSTN_EN BIT(3) +#define DPTX_SYS_CLK_EN BIT(2) +#define CFG_DPTX_VIF_CLK_RSTN_EN BIT(1) +#define CFG_DPTX_VIF_CLK_EN BIT(0) + +#define SOURCE_PHY_RSTN_EN BIT(1) +#define SOURCE_PHY_CLK_EN BIT(0) + +#define SOURCE_PKT_SYS_RSTN_EN BIT(3) +#define SOURCE_PKT_SYS_CLK_EN BIT(2) +#define SOURCE_PKT_DATA_RSTN_EN BIT(1) +#define SOURCE_PKT_DATA_CLK_EN BIT(0) + +#define SPDIF_CDR_CLK_RSTN_EN BIT(5) +#define SPDIF_CDR_CLK_EN BIT(4) +#define SOURCE_AIF_SYS_RSTN_EN BIT(3) +#define SOURCE_AIF_SYS_CLK_EN BIT(2) +#define SOURCE_AIF_CLK_RSTN_EN BIT(1) +#define SOURCE_AIF_CLK_EN BIT(0) + +#define SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN BIT(3) +#define SOURCE_CIPHER_SYS_CLK_EN BIT(2) +#define SOURCE_CIPHER_CHAR_CLK_RSTN_EN BIT(1) +#define SOURCE_CIPHER_CHAR_CLK_EN BIT(0) + +#define SOURCE_CRYPTO_SYS_CLK_RSTN_EN BIT(1) +#define SOURCE_CRYPTO_SYS_CLK_EN BIT(0) + +#define APB_IRAM_PATH BIT(2) +#define APB_DRAM_PATH BIT(1) +#define APB_XT_RESET BIT(0) + +#define MAILBOX_INT_MASK_BIT BIT(1) +#define PIF_INT_MASK_BIT BIT(0) +#define ALL_INT_MASK 3 + +/* mailbox */ +#define MB_OPCODE_ID 0 +#define MB_MODULE_ID 1 +#define MB_SIZE_MSB_ID 2 +#define MB_SIZE_LSB_ID 3 +#define MB_DATA_ID 4 + +#define MB_MODULE_ID_DP_TX 0x01 +#define MB_MODULE_ID_HDCP_TX 0x07 +#define MB_MODULE_ID_HDCP_RX 0x08 +#define MB_MODULE_ID_HDCP_GENERAL 0x09 +#define MB_MODULE_ID_GENERAL 0x0a + +/* general opcode */ +#define GENERAL_MAIN_CONTROL 0x01 +#define GENERAL_TEST_ECHO 0x02 +#define GENERAL_BUS_SETTINGS 0x03 +#define GENERAL_TEST_ACCESS 0x04 + +#define DPTX_SET_POWER_MNG 0x00 +#define DPTX_SET_HOST_CAPABILITIES 0x01 +#define DPTX_GET_EDID 0x02 +#define DPTX_READ_DPCD 0x03 +#define DPTX_WRITE_DPCD 0x04 +#define DPTX_ENABLE_EVENT 0x05 +#define DPTX_WRITE_REGISTER 0x06 +#define DPTX_READ_REGISTER 0x07 +#define DPTX_WRITE_FIELD 0x08 +#define DPTX_TRAINING_CONTROL 0x09 +#define DPTX_READ_EVENT 0x0a +#define DPTX_READ_LINK_STAT 0x0b +#define DPTX_SET_VIDEO 0x0c +#define DPTX_SET_AUDIO 0x0d +#define DPTX_GET_LAST_AUX_STAUS 0x0e +#define DPTX_SET_LINK_BREAK_POINT 0x0f +#define DPTX_FORCE_LANES 0x10 +#define DPTX_HPD_STATE 0x11 + +#define FW_STANDBY 0 +#define FW_ACTIVE 1 + +#define DPTX_EVENT_ENABLE_HPD BIT(0) +#define DPTX_EVENT_ENABLE_TRAINING BIT(1) + +#define LINK_TRAINING_NOT_ACTIVE 0 +#define LINK_TRAINING_RUN 1 +#define LINK_TRAINING_RESTART 2 + +#define CONTROL_VIDEO_IDLE 0 +#define CONTROL_VIDEO_VALID 1 + +#define VIF_BYPASS_INTERLACE BIT(13) +#define INTERLACE_FMT_DET BIT(12) +#define INTERLACE_DTCT_WIN 0x20 + +#define DP_FRAMER_SP_INTERLACE_EN BIT(2) +#define DP_FRAMER_SP_HSP BIT(1) +#define DP_FRAMER_SP_VSP BIT(0) + +/* capability */ +#define AUX_HOST_INVERT 3 +#define FAST_LT_SUPPORT 1 +#define FAST_LT_NOT_SUPPORT 0 +#define LANE_MAPPING_NORMAL 0x1b +#define LANE_MAPPING_FLIPPED 0xe4 +#define ENHANCED 1 + +#define FULL_LT_STARTED BIT(0) +#define FASE_LT_STARTED BIT(1) +#define CLK_RECOVERY_FINISHED BIT(2) +#define EQ_PHASE_FINISHED BIT(3) +#define FASE_LT_START_FINISHED BIT(4) +#define CLK_RECOVERY_FAILED BIT(5) +#define EQ_PHASE_FAILED BIT(6) +#define FASE_LT_FAILED BIT(7) + +#define DPTX_HPD_EVENT BIT(0) +#define DPTX_TRAINING_EVENT BIT(1) +#define HDCP_TX_STATUS_EVENT BIT(4) +#define HDCP2_TX_IS_KM_STORED_EVENT BIT(5) +#define HDCP2_TX_STORE_KM_EVENT BIT(6) +#define HDCP_TX_IS_RECEIVER_ID_VALID_EVENT BIT(7) + +#define TU_SIZE 30 +#define CDN_DP_MAX_LINK_RATE DP_LINK_BW_5_4 + +/* audio */ +#define AUDIO_PACK_EN BIT(8) +#define SAMPLING_FREQ(x) (((x) & 0xf) << 16) +#define ORIGINAL_SAMP_FREQ(x) (((x) & 0xf) << 24) +#define SYNC_WR_TO_CH_ZERO BIT(1) +#define I2S_DEC_START BIT(1) +#define AUDIO_SW_RST BIT(0) +#define SMPL2PKT_EN BIT(1) +#define MAX_NUM_CH(x) (((x) & 0x1f) - 1) +#define NUM_OF_I2S_PORTS(x) ((((x) / 2 - 1) & 0x3) << 5) +#define AUDIO_TYPE_LPCM (2 << 7) +#define CFG_SUB_PCKT_NUM(x) ((((x) - 1) & 0x7) << 11) +#define AUDIO_CH_NUM(x) ((((x) - 1) & 0x1f) << 2) +#define TRANS_SMPL_WIDTH_16 0 +#define TRANS_SMPL_WIDTH_24 BIT(11) +#define TRANS_SMPL_WIDTH_32 (2 << 11) +#define I2S_DEC_PORT_EN(x) (((x) & 0xf) << 17) +#define SPDIF_ENABLE BIT(21) +#define SPDIF_AVG_SEL BIT(20) +#define SPDIF_JITTER_BYPASS BIT(19) +#define SPDIF_FIFO_MID_RANGE(x) (((x) & 0xff) << 11) +#define SPDIF_JITTER_THRSH(x) (((x) & 0xff) << 3) +#define SPDIF_JITTER_AVG_WIN(x) ((x) & 0x7) + +/* Refernce cycles when using lane clock as refernce */ +#define LANE_REF_CYC 0x8000 + +enum voltage_swing_level { + VOLTAGE_LEVEL_0, + VOLTAGE_LEVEL_1, + VOLTAGE_LEVEL_2, + VOLTAGE_LEVEL_3, +}; + +enum pre_emphasis_level { + PRE_EMPHASIS_LEVEL_0, + PRE_EMPHASIS_LEVEL_1, + PRE_EMPHASIS_LEVEL_2, + PRE_EMPHASIS_LEVEL_3, +}; + +enum pattern_set { + PTS1 = BIT(0), + PTS2 = BIT(1), + PTS3 = BIT(2), + PTS4 = BIT(3), + DP_NONE = BIT(4) +}; + +enum vic_color_depth { + BCS_6 = 0x1, + BCS_8 = 0x2, + BCS_10 = 0x4, + BCS_12 = 0x8, + BCS_16 = 0x10, +}; + +enum vic_bt_type { + BT_601 = 0x0, + BT_709 = 0x1, +}; + +void cdn_dp_clock_reset(struct cdn_dp_device *dp); + +void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, u32 clk); +int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem, + u32 i_size, const u32 *d_mem, u32 d_size); +int cdn_dp_set_firmware_active(struct cdn_dp_device *dp, bool enable); +int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip); +int cdn_dp_event_config(struct cdn_dp_device *dp); +u32 cdn_dp_get_event(struct cdn_dp_device *dp); +int cdn_dp_get_hpd_status(struct cdn_dp_device *dp); +int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value); +int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len); +int cdn_dp_get_edid_block(void *dp, u8 *edid, + unsigned int block, size_t length); +int cdn_dp_training_start(struct cdn_dp_device *dp); +int cdn_dp_get_training_status(struct cdn_dp_device *dp); +int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active); +int cdn_dp_config_video(struct cdn_dp_device *dp); +int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio); +int cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable); +int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio); +#endif /* _CDN_DP_REG_H */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index a711589..cc73d56 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1048,9 +1048,11 @@ static void vop_crtc_enable(struct drm_crtc *crtc) vop_dsp_hold_valid_irq_disable(vop); } - pin_pol = 0x8; - pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1; - pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : (1 << 1); + pin_pol = BIT(DCLK_INVERT); + pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? + 0 : BIT(HSYNC_POSITIVE); + pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? + 0 : BIT(VSYNC_POSITIVE); VOP_CTRL_SET(vop, pin_pol, pin_pol); switch (s->output_type) { @@ -1070,6 +1072,11 @@ static void vop_crtc_enable(struct drm_crtc *crtc) VOP_CTRL_SET(vop, mipi_pin_pol, pin_pol); VOP_CTRL_SET(vop, mipi_en, 1); break; + case DRM_MODE_CONNECTOR_DisplayPort: + pin_pol &= ~BIT(DCLK_INVERT); + VOP_CTRL_SET(vop, dp_pin_pol, pin_pol); + VOP_CTRL_SET(vop, dp_en, 1); + break; default: DRM_DEV_ERROR(vop->dev, "unsupported connector_type [%d]\n", s->output_type); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 1dbc526..5a4faa85 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -45,6 +45,7 @@ struct vop_ctrl { struct vop_reg edp_en; struct vop_reg hdmi_en; struct vop_reg mipi_en; + struct vop_reg dp_en; struct vop_reg out_mode; struct vop_reg dither_down; struct vop_reg dither_up; @@ -53,6 +54,7 @@ struct vop_ctrl { struct vop_reg hdmi_pin_pol; struct vop_reg edp_pin_pol; struct vop_reg mipi_pin_pol; + struct vop_reg dp_pin_pol; struct vop_reg htotal_pw; struct vop_reg hact_st_end; @@ -244,6 +246,13 @@ enum scale_down_mode { SCALE_DOWN_AVG = 0x1 }; +enum vop_pol { + HSYNC_POSITIVE = 0, + VSYNC_POSITIVE = 1, + DEN_NEGATIVE = 2, + DCLK_INVERT = 3 +}; + #define FRAC_16_16(mult, div) (((mult) << 16) / (div)) #define SCL_FT_DEFAULT_FIXPOINT_SHIFT 12 #define SCL_MAX_VSKIPLINES 4 diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index eea8427..aaede6b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -283,6 +283,7 @@ static const struct vop_data rk3288_vop = { static const struct vop_ctrl rk3399_ctrl_data = { .standby = VOP_REG(RK3399_SYS_CTRL, 0x1, 22), .gate_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 23), + .dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11), .rgb_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 12), .hdmi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 13), .edp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 14), @@ -292,6 +293,7 @@ static const struct vop_ctrl rk3399_ctrl_data = { .data_blank = VOP_REG(RK3399_DSP_CTRL0, 0x1, 19), .out_mode = VOP_REG(RK3399_DSP_CTRL0, 0xf, 0), .rgb_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16), + .dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16), .hdmi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 20), .edp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 24), .mipi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 28), -- 1.9.1 From mboxrd@z Thu Jan 1 00:00:00 1970 From: Chris Zhong Subject: [PATCH v15 3/5] drm/rockchip: cdn-dp: add cdn DP support for rk3399 Date: Fri, 9 Sep 2016 19:15:46 -0700 Message-ID: <1473473748-22331-4-git-send-email-zyw@rock-chips.com> References: <1473473748-22331-1-git-send-email-zyw@rock-chips.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: In-Reply-To: <1473473748-22331-1-git-send-email-zyw@rock-chips.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: dianders@chromium.org, tfiga@chromium.org, heiko@sntech.de, yzq@rock-chips.com, groeck@chromium.org, myungjoo.ham@samsung.com, cw00.choi@samsung.com, wulf@rock-chips.com, marcheu@chromium.org, briannorris@chromium.org, zhengxing@rock-chips.com, cychiang@chromium.org, hychao@chromium.org, broonie@kernel.org Cc: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-rockchip@lists.infradead.org, Chris Zhong , linux-arm-kernel@lists.infradead.org List-Id: linux-rockchip.vger.kernel.org QWRkIHN1cHBvcnQgZm9yIGNkbiBEUCBjb250cm9sbGVyIHdoaWNoIGlzIGVtYmVkZGVkIGluIHRo ZSByazMzOTkKU29Dcy4gVGhlIERQIGlzIGNvbXBsaWFudCB3aXRoIERpc3BsYXlQb3J0IFNwZWNp ZmljYXRpb24sClZlcnNpb24gMS4zLCBUaGlzIElQIGlzIGNvbXBhdGlibGUgd2l0aCB0aGUgcm9j a2NoaXAgdHlwZS1jIFBIWSBJUC4KVGhlcmUgaXMgYSB1Q1BVIGluIERQIGNvbnRyb2xsZXIsIGl0 IG5lZWQgYSBmaXJtd2FyZSB0byB3b3JrLApwbGVhc2UgcHV0IHRoZSBmaXJtd2FyZSBmaWxlIHRv IC9saWIvZmlybXdhcmUvcm9ja2NoaXAvZHB0eC5iaW4uIFRoZQp1Q1BVIGluIGNoYXJnZSBvZiBh dXggY29tbXVuaWNhdGlvbiBhbmQgbGluayB0cmFpbmluZywgdGhlIGhvc3QgdXNlCm1haWxib3gg dG8gY29tbXVuaWNhdGUgd2l0aCB0aGUgdWNwdS4KVGhlIGRjbGsgcGluX3BvbCBvZiB2b3AgbXVz dCBub3QgYmUgaW52ZXJ0IGZvciBEUC4KClNpZ25lZC1vZmYtYnk6IENocmlzIFpob25nIDx6eXdA cm9jay1jaGlwcy5jb20+ClNpZ25lZC1vZmYtYnk6IFNlYW4gUGF1bCA8c2VhbnBhdWxAY2hyb21p dW0ub3JnPgpSZXZpZXdlZC1ieTogU2VhbiBQYXVsIDxzZWFucGF1bEBjaHJvbWl1bS5vcmc+CkFj a2VkLWJ5OiBNYXJrIFlhbyA8bWFyay55YW9Acm9jay1jaGlwcy5jb20+CgotLS0KCkNoYW5nZXMg aW4gdjE1OgpDaHJpcyBaaG9uZydzIGNoYW5nZXM6Ci0gZml4IGRpc2FibGUgcGh5IHVuYmFsYW5j ZQotIHN1cHBvcnQgQXBwbGUgRG9jayBob3QtcGx1ZyBpbiBIRE1JIHBvcnQKLSByZXRyYWluaW5n IHdoZW4gQXBwbGUgRG9jayBocGQgaXJxIGNvbWluZwpTZWFuIFBhdWwncyBjaGFuZ2VzOgotIFJl c3RydWN0dXJlZCB0aGUgd29ya2VyCi0gU3luY2hyb25pemVkIGJldHdlZW4gd29ya2VyICYgZHJt IGhvb2tzCi0gUHJvcGVybHkgaW1wbGVtZW50ZWQgZW5hYmxlL2Rpc2FibGUKLSBBZGRlZCBlcnJv ciBjaGVja2luZwotIFVzZSBkZXZtIHZhcmlhbnQgb2YgZXh0Y29uCi0gVXNlIERSTV9ERVZfKiBs b2dnaW5nCi0gUmVmYWN0b3JlZCBjb2RlIHRvIChob3BlZnVsbHkpIGJlIG1vcmUgY2xlYXIKCkNo YW5nZXMgaW4gdjE0OgotIE1vZGlmeSBzb21lIGdyYW1tYXRpY2FsIGVycm9ycwotIHJlbW92ZSB0 aGUgbXV0ZXggYXJvdW5kIGNkbl9kcF9hdWRpb19nZXRfZWxkCi0gcG93ZXIgb24gdGhlIHBvd2Vy IGRvbWFpbiBhZnRlciBjbGtfZW5hYmxlCi0gcmV0cnkgdG8gcmVhZCBlZGlkCi0gY2hhbmdlIHN1 cGVyIHNwZWVkIHByb3BlcnR5IG5hbWUgdG8gRVhUQ09OX1BST1BfVVNCX1NTCi0gZG8gYSBjb3Jy ZWN0IG1vZGVfdmFsaWQgY2hlY2sgd2hlbiBicGMgaXMgMAoKQ2hhbmdlcyBpbiB2MTM6Ci0gc3Vw cG9ydCBzdXNwZW5kL3Jlc3VtZQotIHN3aXRjaCBwb3dlciBkb21haW4gZHluYW1pY2FsbHkKLSBy ZS10cmFpbmluZyB3aGVuIGhwZCBzaWduYWwgaXMgdHJpZ2dlcmVkCgpDaGFuZ2VzIGluIHYxMjoK LSB1c2UgRVhUQ09OX1BST1BfVVNCX1NVUEVSU1BFRUQgdG8gcmVwbGFjZSBFWFRDT05fVVNCX0hP U1QKCkNoYW5nZXMgaW4gdjExOgotIGFkZCBiZXN0X2VuY29kZXIgYmFjaywgc2luY2UgaXQgcmVx dWlyZWQgYnkgZHJtX2F0b21pY19oZWxwZXJfY2hlY2sKCkNoYW5nZXMgaW4gdjEwOgotIHJlbW92 ZSBiZXN0X2VuY29kZXIgb3BzCi0gc3VwcG9ydCByZWFkIHNpbmsgY291bnQgZnJvbSBEUENECi0g Y29udHJvbCB0aGUgZ3JmX2NsayBpbiBEUAoKQ2hhbmdlcyBpbiB2OToKLSBkbyBub3QgbmVlZCBy ZXNldCB0aGUgcGh5IGJlZm9yZSBwb3dlcl9vbgotIGFkZCBhIG9yaWVudGF0aW9uIGluZm9ybWF0 aW9uIGZvciBzZXRfY2FwYWJpbGl0eQotIHJldHJ5IHRvIHJlYWQgZHBjZCBpbiAxMCBzZWNvbmRz CgpDaGFuZ2VzIGluIHY4OgotIG9wdGltaXphdGlvbiB0aGUgZXJyIGxvZwoKQ2hhbmdlcyBpbiB2 NzoKLSBzdXBwb3J0IGZpcm13YXJlIHN0YW5kYnkgd2hlbiBubyBkcHR4IGNvbm5lY3Rpb24KLSBv cHRpbWl6YXRpb24gdGhlIGNhbGN1bGF0aW9uIG9mIHR1IHNpemUgYW5kIHZhbGlkIHN5bWJvbAoK Q2hhbmdlcyBpbiB2NjoKLSBhZGQgYSBwb3J0IHN0cnVjdAotIHNlbGVjdCBTTkRfU09DX0hETUlf Q09ERUMKLSBmb3JjZSByZXNldCB0aGUgcGh5IHdoZW4gaHBkIGRldGVjdGVkCgpDaGFuZ2VzIGlu IHY1OgotIGFscGhhYmV0aWNhbCBvcmRlcgotIGRvIG5vdCB1c2UgbG9uZywgdXNlIHUzMiBvciB1 NjQKLSByZXR1cm4gTU9ERV9DTE9DS19ISUdIIHdoZW4gcmVxdWVzdGVkID4gYWN0dWFsCi0gT3B0 aW1pemVkIENvZGluZyBTdHlsZQotIGFkZCBhIGZvcm11bGEgdG8gZ2V0IGJldHRlciB0dSBzaXpl IGFuZCBzeW1ib2wgdmFsdWUuCi0gbW9kaWZ5IGFjY29yZGluZyB0byBTZWFuIFBhdWwncyBjb21t ZW50cwotIGZpeGVkIHRoZSBmd193YWl0IGFsd2F5cyAwCgpDaGFuZ2VzIGluIHY0OgotIHVzZSBw aHkgZnJhbWV3b3JrIHRvIGNvbnRyb2wgRFAgcGh5Ci0gc3VwcG9ydCAyIHBoeXMKCkNoYW5nZXMg aW4gdjM6Ci0gdXNlIEVYVENPTl9ESVNQX0RQIGFuZCBFWFRDT05fRElTUF9EUF9BTFQgY2FibGUg dG8gZ2V0IGRwIHBvcnQgc3RhdGUuCi0gcmVzZXQgc3BkaWYgYmVmb3JlIGNvbmZpZyBpdAotIG1v ZGlmeSB0aGUgZmlybXdhcmUgY2xrIHRvIDEwME1oegotIHJldHJ5IGxvYWQgZmlybXdhcmUgaWYg ZncgZmlsZSBpcyByZXF1ZXN0ZWQgdG9vIGVhcmx5CgpDaGFuZ2VzIGluIHYyOgotIEFscGhhYmV0 aWMgb3JkZXIKLSByZW1vdmUgZXhjZXNzIGVycm9yIG1lc3NhZ2UKLSB1c2UgZGVmaW5lIGNsa19y YXRlCi0gY2hlY2sgYWxsIHJldHVybiB2YWx1ZQotIHJlbW92ZSBkZXZfc2V0X25hbWUoZHAtPmRl diwgImNkbi1kcCIpOwotIHVzZSBzY2hlZHVsZV9kZWxheWVkX3dvcmsKLSByZW1vdmUgbmV2ZXIt Y2FsbGVkIGZ1bmN0aW9ucwotIHJlbW92ZSBzb21lIHVubmVjZXNzYXJ5ICgpCgpDaGFuZ2VzIGlu IHYxOgotIHVzZSBleHRjb24gQVBJCi0gdXNlIGhkbWktY29kZWMgZm9yIHRoZSBEUCBBc29jCi0g ZG8gbm90IGluaXRpYWxpemUgdGhlICJyZXQiCi0gcHJpbnRrIGEgZXJyIGxvZyB3aGVuIGRybV9v Zl9lbmNvZGVyX2FjdGl2ZV9lbmRwb2ludF9pZAotIG1vZGlmeSB0aGUgZGNsayBwaW5fcG9sIHRv IGEgc2luZ2xlIGxpbmUKCiBkcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvS2NvbmZpZyAgICAgICAg ICAgIHwgICAxMCArCiBkcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvTWFrZWZpbGUgICAgICAgICAg IHwgICAgMSArCiBkcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvY2RuLWRwLWNvcmUuYyAgICAgIHwg MTE2MSArKysrKysrKysrKysrKysrKysrKysrKysrKysKIGRyaXZlcnMvZ3B1L2RybS9yb2NrY2hp cC9jZG4tZHAtY29yZS5oICAgICAgfCAgMTA4ICsrKwogZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlw L2Nkbi1kcC1yZWcuYyAgICAgICB8ICA5NTYgKysrKysrKysrKysrKysrKysrKysrKwogZHJpdmVy cy9ncHUvZHJtL3JvY2tjaGlwL2Nkbi1kcC1yZWcuaCAgICAgICB8ICA0ODIgKysrKysrKysrKysK IGRyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9yb2NrY2hpcF9kcm1fdm9wLmMgfCAgIDEzICstCiBk cml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvcm9ja2NoaXBfZHJtX3ZvcC5oIHwgICAgOSArCiBkcml2 ZXJzL2dwdS9kcm0vcm9ja2NoaXAvcm9ja2NoaXBfdm9wX3JlZy5jIHwgICAgMiArCiA5IGZpbGVz IGNoYW5nZWQsIDI3MzkgaW5zZXJ0aW9ucygrKSwgMyBkZWxldGlvbnMoLSkKIGNyZWF0ZSBtb2Rl IDEwMDY0NCBkcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvY2RuLWRwLWNvcmUuYwogY3JlYXRlIG1v ZGUgMTAwNjQ0IGRyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9jZG4tZHAtY29yZS5oCiBjcmVhdGUg bW9kZSAxMDA2NDQgZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL2Nkbi1kcC1yZWcuYwogY3JlYXRl IG1vZGUgMTAwNjQ0IGRyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9jZG4tZHAtcmVnLmgKCmRpZmYg LS1naXQgYS9kcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvS2NvbmZpZyBiL2RyaXZlcnMvZ3B1L2Ry bS9yb2NrY2hpcC9LY29uZmlnCmluZGV4IGQzMGJkYzMuLjIwYWFhZmUgMTAwNjQ0Ci0tLSBhL2Ry aXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9LY29uZmlnCisrKyBiL2RyaXZlcnMvZ3B1L2RybS9yb2Nr Y2hpcC9LY29uZmlnCkBAIC0yNSw2ICsyNSwxNiBAQCBjb25maWcgUk9DS0NISVBfQU5BTE9HSVhf RFAKIAkgIGZvciB0aGUgQW5hbG9naXggQ29yZSBEUCBkcml2ZXIuIElmIHlvdSB3YW50IHRvIGVu YWJsZSBEUAogCSAgb24gUkszMjg4IGJhc2VkIFNvQywgeW91IHNob3VsZCBzZWxldCB0aGlzIG9w dGlvbi4KIAorY29uZmlnIFJPQ0tDSElQX0NETl9EUAorICAgICAgICB0cmlzdGF0ZSAiUm9ja2No aXAgY2RuIERQIgorICAgICAgICBkZXBlbmRzIG9uIERSTV9ST0NLQ0hJUAorCXNlbGVjdCBTTkRf U09DX0hETUlfQ09ERUMgaWYgU05EX1NPQworICAgICAgICBoZWxwCisJICBUaGlzIHNlbGVjdHMg c3VwcG9ydCBmb3IgUm9ja2NoaXAgU29DIHNwZWNpZmljIGV4dGVuc2lvbnMKKwkgIGZvciB0aGUg Y2RuIERQIGRyaXZlci4gSWYgeW91IHdhbnQgdG8gZW5hYmxlIERwIG9uCisJICBSSzMzOTkgYmFz ZWQgU29DLCB5b3Ugc2hvdWxkIHNlbGVjdCB0aGlzCisJICBvcHRpb24uCisKIGNvbmZpZyBST0NL Q0hJUF9EV19IRE1JCiAgICAgICAgIHRyaXN0YXRlICJSb2NrY2hpcCBzcGVjaWZpYyBleHRlbnNp b25zIGZvciBTeW5vcHN5cyBEVyBIRE1JIgogICAgICAgICBkZXBlbmRzIG9uIERSTV9ST0NLQ0hJ UApkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL01ha2VmaWxlIGIvZHJpdmVy cy9ncHUvZHJtL3JvY2tjaGlwL01ha2VmaWxlCmluZGV4IDk3NDYzNjUuLjZhMDc4MDkgMTAwNjQ0 Ci0tLSBhL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9NYWtlZmlsZQorKysgYi9kcml2ZXJzL2dw dS9kcm0vcm9ja2NoaXAvTWFrZWZpbGUKQEAgLTcsNiArNyw3IEBAIHJvY2tjaGlwZHJtLXkgOj0g cm9ja2NoaXBfZHJtX2Rydi5vIHJvY2tjaGlwX2RybV9mYi5vIFwKIHJvY2tjaGlwZHJtLSQoQ09O RklHX0RSTV9GQkRFVl9FTVVMQVRJT04pICs9IHJvY2tjaGlwX2RybV9mYmRldi5vCiAKIG9iai0k KENPTkZJR19ST0NLQ0hJUF9BTkFMT0dJWF9EUCkgKz0gYW5hbG9naXhfZHAtcm9ja2NoaXAubwor b2JqLSQoQ09ORklHX1JPQ0tDSElQX0NETl9EUCkgKz0gY2RuLWRwLWNvcmUubyBjZG4tZHAtcmVn Lm8KIG9iai0kKENPTkZJR19ST0NLQ0hJUF9EV19IRE1JKSArPSBkd19oZG1pLXJvY2tjaGlwLm8K IG9iai0kKENPTkZJR19ST0NLQ0hJUF9EV19NSVBJX0RTSSkgKz0gZHctbWlwaS1kc2kubwogb2Jq LSQoQ09ORklHX1JPQ0tDSElQX0lOTk9fSERNSSkgKz0gaW5ub19oZG1pLm8KZGlmZiAtLWdpdCBh L2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9jZG4tZHAtY29yZS5jIGIvZHJpdmVycy9ncHUvZHJt L3JvY2tjaGlwL2Nkbi1kcC1jb3JlLmMKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAw MC4uOGQ3MDhkMwotLS0gL2Rldi9udWxsCisrKyBiL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9j ZG4tZHAtY29yZS5jCkBAIC0wLDAgKzEsMTE2MSBAQAorLyoKKyAqIENvcHlyaWdodCAoQykgRnV6 aG91IFJvY2tjaGlwIEVsZWN0cm9uaWNzIENvLkx0ZAorICogQXV0aG9yOiBDaHJpcyBaaG9uZyA8 enl3QHJvY2stY2hpcHMuY29tPgorICoKKyAqIFRoaXMgc29mdHdhcmUgaXMgbGljZW5zZWQgdW5k ZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMKKyAqIExpY2Vuc2UgdmVyc2lv biAyLCBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgYW5kCisg KiBtYXkgYmUgY29waWVkLCBkaXN0cmlidXRlZCwgYW5kIG1vZGlmaWVkIHVuZGVyIHRob3NlIHRl cm1zLgorICoKKyAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0 IGl0IHdpbGwgYmUgdXNlZnVsLAorICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0 IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YKKyAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRO RVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUKKyAqIEdOVSBHZW5lcmFsIFB1 YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuCisgKi8KKworI2luY2x1ZGUgPGRybS9kcm1Q Lmg+CisjaW5jbHVkZSA8ZHJtL2RybV9hdG9taWNfaGVscGVyLmg+CisjaW5jbHVkZSA8ZHJtL2Ry bV9jcnRjX2hlbHBlci5oPgorI2luY2x1ZGUgPGRybS9kcm1fZHBfaGVscGVyLmg+CisjaW5jbHVk ZSA8ZHJtL2RybV9lZGlkLmg+CisjaW5jbHVkZSA8ZHJtL2RybV9vZi5oPgorCisjaW5jbHVkZSA8 bGludXgvY2xrLmg+CisjaW5jbHVkZSA8bGludXgvY29tcG9uZW50Lmg+CisjaW5jbHVkZSA8bGlu dXgvZXh0Y29uLmg+CisjaW5jbHVkZSA8bGludXgvZmlybXdhcmUuaD4KKyNpbmNsdWRlIDxsaW51 eC9yZWdtYXAuaD4KKyNpbmNsdWRlIDxsaW51eC9yZXNldC5oPgorI2luY2x1ZGUgPGxpbnV4L21m ZC9zeXNjb24uaD4KKyNpbmNsdWRlIDxsaW51eC9waHkvcGh5Lmg+CisKKyNpbmNsdWRlIDxzb3Vu ZC9oZG1pLWNvZGVjLmg+CisKKyNpbmNsdWRlICJjZG4tZHAtY29yZS5oIgorI2luY2x1ZGUgImNk bi1kcC1yZWcuaCIKKyNpbmNsdWRlICJyb2NrY2hpcF9kcm1fdm9wLmgiCisKKyNkZWZpbmUgY29u bmVjdG9yX3RvX2RwKGMpIFwKKwkJY29udGFpbmVyX29mKGMsIHN0cnVjdCBjZG5fZHBfZGV2aWNl LCBjb25uZWN0b3IpCisKKyNkZWZpbmUgZW5jb2Rlcl90b19kcChjKSBcCisJCWNvbnRhaW5lcl9v ZihjLCBzdHJ1Y3QgY2RuX2RwX2RldmljZSwgZW5jb2RlcikKKworI2RlZmluZSBHUkZfU09DX0NP TjkJCTB4NjIyNAorI2RlZmluZSBEUF9TRUxfVk9QX0xJVAkJQklUKDEyKQorI2RlZmluZSBHUkZf U09DX0NPTjI2CQkweDYyNjgKKyNkZWZpbmUgVVBIWV9TRUxfQklUCQkzCisjZGVmaW5lIFVQSFlf U0VMX01BU0sJCUJJVCgxOSkKKyNkZWZpbmUgRFBUWF9IUERfU0VMCQkoMyA8PCAxMikKKyNkZWZp bmUgRFBUWF9IUERfREVMCQkoMiA8PCAxMikKKyNkZWZpbmUgRFBUWF9IUERfU0VMX01BU0sJKDMg PDwgMjgpCisKKyNkZWZpbmUgQ0ROX0ZXX1RJTUVPVVRfTVMJKDY0ICogMTAwMCkKKyNkZWZpbmUg Q0ROX0RQQ0RfVElNRU9VVF9NUwk1MDAwCisjZGVmaW5lIENETl9EUF9GSVJNV0FSRQkJInJvY2tj aGlwL2RwdHguYmluIgorCitzdHJ1Y3QgY2RuX2RwX2RhdGEgeworCXU4IG1heF9waHk7Cit9Owor CitzdHJ1Y3QgY2RuX2RwX2RhdGEgcmszMzk5X2Nkbl9kcCA9IHsKKwkubWF4X3BoeSA9IDIsCit9 OworCitzdGF0aWMgY29uc3Qgc3RydWN0IG9mX2RldmljZV9pZCBjZG5fZHBfZHRfaWRzW10gPSB7 CisJeyAuY29tcGF0aWJsZSA9ICJyb2NrY2hpcCxyazMzOTktY2RuLWRwIiwKKwkJLmRhdGEgPSAo dm9pZCAqKSZyazMzOTlfY2RuX2RwIH0sCisJe30KK307CisKK01PRFVMRV9ERVZJQ0VfVEFCTEUo b2YsIGNkbl9kcF9kdF9pZHMpOworCitzdGF0aWMgaW50IGNkbl9kcF9ncmZfd3JpdGUoc3RydWN0 IGNkbl9kcF9kZXZpY2UgKmRwLAorCQkJICAgIHVuc2lnbmVkIGludCByZWcsIHVuc2lnbmVkIGlu dCB2YWwpCit7CisJaW50IHJldDsKKworCXJldCA9IGNsa19wcmVwYXJlX2VuYWJsZShkcC0+Z3Jm X2Nsayk7CisJaWYgKHJldCkgeworCQlEUk1fREVWX0VSUk9SKGRwLT5kZXYsICJGYWlsZWQgdG8g cHJlcGFyZV9lbmFibGUgZ3JmIGNsb2NrXG4iKTsKKwkJcmV0dXJuIHJldDsKKwl9CisKKwlyZXQg PSByZWdtYXBfd3JpdGUoZHAtPmdyZiwgcmVnLCB2YWwpOworCWlmIChyZXQpIHsKKwkJRFJNX0RF Vl9FUlJPUihkcC0+ZGV2LCAiQ291bGQgbm90IHdyaXRlIHRvIEdSRjogJWRcbiIsIHJldCk7CisJ CXJldHVybiByZXQ7CisJfQorCisJY2xrX2Rpc2FibGVfdW5wcmVwYXJlKGRwLT5ncmZfY2xrKTsK KworCXJldHVybiAwOworfQorCitzdGF0aWMgaW50IGNkbl9kcF9jbGtfZW5hYmxlKHN0cnVjdCBj ZG5fZHBfZGV2aWNlICpkcCkKK3sKKwlpbnQgcmV0OworCXUzMiByYXRlOworCisJcmV0ID0gY2xr X3ByZXBhcmVfZW5hYmxlKGRwLT5wY2xrKTsKKwlpZiAocmV0IDwgMCkgeworCQlEUk1fREVWX0VS Uk9SKGRwLT5kZXYsICJjYW5ub3QgZW5hYmxlIGRwIHBjbGsgJWRcbiIsIHJldCk7CisJCWdvdG8g ZXJyX3BjbGs7CisJfQorCisJcmV0ID0gY2xrX3ByZXBhcmVfZW5hYmxlKGRwLT5jb3JlX2Nsayk7 CisJaWYgKHJldCA8IDApIHsKKwkJRFJNX0RFVl9FUlJPUihkcC0+ZGV2LCAiY2Fubm90IGVuYWJs ZSBjb3JlX2NsayAlZFxuIiwgcmV0KTsKKwkJZ290byBlcnJfY29yZV9jbGs7CisJfQorCisJcmV0 ID0gcG1fcnVudGltZV9nZXRfc3luYyhkcC0+ZGV2KTsKKwlpZiAocmV0IDwgMCkgeworCQlEUk1f REVWX0VSUk9SKGRwLT5kZXYsICJjYW5ub3QgZ2V0IHBtIHJ1bnRpbWUgJWRcbiIsIHJldCk7CisJ CWdvdG8gZXJyX3BjbGs7CisJfQorCisJcmVzZXRfY29udHJvbF9hc3NlcnQoZHAtPmRwdHhfcnN0 KTsKKwlyZXNldF9jb250cm9sX2Fzc2VydChkcC0+YXBiX3JzdCk7CisJcmVzZXRfY29udHJvbF9k ZWFzc2VydChkcC0+ZHB0eF9yc3QpOworCXJlc2V0X2NvbnRyb2xfZGVhc3NlcnQoZHAtPmFwYl9y c3QpOworCisJcmF0ZSA9IGNsa19nZXRfcmF0ZShkcC0+Y29yZV9jbGspOworCWlmIChyYXRlIDwg MCkgeworCQlEUk1fREVWX0VSUk9SKGRwLT5kZXYsICJnZXQgY2xrIHJhdGUgZmFpbGVkOiAlZFxu IiwgcmF0ZSk7CisJCWdvdG8gZXJyX3NldF9yYXRlOworCX0KKworCWNkbl9kcF9zZXRfZndfY2xr KGRwLCByYXRlKTsKKwljZG5fZHBfY2xvY2tfcmVzZXQoZHApOworCisJcmV0dXJuIDA7CisKK2Vy cl9zZXRfcmF0ZToKKwljbGtfZGlzYWJsZV91bnByZXBhcmUoZHAtPmNvcmVfY2xrKTsKK2Vycl9j b3JlX2NsazoKKwljbGtfZGlzYWJsZV91bnByZXBhcmUoZHAtPnBjbGspOworZXJyX3BjbGs6CisJ cmV0dXJuIHJldDsKK30KKworc3RhdGljIHZvaWQgY2RuX2RwX2Nsa19kaXNhYmxlKHN0cnVjdCBj ZG5fZHBfZGV2aWNlICpkcCkKK3sKKwlwbV9ydW50aW1lX3B1dF9zeW5jKGRwLT5kZXYpOworCWNs a19kaXNhYmxlX3VucHJlcGFyZShkcC0+cGNsayk7CisJY2xrX2Rpc2FibGVfdW5wcmVwYXJlKGRw LT5jb3JlX2Nsayk7Cit9CisKK3N0YXRpYyBpbnQgY2RuX2RwX2dldF9wb3J0X2xhbmVzKHN0cnVj dCBjZG5fZHBfcG9ydCAqcG9ydCkKK3sKKwlzdHJ1Y3QgZXh0Y29uX2RldiAqZWRldiA9IHBvcnQt PmV4dGNvbjsKKwl1bmlvbiBleHRjb25fcHJvcGVydHlfdmFsdWUgcHJvcGVydHk7CisJdTggbGFu ZXMgPSAwOworCWludCBkcHR4OworCisJZHB0eCA9IGV4dGNvbl9nZXRfc3RhdGUoZWRldiwgRVhU Q09OX0RJU1BfRFApOworCWlmIChkcHR4ID4gMCkgeworCQlleHRjb25fZ2V0X3Byb3BlcnR5KGVk ZXYsIEVYVENPTl9ESVNQX0RQLAorCQkJCSAgICBFWFRDT05fUFJPUF9VU0JfU1MsICZwcm9wZXJ0 eSk7CisJCWlmIChwcm9wZXJ0eS5pbnR2YWwpCisJCQlsYW5lcyA9IDI7CisJCWVsc2UKKwkJCWxh bmVzID0gNDsKKwl9CisKKwlyZXR1cm4gbGFuZXM7Cit9CisKK3N0YXRpYyBzdHJ1Y3QgY2RuX2Rw X3BvcnQgKmNkbl9kcF9jb25uZWN0ZWRfcG9ydChzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHApCit7 CisJc3RydWN0IGNkbl9kcF9wb3J0ICpwb3J0OworCWludCBpLCBsYW5lczsKKworCWlmIChkcC0+ bm9fc2luaykKKwkJcmV0dXJuIE5VTEw7CisKKwlmb3IgKGkgPSAwOyBpIDwgZHAtPnBvcnRzOyBp KyspIHsKKwkJcG9ydCA9IGRwLT5wb3J0W2ldOworCQlsYW5lcyA9IGNkbl9kcF9nZXRfcG9ydF9s YW5lcyhwb3J0KTsKKwkJaWYgKGxhbmVzKQorCQkJcmV0dXJuIHBvcnQ7CisJfQorCXJldHVybiBO VUxMOworfQorCitzdGF0aWMgZW51bSBkcm1fY29ubmVjdG9yX3N0YXR1cworY2RuX2RwX2Nvbm5l Y3Rvcl9kZXRlY3Qoc3RydWN0IGRybV9jb25uZWN0b3IgKmNvbm5lY3RvciwgYm9vbCBmb3JjZSkK K3sKKwlzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAgPSBjb25uZWN0b3JfdG9fZHAoY29ubmVjdG9y KTsKKwllbnVtIGRybV9jb25uZWN0b3Jfc3RhdHVzIHN0YXR1cyA9IGNvbm5lY3Rvcl9zdGF0dXNf ZGlzY29ubmVjdGVkOworCisJbXV0ZXhfbG9jaygmZHAtPmxvY2spOworCWlmIChkcC0+YWN0aXZl ICYmIGRwLT5lbmFibGVkKQorCQlzdGF0dXMgPSBjb25uZWN0b3Jfc3RhdHVzX2Nvbm5lY3RlZDsK KwltdXRleF91bmxvY2soJmRwLT5sb2NrKTsKKworCXJldHVybiBzdGF0dXM7Cit9CisKK3N0YXRp YyB2b2lkIGNkbl9kcF9jb25uZWN0b3JfZGVzdHJveShzdHJ1Y3QgZHJtX2Nvbm5lY3RvciAqY29u bmVjdG9yKQoreworCWRybV9jb25uZWN0b3JfdW5yZWdpc3Rlcihjb25uZWN0b3IpOworCWRybV9j b25uZWN0b3JfY2xlYW51cChjb25uZWN0b3IpOworfQorCitzdGF0aWMgc3RydWN0IGRybV9jb25u ZWN0b3JfZnVuY3MgY2RuX2RwX2F0b21pY19jb25uZWN0b3JfZnVuY3MgPSB7CisJLmRwbXMgPSBk cm1fYXRvbWljX2hlbHBlcl9jb25uZWN0b3JfZHBtcywKKwkuZGV0ZWN0ID0gY2RuX2RwX2Nvbm5l Y3Rvcl9kZXRlY3QsCisJLmRlc3Ryb3kgPSBjZG5fZHBfY29ubmVjdG9yX2Rlc3Ryb3ksCisJLmZp bGxfbW9kZXMgPSBkcm1faGVscGVyX3Byb2JlX3NpbmdsZV9jb25uZWN0b3JfbW9kZXMsCisJLnJl c2V0ID0gZHJtX2F0b21pY19oZWxwZXJfY29ubmVjdG9yX3Jlc2V0LAorCS5hdG9taWNfZHVwbGlj YXRlX3N0YXRlID0gZHJtX2F0b21pY19oZWxwZXJfY29ubmVjdG9yX2R1cGxpY2F0ZV9zdGF0ZSwK KwkuYXRvbWljX2Rlc3Ryb3lfc3RhdGUgPSBkcm1fYXRvbWljX2hlbHBlcl9jb25uZWN0b3JfZGVz dHJveV9zdGF0ZSwKK307CisKK3N0YXRpYyBpbnQgY2RuX2RwX2Nvbm5lY3Rvcl9nZXRfbW9kZXMo c3RydWN0IGRybV9jb25uZWN0b3IgKmNvbm5lY3RvcikKK3sKKwlzdHJ1Y3QgY2RuX2RwX2Rldmlj ZSAqZHAgPSBjb25uZWN0b3JfdG9fZHAoY29ubmVjdG9yKTsKKwlzdHJ1Y3QgZWRpZCAqZWRpZDsK KwlpbnQgcmV0ID0gMDsKKworCW11dGV4X2xvY2soJmRwLT5sb2NrKTsKKwlpZiAoV0FSTl9PTigh ZHAtPmZ3X2xvYWRlZCkpCisJCWdvdG8gb3V0OworCisJZWRpZCA9IGRybV9kb19nZXRfZWRpZChj b25uZWN0b3IsIGNkbl9kcF9nZXRfZWRpZF9ibG9jaywgZHApOworCWlmIChlZGlkKSB7CisJCURS TV9ERVZfREVCVUdfS01TKGRwLT5kZXYsICJnb3QgZWRpZDogd2lkdGhbJWRdIHggaGVpZ2h0WyVk XVxuIiwKKwkJCQkgIGVkaWQtPndpZHRoX2NtLCBlZGlkLT5oZWlnaHRfY20pOworCisJCWRwLT5z aW5rX2hhc19hdWRpbyA9IGRybV9kZXRlY3RfbW9uaXRvcl9hdWRpbyhlZGlkKTsKKwkJcmV0ID0g ZHJtX2FkZF9lZGlkX21vZGVzKGNvbm5lY3RvciwgZWRpZCk7CisJCWlmIChyZXQpIHsKKwkJCWRy bV9tb2RlX2Nvbm5lY3Rvcl91cGRhdGVfZWRpZF9wcm9wZXJ0eShjb25uZWN0b3IsCisJCQkJCQkJ CWVkaWQpOworCQkJZHJtX2VkaWRfdG9fZWxkKGNvbm5lY3RvciwgZWRpZCk7CisJCX0KKwkJa2Zy ZWUoZWRpZCk7CisJfQorCitvdXQ6CisJbXV0ZXhfdW5sb2NrKCZkcC0+bG9jayk7CisJcmV0dXJu IHJldDsKK30KKworc3RhdGljIHN0cnVjdCBkcm1fZW5jb2RlciAqCitjZG5fZHBfY29ubmVjdG9y X2Jlc3RfZW5jb2RlcihzdHJ1Y3QgZHJtX2Nvbm5lY3RvciAqY29ubmVjdG9yKQoreworCXN0cnVj dCBjZG5fZHBfZGV2aWNlICpkcCA9IGNvbm5lY3Rvcl90b19kcChjb25uZWN0b3IpOworCisJcmV0 dXJuICZkcC0+ZW5jb2RlcjsKK30KKworc3RhdGljIGludCBjZG5fZHBfY29ubmVjdG9yX21vZGVf dmFsaWQoc3RydWN0IGRybV9jb25uZWN0b3IgKmNvbm5lY3RvciwKKwkJCQkgICAgICAgc3RydWN0 IGRybV9kaXNwbGF5X21vZGUgKm1vZGUpCit7CisJc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwID0g Y29ubmVjdG9yX3RvX2RwKGNvbm5lY3Rvcik7CisJc3RydWN0IGRybV9kaXNwbGF5X2luZm8gKmRp c3BsYXlfaW5mbyA9ICZkcC0+Y29ubmVjdG9yLmRpc3BsYXlfaW5mbzsKKwl1MzIgcmVxdWVzdGVk LCBhY3R1YWwsIHJhdGUsIHNpbmtfbWF4LCBzb3VyY2VfbWF4ID0gMDsKKwl1OCBsYW5lcywgYnBj LCBpOworCisJc3dpdGNoIChkaXNwbGF5X2luZm8tPmJwYykgeworCWNhc2UgMTY6CisJY2FzZSAx MjoKKwljYXNlIDEwOgorCQlicGMgPSAxMDsKKwkJYnJlYWs7CisJY2FzZSA2OgorCQlicGMgPSA2 OworCQlicmVhazsKKwlkZWZhdWx0OgorCQlicGMgPSA4OworCQlicmVhazsKKwl9CisKKwlyZXF1 ZXN0ZWQgPSBtb2RlLT5jbG9jayAqIGJwYyAqIDMgLyAxMDAwOworCisJLyogZmluZCB0aGUgcnVu bmluZyBwb3J0ICovCisJZm9yIChpID0gMDsgaSA8IGRwLT5wb3J0czsgaSsrKSB7CisJCWlmIChk cC0+cG9ydFtpXS0+cGh5X2VuYWJsZWQpIHsKKwkJCXNvdXJjZV9tYXggPSBkcC0+cG9ydFtpXS0+ bGFuZXM7CisJCQlicmVhazsKKwkJfQorCX0KKworCXNpbmtfbWF4ID0gZHJtX2RwX21heF9sYW5l X2NvdW50KGRwLT5kcGNkKTsKKwlsYW5lcyA9IG1pbihzb3VyY2VfbWF4LCBzaW5rX21heCk7CisK Kwlzb3VyY2VfbWF4ID0gZHJtX2RwX2J3X2NvZGVfdG9fbGlua19yYXRlKENETl9EUF9NQVhfTElO S19SQVRFKTsKKwlzaW5rX21heCA9IGRybV9kcF9tYXhfbGlua19yYXRlKGRwLT5kcGNkKTsKKwly YXRlID0gbWluKHNvdXJjZV9tYXgsIHNpbmtfbWF4KTsKKworCWFjdHVhbCA9IHJhdGUgKiBsYW5l cyAvIDEwMDsKKworCS8qIGVmZmljaWVuY3kgaXMgYWJvdXQgMC44ICovCisJYWN0dWFsID0gYWN0 dWFsICogOCAvIDEwOworCisJaWYgKHJlcXVlc3RlZCA+IGFjdHVhbCkgeworCQlEUk1fREVWX0RF QlVHX0tNUyhkcC0+ZGV2LAorCQkJCSAgInJlcXVlc3RlZD0lZCwgYWN0dWFsPSVkLCBjbG9jaz0l ZFxuIiwKKwkJCQkgIHJlcXVlc3RlZCwgYWN0dWFsLCBtb2RlLT5jbG9jayk7CisJCXJldHVybiBN T0RFX0NMT0NLX0hJR0g7CisJfQorCisJcmV0dXJuIE1PREVfT0s7Cit9CisKK3N0YXRpYyBzdHJ1 Y3QgZHJtX2Nvbm5lY3Rvcl9oZWxwZXJfZnVuY3MgY2RuX2RwX2Nvbm5lY3Rvcl9oZWxwZXJfZnVu Y3MgPSB7CisJLmdldF9tb2RlcyA9IGNkbl9kcF9jb25uZWN0b3JfZ2V0X21vZGVzLAorCS5iZXN0 X2VuY29kZXIgPSBjZG5fZHBfY29ubmVjdG9yX2Jlc3RfZW5jb2RlciwKKwkubW9kZV92YWxpZCA9 IGNkbl9kcF9jb25uZWN0b3JfbW9kZV92YWxpZCwKK307CisKK3N0YXRpYyBpbnQgY2RuX2RwX2Zp cm13YXJlX2luaXQoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwKQoreworCWludCByZXQ7CisJY29u c3QgdTMyICppcmFtX2RhdGEsICpkcmFtX2RhdGE7CisJY29uc3Qgc3RydWN0IGZpcm13YXJlICpm dyA9IGRwLT5mdzsKKwljb25zdCBzdHJ1Y3QgY2RuX2Zpcm13YXJlX2hlYWRlciAqaGRyOworCisJ aGRyID0gKHN0cnVjdCBjZG5fZmlybXdhcmVfaGVhZGVyICopZnctPmRhdGE7CisJaWYgKGZ3LT5z aXplICE9IGxlMzJfdG9fY3B1KGhkci0+c2l6ZV9ieXRlcykpIHsKKwkJRFJNX0RFVl9FUlJPUihk cC0+ZGV2LCAiZmlybXdhcmUgaXMgaW52YWxpZFxuIik7CisJCXJldHVybiAtRUlOVkFMOworCX0K KworCWlyYW1fZGF0YSA9IChjb25zdCB1MzIgKikoZnctPmRhdGEgKyBoZHItPmhlYWRlcl9zaXpl KTsKKwlkcmFtX2RhdGEgPSAoY29uc3QgdTMyICopKGZ3LT5kYXRhICsgaGRyLT5oZWFkZXJfc2l6 ZSArIGhkci0+aXJhbV9zaXplKTsKKworCXJldCA9IGNkbl9kcF9sb2FkX2Zpcm13YXJlKGRwLCBp cmFtX2RhdGEsIGhkci0+aXJhbV9zaXplLAorCQkJCSAgIGRyYW1fZGF0YSwgaGRyLT5kcmFtX3Np emUpOworCWlmIChyZXQpCisJCXJldHVybiByZXQ7CisKKwlyZXQgPSBjZG5fZHBfc2V0X2Zpcm13 YXJlX2FjdGl2ZShkcCwgdHJ1ZSk7CisJaWYgKHJldCkgeworCQlEUk1fREVWX0VSUk9SKGRwLT5k ZXYsICJhY3RpdmUgdWNwdSBmYWlsZWQ6ICVkXG4iLCByZXQpOworCQlyZXR1cm4gcmV0OworCX0K KworCXJldHVybiBjZG5fZHBfZXZlbnRfY29uZmlnKGRwKTsKK30KKworc3RhdGljIGludCBjZG5f ZHBfZ2V0X3NpbmtfY2FwYWJpbGl0eShzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAsCisJCQkJICAg ICAgc3RydWN0IGNkbl9kcF9wb3J0ICpwb3J0KQoreworCXU4IHNpbmtfY291bnQ7CisJaW50IHJl dDsKKwl1bnNpZ25lZCBsb25nIHRpbWVvdXQgPSBqaWZmaWVzICsgbXNlY3NfdG9famlmZmllcyhD RE5fRFBDRF9USU1FT1VUX01TKTsKKworCS8qCisJICogQXR0ZW1wdCB0byByZWFkIHNpbmsgY291 bnQgJiBzaW5rIGNhcGFiaWxpdHksIHJldHJ5IGluIGNhc2UgdGhlIHNpbmsKKwkgKiBtYXkgbm90 IGJlIHJlYWR5LgorCSAqCisJICogU2lua3MgYXJlICpzdXBwb3NlZCogdG8gY29tZSB1cCB3aXRo aW4gMW1zIGZyb20gYW4gb2ZmIHN0YXRlLCBidXQKKwkgKiBzb21lIGRvY2tzIG5lZWQgbW9yZSB0 aW1lIHRvIHBvd2VyIHVwLgorCSAqLworCXdoaWxlICh0aW1lX2JlZm9yZShqaWZmaWVzLCB0aW1l b3V0KSkgeworCQlyZXQgPSBjZG5fZHBfZHBjZF9yZWFkKGRwLCBEUF9TSU5LX0NPVU5ULCAmc2lu a19jb3VudCwgMSk7CisJCWlmICghcmV0KSB7CisJCQlEUk1fREVWX0RFQlVHX0tNUyhkcC0+ZGV2 LCAiZ2V0IGRwY2Qgc3VjY2VzcyFcbiIpOworCisJCQlzaW5rX2NvdW50ID0gRFBfR0VUX1NJTktf Q09VTlQoc2lua19jb3VudCk7CisJCQlpZiAoIXNpbmtfY291bnQpIHsKKwkJCQlEUk1fREVWX0VS Uk9SKGRwLT5kZXYsICJTaW5rIGNvdW50IGlzIDBcbiIpOworCQkJCXJldHVybiAtRU5PREVWOwor CQkJfQorCisJCQlyZXQgPSBjZG5fZHBfZHBjZF9yZWFkKGRwLCBEUF9EUENEX1JFViwgZHAtPmRw Y2QsCisJCQkJCSAgICAgICBEUF9SRUNFSVZFUl9DQVBfU0laRSk7CisJCQlpZiAocmV0KQorCQkJ CWNvbnRpbnVlOworCisJCQlyZXR1cm4gMDsKKworCQl9IGVsc2UgaWYgKCFleHRjb25fZ2V0X3N0 YXRlKHBvcnQtPmV4dGNvbiwgRVhUQ09OX0RJU1BfRFApKSB7CisJCQlicmVhazsKKwkJfQorCQl1 c2xlZXBfcmFuZ2UoNTAwMCwgMTAwMDApOworCX0KKworCWRldl9lcnIoZHAtPmRldiwgImdldCBk cGNkIGZhaWxlZCFcbiIpOworCXJldHVybiAtRVRJTUVET1VUOworfQorCitzdGF0aWMgaW50IGNk bl9kcF9lbmFibGVfcGh5KHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCwgc3RydWN0IGNkbl9kcF9w b3J0ICpwb3J0KQoreworCXVuaW9uIGV4dGNvbl9wcm9wZXJ0eV92YWx1ZSBwcm9wZXJ0eTsKKwlp bnQgcmV0OworCisJcmV0ID0gY2RuX2RwX2dyZl93cml0ZShkcCwgR1JGX1NPQ19DT04yNiwKKwkJ CSAgICAgICAocG9ydC0+aWQgPDwgVVBIWV9TRUxfQklUKSB8IFVQSFlfU0VMX01BU0spOworCWlm IChyZXQpCisJCXJldHVybiByZXQ7CisKKwlpZiAoIXBvcnQtPnBoeV9lbmFibGVkKSB7CisJCXJl dCA9IHBoeV9wb3dlcl9vbihwb3J0LT5waHkpOworCQlpZiAocmV0KSB7CisJCQlEUk1fREVWX0VS Uk9SKGRwLT5kZXYsICJwaHkgcG93ZXIgb24gZmFpbGVkOiAlZFxuIiwKKwkJCQkgICAgICByZXQp OworCQkJZ290byBlcnJfcGh5OworCQl9CisJCXBvcnQtPnBoeV9lbmFibGVkID0gdHJ1ZTsKKwl9 CisKKwlyZXQgPSBjZG5fZHBfZ3JmX3dyaXRlKGRwLCBHUkZfU09DX0NPTjI2LAorCQkJICAgICAg IERQVFhfSFBEX1NFTF9NQVNLIHwgRFBUWF9IUERfU0VMKTsKKwlpZiAocmV0KSB7CisJCURSTV9E RVZfRVJST1IoZHAtPmRldiwgIkZhaWxlZCB0byB3cml0ZSBIUERfU0VMICVkXG4iLCByZXQpOwor CQlnb3RvIGVycl9wb3dlcl9vbjsKKwl9CisKKwlyZXQgPSBjZG5fZHBfZ2V0X2hwZF9zdGF0dXMo ZHApOworCWlmIChyZXQgPD0gMCkgeworCQlpZiAoIXJldCkKKwkJCURSTV9ERVZfRVJST1IoZHAt PmRldiwgImhwZCBkb2VzIG5vdCBleGlzdFxuIik7CisJCWdvdG8gZXJyX3Bvd2VyX29uOworCX0K KworCXJldCA9IGV4dGNvbl9nZXRfcHJvcGVydHkocG9ydC0+ZXh0Y29uLCBFWFRDT05fRElTUF9E UCwKKwkJCQkgIEVYVENPTl9QUk9QX1VTQl9UWVBFQ19QT0xBUklUWSwgJnByb3BlcnR5KTsKKwlp ZiAocmV0KSB7CisJCURSTV9ERVZfRVJST1IoZHAtPmRldiwgImdldCBwcm9wZXJ0eSBmYWlsZWRc biIpOworCQlnb3RvIGVycl9wb3dlcl9vbjsKKwl9CisKKwlwb3J0LT5sYW5lcyA9IGNkbl9kcF9n ZXRfcG9ydF9sYW5lcyhwb3J0KTsKKwlyZXQgPSBjZG5fZHBfc2V0X2hvc3RfY2FwKGRwLCBwb3J0 LT5sYW5lcywgcHJvcGVydHkuaW50dmFsKTsKKwlpZiAocmV0KSB7CisJCURSTV9ERVZfRVJST1Io ZHAtPmRldiwgInNldCBob3N0IGNhcGFiaWxpdGllcyBmYWlsZWQ6ICVkXG4iLAorCQkJICAgICAg cmV0KTsKKwkJZ290byBlcnJfcG93ZXJfb247CisJfQorCisJcmV0dXJuIDA7CisKK2Vycl9wb3dl cl9vbjoKKwlpZiAocGh5X3Bvd2VyX29mZihwb3J0LT5waHkpKQorCQlEUk1fREVWX0VSUk9SKGRw LT5kZXYsICJwaHkgcG93ZXIgb2ZmIGZhaWxlZDogJWQiLCByZXQpOworCWVsc2UKKwkJcG9ydC0+ cGh5X2VuYWJsZWQgPSBmYWxzZTsKKworZXJyX3BoeToKKwljZG5fZHBfZ3JmX3dyaXRlKGRwLCBH UkZfU09DX0NPTjI2LAorCQkJIERQVFhfSFBEX1NFTF9NQVNLIHwgRFBUWF9IUERfREVMKTsKKwly ZXR1cm4gcmV0OworfQorCitzdGF0aWMgaW50IGNkbl9kcF9kaXNhYmxlX3BoeShzdHJ1Y3QgY2Ru X2RwX2RldmljZSAqZHAsCisJCQkgICAgICBzdHJ1Y3QgY2RuX2RwX3BvcnQgKnBvcnQpCit7CisJ aW50IHJldDsKKworCWlmIChwb3J0LT5waHlfZW5hYmxlZCkgeworCQlyZXQgPSBwaHlfcG93ZXJf b2ZmKHBvcnQtPnBoeSk7CisJCWlmIChyZXQpIHsKKwkJCURSTV9ERVZfRVJST1IoZHAtPmRldiwg InBoeSBwb3dlciBvZmYgZmFpbGVkOiAlZCIsIHJldCk7CisJCQlyZXR1cm4gcmV0OworCQl9CisJ fQorCisJcG9ydC0+cGh5X2VuYWJsZWQgPSBmYWxzZTsKKwlwb3J0LT5sYW5lcyA9IDA7CisJcmV0 dXJuIDA7Cit9CisKK3N0YXRpYyBpbnQgY2RuX2RwX2VuYWJsZShzdHJ1Y3QgY2RuX2RwX2Rldmlj ZSAqZHApCit7CisJaW50IHJldDsKKwlzdHJ1Y3QgY2RuX2RwX3BvcnQgKnBvcnQ7CisKKwlpZiAo ZHAtPmFjdGl2ZSkKKwkJcmV0dXJuIDA7CisKKwlwb3J0ID0gY2RuX2RwX2Nvbm5lY3RlZF9wb3J0 KGRwKTsKKwlpZiAoIXBvcnQpIHsKKwkJRFJNX0RFVl9FUlJPUihkcC0+ZGV2LCAiQ2FuJ3QgZW5h YmxlIHdpdGhvdXQgY29ubmVjdGlvblxuIik7CisJCXJldHVybiAtRU5PREVWOworCX0KKworCXJl dCA9IGNkbl9kcF9jbGtfZW5hYmxlKGRwKTsKKwlpZiAocmV0KQorCQlyZXR1cm4gcmV0OworCisJ cmV0ID0gY2RuX2RwX2Zpcm13YXJlX2luaXQoZHApOworCWlmIChyZXQpIHsKKwkJRFJNX0RFVl9F UlJPUihkcC0+ZGV2LCAiZmlybXdhcmUgaW5pdCBmYWlsZWQ6ICVkIiwgcmV0KTsKKwkJZ290byBl cnJfY2xrX2Rpc2FibGU7CisJfQorCisJcmV0ID0gY2RuX2RwX2VuYWJsZV9waHkoZHAsIHBvcnQp OworCWlmIChyZXQpCisJCWdvdG8gZXJyX2Nsa19kaXNhYmxlOworCisJcmV0ID0gY2RuX2RwX2dl dF9zaW5rX2NhcGFiaWxpdHkoZHAsIHBvcnQpOworCWlmIChyZXQpCisJCWdvdG8gZXJyX3BoeV9k aXNhYmxlOworCisJZHAtPmFjdGl2ZSA9IHRydWU7CisJcmV0dXJuIDA7CisKK2Vycl9waHlfZGlz YWJsZToKKwljZG5fZHBfZGlzYWJsZV9waHkoZHAsIHBvcnQpOworZXJyX2Nsa19kaXNhYmxlOgor CWNkbl9kcF9jbGtfZGlzYWJsZShkcCk7CisJcmV0dXJuIHJldDsKK30KKworc3RhdGljIGludCBj ZG5fZHBfZGlzYWJsZShzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHApCit7CisJaW50IHJldCwgaTsK KworCWlmICghZHAtPmFjdGl2ZSkKKwkJcmV0dXJuIDA7CisKKwlmb3IgKGkgPSAwOyBpIDwgZHAt PnBvcnRzOyBpKyspIHsKKwkJaWYgKGNkbl9kcF9nZXRfcG9ydF9sYW5lcyhkcC0+cG9ydFtpXSkp CisJCQljZG5fZHBfZGlzYWJsZV9waHkoZHAsIGRwLT5wb3J0W2ldKTsKKwl9CisKKwlyZXQgPSBj ZG5fZHBfZ3JmX3dyaXRlKGRwLCBHUkZfU09DX0NPTjI2LAorCQkJICAgICAgIERQVFhfSFBEX1NF TF9NQVNLIHwgRFBUWF9IUERfREVMKTsKKwlpZiAocmV0KSB7CisJCURSTV9ERVZfRVJST1IoZHAt PmRldiwgIkZhaWxlZCB0byBjbGVhciBocGQgc2VsICVkXG4iLAorCQkJICAgICAgcmV0KTsKKwkJ cmV0dXJuIHJldDsKKwl9CisKKwljZG5fZHBfc2V0X2Zpcm13YXJlX2FjdGl2ZShkcCwgZmFsc2Up OworCWNkbl9kcF9jbGtfZGlzYWJsZShkcCk7CisJZHAtPmFjdGl2ZSA9IGZhbHNlOworCWRwLT5u b19zaW5rID0gZmFsc2U7CisJcmV0dXJuIDA7Cit9CisKK3N0YXRpYyB2b2lkIGNkbl9kcF9lbmNv ZGVyX21vZGVfc2V0KHN0cnVjdCBkcm1fZW5jb2RlciAqZW5jb2RlciwKKwkJCQkgICAgc3RydWN0 IGRybV9kaXNwbGF5X21vZGUgKm1vZGUsCisJCQkJICAgIHN0cnVjdCBkcm1fZGlzcGxheV9tb2Rl ICphZGp1c3RlZCkKK3sKKwlzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAgPSBlbmNvZGVyX3RvX2Rw KGVuY29kZXIpOworCXN0cnVjdCBkcm1fZGlzcGxheV9pbmZvICpkaXNwbGF5X2luZm8gPSAmZHAt PmNvbm5lY3Rvci5kaXNwbGF5X2luZm87CisJc3RydWN0IHJvY2tjaGlwX2NydGNfc3RhdGUgKnN0 YXRlOworCXN0cnVjdCB2aWRlb19pbmZvICp2aWRlbyA9ICZkcC0+dmlkZW9faW5mbzsKKwlpbnQg cmV0LCB2YWw7CisKKwlzd2l0Y2ggKGRpc3BsYXlfaW5mby0+YnBjKSB7CisJY2FzZSAxNjoKKwlj YXNlIDEyOgorCWNhc2UgMTA6CisJCXZpZGVvLT5jb2xvcl9kZXB0aCA9IDEwOworCQlicmVhazsK KwljYXNlIDY6CisJCXZpZGVvLT5jb2xvcl9kZXB0aCA9IDY7CisJCWJyZWFrOworCWRlZmF1bHQ6 CisJCXZpZGVvLT5jb2xvcl9kZXB0aCA9IDg7CisJCWJyZWFrOworCX0KKworCXZpZGVvLT5jb2xv cl9mbXQgPSBQWExfUkdCOworCisJdmlkZW8tPnZfc3luY19wb2xhcml0eSA9ICEhKG1vZGUtPmZs YWdzICYgRFJNX01PREVfRkxBR19OVlNZTkMpOworCXZpZGVvLT5oX3N5bmNfcG9sYXJpdHkgPSAh IShtb2RlLT5mbGFncyAmIERSTV9NT0RFX0ZMQUdfTkhTWU5DKTsKKworCXJldCA9IGRybV9vZl9l bmNvZGVyX2FjdGl2ZV9lbmRwb2ludF9pZChkcC0+ZGV2LT5vZl9ub2RlLCBlbmNvZGVyKTsKKwlp ZiAocmV0IDwgMCkgeworCQlEUk1fREVWX0VSUk9SKGRwLT5kZXYsICJDb3VsZCBub3QgZ2V0IHZv cCBpZCwgJWQiLCByZXQpOworCQlyZXR1cm47CisJfQorCisJRFJNX0RFVl9ERUJVR19LTVMoZHAt PmRldiwgInZvcCAlcyBvdXRwdXQgdG8gY2RuLWRwXG4iLAorCQkJICAocmV0KSA/ICJMSVQiIDog IkJJRyIpOworCXN0YXRlID0gdG9fcm9ja2NoaXBfY3J0Y19zdGF0ZShlbmNvZGVyLT5jcnRjLT5z dGF0ZSk7CisJaWYgKHJldCkgeworCQl2YWwgPSBEUF9TRUxfVk9QX0xJVCB8IChEUF9TRUxfVk9Q X0xJVCA8PCAxNik7CisJCXN0YXRlLT5vdXRwdXRfbW9kZSA9IFJPQ0tDSElQX09VVF9NT0RFX1A4 ODg7CisJfSBlbHNlIHsKKwkJdmFsID0gRFBfU0VMX1ZPUF9MSVQgPDwgMTY7CisJCXN0YXRlLT5v dXRwdXRfbW9kZSA9IFJPQ0tDSElQX09VVF9NT0RFX0FBQUE7CisJfQorCisJcmV0ID0gY2RuX2Rw X2dyZl93cml0ZShkcCwgR1JGX1NPQ19DT045LCB2YWwpOworCWlmIChyZXQpCisJCXJldHVybjsK KworCW1lbWNweSgmZHAtPm1vZGUsIGFkanVzdGVkLCBzaXplb2YoKm1vZGUpKTsKK30KKworc3Rh dGljIHZvaWQgY2RuX2RwX2VuY29kZXJfZW5hYmxlKHN0cnVjdCBkcm1fZW5jb2RlciAqZW5jb2Rl cikKK3sKKwlzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAgPSBlbmNvZGVyX3RvX2RwKGVuY29kZXIp OworCWludCByZXQ7CisKKwltdXRleF9sb2NrKCZkcC0+bG9jayk7CisJaWYgKCFkcC0+YWN0aXZl KSB7CisJCXJldCA9IGNkbl9kcF9lbmFibGUoZHApOworCQlpZiAocmV0KSB7CisJCQlEUk1fREVW X0VSUk9SKGRwLT5kZXYsICJGYWlsZWQgdG8gZW5hYmxlIGVuY29kZXIgJWRcbiIsCisJCQkJICAg ICAgcmV0KTsKKwkJfQorCX0KKworCXJldCA9IGNkbl9kcF90cmFpbmluZ19zdGFydChkcCk7CisJ aWYgKHJldCkgeworCQlEUk1fREVWX0VSUk9SKGRwLT5kZXYsICJGYWlsZWQgdG8gc3RhcnQgdHJh aW5pbmcgJWRcbiIsIHJldCk7CisJCWdvdG8gb3V0OworCX0KKworCXJldCA9IGNkbl9kcF9nZXRf dHJhaW5pbmdfc3RhdHVzKGRwKTsKKwlpZiAocmV0KSB7CisJCURSTV9ERVZfRVJST1IoZHAtPmRl diwgIkZhaWxlZCB0byBnZXQgdHJhaW5pbmcgc3RhdCAlZFxuIiwgcmV0KTsKKwkJZ290byBvdXQ7 CisJfQorCisJRFJNX0RFVl9JTkZPKGRwLT5kZXYsICJyYXRlOjB4JXgsIGxhbmVzOiVkXG4iLCBk cC0+bGluay5yYXRlLAorCQkgICAgIGRwLT5saW5rLm51bV9sYW5lcyk7CisKKwlpZiAoY2RuX2Rw X3NldF92aWRlb19zdGF0dXMoZHAsIENPTlRST0xfVklERU9fSURMRSkpIHsKKwkJRFJNX0RFVl9F UlJPUihkcC0+ZGV2LCAiRmFpbGVkIHRvIGlkbGUgdmlkZW9cbiIpOworCQlnb3RvIG91dDsKKwl9 CisKKwlpZiAoY2RuX2RwX2NvbmZpZ192aWRlbyhkcCkpIHsKKwkJRFJNX0RFVl9FUlJPUihkcC0+ ZGV2LCAiRmFpbGVkIHRvIGNvbmZpZyB2aWRlb1xuIik7CisJCWdvdG8gb3V0OworCX0KKworCWlm IChjZG5fZHBfc2V0X3ZpZGVvX3N0YXR1cyhkcCwgQ09OVFJPTF9WSURFT19WQUxJRCkpIHsKKwkJ RFJNX0RFVl9FUlJPUihkcC0+ZGV2LCAiRmFpbGVkIHRvIHZhbGlkIHZpZGVvXG4iKTsKKwkJZ290 byBvdXQ7CisJfQorCitvdXQ6CisJbXV0ZXhfdW5sb2NrKCZkcC0+bG9jayk7Cit9CisKK3N0YXRp YyB2b2lkIGNkbl9kcF9lbmNvZGVyX2Rpc2FibGUoc3RydWN0IGRybV9lbmNvZGVyICplbmNvZGVy KQoreworCXN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCA9IGVuY29kZXJfdG9fZHAoZW5jb2Rlcik7 CisJaW50IHJldDsKKworCW11dGV4X2xvY2soJmRwLT5sb2NrKTsKKwlpZiAoZHAtPmFjdGl2ZSkg eworCQlyZXQgPSBjZG5fZHBfZGlzYWJsZShkcCk7CisJCWlmIChyZXQpIHsKKwkJCURSTV9ERVZf RVJST1IoZHAtPmRldiwgIkZhaWxlZCB0byBkaXNhYmxlIGVuY29kZXIgJWRcbiIsCisJCQkJICAg ICAgcmV0KTsKKwkJfQorCX0KKwltdXRleF91bmxvY2soJmRwLT5sb2NrKTsKK30KKworc3RhdGlj IGludCBjZG5fZHBfZW5jb2Rlcl9hdG9taWNfY2hlY2soc3RydWN0IGRybV9lbmNvZGVyICplbmNv ZGVyLAorCQkJCSAgICAgICBzdHJ1Y3QgZHJtX2NydGNfc3RhdGUgKmNydGNfc3RhdGUsCisJCQkJ ICAgICAgIHN0cnVjdCBkcm1fY29ubmVjdG9yX3N0YXRlICpjb25uX3N0YXRlKQoreworCXN0cnVj dCByb2NrY2hpcF9jcnRjX3N0YXRlICpzID0gdG9fcm9ja2NoaXBfY3J0Y19zdGF0ZShjcnRjX3N0 YXRlKTsKKworCXMtPm91dHB1dF9tb2RlID0gUk9DS0NISVBfT1VUX01PREVfQUFBQTsKKwlzLT5v dXRwdXRfdHlwZSA9IERSTV9NT0RFX0NPTk5FQ1RPUl9EaXNwbGF5UG9ydDsKKworCXJldHVybiAw OworfQorCitzdGF0aWMgc3RydWN0IGRybV9lbmNvZGVyX2hlbHBlcl9mdW5jcyBjZG5fZHBfZW5j b2Rlcl9oZWxwZXJfZnVuY3MgPSB7CisJLm1vZGVfc2V0ID0gY2RuX2RwX2VuY29kZXJfbW9kZV9z ZXQsCisJLmVuYWJsZSA9IGNkbl9kcF9lbmNvZGVyX2VuYWJsZSwKKwkuZGlzYWJsZSA9IGNkbl9k cF9lbmNvZGVyX2Rpc2FibGUsCisJLmF0b21pY19jaGVjayA9IGNkbl9kcF9lbmNvZGVyX2F0b21p Y19jaGVjaywKK307CisKK3N0YXRpYyBzdHJ1Y3QgZHJtX2VuY29kZXJfZnVuY3MgY2RuX2RwX2Vu Y29kZXJfZnVuY3MgPSB7CisJLmRlc3Ryb3kgPSBkcm1fZW5jb2Rlcl9jbGVhbnVwLAorfTsKKwor c3RhdGljIGludCBjZG5fZHBfcGFyc2VfZHQoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwKQorewor CXN0cnVjdCBkZXZpY2UgKmRldiA9IGRwLT5kZXY7CisJc3RydWN0IGRldmljZV9ub2RlICpucCA9 IGRldi0+b2Zfbm9kZTsKKwlzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2ID0gdG9fcGxhdGZv cm1fZGV2aWNlKGRldik7CisJc3RydWN0IHJlc291cmNlICpyZXM7CisKKwlkcC0+Z3JmID0gc3lz Y29uX3JlZ21hcF9sb29rdXBfYnlfcGhhbmRsZShucCwgInJvY2tjaGlwLGdyZiIpOworCWlmIChJ U19FUlIoZHAtPmdyZikpIHsKKwkJRFJNX0RFVl9FUlJPUihkZXYsICJjZG4tZHAgbmVlZHMgcm9j a2NoaXAsZ3JmIHByb3BlcnR5XG4iKTsKKwkJcmV0dXJuIFBUUl9FUlIoZHAtPmdyZik7CisJfQor CisJcmVzID0gcGxhdGZvcm1fZ2V0X3Jlc291cmNlKHBkZXYsIElPUkVTT1VSQ0VfTUVNLCAwKTsK KwlkcC0+cmVncyA9IGRldm1faW9yZW1hcF9yZXNvdXJjZShkZXYsIHJlcyk7CisJaWYgKElTX0VS UihkcC0+cmVncykpIHsKKwkJRFJNX0RFVl9FUlJPUihkZXYsICJpb3JlbWFwIHJlZyBmYWlsZWRc biIpOworCQlyZXR1cm4gUFRSX0VSUihkcC0+cmVncyk7CisJfQorCisJZHAtPmNvcmVfY2xrID0g ZGV2bV9jbGtfZ2V0KGRldiwgImNvcmUtY2xrIik7CisJaWYgKElTX0VSUihkcC0+Y29yZV9jbGsp KSB7CisJCURSTV9ERVZfRVJST1IoZGV2LCAiY2Fubm90IGdldCBjb3JlX2Nsa19kcFxuIik7CisJ CXJldHVybiBQVFJfRVJSKGRwLT5jb3JlX2Nsayk7CisJfQorCisJZHAtPnBjbGsgPSBkZXZtX2Ns a19nZXQoZGV2LCAicGNsayIpOworCWlmIChJU19FUlIoZHAtPnBjbGspKSB7CisJCURSTV9ERVZf RVJST1IoZGV2LCAiY2Fubm90IGdldCBwY2xrXG4iKTsKKwkJcmV0dXJuIFBUUl9FUlIoZHAtPnBj bGspOworCX0KKworCWRwLT5zcGRpZl9jbGsgPSBkZXZtX2Nsa19nZXQoZGV2LCAic3BkaWYiKTsK KwlpZiAoSVNfRVJSKGRwLT5zcGRpZl9jbGspKSB7CisJCURSTV9ERVZfRVJST1IoZGV2LCAiY2Fu bm90IGdldCBzcGRpZl9jbGtcbiIpOworCQlyZXR1cm4gUFRSX0VSUihkcC0+c3BkaWZfY2xrKTsK Kwl9CisKKwlkcC0+Z3JmX2NsayA9IGRldm1fY2xrX2dldChkZXYsICJncmYiKTsKKwlpZiAoSVNf RVJSKGRwLT5ncmZfY2xrKSkgeworCQlEUk1fREVWX0VSUk9SKGRldiwgImNhbm5vdCBnZXQgZ3Jm IGNsa1xuIik7CisJCXJldHVybiBQVFJfRVJSKGRwLT5ncmZfY2xrKTsKKwl9CisKKwlkcC0+c3Bk aWZfcnN0ID0gZGV2bV9yZXNldF9jb250cm9sX2dldChkZXYsICJzcGRpZiIpOworCWlmIChJU19F UlIoZHAtPnNwZGlmX3JzdCkpIHsKKwkJRFJNX0RFVl9FUlJPUihkZXYsICJubyBzcGRpZiByZXNl dCBjb250cm9sIGZvdW5kXG4iKTsKKwkJcmV0dXJuIFBUUl9FUlIoZHAtPnNwZGlmX3JzdCk7CisJ fQorCisJZHAtPmRwdHhfcnN0ID0gZGV2bV9yZXNldF9jb250cm9sX2dldChkZXYsICJkcHR4Iik7 CisJaWYgKElTX0VSUihkcC0+ZHB0eF9yc3QpKSB7CisJCURSTV9ERVZfRVJST1IoZGV2LCAibm8g dXBoeSByZXNldCBjb250cm9sIGZvdW5kXG4iKTsKKwkJcmV0dXJuIFBUUl9FUlIoZHAtPmRwdHhf cnN0KTsKKwl9CisKKwlkcC0+YXBiX3JzdCA9IGRldm1fcmVzZXRfY29udHJvbF9nZXQoZGV2LCAi YXBiIik7CisJaWYgKElTX0VSUihkcC0+YXBiX3JzdCkpIHsKKwkJRFJNX0RFVl9FUlJPUihkZXYs ICJubyBhcGIgcmVzZXQgY29udHJvbCBmb3VuZFxuIik7CisJCXJldHVybiBQVFJfRVJSKGRwLT5h cGJfcnN0KTsKKwl9CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGludCBjZG5fZHBfYXVkaW9f aHdfcGFyYW1zKHN0cnVjdCBkZXZpY2UgKmRldiwgIHZvaWQgKmRhdGEsCisJCQkJICBzdHJ1Y3Qg aGRtaV9jb2RlY19kYWlmbXQgKmRhaWZtdCwKKwkJCQkgIHN0cnVjdCBoZG1pX2NvZGVjX3BhcmFt cyAqcGFyYW1zKQoreworCXN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCA9IGRldl9nZXRfZHJ2ZGF0 YShkZXYpOworCXN0cnVjdCBhdWRpb19pbmZvIGF1ZGlvID0geworCQkuc2FtcGxlX3dpZHRoID0g cGFyYW1zLT5zYW1wbGVfd2lkdGgsCisJCS5zYW1wbGVfcmF0ZSA9IHBhcmFtcy0+c2FtcGxlX3Jh dGUsCisJCS5jaGFubmVscyA9IHBhcmFtcy0+Y2hhbm5lbHMsCisJfTsKKwlpbnQgcmV0OworCisJ aWYgKCFkcC0+ZW5jb2Rlci5jcnRjKQorCQlyZXR1cm4gLUVOT0RFVjsKKworCXN3aXRjaCAoZGFp Zm10LT5mbXQpIHsKKwljYXNlIEhETUlfSTJTOgorCQlhdWRpby5mb3JtYXQgPSBBRk1UX0kyUzsK KwkJYnJlYWs7CisJY2FzZSBIRE1JX1NQRElGOgorCQlhdWRpby5mb3JtYXQgPSBBRk1UX1NQRElG OworCQlicmVhazsKKwlkZWZhdWx0OgorCQlEUk1fREVWX0VSUk9SKGRldiwgIkludmFsaWQgZm9y bWF0ICVkXG4iLCBkYWlmbXQtPmZtdCk7CisJCXJldHVybiAtRUlOVkFMOworCX0KKworCXJldCA9 IGNkbl9kcF9hdWRpb19jb25maWcoZHAsICZhdWRpbyk7CisJaWYgKCFyZXQpCisJCWRwLT5hdWRp b19pbmZvID0gYXVkaW87CisKKwlyZXR1cm4gcmV0OworfQorCitzdGF0aWMgdm9pZCBjZG5fZHBf YXVkaW9fc2h1dGRvd24oc3RydWN0IGRldmljZSAqZGV2LCB2b2lkICpkYXRhKQoreworCXN0cnVj dCBjZG5fZHBfZGV2aWNlICpkcCA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOworCWludCByZXQ7CisK KwlpZiAoIWRwLT5lbmNvZGVyLmNydGMpCisJCXJldHVybjsKKworCXJldCA9IGNkbl9kcF9hdWRp b19zdG9wKGRwLCAmZHAtPmF1ZGlvX2luZm8pOworCWlmICghcmV0KQorCQlkcC0+YXVkaW9faW5m by5mb3JtYXQgPSBBRk1UX1VOVVNFRDsKK30KKworc3RhdGljIGludCBjZG5fZHBfYXVkaW9fZGln aXRhbF9tdXRlKHN0cnVjdCBkZXZpY2UgKmRldiwgdm9pZCAqZGF0YSwKKwkJCQkgICAgIGJvb2wg ZW5hYmxlKQoreworCXN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCA9IGRldl9nZXRfZHJ2ZGF0YShk ZXYpOworCisJaWYgKCFkcC0+ZW5jb2Rlci5jcnRjKQorCQlyZXR1cm4gLUVOT0RFVjsKKworCXJl dHVybiBjZG5fZHBfYXVkaW9fbXV0ZShkcCwgZW5hYmxlKTsKK30KKworc3RhdGljIGludCBjZG5f ZHBfYXVkaW9fZ2V0X2VsZChzdHJ1Y3QgZGV2aWNlICpkZXYsIHZvaWQgKmRhdGEsCisJCQkJdTgg KmJ1Ziwgc2l6ZV90IGxlbikKK3sKKwlzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAgPSBkZXZfZ2V0 X2RydmRhdGEoZGV2KTsKKworCW1lbWNweShidWYsIGRwLT5jb25uZWN0b3IuZWxkLCBtaW4oc2l6 ZW9mKGRwLT5jb25uZWN0b3IuZWxkKSwgbGVuKSk7CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGlj IGNvbnN0IHN0cnVjdCBoZG1pX2NvZGVjX29wcyBhdWRpb19jb2RlY19vcHMgPSB7CisJLmh3X3Bh cmFtcyA9IGNkbl9kcF9hdWRpb19od19wYXJhbXMsCisJLmF1ZGlvX3NodXRkb3duID0gY2RuX2Rw X2F1ZGlvX3NodXRkb3duLAorCS5kaWdpdGFsX211dGUgPSBjZG5fZHBfYXVkaW9fZGlnaXRhbF9t dXRlLAorCS5nZXRfZWxkID0gY2RuX2RwX2F1ZGlvX2dldF9lbGQsCit9OworCitzdGF0aWMgaW50 IGNkbl9kcF9hdWRpb19jb2RlY19pbml0KHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCwKKwkJCQkg ICBzdHJ1Y3QgZGV2aWNlICpkZXYpCit7CisJc3RydWN0IGhkbWlfY29kZWNfcGRhdGEgY29kZWNf ZGF0YSA9IHsKKwkJLmkycyA9IDEsCisJCS5zcGRpZiA9IDEsCisJCS5vcHMgPSAmYXVkaW9fY29k ZWNfb3BzLAorCQkubWF4X2kyc19jaGFubmVscyA9IDgsCisJfTsKKworCWRwLT5hdWRpb19wZGV2 ID0gcGxhdGZvcm1fZGV2aWNlX3JlZ2lzdGVyX2RhdGEoCisJCQkgZGV2LCBIRE1JX0NPREVDX0RS Vl9OQU1FLCBQTEFURk9STV9ERVZJRF9BVVRPLAorCQkJICZjb2RlY19kYXRhLCBzaXplb2YoY29k ZWNfZGF0YSkpOworCisJcmV0dXJuIFBUUl9FUlJfT1JfWkVSTyhkcC0+YXVkaW9fcGRldik7Cit9 CisKK3N0YXRpYyBpbnQgY2RuX2RwX3JlcXVlc3RfZmlybXdhcmUoc3RydWN0IGNkbl9kcF9kZXZp Y2UgKmRwKQoreworCWludCByZXQ7CisJdW5zaWduZWQgbG9uZyB0aW1lb3V0ID0gamlmZmllcyAr IG1zZWNzX3RvX2ppZmZpZXMoQ0ROX0ZXX1RJTUVPVVRfTVMpOworCXVuc2lnbmVkIGxvbmcgc2xl ZXAgPSAxMDAwOworCisJV0FSTl9PTighbXV0ZXhfaXNfbG9ja2VkKCZkcC0+bG9jaykpOworCisJ aWYgKGRwLT5md19sb2FkZWQpCisJCXJldHVybiAwOworCisJLyogRHJvcCB0aGUgbG9jayBiZWZv cmUgZ2V0dGluZyB0aGUgZmlybXdhcmUgdG8gYXZvaWQgYmxvY2tpbmcgYm9vdCAqLworCW11dGV4 X3VubG9jaygmZHAtPmxvY2spOworCisJd2hpbGUgKHRpbWVfYmVmb3JlKGppZmZpZXMsIHRpbWVv dXQpKSB7CisJCXJldCA9IHJlcXVlc3RfZmlybXdhcmUoJmRwLT5mdywgQ0ROX0RQX0ZJUk1XQVJF LCBkcC0+ZGV2KTsKKwkJaWYgKHJldCA9PSAtRU5PRU5UKSB7CisJCQltc2xlZXAoc2xlZXApOwor CQkJc2xlZXAgKj0gMjsKKwkJCWNvbnRpbnVlOworCQl9IGVsc2UgaWYgKHJldCkgeworCQkJRFJN X0RFVl9FUlJPUihkcC0+ZGV2LAorCQkJCSAgICAgICJmYWlsZWQgdG8gcmVxdWVzdCBmaXJtd2Fy ZTogJWRcbiIsIHJldCk7CisJCQlnb3RvIG91dDsKKwkJfQorCisJCWRwLT5md19sb2FkZWQgPSB0 cnVlOworCQlyZXQgPSAwOworCQlnb3RvIG91dDsKKwl9CisKKwlEUk1fREVWX0VSUk9SKGRwLT5k ZXYsICJUaW1lZCBvdXQgdHJ5aW5nIHRvIGxvYWQgZmlybXdhcmVcbiIpOworCXJldCA9IC1FVElN RURPVVQ7CitvdXQ6CisJbXV0ZXhfbG9jaygmZHAtPmxvY2spOworCXJldHVybiByZXQ7Cit9CisK K3N0YXRpYyB2b2lkIGNkbl9kcF9wZF9ldmVudF93b3JrKHN0cnVjdCB3b3JrX3N0cnVjdCAqd29y aykKK3sKKwlzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAgPSBjb250YWluZXJfb2Yod29yaywgc3Ry dWN0IGNkbl9kcF9kZXZpY2UsCisJCQkJCQlldmVudF93b3JrKTsKKwl1bmlvbiBleHRjb25fcHJv cGVydHlfdmFsdWUgcHJvcGVydHk7CisJc3RydWN0IGNkbl9kcF9wb3J0ICpwb3J0OworCWludCBy ZXQsIGksIGxhbmVzOworCWJvb2wgaHBkX2V2ZW50ID0gZmFsc2U7CisJYm9vbCByZV90cmFpbmlu ZyA9IGZhbHNlOworCXU4IHNpbmtfY291bnQ7CisKKwlEUk1fREVWX0lORk8oZHAtPmRldiwgIlJl Y2VpdmVkIERQIGhvdHBsdWcgZXZlbnRcbiIpOworCisJbXV0ZXhfbG9jaygmZHAtPmxvY2spOwor CWlmICghZHAtPmVuYWJsZWQpCisJCWdvdG8gb3V0OworCisJcmV0ID0gY2RuX2RwX3JlcXVlc3Rf ZmlybXdhcmUoZHApOworCWlmIChyZXQpCisJCWdvdG8gb3V0OworCisJLyogV2UgbWlnaHQgbmVl ZCB0byBub3RpZnkgdXNlcnNwYWNlIGZvciBldmVyeXRoaW5nIGJlbG93IGhlcmUgKi8KKwlocGRf ZXZlbnQgPSB0cnVlOworCisJLyogRGlzYWJsZSBhbnkgcG9ydHMgdGhhdCBoYXZlIGp1c3QgYmVj b21lIGluYWN0aXZlICovCisJZm9yIChpID0gMDsgaSA8IGRwLT5wb3J0czsgaSsrKSB7CisJCXBv cnQgPSBkcC0+cG9ydFtpXTsKKwkJbGFuZXMgPSBjZG5fZHBfZ2V0X3BvcnRfbGFuZXMocG9ydCk7 CisJCWlmIChsYW5lcyAmJiBkcC0+YWN0aXZlKSB7CisJCQlleHRjb25fZ2V0X3Byb3BlcnR5KHBv cnQtPmV4dGNvbiwgRVhUQ09OX0RJU1BfRFAsCisJCQkJCSAgICBFWFRDT05fUFJPUF9ESVNQX0hQ RCwgJnByb3BlcnR5KTsKKworCQkJcmV0ID0gY2RuX2RwX2RwY2RfcmVhZChkcCwgRFBfU0lOS19D T1VOVCwKKwkJCQkJICAgICAgICZzaW5rX2NvdW50LCAxKTsKKwkJCWlmIChyZXQgfHwgIXNpbmtf Y291bnQpIHsKKwkJCQlkcC0+bm9fc2luayA9IHRydWU7CisJCQkJbGFuZXMgPSAwOworCQkJfSBl bHNlIGlmIChwcm9wZXJ0eS5pbnR2YWwpIHsKKwkJCQlyZV90cmFpbmluZyA9IHRydWU7CisJCQkJ Z290byBvdXQ7CisJCQl9CisJCX0KKworCQlpZiAoIWxhbmVzICYmIHBvcnQtPmxhbmVzKQorCQkJ Y2RuX2RwX2Rpc2FibGVfcGh5KGRwLCBwb3J0KTsKKwl9CisKKwkvKiBQb3dlciBvbi9vZmYgdGhl IGJsb2NrIGFuZCBwb3J0cyAqLworCWlmICghY2RuX2RwX2Nvbm5lY3RlZF9wb3J0KGRwKSkgewor CQlyZXQgPSBjZG5fZHBfZGlzYWJsZShkcCk7CisJCWlmIChyZXQpIHsKKwkJCURSTV9ERVZfRVJS T1IoZHAtPmRldiwgIkRpc2FibGUgZHAgZmFpbGVkICVkXG4iLCByZXQpOworCQkJZ290byBvdXQ7 CisJCX0KKworCX0gZWxzZSBpZiAoIWRwLT5hY3RpdmUpIHsKKwkJcmV0ID0gY2RuX2RwX2VuYWJs ZShkcCk7CisJCWlmIChyZXQpIHsKKwkJCURSTV9ERVZfRVJST1IoZHAtPmRldiwgIkZhaWxlZCB0 byBlbmFibGUgZHAgJWRcbiIsIHJldCk7CisJCQlnb3RvIG91dDsKKwkJfQorCX0KKworb3V0Ogor CW11dGV4X3VubG9jaygmZHAtPmxvY2spOworCisJaWYgKGhwZF9ldmVudCkKKwkJZHJtX2hlbHBl cl9ocGRfaXJxX2V2ZW50KGRwLT5kcm1fZGV2KTsKKworCWlmIChyZV90cmFpbmluZykKKwkJY2Ru X2RwX2VuY29kZXJfZW5hYmxlKCZkcC0+ZW5jb2Rlcik7Cit9CisKK3N0YXRpYyBpbnQgY2RuX2Rw X3BkX2V2ZW50KHN0cnVjdCBub3RpZmllcl9ibG9jayAqbmIsCisJCQkgICB1bnNpZ25lZCBsb25n IGV2ZW50LCB2b2lkICpwcml2KQoreworCXN0cnVjdCBjZG5fZHBfcG9ydCAqcG9ydCA9IGNvbnRh aW5lcl9vZihuYiwgc3RydWN0IGNkbl9kcF9wb3J0LAorCQkJCQkJZXZlbnRfbmIpOworCXN0cnVj dCBjZG5fZHBfZGV2aWNlICpkcCA9IHBvcnQtPmRwOworCisJLyoKKwkgKiBJdCB3b3VsZCBiZSBu aWNlIHRvIGJlIGFibGUgdG8ganVzdCBkbyB0aGUgd29yayBpbmxpbmUgcmlnaHQgaGVyZS4KKwkg KiBIb3dldmVyLCB3ZSBuZWVkIHRvIG1ha2UgYSBidW5jaCBvZiBjYWxscyB0aGF0IG1pZ2h0IHNs ZWVwIGluIG9yZGVyCisJICogdG8gdHVybiBvbiB0aGUgYmxvY2svcGh5LCBzbyB1c2UgYSB3b3Jr ZXIgaW5zdGVhZC4KKwkgKi8KKwlzY2hlZHVsZV93b3JrKCZkcC0+ZXZlbnRfd29yayk7CisKKwly ZXR1cm4gTk9USUZZX0RPTkU7Cit9CisKK3N0YXRpYyBpbnQgY2RuX2RwX2JpbmQoc3RydWN0IGRl dmljZSAqZGV2LCBzdHJ1Y3QgZGV2aWNlICptYXN0ZXIsIHZvaWQgKmRhdGEpCit7CisJc3RydWN0 IGNkbl9kcF9kZXZpY2UgKmRwID0gZGV2X2dldF9kcnZkYXRhKGRldik7CisJc3RydWN0IGRybV9l bmNvZGVyICplbmNvZGVyOworCXN0cnVjdCBkcm1fY29ubmVjdG9yICpjb25uZWN0b3I7CisJc3Ry dWN0IGNkbl9kcF9wb3J0ICpwb3J0OworCXN0cnVjdCBkcm1fZGV2aWNlICpkcm1fZGV2ID0gZGF0 YTsKKwlpbnQgcmV0LCBpOworCisJcG1fcnVudGltZV9lbmFibGUoZGV2KTsKKworCXJldCA9IGNk bl9kcF9wYXJzZV9kdChkcCk7CisJaWYgKHJldCA8IDApCisJCXJldHVybiByZXQ7CisKKwlkcC0+ ZHJtX2RldiA9IGRybV9kZXY7CisJZHAtPmVuYWJsZWQgPSB0cnVlOworCWRwLT5hY3RpdmUgPSBm YWxzZTsKKworCW11dGV4X2luaXQoJmRwLT5sb2NrKTsKKwlJTklUX1dPUksoJmRwLT5ldmVudF93 b3JrLCBjZG5fZHBfcGRfZXZlbnRfd29yayk7CisKKwllbmNvZGVyID0gJmRwLT5lbmNvZGVyOwor CisJZW5jb2Rlci0+cG9zc2libGVfY3J0Y3MgPSBkcm1fb2ZfZmluZF9wb3NzaWJsZV9jcnRjcyhk cm1fZGV2LAorCQkJCQkJCSAgICAgZGV2LT5vZl9ub2RlKTsKKwlEUk1fREVCVUdfS01TKCJwb3Nz aWJsZV9jcnRjcyA9IDB4JXhcbiIsIGVuY29kZXItPnBvc3NpYmxlX2NydGNzKTsKKworCXJldCA9 IGRybV9lbmNvZGVyX2luaXQoZHJtX2RldiwgZW5jb2RlciwgJmNkbl9kcF9lbmNvZGVyX2Z1bmNz LAorCQkJICAgICAgIERSTV9NT0RFX0VOQ09ERVJfVE1EUywgTlVMTCk7CisJaWYgKHJldCkgewor CQlEUk1fRVJST1IoImZhaWxlZCB0byBpbml0aWFsaXplIGVuY29kZXIgd2l0aCBkcm1cbiIpOwor CQlyZXR1cm4gcmV0OworCX0KKworCWRybV9lbmNvZGVyX2hlbHBlcl9hZGQoZW5jb2RlciwgJmNk bl9kcF9lbmNvZGVyX2hlbHBlcl9mdW5jcyk7CisKKwljb25uZWN0b3IgPSAmZHAtPmNvbm5lY3Rv cjsKKwljb25uZWN0b3ItPnBvbGxlZCA9IERSTV9DT05ORUNUT1JfUE9MTF9IUEQ7CisJY29ubmVj dG9yLT5kcG1zID0gRFJNX01PREVfRFBNU19PRkY7CisKKwlyZXQgPSBkcm1fY29ubmVjdG9yX2lu aXQoZHJtX2RldiwgY29ubmVjdG9yLAorCQkJCSAmY2RuX2RwX2F0b21pY19jb25uZWN0b3JfZnVu Y3MsCisJCQkJIERSTV9NT0RFX0NPTk5FQ1RPUl9EaXNwbGF5UG9ydCk7CisJaWYgKHJldCkgewor CQlEUk1fRVJST1IoImZhaWxlZCB0byBpbml0aWFsaXplIGNvbm5lY3RvciB3aXRoIGRybVxuIik7 CisJCWdvdG8gZXJyX2ZyZWVfZW5jb2RlcjsKKwl9CisKKwlkcm1fY29ubmVjdG9yX2hlbHBlcl9h ZGQoY29ubmVjdG9yLCAmY2RuX2RwX2Nvbm5lY3Rvcl9oZWxwZXJfZnVuY3MpOworCisJcmV0ID0g ZHJtX21vZGVfY29ubmVjdG9yX2F0dGFjaF9lbmNvZGVyKGNvbm5lY3RvciwgZW5jb2Rlcik7CisJ aWYgKHJldCkgeworCQlEUk1fRVJST1IoImZhaWxlZCB0byBhdHRhY2ggY29ubmVjdG9yIGFuZCBl bmNvZGVyXG4iKTsKKwkJZ290byBlcnJfZnJlZV9jb25uZWN0b3I7CisJfQorCisJY2RuX2RwX2F1 ZGlvX2NvZGVjX2luaXQoZHAsIGRldik7CisKKwlmb3IgKGkgPSAwOyBpIDwgZHAtPnBvcnRzOyBp KyspIHsKKwkJcG9ydCA9IGRwLT5wb3J0W2ldOworCisJCXBvcnQtPmV2ZW50X25iLm5vdGlmaWVy X2NhbGwgPSBjZG5fZHBfcGRfZXZlbnQ7CisJCXJldCA9IGRldm1fZXh0Y29uX3JlZ2lzdGVyX25v dGlmaWVyKGRwLT5kZXYsIHBvcnQtPmV4dGNvbiwKKwkJCQkJCSAgICBFWFRDT05fRElTUF9EUCwK KwkJCQkJCSAgICAmcG9ydC0+ZXZlbnRfbmIpOworCQlpZiAocmV0KSB7CisJCQlEUk1fREVWX0VS Uk9SKGRldiwKKwkJCQkgICAgICAicmVnaXN0ZXIgRVhUQ09OX0RJU1BfRFAgbm90aWZpZXIgZXJy XG4iKTsKKwkJCWdvdG8gZXJyX2ZyZWVfY29ubmVjdG9yOworCQl9CisKKwkJaWYgKGV4dGNvbl9n ZXRfc3RhdGUocG9ydC0+ZXh0Y29uLCBFWFRDT05fRElTUF9EUCkpCisJCQlzY2hlZHVsZV93b3Jr KCZkcC0+ZXZlbnRfd29yayk7CisJfQorCisJcmV0dXJuIDA7CisKK2Vycl9mcmVlX2Nvbm5lY3Rv cjoKKwlkcm1fY29ubmVjdG9yX2NsZWFudXAoY29ubmVjdG9yKTsKK2Vycl9mcmVlX2VuY29kZXI6 CisJZHJtX2VuY29kZXJfY2xlYW51cChlbmNvZGVyKTsKKwlyZXR1cm4gcmV0OworfQorCitzdGF0 aWMgdm9pZCBjZG5fZHBfdW5iaW5kKHN0cnVjdCBkZXZpY2UgKmRldiwgc3RydWN0IGRldmljZSAq bWFzdGVyLCB2b2lkICpkYXRhKQoreworCXN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCA9IGRldl9n ZXRfZHJ2ZGF0YShkZXYpOworCXN0cnVjdCBkcm1fZW5jb2RlciAqZW5jb2RlciA9ICZkcC0+ZW5j b2RlcjsKKwlzdHJ1Y3QgZHJtX2Nvbm5lY3RvciAqY29ubmVjdG9yID0gJmRwLT5jb25uZWN0b3I7 CisKKwlwbGF0Zm9ybV9kZXZpY2VfdW5yZWdpc3RlcihkcC0+YXVkaW9fcGRldik7CisJY2RuX2Rw X2VuY29kZXJfZGlzYWJsZShlbmNvZGVyKTsKKwllbmNvZGVyLT5mdW5jcy0+ZGVzdHJveShlbmNv ZGVyKTsKKwljb25uZWN0b3ItPmZ1bmNzLT5kZXN0cm95KGNvbm5lY3Rvcik7CisKKwlwbV9ydW50 aW1lX2Rpc2FibGUoZGV2KTsKKwlyZWxlYXNlX2Zpcm13YXJlKGRwLT5mdyk7Cit9CisKK3N0YXRp YyBjb25zdCBzdHJ1Y3QgY29tcG9uZW50X29wcyBjZG5fZHBfY29tcG9uZW50X29wcyA9IHsKKwku YmluZCA9IGNkbl9kcF9iaW5kLAorCS51bmJpbmQgPSBjZG5fZHBfdW5iaW5kLAorfTsKKworaW50 IGNkbl9kcF9zdXNwZW5kKHN0cnVjdCBkZXZpY2UgKmRldikKK3sKKwlzdHJ1Y3QgY2RuX2RwX2Rl dmljZSAqZHAgPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsKKworCWlmIChkcC0+YWN0aXZlKQorCQly ZXR1cm4gY2RuX2RwX2Rpc2FibGUoZHApOworCisJcmV0dXJuIDA7Cit9CisKK2ludCBjZG5fZHBf cmVzdW1lKHN0cnVjdCBkZXZpY2UgKmRldikKK3sKKwlzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAg PSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsKKworCXNjaGVkdWxlX3dvcmsoJmRwLT5ldmVudF93b3Jr KTsKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGludCBjZG5fZHBfcHJvYmUoc3RydWN0IHBsYXRm b3JtX2RldmljZSAqcGRldikKK3sKKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSAmcGRldi0+ZGV2Owor CWNvbnN0IHN0cnVjdCBvZl9kZXZpY2VfaWQgKm1hdGNoOworCXN0cnVjdCBjZG5fZHBfZGF0YSAq ZHBfZGF0YTsKKwlzdHJ1Y3QgY2RuX2RwX3BvcnQgKnBvcnQ7CisJc3RydWN0IGNkbl9kcF9kZXZp Y2UgKmRwOworCXN0cnVjdCBleHRjb25fZGV2ICpleHRjb247CisJc3RydWN0IHBoeSAqcGh5Owor CWludCBpOworCisJZHAgPSBkZXZtX2t6YWxsb2MoZGV2LCBzaXplb2YoKmRwKSwgR0ZQX0tFUk5F TCk7CisJaWYgKCFkcCkKKwkJcmV0dXJuIC1FTk9NRU07CisJZHAtPmRldiA9IGRldjsKKworCW1h dGNoID0gb2ZfbWF0Y2hfbm9kZShjZG5fZHBfZHRfaWRzLCBwZGV2LT5kZXYub2Zfbm9kZSk7CisJ ZHBfZGF0YSA9IChzdHJ1Y3QgY2RuX2RwX2RhdGEgKiltYXRjaC0+ZGF0YTsKKworCWZvciAoaSA9 IDA7IGkgPCBkcF9kYXRhLT5tYXhfcGh5OyBpKyspIHsKKwkJZXh0Y29uID0gZXh0Y29uX2dldF9l ZGV2X2J5X3BoYW5kbGUoZGV2LCBpKTsKKwkJcGh5ID0gZGV2bV9vZl9waHlfZ2V0X2J5X2luZGV4 KGRldiwgZGV2LT5vZl9ub2RlLCBpKTsKKworCQlpZiAoUFRSX0VSUihleHRjb24pID09IC1FUFJP QkVfREVGRVIgfHwKKwkJICAgIFBUUl9FUlIocGh5KSA9PSAtRVBST0JFX0RFRkVSKQorCQkJcmV0 dXJuIC1FUFJPQkVfREVGRVI7CisKKwkJaWYgKElTX0VSUihleHRjb24pIHx8IElTX0VSUihwaHkp KQorCQkJY29udGludWU7CisKKwkJcG9ydCA9IGRldm1fa3phbGxvYyhkZXYsIHNpemVvZigqcG9y dCksIEdGUF9LRVJORUwpOworCQlpZiAoIWRwKQorCQkJcmV0dXJuIC1FTk9NRU07CisKKwkJcG9y dC0+ZXh0Y29uID0gZXh0Y29uOworCQlwb3J0LT5waHkgPSBwaHk7CisJCXBvcnQtPmRwID0gZHA7 CisJCXBvcnQtPmlkID0gaTsKKwkJZHAtPnBvcnRbZHAtPnBvcnRzKytdID0gcG9ydDsKKwl9CisK KwlpZiAoIWRwLT5wb3J0cykgeworCQlEUk1fREVWX0VSUk9SKGRldiwgIm1pc3NpbmcgZXh0Y29u IG9yIHBoeVxuIik7CisJCXJldHVybiAtRUlOVkFMOworCX0KKworCWRldl9zZXRfZHJ2ZGF0YShk ZXYsIGRwKTsKKworCXJldHVybiBjb21wb25lbnRfYWRkKGRldiwgJmNkbl9kcF9jb21wb25lbnRf b3BzKTsKK30KKworc3RhdGljIGludCBjZG5fZHBfcmVtb3ZlKHN0cnVjdCBwbGF0Zm9ybV9kZXZp Y2UgKnBkZXYpCit7CisJY29tcG9uZW50X2RlbCgmcGRldi0+ZGV2LCAmY2RuX2RwX2NvbXBvbmVu dF9vcHMpOworCisJcmV0dXJuIDA7Cit9CisKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgZGV2X3BtX29w cyBjZG5fZHBfcG1fb3BzID0geworCVNFVF9TWVNURU1fU0xFRVBfUE1fT1BTKGNkbl9kcF9zdXNw ZW5kLAorCQkJCWNkbl9kcF9yZXN1bWUpCit9OworCitzdGF0aWMgc3RydWN0IHBsYXRmb3JtX2Ry aXZlciBjZG5fZHBfZHJpdmVyID0geworCS5wcm9iZSA9IGNkbl9kcF9wcm9iZSwKKwkucmVtb3Zl ID0gY2RuX2RwX3JlbW92ZSwKKwkuZHJpdmVyID0geworCQkgICAubmFtZSA9ICJjZG4tZHAiLAor CQkgICAub3duZXIgPSBUSElTX01PRFVMRSwKKwkJICAgLm9mX21hdGNoX3RhYmxlID0gb2ZfbWF0 Y2hfcHRyKGNkbl9kcF9kdF9pZHMpLAorCQkgICAucG0gPSAmY2RuX2RwX3BtX29wcywKKwl9LAor fTsKKworbW9kdWxlX3BsYXRmb3JtX2RyaXZlcihjZG5fZHBfZHJpdmVyKTsKKworTU9EVUxFX0FV VEhPUigiQ2hyaXMgWmhvbmcgPHp5d0Byb2NrLWNoaXBzLmNvbT4iKTsKK01PRFVMRV9ERVNDUklQ VElPTigiY2RuIERQIERyaXZlciIpOworTU9EVUxFX0xJQ0VOU0UoIkdQTCB2MiIpOwpkaWZmIC0t Z2l0IGEvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL2Nkbi1kcC1jb3JlLmggYi9kcml2ZXJzL2dw dS9kcm0vcm9ja2NoaXAvY2RuLWRwLWNvcmUuaApuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAw MDAwMDAwLi5jMGY3ZDA0Ci0tLSAvZGV2L251bGwKKysrIGIvZHJpdmVycy9ncHUvZHJtL3JvY2tj aGlwL2Nkbi1kcC1jb3JlLmgKQEAgLTAsMCArMSwxMDggQEAKKy8qCisgKiBDb3B5cmlnaHQgKEMp IDIwMTYgQ2hyaXMgWmhvbmcgPHp5d0Byb2NrLWNoaXBzLmNvbT4KKyAqIENvcHlyaWdodCAoQykg MjAxNiBST0NLQ0hJUCwgSW5jLgorICoKKyAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJl OyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5CisgKiBpdCB1bmRlciB0aGUg dGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieQor ICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyIHZlcnNpb24gMiBvZiB0aGUg TGljZW5zZS4KKyAqCisgKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUg dGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwKKyAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0 aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mCisgKiBNRVJDSEFOVEFCSUxJVFkgb3Ig RklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlCisgKiBHTlUgR2VuZXJh bCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLgorICovCisKKyNpZm5kZWYgX0NETl9E UF9DT1JFX0gKKyNkZWZpbmUgX0NETl9EUF9DT1JFX0gKKworI2luY2x1ZGUgPGRybS9kcm1QLmg+ CisjaW5jbHVkZSA8ZHJtL2RybV9jcnRjX2hlbHBlci5oPgorI2luY2x1ZGUgPGRybS9kcm1fZHBf aGVscGVyLmg+CisjaW5jbHVkZSA8ZHJtL2RybV9wYW5lbC5oPgorI2luY2x1ZGUgInJvY2tjaGlw X2RybV9kcnYuaCIKKworI2RlZmluZSBNQVhfUEhZCQkyCisKK2VudW0gYXVkaW9fZm9ybWF0IHsK KwlBRk1UX0kyUyA9IDAsCisJQUZNVF9TUERJRiA9IDEsCisJQUZNVF9VTlVTRUQsCit9OworCitz dHJ1Y3QgYXVkaW9faW5mbyB7CisJZW51bSBhdWRpb19mb3JtYXQgZm9ybWF0OworCWludCBzYW1w bGVfcmF0ZTsKKwlpbnQgY2hhbm5lbHM7CisJaW50IHNhbXBsZV93aWR0aDsKK307CisKK2VudW0g dmljX3B4bF9lbmNvZGluZ19mb3JtYXQgeworCVBYTF9SR0IgPSAweDEsCisJWUNCQ1JfNF80XzQg PSAweDIsCisJWUNCQ1JfNF8yXzIgPSAweDQsCisJWUNCQ1JfNF8yXzAgPSAweDgsCisJWV9PTkxZ ID0gMHgxMCwKK307CisKK3N0cnVjdCB2aWRlb19pbmZvIHsKKwlib29sIGhfc3luY19wb2xhcml0 eTsKKwlib29sIHZfc3luY19wb2xhcml0eTsKKwlib29sIGludGVybGFjZWQ7CisJaW50IGNvbG9y X2RlcHRoOworCWVudW0gdmljX3B4bF9lbmNvZGluZ19mb3JtYXQgY29sb3JfZm10OworfTsKKwor c3RydWN0IGNkbl9maXJtd2FyZV9oZWFkZXIgeworCXUzMiBzaXplX2J5dGVzOyAvKiBzaXplIG9m IHRoZSBlbnRpcmUgaGVhZGVyK2ltYWdlKHMpIGluIGJ5dGVzICovCisJdTMyIGhlYWRlcl9zaXpl OyAvKiBzaXplIG9mIGp1c3QgdGhlIGhlYWRlciBpbiBieXRlcyAqLworCXUzMiBpcmFtX3NpemU7 IC8qIHNpemUgb2YgaXJhbSAqLworCXUzMiBkcmFtX3NpemU7IC8qIHNpemUgb2YgZHJhbSAqLwor fTsKKworc3RydWN0IGNkbl9kcF9wb3J0IHsKKwlzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHA7CisJ c3RydWN0IG5vdGlmaWVyX2Jsb2NrIGV2ZW50X25iOworCXN0cnVjdCBleHRjb25fZGV2ICpleHRj b247CisJc3RydWN0IHBoeSAqcGh5OworCXU4IGxhbmVzOworCWJvb2wgcGh5X2VuYWJsZWQ7CisJ dTggaWQ7Cit9OworCitzdHJ1Y3QgY2RuX2RwX2RldmljZSB7CisJc3RydWN0IGRldmljZSAqZGV2 OworCXN0cnVjdCBkcm1fZGV2aWNlICpkcm1fZGV2OworCXN0cnVjdCBkcm1fY29ubmVjdG9yIGNv bm5lY3RvcjsKKwlzdHJ1Y3QgZHJtX2VuY29kZXIgZW5jb2RlcjsKKwlzdHJ1Y3QgZHJtX2Rpc3Bs YXlfbW9kZSBtb2RlOworCXN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKmF1ZGlvX3BkZXY7CisJc3Ry dWN0IHdvcmtfc3RydWN0IGV2ZW50X3dvcms7CisKKwlzdHJ1Y3QgbXV0ZXggbG9jazsKKwlib29s IGVuYWJsZWQ7CisJYm9vbCBhY3RpdmU7CisKKwljb25zdCBzdHJ1Y3QgZmlybXdhcmUgKmZ3Owkv KiBjZG4gZHAgZmlybXdhcmUgKi8KKwl1bnNpZ25lZCBpbnQgZndfdmVyc2lvbjsJLyogY2RuIGZ3 IHZlcnNpb24gKi8KKwlib29sIGZ3X2xvYWRlZDsKKworCXZvaWQgX19pb21lbSAqcmVnczsKKwlz dHJ1Y3QgcmVnbWFwICpncmY7CisJc3RydWN0IGNsayAqY29yZV9jbGs7CisJc3RydWN0IGNsayAq cGNsazsKKwlzdHJ1Y3QgY2xrICpzcGRpZl9jbGs7CisJc3RydWN0IGNsayAqZ3JmX2NsazsKKwlz dHJ1Y3QgcmVzZXRfY29udHJvbCAqc3BkaWZfcnN0OworCXN0cnVjdCByZXNldF9jb250cm9sICpk cHR4X3JzdDsKKwlzdHJ1Y3QgcmVzZXRfY29udHJvbCAqYXBiX3JzdDsKKwlzdHJ1Y3QgYXVkaW9f aW5mbyBhdWRpb19pbmZvOworCXN0cnVjdCB2aWRlb19pbmZvIHZpZGVvX2luZm87CisJc3RydWN0 IGRybV9kcF9saW5rIGxpbms7CisJc3RydWN0IGNkbl9kcF9wb3J0ICpwb3J0W01BWF9QSFldOwor CXU4IHBvcnRzOworCisJdTggZHBjZFtEUF9SRUNFSVZFUl9DQVBfU0laRV07CisJYm9vbCBzaW5r X2hhc19hdWRpbzsKKwlib29sIG5vX3Npbms7Cit9OworI2VuZGlmICAvKiBfQ0ROX0RQX0NPUkVf SCAqLwpkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL2Nkbi1kcC1yZWcuYyBi L2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9jZG4tZHAtcmVnLmMKbmV3IGZpbGUgbW9kZSAxMDA2 NDQKaW5kZXggMDAwMDAwMC4uOGQ3ZDFjOQotLS0gL2Rldi9udWxsCisrKyBiL2RyaXZlcnMvZ3B1 L2RybS9yb2NrY2hpcC9jZG4tZHAtcmVnLmMKQEAgLTAsMCArMSw5NTYgQEAKKy8qCisgKiBDb3B5 cmlnaHQgKEMpIEZ1emhvdSBSb2NrY2hpcCBFbGVjdHJvbmljcyBDby5MdGQKKyAqIEF1dGhvcjog Q2hyaXMgWmhvbmcgPHp5d0Byb2NrLWNoaXBzLmNvbT4KKyAqCisgKiBUaGlzIHNvZnR3YXJlIGlz IGxpY2Vuc2VkIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljCisgKiBM aWNlbnNlIHZlcnNpb24gMiwgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5k YXRpb24sIGFuZAorICogbWF5IGJlIGNvcGllZCwgZGlzdHJpYnV0ZWQsIGFuZCBtb2RpZmllZCB1 bmRlciB0aG9zZSB0ZXJtcy4KKyAqCisgKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4g dGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwKKyAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJS QU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mCisgKiBNRVJDSEFOVEFC SUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlCisgKiBH TlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLgorICovCisKKyNpbmNs dWRlIDxsaW51eC9jbGsuaD4KKyNpbmNsdWRlIDxsaW51eC9kZXZpY2UuaD4KKyNpbmNsdWRlIDxs aW51eC9kZWxheS5oPgorI2luY2x1ZGUgPGxpbnV4L2lvLmg+CisjaW5jbHVkZSA8bGludXgvaW9w b2xsLmg+CisjaW5jbHVkZSA8bGludXgvcmVzZXQuaD4KKworI2luY2x1ZGUgImNkbi1kcC1jb3Jl LmgiCisjaW5jbHVkZSAiY2RuLWRwLXJlZy5oIgorCisjZGVmaW5lIENETl9EUF9TUERJRl9DTEsJ CTIwMDAwMDAwMAorI2RlZmluZSBGV19BTElWRV9USU1FT1VUX1VTCQkxMDAwMDAwCisjZGVmaW5l IE1BSUxCT1hfUkVUUllfVVMJCTEwMDAKKyNkZWZpbmUgTUFJTEJPWF9USU1FT1VUX1VTCQk1MDAw MDAwCisjZGVmaW5lIExJTktfVFJBSU5JTkdfUkVUUllfTVMJCTIwCisjZGVmaW5lIExJTktfVFJB SU5JTkdfVElNRU9VVF9NUwk1MDAKKwordm9pZCBjZG5fZHBfc2V0X2Z3X2NsayhzdHJ1Y3QgY2Ru X2RwX2RldmljZSAqZHAsIHUzMiBjbGspCit7CisJd3JpdGVsKGNsayAvIDEwMDAwMDAsIGRwLT5y ZWdzICsgU1dfQ0xLX0gpOworfQorCit2b2lkIGNkbl9kcF9jbG9ja19yZXNldChzdHJ1Y3QgY2Ru X2RwX2RldmljZSAqZHApCit7CisJdTMyIHZhbDsKKworCXZhbCA9IERQVFhfRlJNUl9EQVRBX0NM S19SU1ROX0VOIHwKKwkgICAgICBEUFRYX0ZSTVJfREFUQV9DTEtfRU4gfAorCSAgICAgIERQVFhf UEhZX0RBVEFfUlNUTl9FTiB8CisJICAgICAgRFBUWF9QSFlfREFUQV9DTEtfRU4gfAorCSAgICAg IERQVFhfUEhZX0NIQVJfUlNUTl9FTiB8CisJICAgICAgRFBUWF9QSFlfQ0hBUl9DTEtfRU4gfAor CSAgICAgIFNPVVJDRV9BVVhfU1lTX0NMS19SU1ROX0VOIHwKKwkgICAgICBTT1VSQ0VfQVVYX1NZ U19DTEtfRU4gfAorCSAgICAgIERQVFhfU1lTX0NMS19SU1ROX0VOIHwKKwkgICAgICBEUFRYX1NZ U19DTEtfRU4gfAorCSAgICAgIENGR19EUFRYX1ZJRl9DTEtfUlNUTl9FTiB8CisJICAgICAgQ0ZH X0RQVFhfVklGX0NMS19FTjsKKwl3cml0ZWwodmFsLCBkcC0+cmVncyArIFNPVVJDRV9EUFRYX0NB Uik7CisKKwl2YWwgPSBTT1VSQ0VfUEhZX1JTVE5fRU4gfCBTT1VSQ0VfUEhZX0NMS19FTjsKKwl3 cml0ZWwodmFsLCBkcC0+cmVncyArIFNPVVJDRV9QSFlfQ0FSKTsKKworCXZhbCA9IFNPVVJDRV9Q S1RfU1lTX1JTVE5fRU4gfAorCSAgICAgIFNPVVJDRV9QS1RfU1lTX0NMS19FTiB8CisJICAgICAg U09VUkNFX1BLVF9EQVRBX1JTVE5fRU4gfAorCSAgICAgIFNPVVJDRV9QS1RfREFUQV9DTEtfRU47 CisJd3JpdGVsKHZhbCwgZHAtPnJlZ3MgKyBTT1VSQ0VfUEtUX0NBUik7CisKKwl2YWwgPSBTUERJ Rl9DRFJfQ0xLX1JTVE5fRU4gfAorCSAgICAgIFNQRElGX0NEUl9DTEtfRU4gfAorCSAgICAgIFNP VVJDRV9BSUZfU1lTX1JTVE5fRU4gfAorCSAgICAgIFNPVVJDRV9BSUZfU1lTX0NMS19FTiB8CisJ ICAgICAgU09VUkNFX0FJRl9DTEtfUlNUTl9FTiB8CisJICAgICAgU09VUkNFX0FJRl9DTEtfRU47 CisJd3JpdGVsKHZhbCwgZHAtPnJlZ3MgKyBTT1VSQ0VfQUlGX0NBUik7CisKKwl2YWwgPSBTT1VS Q0VfQ0lQSEVSX1NZU1RFTV9DTEtfUlNUTl9FTiB8CisJICAgICAgU09VUkNFX0NJUEhFUl9TWVNf Q0xLX0VOIHwKKwkgICAgICBTT1VSQ0VfQ0lQSEVSX0NIQVJfQ0xLX1JTVE5fRU4gfAorCSAgICAg IFNPVVJDRV9DSVBIRVJfQ0hBUl9DTEtfRU47CisJd3JpdGVsKHZhbCwgZHAtPnJlZ3MgKyBTT1VS Q0VfQ0lQSEVSX0NBUik7CisKKwl2YWwgPSBTT1VSQ0VfQ1JZUFRPX1NZU19DTEtfUlNUTl9FTiB8 CisJICAgICAgU09VUkNFX0NSWVBUT19TWVNfQ0xLX0VOOworCXdyaXRlbCh2YWwsIGRwLT5yZWdz ICsgU09VUkNFX0NSWVBUT19DQVIpOworCisJdmFsID0gfihNQUlMQk9YX0lOVF9NQVNLX0JJVCB8 IFBJRl9JTlRfTUFTS19CSVQpICYgQUxMX0lOVF9NQVNLOworCXdyaXRlbCh2YWwsIGRwLT5yZWdz ICsgQVBCX0lOVF9NQVNLKTsKK30KKworc3RhdGljIGludCBjZG5fZHBfbWFpbGJveF9yZWFkKHN0 cnVjdCBjZG5fZHBfZGV2aWNlICpkcCwgYm9vbCBmb3JjZSkKK3sKKwlpbnQgdmFsLCByZXQ7CisK KwlyZXQgPSByZWFkeF9wb2xsX3RpbWVvdXQocmVhZGwsIGRwLT5yZWdzICsgTUFJTEJPWF9FTVBU WV9BRERSLAorCQkJCSB2YWwsICF2YWwsIE1BSUxCT1hfUkVUUllfVVMsCisJCQkJIE1BSUxCT1hf VElNRU9VVF9VUyk7CisJaWYgKHJldCA8IDApCisJCXJldHVybiByZXQ7CisKKwlyZXR1cm4gcmVh ZGwoZHAtPnJlZ3MgKyBNQUlMQk9YMF9SRF9EQVRBKSAmIDB4ZmY7Cit9CisKK3N0YXRpYyBpbnQg Y2RwX2RwX21haWxib3hfd3JpdGUoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLCB1OCB2YWwsIGJv b2wgZm9yY2UpCit7CisJaW50IHJldCwgZnVsbDsKKworCXJldCA9IHJlYWR4X3BvbGxfdGltZW91 dChyZWFkbCwgZHAtPnJlZ3MgKyBNQUlMQk9YX0ZVTExfQUREUiwKKwkJCQkgZnVsbCwgIWZ1bGws IE1BSUxCT1hfUkVUUllfVVMsCisJCQkJIE1BSUxCT1hfVElNRU9VVF9VUyk7CisJaWYgKHJldCA8 IDApCisJCXJldHVybiByZXQ7CisKKwl3cml0ZWwodmFsLCBkcC0+cmVncyArIE1BSUxCT1gwX1dS X0RBVEEpOworCisJcmV0dXJuIDA7Cit9CisKK3N0YXRpYyBpbnQgY2RuX2RwX21haWxib3hfdmFs aWRhdGVfcmVjZWl2ZShzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAsCisJCQkJCSAgIHU4IG1vZHVs ZV9pZCwgdTggb3Bjb2RlLAorCQkJCQkgICB1OCByZXFfc2l6ZSkKK3sKKwl1MzIgbWJveF9zaXpl LCBpOworCXU4IGhlYWRlcls0XTsKKwlpbnQgcmV0OworCisJLyogcmVhZCB0aGUgaGVhZGVyIG9m IHRoZSBtZXNzYWdlICovCisJZm9yIChpID0gMDsgaSA8IDQ7IGkrKykgeworCQlyZXQgPSBjZG5f ZHBfbWFpbGJveF9yZWFkKGRwLCAwKTsKKwkJaWYgKHJldCA8IDApCisJCQlyZXR1cm4gcmV0Owor CisJCWhlYWRlcltpXSA9IHJldDsKKwl9CisKKwltYm94X3NpemUgPSAoaGVhZGVyWzJdIDw8IDgp IHwgaGVhZGVyWzNdOworCisJaWYgKG9wY29kZSAhPSBoZWFkZXJbMF0gfHwgbW9kdWxlX2lkICE9 IGhlYWRlclsxXSB8fAorCSAgICByZXFfc2l6ZSAhPSBtYm94X3NpemUpIHsKKwkJLyoKKwkJICog SWYgdGhlIG1lc3NhZ2UgaW4gbWFpbGJveCBpcyBub3Qgd2hhdCB3ZSB3YW50LCB3ZSBuZWVkIHRv CisJCSAqIGNsZWFyIHRoZSBtYWlsYm94IGJ5IHJlYWRpbmcgaXRzIGNvbnRlbnRzLgorCQkgKi8K KwkJZm9yIChpID0gMDsgaSA8IG1ib3hfc2l6ZTsgaSsrKQorCQkJaWYgKGNkbl9kcF9tYWlsYm94 X3JlYWQoZHAsIDApIDwgMCkKKwkJCQlicmVhazsKKworCQlyZXR1cm4gLUVJTlZBTDsKKwl9CisK KwlyZXR1cm4gMDsKK30KKworc3RhdGljIGludCBjZG5fZHBfbWFpbGJveF9yZWFkX3JlY2VpdmUo c3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLAorCQkJCSAgICAgICB1OCAqYnVmZiwgdTggYnVmZl9z aXplKQoreworCXUzMiBpOworCWludCByZXQ7CisKKwlmb3IgKGkgPSAwOyBpIDwgYnVmZl9zaXpl OyBpKyspIHsKKwkJcmV0ID0gY2RuX2RwX21haWxib3hfcmVhZChkcCwgMCk7CisJCWlmIChyZXQg PCAwKQorCQkJcmV0dXJuIHJldDsKKworCQlidWZmW2ldID0gcmV0OworCX0KKworCXJldHVybiAw OworfQorCitzdGF0aWMgaW50IGNkbl9kcF9tYWlsYm94X3NlbmQoc3RydWN0IGNkbl9kcF9kZXZp Y2UgKmRwLCB1OCBtb2R1bGVfaWQsCisJCQkgICAgICAgdTggb3Bjb2RlLCB1MTYgc2l6ZSwgdTgg Km1lc3NhZ2UpCit7CisJdTggaGVhZGVyWzRdOworCWludCByZXQsIGk7CisKKwloZWFkZXJbMF0g PSBvcGNvZGU7CisJaGVhZGVyWzFdID0gbW9kdWxlX2lkOworCWhlYWRlclsyXSA9IChzaXplID4+ IDgpICYgMHhmZjsKKwloZWFkZXJbM10gPSBzaXplICYgMHhmZjsKKworCWZvciAoaSA9IDA7IGkg PCA0OyBpKyspIHsKKwkJcmV0ID0gY2RwX2RwX21haWxib3hfd3JpdGUoZHAsIGhlYWRlcltpXSwg MCk7CisJCWlmIChyZXQpCisJCQlyZXR1cm4gcmV0OworCX0KKworCWZvciAoaSA9IDA7IGkgPCBz aXplOyBpKyspIHsKKwkJcmV0ID0gY2RwX2RwX21haWxib3hfd3JpdGUoZHAsIG1lc3NhZ2VbaV0s IDApOworCQlpZiAocmV0KQorCQkJcmV0dXJuIHJldDsKKwl9CisKKwlyZXR1cm4gMDsKK30KKwor c3RhdGljIGludCBjZG5fZHBfcmVnX3dyaXRlKHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCwgdTE2 IGFkZHIsIHUzMiB2YWwpCit7CisJdTggbXNnWzZdOworCisJbXNnWzBdID0gKGFkZHIgPj4gOCkg JiAweGZmOworCW1zZ1sxXSA9IGFkZHIgJiAweGZmOworCW1zZ1syXSA9ICh2YWwgPj4gMjQpICYg MHhmZjsKKwltc2dbM10gPSAodmFsID4+IDE2KSAmIDB4ZmY7CisJbXNnWzRdID0gKHZhbCA+PiA4 KSAmIDB4ZmY7CisJbXNnWzVdID0gdmFsICYgMHhmZjsKKwlyZXR1cm4gY2RuX2RwX21haWxib3hf c2VuZChkcCwgTUJfTU9EVUxFX0lEX0RQX1RYLCBEUFRYX1dSSVRFX1JFR0lTVEVSLAorCQkJCSAg IHNpemVvZihtc2cpLCBtc2cpOworfQorCitzdGF0aWMgaW50IGNkbl9kcF9yZWdfd3JpdGVfYml0 KHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCwgdTE2IGFkZHIsCisJCQkJdTggc3RhcnRfYml0LCB1 OCBiaXRzX25vLCB1MzIgdmFsKQoreworCXU4IGZpZWxkWzhdOworCisJZmllbGRbMF0gPSAoYWRk ciA+PiA4KSAmIDB4ZmY7CisJZmllbGRbMV0gPSBhZGRyICYgMHhmZjsKKwlmaWVsZFsyXSA9IHN0 YXJ0X2JpdDsKKwlmaWVsZFszXSA9IGJpdHNfbm87CisJZmllbGRbNF0gPSAodmFsID4+IDI0KSAm IDB4ZmY7CisJZmllbGRbNV0gPSAodmFsID4+IDE2KSAmIDB4ZmY7CisJZmllbGRbNl0gPSAodmFs ID4+IDgpICYgMHhmZjsKKwlmaWVsZFs3XSA9IHZhbCAmIDB4ZmY7CisKKwlyZXR1cm4gY2RuX2Rw X21haWxib3hfc2VuZChkcCwgTUJfTU9EVUxFX0lEX0RQX1RYLCBEUFRYX1dSSVRFX0ZJRUxELAor CQkJCSAgIHNpemVvZihmaWVsZCksIGZpZWxkKTsKK30KKworaW50IGNkbl9kcF9kcGNkX3JlYWQo c3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLCB1MzIgYWRkciwgdTggKmRhdGEsIHUxNiBsZW4pCit7 CisJdTggbXNnWzVdLCByZWdbNV07CisJaW50IHJldDsKKworCW1zZ1swXSA9IChsZW4gPj4gOCkg JiAweGZmOworCW1zZ1sxXSA9IGxlbiAmIDB4ZmY7CisJbXNnWzJdID0gKGFkZHIgPj4gMTYpICYg MHhmZjsKKwltc2dbM10gPSAoYWRkciA+PiA4KSAmIDB4ZmY7CisJbXNnWzRdID0gYWRkciAmIDB4 ZmY7CisJcmV0ID0gY2RuX2RwX21haWxib3hfc2VuZChkcCwgTUJfTU9EVUxFX0lEX0RQX1RYLCBE UFRYX1JFQURfRFBDRCwKKwkJCQkgIHNpemVvZihtc2cpLCBtc2cpOworCWlmIChyZXQpCisJCWdv dG8gZXJyX2RwY2RfcmVhZDsKKworCXJldCA9IGNkbl9kcF9tYWlsYm94X3ZhbGlkYXRlX3JlY2Vp dmUoZHAsIE1CX01PRFVMRV9JRF9EUF9UWCwKKwkJCQkJICAgICAgRFBUWF9SRUFEX0RQQ0QsCisJ CQkJCSAgICAgIHNpemVvZihyZWcpICsgbGVuKTsKKwlpZiAocmV0KQorCQlnb3RvIGVycl9kcGNk X3JlYWQ7CisKKwlyZXQgPSBjZG5fZHBfbWFpbGJveF9yZWFkX3JlY2VpdmUoZHAsIHJlZywgc2l6 ZW9mKHJlZykpOworCWlmIChyZXQpCisJCWdvdG8gZXJyX2RwY2RfcmVhZDsKKworCXJldCA9IGNk bl9kcF9tYWlsYm94X3JlYWRfcmVjZWl2ZShkcCwgZGF0YSwgbGVuKTsKKworZXJyX2RwY2RfcmVh ZDoKKwlyZXR1cm4gcmV0OworfQorCitpbnQgY2RuX2RwX2RwY2Rfd3JpdGUoc3RydWN0IGNkbl9k cF9kZXZpY2UgKmRwLCB1MzIgYWRkciwgdTggdmFsdWUpCit7CisJdTggbXNnWzZdLCByZWdbNV07 CisJaW50IHJldDsKKworCW1zZ1swXSA9IDA7CisJbXNnWzFdID0gMTsKKwltc2dbMl0gPSAoYWRk ciA+PiAxNikgJiAweGZmOworCW1zZ1szXSA9IChhZGRyID4+IDgpICYgMHhmZjsKKwltc2dbNF0g PSBhZGRyICYgMHhmZjsKKwltc2dbNV0gPSB2YWx1ZTsKKwlyZXQgPSBjZG5fZHBfbWFpbGJveF9z ZW5kKGRwLCBNQl9NT0RVTEVfSURfRFBfVFgsIERQVFhfV1JJVEVfRFBDRCwKKwkJCQkgIHNpemVv Zihtc2cpLCBtc2cpOworCWlmIChyZXQpCisJCWdvdG8gZXJyX2RwY2Rfd3JpdGU7CisKKwlyZXQg PSBjZG5fZHBfbWFpbGJveF92YWxpZGF0ZV9yZWNlaXZlKGRwLCBNQl9NT0RVTEVfSURfRFBfVFgs CisJCQkJCSAgICAgIERQVFhfV1JJVEVfRFBDRCwgc2l6ZW9mKHJlZykpOworCWlmIChyZXQpCisJ CWdvdG8gZXJyX2RwY2Rfd3JpdGU7CisKKwlyZXQgPSBjZG5fZHBfbWFpbGJveF9yZWFkX3JlY2Vp dmUoZHAsIHJlZywgc2l6ZW9mKHJlZykpOworCWlmIChyZXQpCisJCWdvdG8gZXJyX2RwY2Rfd3Jp dGU7CisKKwlpZiAoYWRkciAhPSAocmVnWzJdIDw8IDE2IHwgcmVnWzNdIDw8IDggfCByZWdbNF0p KQorCQlyZXQgPSAtRUlOVkFMOworCitlcnJfZHBjZF93cml0ZToKKwlpZiAocmV0KQorCQlEUk1f REVWX0VSUk9SKGRwLT5kZXYsICJkcGNkIHdyaXRlIGZhaWxlZDogJWRcbiIsIHJldCk7CisJcmV0 dXJuIHJldDsKK30KKworaW50IGNkbl9kcF9sb2FkX2Zpcm13YXJlKHN0cnVjdCBjZG5fZHBfZGV2 aWNlICpkcCwgY29uc3QgdTMyICppX21lbSwKKwkJCSB1MzIgaV9zaXplLCBjb25zdCB1MzIgKmRf bWVtLCB1MzIgZF9zaXplKQoreworCXUzMiByZWc7CisJaW50IGksIHJldDsKKworCS8qIHJlc2V0 IHVjcHUgYmVmb3JlIGxvYWQgZmlybXdhcmUqLworCXdyaXRlbChBUEJfSVJBTV9QQVRIIHwgQVBC X0RSQU1fUEFUSCB8IEFQQl9YVF9SRVNFVCwKKwkgICAgICAgZHAtPnJlZ3MgKyBBUEJfQ1RSTCk7 CisKKwlmb3IgKGkgPSAwOyBpIDwgaV9zaXplOyBpICs9IDQpCisJCXdyaXRlbCgqaV9tZW0rKywg ZHAtPnJlZ3MgKyBBRERSX0lNRU0gKyBpKTsKKworCWZvciAoaSA9IDA7IGkgPCBkX3NpemU7IGkg Kz0gNCkKKwkJd3JpdGVsKCpkX21lbSsrLCBkcC0+cmVncyArIEFERFJfRE1FTSArIGkpOworCisJ LyogdW4tcmVzZXQgdWNwdSAqLworCXdyaXRlbCgwLCBkcC0+cmVncyArIEFQQl9DVFJMKTsKKwor CS8qIGNoZWNrIHRoZSBrZWVwIGFsaXZlIHJlZ2lzdGVyIHRvIG1ha2Ugc3VyZSBmdyB3b3JraW5n ICovCisJcmV0ID0gcmVhZHhfcG9sbF90aW1lb3V0KHJlYWRsLCBkcC0+cmVncyArIEtFRVBfQUxJ VkUsCisJCQkJIHJlZywgcmVnLCAyMDAwLCBGV19BTElWRV9USU1FT1VUX1VTKTsKKwlpZiAocmV0 IDwgMCkgeworCQlEUk1fREVWX0VSUk9SKGRwLT5kZXYsICJmYWlsZWQgdG8gbG9hZGVkIHRoZSBG VyByZWcgPSAleFxuIiwKKwkJCSAgICAgIHJlZyk7CisJCXJldHVybiAtRUlOVkFMOworCX0KKwor CXJlZyA9IHJlYWRsKGRwLT5yZWdzICsgVkVSX0wpICYgMHhmZjsKKwlkcC0+ZndfdmVyc2lvbiA9 IHJlZzsKKwlyZWcgPSByZWFkbChkcC0+cmVncyArIFZFUl9IKSAmIDB4ZmY7CisJZHAtPmZ3X3Zl cnNpb24gfD0gcmVnIDw8IDg7CisJcmVnID0gcmVhZGwoZHAtPnJlZ3MgKyBWRVJfTElCX0xfQURE UikgJiAweGZmOworCWRwLT5md192ZXJzaW9uIHw9IHJlZyA8PCAxNjsKKwlyZWcgPSByZWFkbChk cC0+cmVncyArIFZFUl9MSUJfSF9BRERSKSAmIDB4ZmY7CisJZHAtPmZ3X3ZlcnNpb24gfD0gcmVn IDw8IDI0OworCisJZGV2X2RiZyhkcC0+ZGV2LCAiZmlybXdhcmUgdmVyc2lvbjogJXhcbiIsIGRw LT5md192ZXJzaW9uKTsKKworCXJldHVybiAwOworfQorCitpbnQgY2RuX2RwX3NldF9maXJtd2Fy ZV9hY3RpdmUoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLCBib29sIGVuYWJsZSkKK3sKKwl1OCBt c2dbNV07CisJaW50IHJldCwgaTsKKworCW1zZ1swXSA9IEdFTkVSQUxfTUFJTl9DT05UUk9MOwor CW1zZ1sxXSA9IE1CX01PRFVMRV9JRF9HRU5FUkFMOworCW1zZ1syXSA9IDA7CisJbXNnWzNdID0g MTsKKwltc2dbNF0gPSBlbmFibGUgPyBGV19BQ1RJVkUgOiBGV19TVEFOREJZOworCisJZm9yIChp ID0gMDsgaSA8IHNpemVvZihtc2cpOyBpKyspIHsKKwkJcmV0ID0gY2RwX2RwX21haWxib3hfd3Jp dGUoZHAsIG1zZ1tpXSwgMSk7CisJCWlmIChyZXQpCisJCQlnb3RvIGVycl9zZXRfZmlybXdhcmVf YWN0aXZlOworCX0KKworCS8qIHJlYWQgdGhlIGZpcm13YXJlIHN0YXRlICovCisJZm9yIChpID0g MDsgaSA8IHNpemVvZihtc2cpOyBpKyspICB7CisJCXJldCA9IGNkbl9kcF9tYWlsYm94X3JlYWQo ZHAsIDEpOworCQlpZiAocmV0IDwgMCkKKwkJCWdvdG8gZXJyX3NldF9maXJtd2FyZV9hY3RpdmU7 CisKKwkJbXNnW2ldID0gcmV0OworCX0KKworCXJldCA9IDA7CisKK2Vycl9zZXRfZmlybXdhcmVf YWN0aXZlOgorCWlmIChyZXQgPCAwKQorCQlEUk1fREVWX0VSUk9SKGRwLT5kZXYsICJzZXQgZmly bXdhcmUgYWN0aXZlIGZhaWxlZFxuIik7CisJcmV0dXJuIHJldDsKK30KKworaW50IGNkbl9kcF9z ZXRfaG9zdF9jYXAoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLCB1OCBsYW5lcywgYm9vbCBmbGlw KQoreworCXU4IG1zZ1s4XTsKKwlpbnQgcmV0OworCisJbXNnWzBdID0gQ0ROX0RQX01BWF9MSU5L X1JBVEU7CisJbXNnWzFdID0gbGFuZXM7CisJbXNnWzJdID0gVk9MVEFHRV9MRVZFTF8yOworCW1z Z1szXSA9IFBSRV9FTVBIQVNJU19MRVZFTF8zOworCW1zZ1s0XSA9IFBUUzEgfCBQVFMyIHwgUFRT MyB8IFBUUzQ7CisJbXNnWzVdID0gRkFTVF9MVF9OT1RfU1VQUE9SVDsKKwltc2dbNl0gPSBmbGlw ID8gTEFORV9NQVBQSU5HX0ZMSVBQRUQgOiBMQU5FX01BUFBJTkdfTk9STUFMOworCW1zZ1s3XSA9 IEVOSEFOQ0VEOworCisJcmV0ID0gY2RuX2RwX21haWxib3hfc2VuZChkcCwgTUJfTU9EVUxFX0lE X0RQX1RYLAorCQkJCSAgRFBUWF9TRVRfSE9TVF9DQVBBQklMSVRJRVMsCisJCQkJICBzaXplb2Yo bXNnKSwgbXNnKTsKKwlpZiAocmV0KQorCQlnb3RvIGVycl9zZXRfaG9zdF9jYXA7CisKKwlyZXQg PSBjZG5fZHBfcmVnX3dyaXRlKGRwLCBEUF9BVVhfU1dBUF9JTlZFUlNJT05fQ09OVFJPTCwKKwkJ CSAgICAgICBBVVhfSE9TVF9JTlZFUlQpOworCitlcnJfc2V0X2hvc3RfY2FwOgorCWlmIChyZXQp CisJCURSTV9ERVZfRVJST1IoZHAtPmRldiwgInNldCBob3N0IGNhcCBmYWlsZWQ6ICVkXG4iLCBy ZXQpOworCXJldHVybiByZXQ7Cit9CisKK2ludCBjZG5fZHBfZXZlbnRfY29uZmlnKHN0cnVjdCBj ZG5fZHBfZGV2aWNlICpkcCkKK3sKKwl1OCBtc2dbNV07CisJaW50IHJldDsKKworCW1lbXNldCht c2csIDAsIHNpemVvZihtc2cpKTsKKworCW1zZ1swXSA9IERQVFhfRVZFTlRfRU5BQkxFX0hQRCB8 IERQVFhfRVZFTlRfRU5BQkxFX1RSQUlOSU5HOworCisJcmV0ID0gY2RuX2RwX21haWxib3hfc2Vu ZChkcCwgTUJfTU9EVUxFX0lEX0RQX1RYLCBEUFRYX0VOQUJMRV9FVkVOVCwKKwkJCQkgIHNpemVv Zihtc2cpLCBtc2cpOworCWlmIChyZXQpCisJCURSTV9ERVZfRVJST1IoZHAtPmRldiwgInNldCBl dmVudCBjb25maWcgZmFpbGVkOiAlZFxuIiwgcmV0KTsKKworCXJldHVybiByZXQ7Cit9CisKK3Uz MiBjZG5fZHBfZ2V0X2V2ZW50KHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCkKK3sKKwlyZXR1cm4g cmVhZGwoZHAtPnJlZ3MgKyBTV19FVkVOVFMwKTsKK30KKworaW50IGNkbl9kcF9nZXRfaHBkX3N0 YXR1cyhzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHApCit7CisJdTggc3RhdHVzOworCWludCByZXQ7 CisKKwlyZXQgPSBjZG5fZHBfbWFpbGJveF9zZW5kKGRwLCBNQl9NT0RVTEVfSURfRFBfVFgsIERQ VFhfSFBEX1NUQVRFLAorCQkJCSAgMCwgTlVMTCk7CisJaWYgKHJldCkKKwkJZ290byBlcnJfZ2V0 X2hwZDsKKworCXJldCA9IGNkbl9kcF9tYWlsYm94X3ZhbGlkYXRlX3JlY2VpdmUoZHAsIE1CX01P RFVMRV9JRF9EUF9UWCwKKwkJCQkJICAgICAgRFBUWF9IUERfU1RBVEUsIHNpemVvZihzdGF0dXMp KTsKKwlpZiAocmV0KQorCQlnb3RvIGVycl9nZXRfaHBkOworCisJcmV0ID0gY2RuX2RwX21haWxi b3hfcmVhZF9yZWNlaXZlKGRwLCAmc3RhdHVzLCBzaXplb2Yoc3RhdHVzKSk7CisJaWYgKHJldCkK KwkJZ290byBlcnJfZ2V0X2hwZDsKKworCXJldHVybiBzdGF0dXM7CisKK2Vycl9nZXRfaHBkOgor CURSTV9ERVZfRVJST1IoZHAtPmRldiwgImdldCBocGQgc3RhdHVzIGZhaWxlZDogJWRcbiIsIHJl dCk7CisJcmV0dXJuIHJldDsKK30KKworaW50IGNkbl9kcF9nZXRfZWRpZF9ibG9jayh2b2lkICpk YXRhLCB1OCAqZWRpZCwKKwkJCSAgdW5zaWduZWQgaW50IGJsb2NrLCBzaXplX3QgbGVuZ3RoKQor eworCXN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCA9IGRhdGE7CisJdTggbXNnWzJdLCByZWdbMl0s IGk7CisJaW50IHJldDsKKworCWZvciAoaSA9IDA7IGkgPCA0OyBpKyspIHsKKwkJbXNnWzBdID0g YmxvY2sgLyAyOworCQltc2dbMV0gPSBibG9jayAlIDI7CisKKwkJcmV0ID0gY2RuX2RwX21haWxi b3hfc2VuZChkcCwgTUJfTU9EVUxFX0lEX0RQX1RYLCBEUFRYX0dFVF9FRElELAorCQkJCQkgIHNp emVvZihtc2cpLCBtc2cpOworCQlpZiAocmV0KQorCQkJY29udGludWU7CisKKwkJcmV0ID0gY2Ru X2RwX21haWxib3hfdmFsaWRhdGVfcmVjZWl2ZShkcCwgTUJfTU9EVUxFX0lEX0RQX1RYLAorCQkJ CQkJICAgICAgRFBUWF9HRVRfRURJRCwKKwkJCQkJCSAgICAgIHNpemVvZihyZWcpICsgbGVuZ3Ro KTsKKwkJaWYgKHJldCkKKwkJCWNvbnRpbnVlOworCisJCXJldCA9IGNkbl9kcF9tYWlsYm94X3Jl YWRfcmVjZWl2ZShkcCwgcmVnLCBzaXplb2YocmVnKSk7CisJCWlmIChyZXQpCisJCQljb250aW51 ZTsKKworCQlyZXQgPSBjZG5fZHBfbWFpbGJveF9yZWFkX3JlY2VpdmUoZHAsIGVkaWQsIGxlbmd0 aCk7CisJCWlmIChyZXQpCisJCQljb250aW51ZTsKKworCQlpZiAocmVnWzBdID09IGxlbmd0aCAm JiByZWdbMV0gPT0gYmxvY2sgLyAyKQorCQkJYnJlYWs7CisJfQorCisJaWYgKHJldCkKKwkJRFJN X0RFVl9FUlJPUihkcC0+ZGV2LCAiZ2V0IGJsb2NrWyVkXSBlZGlkIGZhaWxlZDogJWRcbiIsIGJs b2NrLAorCQkJICAgICAgcmV0KTsKKworCXJldHVybiByZXQ7Cit9CisKK2ludCBjZG5fZHBfdHJh aW5pbmdfc3RhcnQoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwKQoreworCXVuc2lnbmVkIGxvbmcg dGltZW91dDsKKwl1OCBtc2csIGV2ZW50WzJdOworCWludCByZXQ7CisKKwltc2cgPSBMSU5LX1RS QUlOSU5HX1JVTjsKKworCS8qIHN0YXJ0IHRyYWluaW5nICovCisJcmV0ID0gY2RuX2RwX21haWxi b3hfc2VuZChkcCwgTUJfTU9EVUxFX0lEX0RQX1RYLCBEUFRYX1RSQUlOSU5HX0NPTlRST0wsCisJ CQkJICBzaXplb2YobXNnKSwgJm1zZyk7CisJaWYgKHJldCkKKwkJZ290byBlcnJfdHJhaW5pbmdf c3RhcnQ7CisKKwl0aW1lb3V0ID0gamlmZmllcyArIG1zZWNzX3RvX2ppZmZpZXMoTElOS19UUkFJ TklOR19USU1FT1VUX01TKTsKKwl3aGlsZSAodGltZV9iZWZvcmUoamlmZmllcywgdGltZW91dCkp IHsKKwkJbXNsZWVwKExJTktfVFJBSU5JTkdfUkVUUllfTVMpOworCQlyZXQgPSBjZG5fZHBfbWFp bGJveF9zZW5kKGRwLCBNQl9NT0RVTEVfSURfRFBfVFgsCisJCQkJCSAgRFBUWF9SRUFEX0VWRU5U LCAwLCBOVUxMKTsKKwkJaWYgKHJldCkKKwkJCWdvdG8gZXJyX3RyYWluaW5nX3N0YXJ0OworCisJ CXJldCA9IGNkbl9kcF9tYWlsYm94X3ZhbGlkYXRlX3JlY2VpdmUoZHAsIE1CX01PRFVMRV9JRF9E UF9UWCwKKwkJCQkJCSAgICAgIERQVFhfUkVBRF9FVkVOVCwKKwkJCQkJCSAgICAgIHNpemVvZihl dmVudCkpOworCQlpZiAocmV0KQorCQkJZ290byBlcnJfdHJhaW5pbmdfc3RhcnQ7CisKKwkJcmV0 ID0gY2RuX2RwX21haWxib3hfcmVhZF9yZWNlaXZlKGRwLCBldmVudCwgc2l6ZW9mKGV2ZW50KSk7 CisJCWlmIChyZXQpCisJCQlnb3RvIGVycl90cmFpbmluZ19zdGFydDsKKworCQlpZiAoZXZlbnRb MV0gJiBFUV9QSEFTRV9GSU5JU0hFRCkKKwkJCXJldHVybiAwOworCX0KKworCXJldCA9IC1FVElN RURPVVQ7CisKK2Vycl90cmFpbmluZ19zdGFydDoKKwlEUk1fREVWX0VSUk9SKGRwLT5kZXYsICJ0 cmFpbmluZyBmYWlsZWQ6ICVkXG4iLCByZXQpOworCXJldHVybiByZXQ7Cit9CisKK2ludCBjZG5f ZHBfZ2V0X3RyYWluaW5nX3N0YXR1cyhzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHApCit7CisJdTgg c3RhdHVzWzEwXTsKKwlpbnQgcmV0OworCisJcmV0ID0gY2RuX2RwX21haWxib3hfc2VuZChkcCwg TUJfTU9EVUxFX0lEX0RQX1RYLCBEUFRYX1JFQURfTElOS19TVEFULAorCQkJCSAgMCwgTlVMTCk7 CisJaWYgKHJldCkKKwkJZ290byBlcnJfZ2V0X3RyYWluaW5nX3N0YXR1czsKKworCXJldCA9IGNk bl9kcF9tYWlsYm94X3ZhbGlkYXRlX3JlY2VpdmUoZHAsIE1CX01PRFVMRV9JRF9EUF9UWCwKKwkJ CQkJICAgICAgRFBUWF9SRUFEX0xJTktfU1RBVCwKKwkJCQkJICAgICAgc2l6ZW9mKHN0YXR1cykp OworCWlmIChyZXQpCisJCWdvdG8gZXJyX2dldF90cmFpbmluZ19zdGF0dXM7CisKKwlyZXQgPSBj ZG5fZHBfbWFpbGJveF9yZWFkX3JlY2VpdmUoZHAsIHN0YXR1cywgc2l6ZW9mKHN0YXR1cykpOwor CWlmIChyZXQpCisJCWdvdG8gZXJyX2dldF90cmFpbmluZ19zdGF0dXM7CisKKwlkcC0+bGluay5y YXRlID0gc3RhdHVzWzBdOworCWRwLT5saW5rLm51bV9sYW5lcyA9IHN0YXR1c1sxXTsKKworZXJy X2dldF90cmFpbmluZ19zdGF0dXM6CisJaWYgKHJldCkKKwkJRFJNX0RFVl9FUlJPUihkcC0+ZGV2 LCAiZ2V0IHRyYWluaW5nIHN0YXR1cyBmYWlsZWQ6ICVkXG4iLCByZXQpOworCXJldHVybiByZXQ7 Cit9CisKK2ludCBjZG5fZHBfc2V0X3ZpZGVvX3N0YXR1cyhzdHJ1Y3QgY2RuX2RwX2RldmljZSAq ZHAsIGludCBhY3RpdmUpCit7CisJdTggbXNnOworCWludCByZXQ7CisKKwltc2cgPSAhIWFjdGl2 ZTsKKworCXJldCA9IGNkbl9kcF9tYWlsYm94X3NlbmQoZHAsIE1CX01PRFVMRV9JRF9EUF9UWCwg RFBUWF9TRVRfVklERU8sCisJCQkJICBzaXplb2YobXNnKSwgJm1zZyk7CisJaWYgKHJldCkKKwkJ RFJNX0RFVl9FUlJPUihkcC0+ZGV2LCAic2V0IHZpZGVvIHN0YXR1cyBmYWlsZWQ6ICVkXG4iLCBy ZXQpOworCisJcmV0dXJuIHJldDsKK30KKworc3RhdGljIGludCBjZG5fZHBfZ2V0X21zYV9taXNj KHN0cnVjdCB2aWRlb19pbmZvICp2aWRlbywKKwkJCSAgICAgICBzdHJ1Y3QgZHJtX2Rpc3BsYXlf bW9kZSAqbW9kZSkKK3sKKwl1MzIgbXNhX21pc2M7CisJdTggdmFsWzJdOworCisJc3dpdGNoICh2 aWRlby0+Y29sb3JfZm10KSB7CisJY2FzZSBQWExfUkdCOgorCWNhc2UgWV9PTkxZOgorCQl2YWxb MF0gPSAwOworCQlicmVhazsKKwkvKiBzZXQgWVVWIGRlZmF1bHQgY29sb3Igc3BhY2UgY29udmVy c2lvbiB0byBCVDYwMSAqLworCWNhc2UgWUNCQ1JfNF80XzQ6CisJCXZhbFswXSA9IDYgKyBCVF82 MDEgKiA4OworCQlicmVhazsKKwljYXNlIFlDQkNSXzRfMl8yOgorCQl2YWxbMF0gPSA1ICsgQlRf NjAxICogODsKKwkJYnJlYWs7CisJY2FzZSBZQ0JDUl80XzJfMDoKKwkJdmFsWzBdID0gNTsKKwkJ YnJlYWs7CisJfTsKKworCXN3aXRjaCAodmlkZW8tPmNvbG9yX2RlcHRoKSB7CisJY2FzZSA2Ogor CQl2YWxbMV0gPSAwOworCQlicmVhazsKKwljYXNlIDg6CisJCXZhbFsxXSA9IDE7CisJCWJyZWFr OworCWNhc2UgMTA6CisJCXZhbFsxXSA9IDI7CisJCWJyZWFrOworCWNhc2UgMTI6CisJCXZhbFsx XSA9IDM7CisJCWJyZWFrOworCWNhc2UgMTY6CisJCXZhbFsxXSA9IDQ7CisJCWJyZWFrOworCX07 CisKKwltc2FfbWlzYyA9IDIgKiB2YWxbMF0gKyAzMiAqIHZhbFsxXSArCisJCSAgICgodmlkZW8t PmNvbG9yX2ZtdCA9PSBZX09OTFkpID8gKDEgPDwgMTQpIDogMCk7CisKKwlyZXR1cm4gbXNhX21p c2M7Cit9CisKK2ludCBjZG5fZHBfY29uZmlnX3ZpZGVvKHN0cnVjdCBjZG5fZHBfZGV2aWNlICpk cCkKK3sKKwlzdHJ1Y3QgdmlkZW9faW5mbyAqdmlkZW8gPSAmZHAtPnZpZGVvX2luZm87CisJc3Ry dWN0IGRybV9kaXNwbGF5X21vZGUgKm1vZGUgPSAmZHAtPm1vZGU7CisJdTY0IHN5bWJvbCwgdG1w OworCXUzMiB2YWwsIGxpbmtfcmF0ZTsKKwl1OCBiaXRfcGVyX3BpeCwgdHVfc2l6ZV9yZWcgPSBU VV9TSVpFOworCWludCByZXQ7CisKKwliaXRfcGVyX3BpeCA9ICh2aWRlby0+Y29sb3JfZm10ID09 IFlDQkNSXzRfMl8yKSA/CisJCSAgICAgICh2aWRlby0+Y29sb3JfZGVwdGggKiAyKSA6ICh2aWRl by0+Y29sb3JfZGVwdGggKiAzKTsKKworCWxpbmtfcmF0ZSA9IGRybV9kcF9id19jb2RlX3RvX2xp bmtfcmF0ZShkcC0+bGluay5yYXRlKSAvIDEwMDA7CisKKwl2YWwgPSBWSUZfQllQQVNTX0lOVEVS TEFDRTsKKwlyZXQgPSBjZG5fZHBfcmVnX3dyaXRlKGRwLCBCTkRfSFNZTkMyVlNZTkMsIHZhbCk7 CisJaWYgKHJldCkKKwkJZ290byBlcnJfY29uZmlnX3ZpZGVvOworCisJcmV0ID0gY2RuX2RwX3Jl Z193cml0ZShkcCwgSFNZTkMyVlNZTkNfUE9MX0NUUkwsIDApOworCWlmIChyZXQpCisJCWdvdG8g ZXJyX2NvbmZpZ192aWRlbzsKKworCS8qCisJICogZ2V0IGEgYmVzdCB0dV9zaXplIGFuZCB2YWxp ZCBzeW1ib2w6CisJICogMS4gY2hvc2UgTGNsayBmcmVxKDE2Mk1oeiwgMjcwTWh6LCA1NDBNaHop LCBzZXQgVFUgdG8gMzIKKwkgKiAyLiBjYWxjdWxhdGUgVlModmFsaWQgc3ltYm9sKSA9IFRVICog UGNsayAqIEJwcCAvIChMY2xrICogTGFuZXMpCisJICogMy4gaWYgVlMgPiAqLjg1IG9yIFZTIDwg Ki4xIG9yIFZTIDwgMiBvciBUVSA8IFZTICsgNCwgdGhlbiBzZXQKKwkgKiAgICBUVSArPSAyIGFu ZCByZXBlYXQgMm5kIHN0ZXAuCisJICovCisJZG8geworCQl0dV9zaXplX3JlZyArPSAyOworCQl0 bXAgPSB0dV9zaXplX3JlZyAqIG1vZGUtPmNsb2NrICogYml0X3Blcl9waXg7CisJCXRtcCAvPSBk cC0+bGluay5udW1fbGFuZXMgKiBsaW5rX3JhdGUgKiA4OworCQlzeW1ib2wgPSB0bXAgLyAxMDAw OworCX0gd2hpbGUgKChzeW1ib2wgPD0gMSkgfHwgKHR1X3NpemVfcmVnIC0gc3ltYm9sIDwgNCkg fHwKKwkJICh0bXAgJSAxMDAwID4gODUwKSB8fCAodG1wICUgMTAwMCA8IDEwMCkpOworCisJdmFs ID0gc3ltYm9sICsgKHR1X3NpemVfcmVnIDw8IDgpOworCXJldCA9IGNkbl9kcF9yZWdfd3JpdGUo ZHAsIERQX0ZSQU1FUl9UVSwgdmFsKTsKKwlpZiAocmV0KQorCQlnb3RvIGVycl9jb25maWdfdmlk ZW87CisKKwkvKiBzZXQgdGhlIEZJRk8gQnVmZmVyIHNpemUgKi8KKwl2YWwgPSAoKG1vZGUtPmNs b2NrICogKHN5bWJvbCArIDEpIC8gMTAwMCkgKyBsaW5rX3JhdGUpOworCXZhbCAvPSAoZHAtPmxp bmsubnVtX2xhbmVzICogbGlua19yYXRlKTsKKwl2YWwgPSA4ICogKHN5bWJvbCArIDEpIC8gYml0 X3Blcl9waXggLSB2YWw7CisJdmFsICs9IDI7CisJcmV0ID0gY2RuX2RwX3JlZ193cml0ZShkcCwg RFBfVkNfVEFCTEUoMTUpLCB2YWwpOworCisJc3dpdGNoICh2aWRlby0+Y29sb3JfZGVwdGgpIHsK KwljYXNlIDY6CisJCXZhbCA9IEJDU182OworCQlicmVhazsKKwljYXNlIDg6CisJCXZhbCA9IEJD U184OworCQlicmVhazsKKwljYXNlIDEwOgorCQl2YWwgPSBCQ1NfMTA7CisJCWJyZWFrOworCWNh c2UgMTI6CisJCXZhbCA9IEJDU18xMjsKKwkJYnJlYWs7CisJY2FzZSAxNjoKKwkJdmFsID0gQkNT XzE2OworCQlicmVhazsKKwl9OworCisJdmFsICs9IHZpZGVvLT5jb2xvcl9mbXQgPDwgODsKKwly ZXQgPSBjZG5fZHBfcmVnX3dyaXRlKGRwLCBEUF9GUkFNRVJfUFhMX1JFUFIsIHZhbCk7CisJaWYg KHJldCkKKwkJZ290byBlcnJfY29uZmlnX3ZpZGVvOworCisJdmFsID0gdmlkZW8tPmhfc3luY19w b2xhcml0eSA/IERQX0ZSQU1FUl9TUF9IU1AgOiAwOworCXZhbCB8PSB2aWRlby0+dl9zeW5jX3Bv bGFyaXR5ID8gRFBfRlJBTUVSX1NQX1ZTUCA6IDA7CisJcmV0ID0gY2RuX2RwX3JlZ193cml0ZShk cCwgRFBfRlJBTUVSX1NQLCB2YWwpOworCWlmIChyZXQpCisJCWdvdG8gZXJyX2NvbmZpZ192aWRl bzsKKworCXZhbCA9IChtb2RlLT5oc3luY19zdGFydCAtIG1vZGUtPmhkaXNwbGF5KSA8PCAxNjsK Kwl2YWwgfD0gbW9kZS0+aHRvdGFsIC0gbW9kZS0+aHN5bmNfZW5kOworCXJldCA9IGNkbl9kcF9y ZWdfd3JpdGUoZHAsIERQX0ZST05UX0JBQ0tfUE9SQ0gsIHZhbCk7CisJaWYgKHJldCkKKwkJZ290 byBlcnJfY29uZmlnX3ZpZGVvOworCisJdmFsID0gbW9kZS0+aGRpc3BsYXkgKiBiaXRfcGVyX3Bp eCAvIDg7CisJcmV0ID0gY2RuX2RwX3JlZ193cml0ZShkcCwgRFBfQllURV9DT1VOVCwgdmFsKTsK KwlpZiAocmV0KQorCQlnb3RvIGVycl9jb25maWdfdmlkZW87CisKKwl2YWwgPSBtb2RlLT5odG90 YWwgfCAoKG1vZGUtPmh0b3RhbCAtIG1vZGUtPmhzeW5jX3N0YXJ0KSA8PCAxNik7CisJcmV0ID0g Y2RuX2RwX3JlZ193cml0ZShkcCwgTVNBX0hPUklaT05UQUxfMCwgdmFsKTsKKwlpZiAocmV0KQor CQlnb3RvIGVycl9jb25maWdfdmlkZW87CisKKwl2YWwgPSBtb2RlLT5oc3luY19lbmQgLSBtb2Rl LT5oc3luY19zdGFydDsKKwl2YWwgfD0gKG1vZGUtPmhkaXNwbGF5IDw8IDE2KSB8ICh2aWRlby0+ aF9zeW5jX3BvbGFyaXR5IDw8IDE1KTsKKwlyZXQgPSBjZG5fZHBfcmVnX3dyaXRlKGRwLCBNU0Ff SE9SSVpPTlRBTF8xLCB2YWwpOworCWlmIChyZXQpCisJCWdvdG8gZXJyX2NvbmZpZ192aWRlbzsK KworCXZhbCA9IG1vZGUtPnZ0b3RhbDsKKwl2YWwgfD0gKChtb2RlLT52dG90YWwgLSBtb2RlLT52 c3luY19zdGFydCkgPDwgMTYpOworCXJldCA9IGNkbl9kcF9yZWdfd3JpdGUoZHAsIE1TQV9WRVJU SUNBTF8wLCB2YWwpOworCWlmIChyZXQpCisJCWdvdG8gZXJyX2NvbmZpZ192aWRlbzsKKworCXZh bCA9IG1vZGUtPnZzeW5jX2VuZCAtIG1vZGUtPnZzeW5jX3N0YXJ0OworCXZhbCB8PSBtb2RlLT52 ZGlzcGxheSA8PCAxNiB8ICh2aWRlby0+dl9zeW5jX3BvbGFyaXR5IDw8IDE1KTsKKwlyZXQgPSBj ZG5fZHBfcmVnX3dyaXRlKGRwLCBNU0FfVkVSVElDQUxfMSwgdmFsKTsKKwlpZiAocmV0KQorCQln b3RvIGVycl9jb25maWdfdmlkZW87CisKKwl2YWwgPSBjZG5fZHBfZ2V0X21zYV9taXNjKHZpZGVv LCBtb2RlKTsKKwlyZXQgPSBjZG5fZHBfcmVnX3dyaXRlKGRwLCBNU0FfTUlTQywgdmFsKTsKKwlp ZiAocmV0KQorCQlnb3RvIGVycl9jb25maWdfdmlkZW87CisKKwlyZXQgPSBjZG5fZHBfcmVnX3dy aXRlKGRwLCBTVFJFQU1fQ09ORklHLCAxKTsKKwlpZiAocmV0KQorCQlnb3RvIGVycl9jb25maWdf dmlkZW87CisKKwl2YWwgPSBtb2RlLT5oc3luY19lbmQgLSBtb2RlLT5oc3luY19zdGFydDsKKwl2 YWwgfD0gKG1vZGUtPmhkaXNwbGF5IDw8IDE2KTsKKwlyZXQgPSBjZG5fZHBfcmVnX3dyaXRlKGRw LCBEUF9IT1JJWk9OVEFMLCB2YWwpOworCWlmIChyZXQpCisJCWdvdG8gZXJyX2NvbmZpZ192aWRl bzsKKworCXZhbCA9IG1vZGUtPnZ0b3RhbDsKKwl2YWwgLT0gKG1vZGUtPnZ0b3RhbCAtIG1vZGUt PnZkaXNwbGF5KTsKKwl2YWwgfD0gKG1vZGUtPnZ0b3RhbCAtIG1vZGUtPnZzeW5jX3N0YXJ0KSA8 PCAxNjsKKwlyZXQgPSBjZG5fZHBfcmVnX3dyaXRlKGRwLCBEUF9WRVJUSUNBTF8wLCB2YWwpOwor CWlmIChyZXQpCisJCWdvdG8gZXJyX2NvbmZpZ192aWRlbzsKKworCXZhbCA9IG1vZGUtPnZ0b3Rh bDsKKwlyZXQgPSBjZG5fZHBfcmVnX3dyaXRlKGRwLCBEUF9WRVJUSUNBTF8xLCB2YWwpOworCWlm IChyZXQpCisJCWdvdG8gZXJyX2NvbmZpZ192aWRlbzsKKworCXZhbCA9ICAwOworCXJldCA9IGNk bl9kcF9yZWdfd3JpdGVfYml0KGRwLCBEUF9WQl9JRCwgMiwgMSwgdmFsKTsKKworZXJyX2NvbmZp Z192aWRlbzoKKwlpZiAocmV0KQorCQlEUk1fREVWX0VSUk9SKGRwLT5kZXYsICJjb25maWcgdmlk ZW8gZmFpbGVkOiAlZFxuIiwgcmV0KTsKKwlyZXR1cm4gcmV0OworfQorCitpbnQgY2RuX2RwX2F1 ZGlvX3N0b3Aoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLCBzdHJ1Y3QgYXVkaW9faW5mbyAqYXVk aW8pCit7CisJdTMyIHZhbDsKKwlpbnQgcmV0OworCisJcmV0ID0gY2RuX2RwX3JlZ193cml0ZShk cCwgQVVESU9fUEFDS19DT05UUk9MLCAwKTsKKwlpZiAocmV0KSB7CisJCURSTV9ERVZfRVJST1Io ZHAtPmRldiwgImF1ZGlvIHN0b3AgZmFpbGVkOiAlZFxuIiwgcmV0KTsKKwkJcmV0dXJuIHJldDsK Kwl9CisKKwl2YWwgPSBTUERJRl9BVkdfU0VMIHwgU1BESUZfSklUVEVSX0JZUEFTUzsKKwl2YWwg fD0gU1BESUZfRklGT19NSURfUkFOR0UoMHhlMCk7CisJdmFsIHw9IFNQRElGX0pJVFRFUl9USFJT SCgweGUwKTsKKwl2YWwgfD0gU1BESUZfSklUVEVSX0FWR19XSU4oNyk7CisJd3JpdGVsKHZhbCwg ZHAtPnJlZ3MgKyBTUERJRl9DVFJMX0FERFIpOworCisJLyogY2xlYXJuIHRoZSBhdWRpbyBjb25m aWcgYW5kIHJlc2V0ICovCisJd3JpdGVsKDAsIGRwLT5yZWdzICsgQVVESU9fU1JDX0NOVEwpOwor CXdyaXRlbCgwLCBkcC0+cmVncyArIEFVRElPX1NSQ19DTkZHKTsKKwl3cml0ZWwoQVVESU9fU1df UlNULCBkcC0+cmVncyArIEFVRElPX1NSQ19DTlRMKTsKKwl3cml0ZWwoMCwgZHAtPnJlZ3MgKyBB VURJT19TUkNfQ05UTCk7CisKKwkvKiByZXNldCBzbXBsMnBja3QgY29tcG9uZW50ICAqLworCXdy aXRlbCgwLCBkcC0+cmVncyArIFNNUEwyUEtUX0NOVEwpOworCXdyaXRlbChBVURJT19TV19SU1Qs IGRwLT5yZWdzICsgU01QTDJQS1RfQ05UTCk7CisJd3JpdGVsKDAsIGRwLT5yZWdzICsgU01QTDJQ S1RfQ05UTCk7CisKKwkvKiByZXNldCBGSUZPICovCisJd3JpdGVsKEFVRElPX1NXX1JTVCwgZHAt PnJlZ3MgKyBGSUZPX0NOVEwpOworCXdyaXRlbCgwLCBkcC0+cmVncyArIEZJRk9fQ05UTCk7CisK KwlpZiAoYXVkaW8tPmZvcm1hdCA9PSBBRk1UX1NQRElGKQorCQljbGtfZGlzYWJsZV91bnByZXBh cmUoZHAtPnNwZGlmX2Nsayk7CisKKwlyZXR1cm4gMDsKK30KKworaW50IGNkbl9kcF9hdWRpb19t dXRlKHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCwgYm9vbCBlbmFibGUpCit7CisJaW50IHJldDsK KworCXJldCA9IGNkbl9kcF9yZWdfd3JpdGVfYml0KGRwLCBEUF9WQl9JRCwgNCwgMSwgZW5hYmxl KTsKKwlpZiAocmV0KQorCQlEUk1fREVWX0VSUk9SKGRwLT5kZXYsICJhdWRpbyBtdXRlIGZhaWxl ZDogJWRcbiIsIHJldCk7CisKKwlyZXR1cm4gcmV0OworfQorCitzdGF0aWMgdm9pZCBjZG5fZHBf YXVkaW9fY29uZmlnX2kycyhzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAsCisJCQkJICAgIHN0cnVj dCBhdWRpb19pbmZvICphdWRpbykKK3sKKwlpbnQgc3ViX3Bja3RfbnVtID0gMSwgaTJzX3BvcnRf ZW5fdmFsID0gMHhmLCBpOworCXUzMiB2YWw7CisKKwlpZiAoYXVkaW8tPmNoYW5uZWxzID09IDIp IHsKKwkJaWYgKGRwLT5saW5rLm51bV9sYW5lcyA9PSAxKQorCQkJc3ViX3Bja3RfbnVtID0gMjsK KwkJZWxzZQorCQkJc3ViX3Bja3RfbnVtID0gNDsKKworCQlpMnNfcG9ydF9lbl92YWwgPSAxOwor CX0gZWxzZSBpZiAoYXVkaW8tPmNoYW5uZWxzID09IDQpIHsKKwkJaTJzX3BvcnRfZW5fdmFsID0g MzsKKwl9CisKKwl3cml0ZWwoMHgwLCBkcC0+cmVncyArIFNQRElGX0NUUkxfQUREUik7CisKKwl3 cml0ZWwoU1lOQ19XUl9UT19DSF9aRVJPLCBkcC0+cmVncyArIEZJRk9fQ05UTCk7CisKKwl2YWwg PSBNQVhfTlVNX0NIKGF1ZGlvLT5jaGFubmVscyk7CisJdmFsIHw9IE5VTV9PRl9JMlNfUE9SVFMo YXVkaW8tPmNoYW5uZWxzKTsKKwl2YWwgfD0gQVVESU9fVFlQRV9MUENNOworCXZhbCB8PSBDRkdf U1VCX1BDS1RfTlVNKHN1Yl9wY2t0X251bSk7CisJd3JpdGVsKHZhbCwgZHAtPnJlZ3MgKyBTTVBM MlBLVF9DTkZHKTsKKworCWlmIChhdWRpby0+c2FtcGxlX3dpZHRoID09IDE2KQorCQl2YWwgPSAw OworCWVsc2UgaWYgKGF1ZGlvLT5zYW1wbGVfd2lkdGggPT0gMjQpCisJCXZhbCA9IDEgPDwgOTsK KwllbHNlCisJCXZhbCA9IDIgPDwgOTsKKworCXZhbCB8PSBBVURJT19DSF9OVU0oYXVkaW8tPmNo YW5uZWxzKTsKKwl2YWwgfD0gSTJTX0RFQ19QT1JUX0VOKGkyc19wb3J0X2VuX3ZhbCk7CisJdmFs IHw9IFRSQU5TX1NNUExfV0lEVEhfMzI7CisJd3JpdGVsKHZhbCwgZHAtPnJlZ3MgKyBBVURJT19T UkNfQ05GRyk7CisKKwlmb3IgKGkgPSAwOyBpIDwgKGF1ZGlvLT5jaGFubmVscyArIDEpIC8gMjsg aSsrKSB7CisJCWlmIChhdWRpby0+c2FtcGxlX3dpZHRoID09IDE2KQorCQkJdmFsID0gKDB4MDgg PDwgOCkgfCAoMHgwOCA8PCAyMCk7CisJCWVsc2UgaWYgKGF1ZGlvLT5zYW1wbGVfd2lkdGggPT0g MjQpCisJCQl2YWwgPSAoMHgwYiA8PCA4KSB8ICgweDBiIDw8IDIwKTsKKworCQl2YWwgfD0gKCgy ICogaSkgPDwgNCkgfCAoKDIgKiBpICsgMSkgPDwgMTYpOworCQl3cml0ZWwodmFsLCBkcC0+cmVn cyArIFNUVFNfQklUX0NIKGkpKTsKKwl9CisKKwlzd2l0Y2ggKGF1ZGlvLT5zYW1wbGVfcmF0ZSkg eworCWNhc2UgMzIwMDA6CisJCXZhbCA9IFNBTVBMSU5HX0ZSRVEoMykgfAorCQkgICAgICBPUklH SU5BTF9TQU1QX0ZSRVEoMHhjKTsKKwkJYnJlYWs7CisJY2FzZSA0NDEwMDoKKwkJdmFsID0gU0FN UExJTkdfRlJFUSgwKSB8CisJCSAgICAgIE9SSUdJTkFMX1NBTVBfRlJFUSgweGYpOworCQlicmVh azsKKwljYXNlIDQ4MDAwOgorCQl2YWwgPSBTQU1QTElOR19GUkVRKDIpIHwKKwkJICAgICAgT1JJ R0lOQUxfU0FNUF9GUkVRKDB4ZCk7CisJCWJyZWFrOworCWNhc2UgODgyMDA6CisJCXZhbCA9IFNB TVBMSU5HX0ZSRVEoOCkgfAorCQkgICAgICBPUklHSU5BTF9TQU1QX0ZSRVEoMHg3KTsKKwkJYnJl YWs7CisJY2FzZSA5NjAwMDoKKwkJdmFsID0gU0FNUExJTkdfRlJFUSgweGEpIHwKKwkJICAgICAg T1JJR0lOQUxfU0FNUF9GUkVRKDUpOworCQlicmVhazsKKwljYXNlIDE3NjQwMDoKKwkJdmFsID0g U0FNUExJTkdfRlJFUSgweGMpIHwKKwkJICAgICAgT1JJR0lOQUxfU0FNUF9GUkVRKDMpOworCQli cmVhazsKKwljYXNlIDE5MjAwMDoKKwkJdmFsID0gU0FNUExJTkdfRlJFUSgweGUpIHwKKwkJICAg ICAgT1JJR0lOQUxfU0FNUF9GUkVRKDEpOworCQlicmVhazsKKwl9CisJdmFsIHw9IDQ7CisJd3Jp dGVsKHZhbCwgZHAtPnJlZ3MgKyBDT01fQ0hfU1RUU19CSVRTKTsKKworCXdyaXRlbChTTVBMMlBL VF9FTiwgZHAtPnJlZ3MgKyBTTVBMMlBLVF9DTlRMKTsKKwl3cml0ZWwoSTJTX0RFQ19TVEFSVCwg ZHAtPnJlZ3MgKyBBVURJT19TUkNfQ05UTCk7Cit9CisKK3N0YXRpYyB2b2lkIGNkbl9kcF9hdWRp b19jb25maWdfc3BkaWYoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwKQoreworCXUzMiB2YWw7CisK Kwl2YWwgPSBTUERJRl9BVkdfU0VMIHwgU1BESUZfSklUVEVSX0JZUEFTUzsKKwl2YWwgfD0gU1BE SUZfRklGT19NSURfUkFOR0UoMHhlMCk7CisJdmFsIHw9IFNQRElGX0pJVFRFUl9USFJTSCgweGUw KTsKKwl2YWwgfD0gU1BESUZfSklUVEVSX0FWR19XSU4oNyk7CisJd3JpdGVsKHZhbCwgZHAtPnJl Z3MgKyBTUERJRl9DVFJMX0FERFIpOworCisJd3JpdGVsKFNZTkNfV1JfVE9fQ0hfWkVSTywgZHAt PnJlZ3MgKyBGSUZPX0NOVEwpOworCisJdmFsID0gTUFYX05VTV9DSCgyKSB8IEFVRElPX1RZUEVf TFBDTSB8IENGR19TVUJfUENLVF9OVU0oNCk7CisJd3JpdGVsKHZhbCwgZHAtPnJlZ3MgKyBTTVBM MlBLVF9DTkZHKTsKKwl3cml0ZWwoU01QTDJQS1RfRU4sIGRwLT5yZWdzICsgU01QTDJQS1RfQ05U TCk7CisKKwl2YWwgPSBTUERJRl9FTkFCTEUgfCBTUERJRl9BVkdfU0VMIHwgU1BESUZfSklUVEVS X0JZUEFTUzsKKwl2YWwgfD0gU1BESUZfRklGT19NSURfUkFOR0UoMHhlMCk7CisJdmFsIHw9IFNQ RElGX0pJVFRFUl9USFJTSCgweGUwKTsKKwl2YWwgfD0gU1BESUZfSklUVEVSX0FWR19XSU4oNyk7 CisJd3JpdGVsKHZhbCwgZHAtPnJlZ3MgKyBTUERJRl9DVFJMX0FERFIpOworCisJY2xrX3ByZXBh cmVfZW5hYmxlKGRwLT5zcGRpZl9jbGspOworCWNsa19zZXRfcmF0ZShkcC0+c3BkaWZfY2xrLCBD RE5fRFBfU1BESUZfQ0xLKTsKK30KKworaW50IGNkbl9kcF9hdWRpb19jb25maWcoc3RydWN0IGNk bl9kcF9kZXZpY2UgKmRwLCBzdHJ1Y3QgYXVkaW9faW5mbyAqYXVkaW8pCit7CisJaW50IHJldDsK KworCS8qIHJlc2V0IHRoZSBzcGRpZiBjbGsgYmVmb3JlIGNvbmZpZyAqLworCWlmIChhdWRpby0+ Zm9ybWF0ID09IEFGTVRfU1BESUYpIHsKKwkJcmVzZXRfY29udHJvbF9hc3NlcnQoZHAtPnNwZGlm X3JzdCk7CisJCXJlc2V0X2NvbnRyb2xfZGVhc3NlcnQoZHAtPnNwZGlmX3JzdCk7CisJfQorCisJ cmV0ID0gY2RuX2RwX3JlZ193cml0ZShkcCwgQ01fTEFORV9DVFJMLCBMQU5FX1JFRl9DWUMpOwor CWlmIChyZXQpCisJCWdvdG8gZXJyX2F1ZGlvX2NvbmZpZzsKKworCXJldCA9IGNkbl9kcF9yZWdf d3JpdGUoZHAsIENNX0NUUkwsIDApOworCWlmIChyZXQpCisJCWdvdG8gZXJyX2F1ZGlvX2NvbmZp ZzsKKworCWlmIChhdWRpby0+Zm9ybWF0ID09IEFGTVRfSTJTKQorCQljZG5fZHBfYXVkaW9fY29u ZmlnX2kycyhkcCwgYXVkaW8pOworCWVsc2UgaWYgKGF1ZGlvLT5mb3JtYXQgPT0gQUZNVF9TUERJ RikKKwkJY2RuX2RwX2F1ZGlvX2NvbmZpZ19zcGRpZihkcCk7CisKKwlyZXQgPSBjZG5fZHBfcmVn X3dyaXRlKGRwLCBBVURJT19QQUNLX0NPTlRST0wsIEFVRElPX1BBQ0tfRU4pOworCitlcnJfYXVk aW9fY29uZmlnOgorCWlmIChyZXQpCisJCURSTV9ERVZfRVJST1IoZHAtPmRldiwgImF1ZGlvIGNv bmZpZyBmYWlsZWQ6ICVkXG4iLCByZXQpOworCXJldHVybiByZXQ7Cit9CmRpZmYgLS1naXQgYS9k cml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvY2RuLWRwLXJlZy5oIGIvZHJpdmVycy9ncHUvZHJtL3Jv Y2tjaGlwL2Nkbi1kcC1yZWcuaApuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAwLi42 YWMzNjc0Ci0tLSAvZGV2L251bGwKKysrIGIvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL2Nkbi1k cC1yZWcuaApAQCAtMCwwICsxLDQ4MiBAQAorLyoKKyAqIENvcHlyaWdodCAoQykgRnV6aG91IFJv Y2tjaGlwIEVsZWN0cm9uaWNzIENvLkx0ZAorICogQXV0aG9yOiBDaHJpcyBaaG9uZyA8enl3QHJv Y2stY2hpcHMuY29tPgorICoKKyAqIFRoaXMgc29mdHdhcmUgaXMgbGljZW5zZWQgdW5kZXIgdGhl IHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMKKyAqIExpY2Vuc2UgdmVyc2lvbiAyLCBh cyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgYW5kCisgKiBtYXkg YmUgY29waWVkLCBkaXN0cmlidXRlZCwgYW5kIG1vZGlmaWVkIHVuZGVyIHRob3NlIHRlcm1zLgor ICoKKyAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdp bGwgYmUgdXNlZnVsLAorICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4g dGhlIGltcGxpZWQgd2FycmFudHkgb2YKKyAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZP UiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUKKyAqIEdOVSBHZW5lcmFsIFB1YmxpYyBM aWNlbnNlIGZvciBtb3JlIGRldGFpbHMuCisgKi8KKworI2lmbmRlZiBfQ0ROX0RQX1JFR19ICisj ZGVmaW5lIF9DRE5fRFBfUkVHX0gKKworI2luY2x1ZGUgPGxpbnV4L2JpdG9wcy5oPgorCisjZGVm aW5lIEFERFJfSU1FTQkJMHgxMDAwMAorI2RlZmluZSBBRERSX0RNRU0JCTB4MjAwMDAKKworLyog QVBCIENGRyBhZGRyICovCisjZGVmaW5lIEFQQl9DVFJMCQkJMAorI2RlZmluZSBYVF9JTlRfQ1RS TAkJCTB4MDQKKyNkZWZpbmUgTUFJTEJPWF9GVUxMX0FERFIJCTB4MDgKKyNkZWZpbmUgTUFJTEJP WF9FTVBUWV9BRERSCQkweDBjCisjZGVmaW5lIE1BSUxCT1gwX1dSX0RBVEEJCTB4MTAKKyNkZWZp bmUgTUFJTEJPWDBfUkRfREFUQQkJMHgxNAorI2RlZmluZSBLRUVQX0FMSVZFCQkJMHgxOAorI2Rl ZmluZSBWRVJfTAkJCQkweDFjCisjZGVmaW5lIFZFUl9ICQkJCTB4MjAKKyNkZWZpbmUgVkVSX0xJ Ql9MX0FERFIJCQkweDI0CisjZGVmaW5lIFZFUl9MSUJfSF9BRERSCQkJMHgyOAorI2RlZmluZSBT V19ERUJVR19MCQkJMHgyYworI2RlZmluZSBTV19ERUJVR19ICQkJMHgzMAorI2RlZmluZSBNQUlM Qk9YX0lOVF9NQVNLCQkweDM0CisjZGVmaW5lIE1BSUxCT1hfSU5UX1NUQVRVUwkJMHgzOAorI2Rl ZmluZSBTV19DTEtfTAkJCTB4M2MKKyNkZWZpbmUgU1dfQ0xLX0gJCQkweDQwCisjZGVmaW5lIFNX X0VWRU5UUzAJCQkweDQ0CisjZGVmaW5lIFNXX0VWRU5UUzEJCQkweDQ4CisjZGVmaW5lIFNXX0VW RU5UUzIJCQkweDRjCisjZGVmaW5lIFNXX0VWRU5UUzMJCQkweDUwCisjZGVmaW5lIFhUX09DRF9D VFJMCQkJMHg2MAorI2RlZmluZSBBUEJfSU5UX01BU0sJCQkweDZjCisjZGVmaW5lIEFQQl9TVEFU VVNfTUFTSwkJCTB4NzAKKworLyogYXVkaW8gZGVjb2RlciBhZGRyICovCisjZGVmaW5lIEFVRElP X1NSQ19DTlRMCQkJMHgzMDAwMAorI2RlZmluZSBBVURJT19TUkNfQ05GRwkJCTB4MzAwMDQKKyNk ZWZpbmUgQ09NX0NIX1NUVFNfQklUUwkJMHgzMDAwOAorI2RlZmluZSBTVFRTX0JJVF9DSCh4KQkJ CSgweDMwMDBjICsgKCh4KSA8PCAyKSkKKyNkZWZpbmUgU1BESUZfQ1RSTF9BRERSCQkJMHgzMDA0 YworI2RlZmluZSBTUERJRl9DSDFfQ1NfMzEwMF9BRERSCQkweDMwMDUwCisjZGVmaW5lIFNQRElG X0NIMV9DU182MzMyX0FERFIJCTB4MzAwNTQKKyNkZWZpbmUgU1BESUZfQ0gxX0NTXzk1NjRfQURE UgkJMHgzMDA1OAorI2RlZmluZSBTUERJRl9DSDFfQ1NfMTI3OTZfQUREUgkJMHgzMDA1YworI2Rl ZmluZSBTUERJRl9DSDFfQ1NfMTU5MTI4X0FERFIJMHgzMDA2MAorI2RlZmluZSBTUERJRl9DSDFf Q1NfMTkxMTYwX0FERFIJMHgzMDA2NAorI2RlZmluZSBTUERJRl9DSDJfQ1NfMzEwMF9BRERSCQkw eDMwMDY4CisjZGVmaW5lIFNQRElGX0NIMl9DU182MzMyX0FERFIJCTB4MzAwNmMKKyNkZWZpbmUg U1BESUZfQ0gyX0NTXzk1NjRfQUREUgkJMHgzMDA3MAorI2RlZmluZSBTUERJRl9DSDJfQ1NfMTI3 OTZfQUREUgkJMHgzMDA3NAorI2RlZmluZSBTUERJRl9DSDJfQ1NfMTU5MTI4X0FERFIJMHgzMDA3 OAorI2RlZmluZSBTUERJRl9DSDJfQ1NfMTkxMTYwX0FERFIJMHgzMDA3YworI2RlZmluZSBTTVBM MlBLVF9DTlRMCQkJMHgzMDA4MAorI2RlZmluZSBTTVBMMlBLVF9DTkZHCQkJMHgzMDA4NAorI2Rl ZmluZSBGSUZPX0NOVEwJCQkweDMwMDg4CisjZGVmaW5lIEZJRk9fU1RUUwkJCTB4MzAwOGMKKwor Lyogc291cmNlIHBpZiBhZGRyICovCisjZGVmaW5lIFNPVVJDRV9QSUZfV1JfQUREUgkJMHgzMDgw MAorI2RlZmluZSBTT1VSQ0VfUElGX1dSX1JFUQkJMHgzMDgwNAorI2RlZmluZSBTT1VSQ0VfUElG X1JEX0FERFIJCTB4MzA4MDgKKyNkZWZpbmUgU09VUkNFX1BJRl9SRF9SRVEJCTB4MzA4MGMKKyNk ZWZpbmUgU09VUkNFX1BJRl9EQVRBX1dSCQkweDMwODEwCisjZGVmaW5lIFNPVVJDRV9QSUZfREFU QV9SRAkJMHgzMDgxNAorI2RlZmluZSBTT1VSQ0VfUElGX0ZJRk8xX0ZMVVNICQkweDMwODE4Cisj ZGVmaW5lIFNPVVJDRV9QSUZfRklGTzJfRkxVU0gJCTB4MzA4MWMKKyNkZWZpbmUgU09VUkNFX1BJ Rl9TVEFUVVMJCTB4MzA4MjAKKyNkZWZpbmUgU09VUkNFX1BJRl9JTlRFUlJVUFRfU09VUkNFCTB4 MzA4MjQKKyNkZWZpbmUgU09VUkNFX1BJRl9JTlRFUlJVUFRfTUFTSwkweDMwODI4CisjZGVmaW5l IFNPVVJDRV9QSUZfUEtUX0FMTE9DX1JFRwkweDMwODJjCisjZGVmaW5lIFNPVVJDRV9QSUZfUEtU X0FMTE9DX1dSX0VOCTB4MzA4MzAKKyNkZWZpbmUgU09VUkNFX1BJRl9TV19SRVNFVAkJMHgzMDgz NAorCisvKiBiZWxsb3cgcmVnaXN0ZXJzIG5lZWQgYWNjZXNzIGJ5IG1haWxib3ggKi8KKy8qIHNv dXJjZSBjYXIgYWRkciAqLworI2RlZmluZSBTT1VSQ0VfSERUWF9DQVIJCQkweDA5MDAKKyNkZWZp bmUgU09VUkNFX0RQVFhfQ0FSCQkJMHgwOTA0CisjZGVmaW5lIFNPVVJDRV9QSFlfQ0FSCQkJMHgw OTA4CisjZGVmaW5lIFNPVVJDRV9DRUNfQ0FSCQkJMHgwOTBjCisjZGVmaW5lIFNPVVJDRV9DQlVT X0NBUgkJCTB4MDkxMAorI2RlZmluZSBTT1VSQ0VfUEtUX0NBUgkJCTB4MDkxOAorI2RlZmluZSBT T1VSQ0VfQUlGX0NBUgkJCTB4MDkxYworI2RlZmluZSBTT1VSQ0VfQ0lQSEVSX0NBUgkJMHgwOTIw CisjZGVmaW5lIFNPVVJDRV9DUllQVE9fQ0FSCQkweDA5MjQKKworLyogY2xvY2sgbWV0ZXJzIGFk ZHIgKi8KKyNkZWZpbmUgQ01fQ1RSTAkJCQkweDBhMDAKKyNkZWZpbmUgQ01fSTJTX0NUUkwJCQkw eDBhMDQKKyNkZWZpbmUgQ01fU1BESUZfQ1RSTAkJCTB4MGEwOAorI2RlZmluZSBDTV9WSURfQ1RS TAkJCTB4MGEwYworI2RlZmluZSBDTV9MQU5FX0NUUkwJCQkweDBhMTAKKyNkZWZpbmUgSTJTX05N X1NUQUJMRQkJCTB4MGExNAorI2RlZmluZSBJMlNfTkNUU19TVEFCTEUJCQkweDBhMTgKKyNkZWZp bmUgU1BESUZfTk1fU1RBQkxFCQkJMHgwYTFjCisjZGVmaW5lIFNQRElGX05DVFNfU1RBQkxFCQkw eDBhMjAKKyNkZWZpbmUgTk1WSURfTUVBU19TVEFCTEUJCTB4MGEyNAorI2RlZmluZSBJMlNfTUVB UwkJCTB4MGE0MAorI2RlZmluZSBTUERJRl9NRUFTCQkJMHgwYTgwCisjZGVmaW5lIE5NVklEX01F QVMJCQkweDBhYzAKKworLyogc291cmNlIHZpZiBhZGRyICovCisjZGVmaW5lIEJORF9IU1lOQzJW U1lOQwkJCTB4MGIwMAorI2RlZmluZSBIU1lOQzJWU1lOQ19GMV9MMQkJMHgwYjA0CisjZGVmaW5l IEhTWU5DMlZTWU5DX0YyX0wxCQkweDBiMDgKKyNkZWZpbmUgSFNZTkMyVlNZTkNfU1RBVFVTCQkw eDBiMGMKKyNkZWZpbmUgSFNZTkMyVlNZTkNfUE9MX0NUUkwJCTB4MGIxMAorCisvKiBkcHR4IHBo eSBhZGRyICovCisjZGVmaW5lIERQX1RYX1BIWV9DT05GSUdfUkVHCQkweDIwMDAKKyNkZWZpbmUg RFBfVFhfUEhZX1NUQVRVU19SRUcJCTB4MjAwNAorI2RlZmluZSBEUF9UWF9QSFlfU1dfUkVTRVQJ CTB4MjAwOAorI2RlZmluZSBEUF9UWF9QSFlfU0NSQU1CTEVSX1NFRUQJMHgyMDBjCisjZGVmaW5l IERQX1RYX1BIWV9UUkFJTklOR18wMV8wNAkweDIwMTAKKyNkZWZpbmUgRFBfVFhfUEhZX1RSQUlO SU5HXzA1XzA4CTB4MjAxNAorI2RlZmluZSBEUF9UWF9QSFlfVFJBSU5JTkdfMDlfMTAJMHgyMDE4 CisjZGVmaW5lIFRFU1RfQ09SCQkJMHgyM2ZjCisKKy8qIGRwdHggaHBkIGFkZHIgKi8KKyNkZWZp bmUgSFBEX0lSUV9ERVRfTUlOX1RJTUVSCQkweDIxMDAKKyNkZWZpbmUgSFBEX0lSUV9ERVRfTUFY X1RJTUVSCQkweDIxMDQKKyNkZWZpbmUgSFBEX1VOUExHRURfREVUX01JTl9USU1FUgkweDIxMDgK KyNkZWZpbmUgSFBEX1NUQUJMRV9USU1FUgkJMHgyMTBjCisjZGVmaW5lIEhQRF9GSUxURVJfVElN RVIJCTB4MjExMAorI2RlZmluZSBIUERfRVZFTlRfTUFTSwkJCTB4MjExYworI2RlZmluZSBIUERf RVZFTlRfREVUCQkJMHgyMTIwCisKKy8qIGRweXggZnJhbWVyIGFkZHIgKi8KKyNkZWZpbmUgRFBf RlJBTUVSX0dMT0JBTF9DT05GSUcJCTB4MjIwMAorI2RlZmluZSBEUF9TV19SRVNFVAkJCTB4MjIw NAorI2RlZmluZSBEUF9GUkFNRVJfVFUJCQkweDIyMDgKKyNkZWZpbmUgRFBfRlJBTUVSX1BYTF9S RVBSCQkweDIyMGMKKyNkZWZpbmUgRFBfRlJBTUVSX1NQCQkJMHgyMjEwCisjZGVmaW5lIEFVRElP X1BBQ0tfQ09OVFJPTAkJMHgyMjE0CisjZGVmaW5lIERQX1ZDX1RBQkxFKHgpCQkJKDB4MjIxOCAr ICgoeCkgPDwgMikpCisjZGVmaW5lIERQX1ZCX0lECQkJMHgyMjU4CisjZGVmaW5lIERQX01UUEhf TFZQX0NPTlRST0wJCTB4MjI1YworI2RlZmluZSBEUF9NVFBIX1NZTUJPTF9WQUxVRVMJCTB4MjI2 MAorI2RlZmluZSBEUF9NVFBIX0VDRl9DT05UUk9MCQkweDIyNjQKKyNkZWZpbmUgRFBfTVRQSF9B Q1RfQ09OVFJPTAkJMHgyMjY4CisjZGVmaW5lIERQX01UUEhfU1RBVFVTCQkJMHgyMjZjCisjZGVm aW5lIERQX0lOVEVSUlVQVF9TT1VSQ0UJCTB4MjI3MAorI2RlZmluZSBEUF9JTlRFUlJVUFRfTUFT SwkJMHgyMjc0CisjZGVmaW5lIERQX0ZST05UX0JBQ0tfUE9SQ0gJCTB4MjI3OAorI2RlZmluZSBE UF9CWVRFX0NPVU5UCQkJMHgyMjdjCisKKy8qIGRwdHggc3RyZWFtIGFkZHIgKi8KKyNkZWZpbmUg TVNBX0hPUklaT05UQUxfMAkJMHgyMjgwCisjZGVmaW5lIE1TQV9IT1JJWk9OVEFMXzEJCTB4MjI4 NAorI2RlZmluZSBNU0FfVkVSVElDQUxfMAkJCTB4MjI4OAorI2RlZmluZSBNU0FfVkVSVElDQUxf MQkJCTB4MjI4YworI2RlZmluZSBNU0FfTUlTQwkJCTB4MjI5MAorI2RlZmluZSBTVFJFQU1fQ09O RklHCQkJMHgyMjk0CisjZGVmaW5lIEFVRElPX1BBQ0tfU1RBVFVTCQkweDIyOTgKKyNkZWZpbmUg VklGX1NUQVRVUwkJCTB4MjI5YworI2RlZmluZSBQQ0tfU1RVRkZfU1RBVFVTXzAJCTB4MjJhMAor I2RlZmluZSBQQ0tfU1RVRkZfU1RBVFVTXzEJCTB4MjJhNAorI2RlZmluZSBJTkZPX1BBQ0tfU1RB VFVTCQkweDIyYTgKKyNkZWZpbmUgUkFURV9HT1ZFUk5PUl9TVEFUVVMJCTB4MjJhYworI2RlZmlu ZSBEUF9IT1JJWk9OVEFMCQkJMHgyMmIwCisjZGVmaW5lIERQX1ZFUlRJQ0FMXzAJCQkweDIyYjQK KyNkZWZpbmUgRFBfVkVSVElDQUxfMQkJCTB4MjJiOAorI2RlZmluZSBEUF9CTE9DS19TRFAJCQkw eDIyYmMKKworLyogZHB0eCBnbGJsIGFkZHIgKi8KKyNkZWZpbmUgRFBUWF9MQU5FX0VOCQkJMHgy MzAwCisjZGVmaW5lIERQVFhfRU5ITkNECQkJMHgyMzA0CisjZGVmaW5lIERQVFhfSU5UX01BU0sJ CQkweDIzMDgKKyNkZWZpbmUgRFBUWF9JTlRfU1RBVFVTCQkJMHgyMzBjCisKKy8qIGRwIGF1eCBh ZGRyICovCisjZGVmaW5lIERQX0FVWF9IT1NUX0NPTlRST0wJCTB4MjgwMAorI2RlZmluZSBEUF9B VVhfSU5URVJSVVBUX1NPVVJDRQkJMHgyODA0CisjZGVmaW5lIERQX0FVWF9JTlRFUlJVUFRfTUFT SwkJMHgyODA4CisjZGVmaW5lIERQX0FVWF9TV0FQX0lOVkVSU0lPTl9DT05UUk9MCTB4MjgwYwor I2RlZmluZSBEUF9BVVhfU0VORF9OQUNLX1RSQU5TQUNUSU9OCTB4MjgxMAorI2RlZmluZSBEUF9B VVhfQ0xFQVJfUlgJCQkweDI4MTQKKyNkZWZpbmUgRFBfQVVYX0NMRUFSX1RYCQkJMHgyODE4Cisj ZGVmaW5lIERQX0FVWF9USU1FUl9TVE9QCQkweDI4MWMKKyNkZWZpbmUgRFBfQVVYX1RJTUVSX0NM RUFSCQkweDI4MjAKKyNkZWZpbmUgRFBfQVVYX1JFU0VUX1NXCQkJMHgyODI0CisjZGVmaW5lIERQ X0FVWF9ESVZJREVfMk0JCTB4MjgyOAorI2RlZmluZSBEUF9BVVhfVFhfUFJFQUNIQVJHRV9MRU5H VEgJMHgyODJjCisjZGVmaW5lIERQX0FVWF9GUkVRVUVOQ1lfMU1fTUFYCQkweDI4MzAKKyNkZWZp bmUgRFBfQVVYX0ZSRVFVRU5DWV8xTV9NSU4JCTB4MjgzNAorI2RlZmluZSBEUF9BVVhfUlhfUFJF X01JTgkJMHgyODM4CisjZGVmaW5lIERQX0FVWF9SWF9QUkVfTUFYCQkweDI4M2MKKyNkZWZpbmUg RFBfQVVYX1RJTUVSX1BSRVNFVAkJMHgyODQwCisjZGVmaW5lIERQX0FVWF9OQUNLX0ZPUk1BVAkJ MHgyODQ0CisjZGVmaW5lIERQX0FVWF9UWF9EQVRBCQkJMHgyODQ4CisjZGVmaW5lIERQX0FVWF9S WF9EQVRBCQkJMHgyODRjCisjZGVmaW5lIERQX0FVWF9UWF9TVEFUVVMJCTB4Mjg1MAorI2RlZmlu ZSBEUF9BVVhfUlhfU1RBVFVTCQkweDI4NTQKKyNkZWZpbmUgRFBfQVVYX1JYX0NZQ0xFX0NPVU5U RVIJCTB4Mjg1OAorI2RlZmluZSBEUF9BVVhfTUFJTl9TVEFURVMJCTB4Mjg1YworI2RlZmluZSBE UF9BVVhfTUFJTl9USU1FUgkJMHgyODYwCisjZGVmaW5lIERQX0FVWF9BRkVfT1VUCQkJMHgyODY0 CisKKy8qIGNyeXB0byBhZGRyICovCisjZGVmaW5lIENSWVBUT19IRENQX1JFVklTSU9OCQkweDU4 MDAKKyNkZWZpbmUgSERDUF9DUllQVE9fQ09ORklHCQkweDU4MDQKKyNkZWZpbmUgQ1JZUFRPX0lO VEVSUlVQVF9TT1VSQ0UJCTB4NTgwOAorI2RlZmluZSBDUllQVE9fSU5URVJSVVBUX01BU0sJCTB4 NTgwYworI2RlZmluZSBDUllQVE8yMl9DT05GSUcJCQkweDU4MTgKKyNkZWZpbmUgQ1JZUFRPMjJf U1RBVFVTCQkJMHg1ODFjCisjZGVmaW5lIFNIQV8yNTZfREFUQV9JTgkJCTB4NTgzYworI2RlZmlu ZSBTSEFfMjU2X0RBVEFfT1VUXyh4KQkJKDB4NTg1MCArICgoeCkgPDwgMikpCisjZGVmaW5lIEFF U18zMl9LRVlfKHgpCQkJKDB4NTg3MCArICgoeCkgPDwgMikpCisjZGVmaW5lIEFFU18zMl9EQVRB X0lOCQkJMHg1ODgwCisjZGVmaW5lIEFFU18zMl9EQVRBX09VVF8oeCkJCSgweDU4ODQgKyAoKHgp IDw8IDIpKQorI2RlZmluZSBDUllQVE8xNF9DT05GSUcJCQkweDU4YTAKKyNkZWZpbmUgQ1JZUFRP MTRfU1RBVFVTCQkJMHg1OGE0CisjZGVmaW5lIENSWVBUTzE0X1BSTk1fT1VUCQkweDU4YTgKKyNk ZWZpbmUgQ1JZUFRPMTRfS01fMAkJCTB4NThhYworI2RlZmluZSBDUllQVE8xNF9LTV8xCQkJMHg1 OGIwCisjZGVmaW5lIENSWVBUTzE0X0FOXzAJCQkweDU4YjQKKyNkZWZpbmUgQ1JZUFRPMTRfQU5f MQkJCTB4NThiOAorI2RlZmluZSBDUllQVE8xNF9ZT1VSX0tTVl8wCQkweDU4YmMKKyNkZWZpbmUg Q1JZUFRPMTRfWU9VUl9LU1ZfMQkJMHg1OGMwCisjZGVmaW5lIENSWVBUTzE0X01JXzAJCQkweDU4 YzQKKyNkZWZpbmUgQ1JZUFRPMTRfTUlfMQkJCTB4NThjOAorI2RlZmluZSBDUllQVE8xNF9USV8w CQkJMHg1OGNjCisjZGVmaW5lIENSWVBUTzE0X0tJXzAJCQkweDU4ZDAKKyNkZWZpbmUgQ1JZUFRP MTRfS0lfMQkJCTB4NThkNAorI2RlZmluZSBDUllQVE8xNF9CTE9DS1NfTlVNCQkweDU4ZDgKKyNk ZWZpbmUgQ1JZUFRPMTRfS0VZX01FTV9EQVRBXzAJCTB4NThkYworI2RlZmluZSBDUllQVE8xNF9L RVlfTUVNX0RBVEFfMQkJMHg1OGUwCisjZGVmaW5lIENSWVBUTzE0X1NIQTFfTVNHX0RBVEEJCTB4 NThlNAorI2RlZmluZSBDUllQVE8xNF9TSEExX1ZfVkFMVUVfKHgpCSgweDU4ZTggKyAoKHgpIDw8 IDIpKQorI2RlZmluZSBUUk5HX0NUUkwJCQkweDU4ZmMKKyNkZWZpbmUgVFJOR19EQVRBX1JEWQkJ CTB4NTkwMAorI2RlZmluZSBUUk5HX0RBVEEJCQkweDU5MDQKKworLyogY2lwaGVyIGFkZHIgKi8K KyNkZWZpbmUgSERDUF9SRVZJU0lPTgkJCTB4NjAwMDAKKyNkZWZpbmUgSU5URVJSVVBUX1NPVVJD RQkJMHg2MDAwNAorI2RlZmluZSBJTlRFUlJVUFRfTUFTSwkJCTB4NjAwMDgKKyNkZWZpbmUgSERD UF9DSVBIRVJfQ09ORklHCQkweDYwMDBjCisjZGVmaW5lIEFFU18xMjhfS0VZXzAJCQkweDYwMDEw CisjZGVmaW5lIEFFU18xMjhfS0VZXzEJCQkweDYwMDE0CisjZGVmaW5lIEFFU18xMjhfS0VZXzIJ CQkweDYwMDE4CisjZGVmaW5lIEFFU18xMjhfS0VZXzMJCQkweDYwMDFjCisjZGVmaW5lIEFFU18x MjhfUkFORE9NXzAJCTB4NjAwMjAKKyNkZWZpbmUgQUVTXzEyOF9SQU5ET01fMQkJMHg2MDAyNAor I2RlZmluZSBDSVBIRVIxNF9LTV8wCQkJMHg2MDAyOAorI2RlZmluZSBDSVBIRVIxNF9LTV8xCQkJ MHg2MDAyYworI2RlZmluZSBDSVBIRVIxNF9TVEFUVVMJCQkweDYwMDMwCisjZGVmaW5lIENJUEhF UjE0X1JJX1BKX1NUQVRVUwkJMHg2MDAzNAorI2RlZmluZSBDSVBIRVJfTU9ERQkJCTB4NjAwMzgK KyNkZWZpbmUgQ0lQSEVSMTRfQU5fMAkJCTB4NjAwM2MKKyNkZWZpbmUgQ0lQSEVSMTRfQU5fMQkJ CTB4NjAwNDAKKyNkZWZpbmUgQ0lQSEVSMjJfQVVUSAkJCTB4NjAwNDQKKyNkZWZpbmUgQ0lQSEVS MTRfUjBfRFBfU1RBVFVTCQkweDYwMDQ4CisjZGVmaW5lIENJUEhFUjE0X0JPT1RTVFJBUAkJMHg2 MDA0YworCisjZGVmaW5lIERQVFhfRlJNUl9EQVRBX0NMS19SU1ROX0VOCUJJVCgxMSkKKyNkZWZp bmUgRFBUWF9GUk1SX0RBVEFfQ0xLX0VOCQlCSVQoMTApCisjZGVmaW5lIERQVFhfUEhZX0RBVEFf UlNUTl9FTgkJQklUKDkpCisjZGVmaW5lIERQVFhfUEhZX0RBVEFfQ0xLX0VOCQlCSVQoOCkKKyNk ZWZpbmUgRFBUWF9QSFlfQ0hBUl9SU1ROX0VOCQlCSVQoNykKKyNkZWZpbmUgRFBUWF9QSFlfQ0hB Ul9DTEtfRU4JCUJJVCg2KQorI2RlZmluZSBTT1VSQ0VfQVVYX1NZU19DTEtfUlNUTl9FTglCSVQo NSkKKyNkZWZpbmUgU09VUkNFX0FVWF9TWVNfQ0xLX0VOCQlCSVQoNCkKKyNkZWZpbmUgRFBUWF9T WVNfQ0xLX1JTVE5fRU4JCUJJVCgzKQorI2RlZmluZSBEUFRYX1NZU19DTEtfRU4JCQlCSVQoMikK KyNkZWZpbmUgQ0ZHX0RQVFhfVklGX0NMS19SU1ROX0VOCUJJVCgxKQorI2RlZmluZSBDRkdfRFBU WF9WSUZfQ0xLX0VOCQlCSVQoMCkKKworI2RlZmluZSBTT1VSQ0VfUEhZX1JTVE5fRU4JCUJJVCgx KQorI2RlZmluZSBTT1VSQ0VfUEhZX0NMS19FTgkJQklUKDApCisKKyNkZWZpbmUgU09VUkNFX1BL VF9TWVNfUlNUTl9FTgkJQklUKDMpCisjZGVmaW5lIFNPVVJDRV9QS1RfU1lTX0NMS19FTgkJQklU KDIpCisjZGVmaW5lIFNPVVJDRV9QS1RfREFUQV9SU1ROX0VOCQlCSVQoMSkKKyNkZWZpbmUgU09V UkNFX1BLVF9EQVRBX0NMS19FTgkJQklUKDApCisKKyNkZWZpbmUgU1BESUZfQ0RSX0NMS19SU1RO X0VOCQlCSVQoNSkKKyNkZWZpbmUgU1BESUZfQ0RSX0NMS19FTgkJQklUKDQpCisjZGVmaW5lIFNP VVJDRV9BSUZfU1lTX1JTVE5fRU4JCUJJVCgzKQorI2RlZmluZSBTT1VSQ0VfQUlGX1NZU19DTEtf RU4JCUJJVCgyKQorI2RlZmluZSBTT1VSQ0VfQUlGX0NMS19SU1ROX0VOCQlCSVQoMSkKKyNkZWZp bmUgU09VUkNFX0FJRl9DTEtfRU4JCUJJVCgwKQorCisjZGVmaW5lIFNPVVJDRV9DSVBIRVJfU1lT VEVNX0NMS19SU1ROX0VOCUJJVCgzKQorI2RlZmluZSBTT1VSQ0VfQ0lQSEVSX1NZU19DTEtfRU4J CUJJVCgyKQorI2RlZmluZSBTT1VSQ0VfQ0lQSEVSX0NIQVJfQ0xLX1JTVE5fRU4JCUJJVCgxKQor I2RlZmluZSBTT1VSQ0VfQ0lQSEVSX0NIQVJfQ0xLX0VOCQlCSVQoMCkKKworI2RlZmluZSBTT1VS Q0VfQ1JZUFRPX1NZU19DTEtfUlNUTl9FTglCSVQoMSkKKyNkZWZpbmUgU09VUkNFX0NSWVBUT19T WVNfQ0xLX0VOCUJJVCgwKQorCisjZGVmaW5lIEFQQl9JUkFNX1BBVEgJCQlCSVQoMikKKyNkZWZp bmUgQVBCX0RSQU1fUEFUSAkJCUJJVCgxKQorI2RlZmluZSBBUEJfWFRfUkVTRVQJCQlCSVQoMCkK KworI2RlZmluZSBNQUlMQk9YX0lOVF9NQVNLX0JJVAkJQklUKDEpCisjZGVmaW5lIFBJRl9JTlRf TUFTS19CSVQJCUJJVCgwKQorI2RlZmluZSBBTExfSU5UX01BU0sJCQkzCisKKy8qIG1haWxib3gg Ki8KKyNkZWZpbmUgTUJfT1BDT0RFX0lECQkJMAorI2RlZmluZSBNQl9NT0RVTEVfSUQJCQkxCisj ZGVmaW5lIE1CX1NJWkVfTVNCX0lECQkJMgorI2RlZmluZSBNQl9TSVpFX0xTQl9JRAkJCTMKKyNk ZWZpbmUgTUJfREFUQV9JRAkJCTQKKworI2RlZmluZSBNQl9NT0RVTEVfSURfRFBfVFgJCTB4MDEK KyNkZWZpbmUgTUJfTU9EVUxFX0lEX0hEQ1BfVFgJCTB4MDcKKyNkZWZpbmUgTUJfTU9EVUxFX0lE X0hEQ1BfUlgJCTB4MDgKKyNkZWZpbmUgTUJfTU9EVUxFX0lEX0hEQ1BfR0VORVJBTAkweDA5Cisj ZGVmaW5lIE1CX01PRFVMRV9JRF9HRU5FUkFMCQkweDBhCisKKy8qIGdlbmVyYWwgb3Bjb2RlICov CisjZGVmaW5lIEdFTkVSQUxfTUFJTl9DT05UUk9MICAgICAgICAgICAgMHgwMQorI2RlZmluZSBH RU5FUkFMX1RFU1RfRUNITyAgICAgICAgICAgICAgIDB4MDIKKyNkZWZpbmUgR0VORVJBTF9CVVNf U0VUVElOR1MgICAgICAgICAgICAweDAzCisjZGVmaW5lIEdFTkVSQUxfVEVTVF9BQ0NFU1MgICAg ICAgICAgICAgMHgwNAorCisjZGVmaW5lIERQVFhfU0VUX1BPV0VSX01ORwkJCTB4MDAKKyNkZWZp bmUgRFBUWF9TRVRfSE9TVF9DQVBBQklMSVRJRVMJCTB4MDEKKyNkZWZpbmUgRFBUWF9HRVRfRURJ RAkJCQkweDAyCisjZGVmaW5lIERQVFhfUkVBRF9EUENECQkJCTB4MDMKKyNkZWZpbmUgRFBUWF9X UklURV9EUENECQkJCTB4MDQKKyNkZWZpbmUgRFBUWF9FTkFCTEVfRVZFTlQJCQkweDA1CisjZGVm aW5lIERQVFhfV1JJVEVfUkVHSVNURVIJCQkweDA2CisjZGVmaW5lIERQVFhfUkVBRF9SRUdJU1RF UgkJCTB4MDcKKyNkZWZpbmUgRFBUWF9XUklURV9GSUVMRAkJCTB4MDgKKyNkZWZpbmUgRFBUWF9U UkFJTklOR19DT05UUk9MCQkJMHgwOQorI2RlZmluZSBEUFRYX1JFQURfRVZFTlQJCQkJMHgwYQor I2RlZmluZSBEUFRYX1JFQURfTElOS19TVEFUCQkJMHgwYgorI2RlZmluZSBEUFRYX1NFVF9WSURF TwkJCQkweDBjCisjZGVmaW5lIERQVFhfU0VUX0FVRElPCQkJCTB4MGQKKyNkZWZpbmUgRFBUWF9H RVRfTEFTVF9BVVhfU1RBVVMJCQkweDBlCisjZGVmaW5lIERQVFhfU0VUX0xJTktfQlJFQUtfUE9J TlQJCTB4MGYKKyNkZWZpbmUgRFBUWF9GT1JDRV9MQU5FUwkJCTB4MTAKKyNkZWZpbmUgRFBUWF9I UERfU1RBVEUJCQkJMHgxMQorCisjZGVmaW5lIEZXX1NUQU5EQlkJCQkJMAorI2RlZmluZSBGV19B Q1RJVkUJCQkJMQorCisjZGVmaW5lIERQVFhfRVZFTlRfRU5BQkxFX0hQRAkJCUJJVCgwKQorI2Rl ZmluZSBEUFRYX0VWRU5UX0VOQUJMRV9UUkFJTklORwkJQklUKDEpCisKKyNkZWZpbmUgTElOS19U UkFJTklOR19OT1RfQUNUSVZFCQkwCisjZGVmaW5lIExJTktfVFJBSU5JTkdfUlVOCQkJMQorI2Rl ZmluZSBMSU5LX1RSQUlOSU5HX1JFU1RBUlQJCQkyCisKKyNkZWZpbmUgQ09OVFJPTF9WSURFT19J RExFCQkJMAorI2RlZmluZSBDT05UUk9MX1ZJREVPX1ZBTElECQkJMQorCisjZGVmaW5lIFZJRl9C WVBBU1NfSU5URVJMQUNFCQkJQklUKDEzKQorI2RlZmluZSBJTlRFUkxBQ0VfRk1UX0RFVAkJCUJJ VCgxMikKKyNkZWZpbmUgSU5URVJMQUNFX0RUQ1RfV0lOCQkJMHgyMAorCisjZGVmaW5lIERQX0ZS QU1FUl9TUF9JTlRFUkxBQ0VfRU4JCUJJVCgyKQorI2RlZmluZSBEUF9GUkFNRVJfU1BfSFNQCQkJ QklUKDEpCisjZGVmaW5lIERQX0ZSQU1FUl9TUF9WU1AJCQlCSVQoMCkKKworLyogY2FwYWJpbGl0 eSAqLworI2RlZmluZSBBVVhfSE9TVF9JTlZFUlQJCQkJMworI2RlZmluZQlGQVNUX0xUX1NVUFBP UlQJCQkJMQorI2RlZmluZSBGQVNUX0xUX05PVF9TVVBQT1JUCQkJMAorI2RlZmluZSBMQU5FX01B UFBJTkdfTk9STUFMCQkJMHgxYgorI2RlZmluZSBMQU5FX01BUFBJTkdfRkxJUFBFRAkJCTB4ZTQK KyNkZWZpbmUgRU5IQU5DRUQJCQkJMQorCisjZGVmaW5lCUZVTExfTFRfU1RBUlRFRAkJCQlCSVQo MCkKKyNkZWZpbmUgRkFTRV9MVF9TVEFSVEVECQkJCUJJVCgxKQorI2RlZmluZSBDTEtfUkVDT1ZF UllfRklOSVNIRUQJCQlCSVQoMikKKyNkZWZpbmUgRVFfUEhBU0VfRklOSVNIRUQJCQlCSVQoMykK KyNkZWZpbmUgRkFTRV9MVF9TVEFSVF9GSU5JU0hFRAkJCUJJVCg0KQorI2RlZmluZSBDTEtfUkVD T1ZFUllfRkFJTEVECQkJQklUKDUpCisjZGVmaW5lIEVRX1BIQVNFX0ZBSUxFRAkJCQlCSVQoNikK KyNkZWZpbmUgRkFTRV9MVF9GQUlMRUQJCQkJQklUKDcpCisKKyNkZWZpbmUgRFBUWF9IUERfRVZF TlQJCQkJQklUKDApCisjZGVmaW5lIERQVFhfVFJBSU5JTkdfRVZFTlQJCQlCSVQoMSkKKyNkZWZp bmUgSERDUF9UWF9TVEFUVVNfRVZFTlQJCQlCSVQoNCkKKyNkZWZpbmUgSERDUDJfVFhfSVNfS01f U1RPUkVEX0VWRU5UCQlCSVQoNSkKKyNkZWZpbmUgSERDUDJfVFhfU1RPUkVfS01fRVZFTlQJCQlC SVQoNikKKyNkZWZpbmUgSERDUF9UWF9JU19SRUNFSVZFUl9JRF9WQUxJRF9FVkVOVAlCSVQoNykK KworI2RlZmluZSBUVV9TSVpFCQkJCQkzMAorI2RlZmluZSBDRE5fRFBfTUFYX0xJTktfUkFURQkJ CURQX0xJTktfQldfNV80CisKKy8qIGF1ZGlvICovCisjZGVmaW5lIEFVRElPX1BBQ0tfRU4JCQkJ QklUKDgpCisjZGVmaW5lIFNBTVBMSU5HX0ZSRVEoeCkJCQkoKCh4KSAmIDB4ZikgPDwgMTYpCisj ZGVmaW5lIE9SSUdJTkFMX1NBTVBfRlJFUSh4KQkJCSgoKHgpICYgMHhmKSA8PCAyNCkKKyNkZWZp bmUgU1lOQ19XUl9UT19DSF9aRVJPCQkJQklUKDEpCisjZGVmaW5lIEkyU19ERUNfU1RBUlQJCQkJ QklUKDEpCisjZGVmaW5lIEFVRElPX1NXX1JTVAkJCQlCSVQoMCkKKyNkZWZpbmUgU01QTDJQS1Rf RU4JCQkJQklUKDEpCisjZGVmaW5lIE1BWF9OVU1fQ0goeCkJCQkJKCgoeCkgJiAweDFmKSAtIDEp CisjZGVmaW5lIE5VTV9PRl9JMlNfUE9SVFMoeCkJCQkoKCgoeCkgLyAyIC0gMSkgJiAweDMpIDw8 IDUpCisjZGVmaW5lIEFVRElPX1RZUEVfTFBDTQkJCQkoMiA8PCA3KQorI2RlZmluZSBDRkdfU1VC X1BDS1RfTlVNKHgpCQkJKCgoKHgpIC0gMSkgJiAweDcpIDw8IDExKQorI2RlZmluZSBBVURJT19D SF9OVU0oeCkJCQkJKCgoKHgpIC0gMSkgJiAweDFmKSA8PCAyKQorI2RlZmluZSBUUkFOU19TTVBM X1dJRFRIXzE2CQkJMAorI2RlZmluZSBUUkFOU19TTVBMX1dJRFRIXzI0CQkJQklUKDExKQorI2Rl ZmluZSBUUkFOU19TTVBMX1dJRFRIXzMyCQkJKDIgPDwgMTEpCisjZGVmaW5lIEkyU19ERUNfUE9S VF9FTih4KQkJCSgoKHgpICYgMHhmKSA8PCAxNykKKyNkZWZpbmUgU1BESUZfRU5BQkxFCQkJCUJJ VCgyMSkKKyNkZWZpbmUgU1BESUZfQVZHX1NFTAkJCQlCSVQoMjApCisjZGVmaW5lIFNQRElGX0pJ VFRFUl9CWVBBU1MJCQlCSVQoMTkpCisjZGVmaW5lIFNQRElGX0ZJRk9fTUlEX1JBTkdFKHgpCQkJ KCgoeCkgJiAweGZmKSA8PCAxMSkKKyNkZWZpbmUgU1BESUZfSklUVEVSX1RIUlNIKHgpCQkJKCgo eCkgJiAweGZmKSA8PCAzKQorI2RlZmluZSBTUERJRl9KSVRURVJfQVZHX1dJTih4KQkJCSgoeCkg JiAweDcpCisKKy8qIFJlZmVybmNlIGN5Y2xlcyB3aGVuIHVzaW5nIGxhbmUgY2xvY2sgYXMgcmVm ZXJuY2UgKi8KKyNkZWZpbmUgTEFORV9SRUZfQ1lDCQkJCTB4ODAwMAorCitlbnVtIHZvbHRhZ2Vf c3dpbmdfbGV2ZWwgeworCVZPTFRBR0VfTEVWRUxfMCwKKwlWT0xUQUdFX0xFVkVMXzEsCisJVk9M VEFHRV9MRVZFTF8yLAorCVZPTFRBR0VfTEVWRUxfMywKK307CisKK2VudW0gcHJlX2VtcGhhc2lz X2xldmVsIHsKKwlQUkVfRU1QSEFTSVNfTEVWRUxfMCwKKwlQUkVfRU1QSEFTSVNfTEVWRUxfMSwK KwlQUkVfRU1QSEFTSVNfTEVWRUxfMiwKKwlQUkVfRU1QSEFTSVNfTEVWRUxfMywKK307CisKK2Vu dW0gcGF0dGVybl9zZXQgeworCVBUUzEJCT0gQklUKDApLAorCVBUUzIJCT0gQklUKDEpLAorCVBU UzMJCT0gQklUKDIpLAorCVBUUzQJCT0gQklUKDMpLAorCURQX05PTkUJCT0gQklUKDQpCit9Owor CitlbnVtIHZpY19jb2xvcl9kZXB0aCB7CisJQkNTXzYgPSAweDEsCisJQkNTXzggPSAweDIsCisJ QkNTXzEwID0gMHg0LAorCUJDU18xMiA9IDB4OCwKKwlCQ1NfMTYgPSAweDEwLAorfTsKKworZW51 bSB2aWNfYnRfdHlwZSB7CisJQlRfNjAxID0gMHgwLAorCUJUXzcwOSA9IDB4MSwKK307CisKK3Zv aWQgY2RuX2RwX2Nsb2NrX3Jlc2V0KHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCk7CisKK3ZvaWQg Y2RuX2RwX3NldF9md19jbGsoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLCB1MzIgY2xrKTsKK2lu dCBjZG5fZHBfbG9hZF9maXJtd2FyZShzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAsIGNvbnN0IHUz MiAqaV9tZW0sCisJCQkgdTMyIGlfc2l6ZSwgY29uc3QgdTMyICpkX21lbSwgdTMyIGRfc2l6ZSk7 CitpbnQgY2RuX2RwX3NldF9maXJtd2FyZV9hY3RpdmUoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRw LCBib29sIGVuYWJsZSk7CitpbnQgY2RuX2RwX3NldF9ob3N0X2NhcChzdHJ1Y3QgY2RuX2RwX2Rl dmljZSAqZHAsIHU4IGxhbmVzLCBib29sIGZsaXApOworaW50IGNkbl9kcF9ldmVudF9jb25maWco c3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwKTsKK3UzMiBjZG5fZHBfZ2V0X2V2ZW50KHN0cnVjdCBj ZG5fZHBfZGV2aWNlICpkcCk7CitpbnQgY2RuX2RwX2dldF9ocGRfc3RhdHVzKHN0cnVjdCBjZG5f ZHBfZGV2aWNlICpkcCk7CitpbnQgY2RuX2RwX2RwY2Rfd3JpdGUoc3RydWN0IGNkbl9kcF9kZXZp Y2UgKmRwLCB1MzIgYWRkciwgdTggdmFsdWUpOworaW50IGNkbl9kcF9kcGNkX3JlYWQoc3RydWN0 IGNkbl9kcF9kZXZpY2UgKmRwLCB1MzIgYWRkciwgdTggKmRhdGEsIHUxNiBsZW4pOworaW50IGNk bl9kcF9nZXRfZWRpZF9ibG9jayh2b2lkICpkcCwgdTggKmVkaWQsCisJCQkgIHVuc2lnbmVkIGlu dCBibG9jaywgc2l6ZV90IGxlbmd0aCk7CitpbnQgY2RuX2RwX3RyYWluaW5nX3N0YXJ0KHN0cnVj dCBjZG5fZHBfZGV2aWNlICpkcCk7CitpbnQgY2RuX2RwX2dldF90cmFpbmluZ19zdGF0dXMoc3Ry dWN0IGNkbl9kcF9kZXZpY2UgKmRwKTsKK2ludCBjZG5fZHBfc2V0X3ZpZGVvX3N0YXR1cyhzdHJ1 Y3QgY2RuX2RwX2RldmljZSAqZHAsIGludCBhY3RpdmUpOworaW50IGNkbl9kcF9jb25maWdfdmlk ZW8oc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwKTsKK2ludCBjZG5fZHBfYXVkaW9fc3RvcChzdHJ1 Y3QgY2RuX2RwX2RldmljZSAqZHAsIHN0cnVjdCBhdWRpb19pbmZvICphdWRpbyk7CitpbnQgY2Ru X2RwX2F1ZGlvX211dGUoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLCBib29sIGVuYWJsZSk7Citp bnQgY2RuX2RwX2F1ZGlvX2NvbmZpZyhzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAsIHN0cnVjdCBh dWRpb19pbmZvICphdWRpbyk7CisjZW5kaWYgLyogX0NETl9EUF9SRUdfSCAqLwpkaWZmIC0tZ2l0 IGEvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL3JvY2tjaGlwX2RybV92b3AuYyBiL2RyaXZlcnMv Z3B1L2RybS9yb2NrY2hpcC9yb2NrY2hpcF9kcm1fdm9wLmMKaW5kZXggYTcxMTU4OS4uY2M3M2Q1 NiAxMDA2NDQKLS0tIGEvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL3JvY2tjaGlwX2RybV92b3Au YworKysgYi9kcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvcm9ja2NoaXBfZHJtX3ZvcC5jCkBAIC0x MDQ4LDkgKzEwNDgsMTEgQEAgc3RhdGljIHZvaWQgdm9wX2NydGNfZW5hYmxlKHN0cnVjdCBkcm1f Y3J0YyAqY3J0YykKIAkJdm9wX2RzcF9ob2xkX3ZhbGlkX2lycV9kaXNhYmxlKHZvcCk7CiAJfQog Ci0JcGluX3BvbCA9IDB4ODsKLQlwaW5fcG9sIHw9IChhZGp1c3RlZF9tb2RlLT5mbGFncyAmIERS TV9NT0RFX0ZMQUdfTkhTWU5DKSA/IDAgOiAxOwotCXBpbl9wb2wgfD0gKGFkanVzdGVkX21vZGUt PmZsYWdzICYgRFJNX01PREVfRkxBR19OVlNZTkMpID8gMCA6ICgxIDw8IDEpOworCXBpbl9wb2wg PSBCSVQoRENMS19JTlZFUlQpOworCXBpbl9wb2wgfD0gKGFkanVzdGVkX21vZGUtPmZsYWdzICYg RFJNX01PREVfRkxBR19OSFNZTkMpID8KKwkJICAgMCA6IEJJVChIU1lOQ19QT1NJVElWRSk7CisJ cGluX3BvbCB8PSAoYWRqdXN0ZWRfbW9kZS0+ZmxhZ3MgJiBEUk1fTU9ERV9GTEFHX05WU1lOQykg PworCQkgICAwIDogQklUKFZTWU5DX1BPU0lUSVZFKTsKIAlWT1BfQ1RSTF9TRVQodm9wLCBwaW5f cG9sLCBwaW5fcG9sKTsKIAogCXN3aXRjaCAocy0+b3V0cHV0X3R5cGUpIHsKQEAgLTEwNzAsNiAr MTA3MiwxMSBAQCBzdGF0aWMgdm9pZCB2b3BfY3J0Y19lbmFibGUoc3RydWN0IGRybV9jcnRjICpj cnRjKQogCQlWT1BfQ1RSTF9TRVQodm9wLCBtaXBpX3Bpbl9wb2wsIHBpbl9wb2wpOwogCQlWT1Bf Q1RSTF9TRVQodm9wLCBtaXBpX2VuLCAxKTsKIAkJYnJlYWs7CisJY2FzZSBEUk1fTU9ERV9DT05O RUNUT1JfRGlzcGxheVBvcnQ6CisJCXBpbl9wb2wgJj0gfkJJVChEQ0xLX0lOVkVSVCk7CisJCVZP UF9DVFJMX1NFVCh2b3AsIGRwX3Bpbl9wb2wsIHBpbl9wb2wpOworCQlWT1BfQ1RSTF9TRVQodm9w LCBkcF9lbiwgMSk7CisJCWJyZWFrOwogCWRlZmF1bHQ6CiAJCURSTV9ERVZfRVJST1Iodm9wLT5k ZXYsICJ1bnN1cHBvcnRlZCBjb25uZWN0b3JfdHlwZSBbJWRdXG4iLAogCQkJICAgICAgcy0+b3V0 cHV0X3R5cGUpOwpkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL3JvY2tjaGlw X2RybV92b3AuaCBiL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9yb2NrY2hpcF9kcm1fdm9wLmgK aW5kZXggMWRiYzUyNi4uNWE0ZmFhODUgMTAwNjQ0Ci0tLSBhL2RyaXZlcnMvZ3B1L2RybS9yb2Nr Y2hpcC9yb2NrY2hpcF9kcm1fdm9wLmgKKysrIGIvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL3Jv Y2tjaGlwX2RybV92b3AuaApAQCAtNDUsNiArNDUsNyBAQCBzdHJ1Y3Qgdm9wX2N0cmwgewogCXN0 cnVjdCB2b3BfcmVnIGVkcF9lbjsKIAlzdHJ1Y3Qgdm9wX3JlZyBoZG1pX2VuOwogCXN0cnVjdCB2 b3BfcmVnIG1pcGlfZW47CisJc3RydWN0IHZvcF9yZWcgZHBfZW47CiAJc3RydWN0IHZvcF9yZWcg b3V0X21vZGU7CiAJc3RydWN0IHZvcF9yZWcgZGl0aGVyX2Rvd247CiAJc3RydWN0IHZvcF9yZWcg ZGl0aGVyX3VwOwpAQCAtNTMsNiArNTQsNyBAQCBzdHJ1Y3Qgdm9wX2N0cmwgewogCXN0cnVjdCB2 b3BfcmVnIGhkbWlfcGluX3BvbDsKIAlzdHJ1Y3Qgdm9wX3JlZyBlZHBfcGluX3BvbDsKIAlzdHJ1 Y3Qgdm9wX3JlZyBtaXBpX3Bpbl9wb2w7CisJc3RydWN0IHZvcF9yZWcgZHBfcGluX3BvbDsKIAog CXN0cnVjdCB2b3BfcmVnIGh0b3RhbF9wdzsKIAlzdHJ1Y3Qgdm9wX3JlZyBoYWN0X3N0X2VuZDsK QEAgLTI0NCw2ICsyNDYsMTMgQEAgZW51bSBzY2FsZV9kb3duX21vZGUgewogCVNDQUxFX0RPV05f QVZHID0gMHgxCiB9OwogCitlbnVtIHZvcF9wb2wgeworCUhTWU5DX1BPU0lUSVZFID0gMCwKKwlW U1lOQ19QT1NJVElWRSA9IDEsCisJREVOX05FR0FUSVZFICAgPSAyLAorCURDTEtfSU5WRVJUICAg ID0gMworfTsKKwogI2RlZmluZSBGUkFDXzE2XzE2KG11bHQsIGRpdikgICAgKCgobXVsdCkgPDwg MTYpIC8gKGRpdikpCiAjZGVmaW5lIFNDTF9GVF9ERUZBVUxUX0ZJWFBPSU5UX1NISUZUCTEyCiAj ZGVmaW5lIFNDTF9NQVhfVlNLSVBMSU5FUwkJNApkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJt L3JvY2tjaGlwL3JvY2tjaGlwX3ZvcF9yZWcuYyBiL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9y b2NrY2hpcF92b3BfcmVnLmMKaW5kZXggZWVhODQyNy4uYWFlZGU2YiAxMDA2NDQKLS0tIGEvZHJp dmVycy9ncHUvZHJtL3JvY2tjaGlwL3JvY2tjaGlwX3ZvcF9yZWcuYworKysgYi9kcml2ZXJzL2dw dS9kcm0vcm9ja2NoaXAvcm9ja2NoaXBfdm9wX3JlZy5jCkBAIC0yODMsNiArMjgzLDcgQEAgc3Rh dGljIGNvbnN0IHN0cnVjdCB2b3BfZGF0YSByazMyODhfdm9wID0gewogc3RhdGljIGNvbnN0IHN0 cnVjdCB2b3BfY3RybCByazMzOTlfY3RybF9kYXRhID0gewogCS5zdGFuZGJ5ID0gVk9QX1JFRyhS SzMzOTlfU1lTX0NUUkwsIDB4MSwgMjIpLAogCS5nYXRlX2VuID0gVk9QX1JFRyhSSzMzOTlfU1lT X0NUUkwsIDB4MSwgMjMpLAorCS5kcF9lbiA9IFZPUF9SRUcoUkszMzk5X1NZU19DVFJMLCAweDEs IDExKSwKIAkucmdiX2VuID0gVk9QX1JFRyhSSzMzOTlfU1lTX0NUUkwsIDB4MSwgMTIpLAogCS5o ZG1pX2VuID0gVk9QX1JFRyhSSzMzOTlfU1lTX0NUUkwsIDB4MSwgMTMpLAogCS5lZHBfZW4gPSBW T1BfUkVHKFJLMzM5OV9TWVNfQ1RSTCwgMHgxLCAxNCksCkBAIC0yOTIsNiArMjkzLDcgQEAgc3Rh dGljIGNvbnN0IHN0cnVjdCB2b3BfY3RybCByazMzOTlfY3RybF9kYXRhID0gewogCS5kYXRhX2Js YW5rID0gVk9QX1JFRyhSSzMzOTlfRFNQX0NUUkwwLCAweDEsIDE5KSwKIAkub3V0X21vZGUgPSBW T1BfUkVHKFJLMzM5OV9EU1BfQ1RSTDAsIDB4ZiwgMCksCiAJLnJnYl9waW5fcG9sID0gVk9QX1JF RyhSSzMzOTlfRFNQX0NUUkwxLCAweGYsIDE2KSwKKwkuZHBfcGluX3BvbCA9IFZPUF9SRUcoUksz Mzk5X0RTUF9DVFJMMSwgMHhmLCAxNiksCiAJLmhkbWlfcGluX3BvbCA9IFZPUF9SRUcoUkszMzk5 X0RTUF9DVFJMMSwgMHhmLCAyMCksCiAJLmVkcF9waW5fcG9sID0gVk9QX1JFRyhSSzMzOTlfRFNQ X0NUUkwxLCAweGYsIDI0KSwKIAkubWlwaV9waW5fcG9sID0gVk9QX1JFRyhSSzMzOTlfRFNQX0NU UkwxLCAweGYsIDI4KSwKLS0gCjEuOS4xCgpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fX19fX19fXwpkcmktZGV2ZWwgbWFpbGluZyBsaXN0CmRyaS1kZXZlbEBsaXN0cy5m cmVlZGVza3RvcC5vcmcKaHR0cHM6Ly9saXN0cy5mcmVlZGVza3RvcC5vcmcvbWFpbG1hbi9saXN0 aW5mby9kcmktZGV2ZWwK From mboxrd@z Thu Jan 1 00:00:00 1970 From: zyw@rock-chips.com (Chris Zhong) Date: Fri, 9 Sep 2016 19:15:46 -0700 Subject: [PATCH v15 3/5] drm/rockchip: cdn-dp: add cdn DP support for rk3399 In-Reply-To: <1473473748-22331-1-git-send-email-zyw@rock-chips.com> References: <1473473748-22331-1-git-send-email-zyw@rock-chips.com> Message-ID: <1473473748-22331-4-git-send-email-zyw@rock-chips.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Add support for cdn DP controller which is embedded in the rk3399 SoCs. The DP is compliant with DisplayPort Specification, Version 1.3, This IP is compatible with the rockchip type-c PHY IP. There is a uCPU in DP controller, it need a firmware to work, please put the firmware file to /lib/firmware/rockchip/dptx.bin. The uCPU in charge of aux communication and link training, the host use mailbox to communicate with the ucpu. The dclk pin_pol of vop must not be invert for DP. Signed-off-by: Chris Zhong Signed-off-by: Sean Paul Reviewed-by: Sean Paul Acked-by: Mark Yao --- Changes in v15: Chris Zhong's changes: - fix disable phy unbalance - support Apple Dock hot-plug in HDMI port - retraining when Apple Dock hpd irq coming Sean Paul's changes: - Restructured the worker - Synchronized between worker & drm hooks - Properly implemented enable/disable - Added error checking - Use devm variant of extcon - Use DRM_DEV_* logging - Refactored code to (hopefully) be more clear Changes in v14: - Modify some grammatical errors - remove the mutex around cdn_dp_audio_get_eld - power on the power domain after clk_enable - retry to read edid - change super speed property name to EXTCON_PROP_USB_SS - do a correct mode_valid check when bpc is 0 Changes in v13: - support suspend/resume - switch power domain dynamically - re-training when hpd signal is triggered Changes in v12: - use EXTCON_PROP_USB_SUPERSPEED to replace EXTCON_USB_HOST Changes in v11: - add best_encoder back, since it required by drm_atomic_helper_check Changes in v10: - remove best_encoder ops - support read sink count from DPCD - control the grf_clk in DP Changes in v9: - do not need reset the phy before power_on - add a orientation information for set_capability - retry to read dpcd in 10 seconds Changes in v8: - optimization the err log Changes in v7: - support firmware standby when no dptx connection - optimization the calculation of tu size and valid symbol Changes in v6: - add a port struct - select SND_SOC_HDMI_CODEC - force reset the phy when hpd detected Changes in v5: - alphabetical order - do not use long, use u32 or u64 - return MODE_CLOCK_HIGH when requested > actual - Optimized Coding Style - add a formula to get better tu size and symbol value. - modify according to Sean Paul's comments - fixed the fw_wait always 0 Changes in v4: - use phy framework to control DP phy - support 2 phys Changes in v3: - use EXTCON_DISP_DP and EXTCON_DISP_DP_ALT cable to get dp port state. - reset spdif before config it - modify the firmware clk to 100Mhz - retry load firmware if fw file is requested too early Changes in v2: - Alphabetic order - remove excess error message - use define clk_rate - check all return value - remove dev_set_name(dp->dev, "cdn-dp"); - use schedule_delayed_work - remove never-called functions - remove some unnecessary () Changes in v1: - use extcon API - use hdmi-codec for the DP Asoc - do not initialize the "ret" - printk a err log when drm_of_encoder_active_endpoint_id - modify the dclk pin_pol to a single line drivers/gpu/drm/rockchip/Kconfig | 10 + drivers/gpu/drm/rockchip/Makefile | 1 + drivers/gpu/drm/rockchip/cdn-dp-core.c | 1161 +++++++++++++++++++++++++++ drivers/gpu/drm/rockchip/cdn-dp-core.h | 108 +++ drivers/gpu/drm/rockchip/cdn-dp-reg.c | 956 ++++++++++++++++++++++ drivers/gpu/drm/rockchip/cdn-dp-reg.h | 482 +++++++++++ drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 13 +- drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 9 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 2 + 9 files changed, 2739 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-core.c create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-core.h create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.c create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.h diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index d30bdc3..20aaafe 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -25,6 +25,16 @@ config ROCKCHIP_ANALOGIX_DP for the Analogix Core DP driver. If you want to enable DP on RK3288 based SoC, you should selet this option. +config ROCKCHIP_CDN_DP + tristate "Rockchip cdn DP" + depends on DRM_ROCKCHIP + select SND_SOC_HDMI_CODEC if SND_SOC + help + This selects support for Rockchip SoC specific extensions + for the cdn DP driver. If you want to enable Dp on + RK3399 based SoC, you should select this + option. + config ROCKCHIP_DW_HDMI tristate "Rockchip specific extensions for Synopsys DW HDMI" depends on DRM_ROCKCHIP diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 9746365..6a07809 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -7,6 +7,7 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o +obj-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o obj-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c new file mode 100644 index 0000000..8d708d3 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -0,0 +1,1161 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" +#include "rockchip_drm_vop.h" + +#define connector_to_dp(c) \ + container_of(c, struct cdn_dp_device, connector) + +#define encoder_to_dp(c) \ + container_of(c, struct cdn_dp_device, encoder) + +#define GRF_SOC_CON9 0x6224 +#define DP_SEL_VOP_LIT BIT(12) +#define GRF_SOC_CON26 0x6268 +#define UPHY_SEL_BIT 3 +#define UPHY_SEL_MASK BIT(19) +#define DPTX_HPD_SEL (3 << 12) +#define DPTX_HPD_DEL (2 << 12) +#define DPTX_HPD_SEL_MASK (3 << 28) + +#define CDN_FW_TIMEOUT_MS (64 * 1000) +#define CDN_DPCD_TIMEOUT_MS 5000 +#define CDN_DP_FIRMWARE "rockchip/dptx.bin" + +struct cdn_dp_data { + u8 max_phy; +}; + +struct cdn_dp_data rk3399_cdn_dp = { + .max_phy = 2, +}; + +static const struct of_device_id cdn_dp_dt_ids[] = { + { .compatible = "rockchip,rk3399-cdn-dp", + .data = (void *)&rk3399_cdn_dp }, + {} +}; + +MODULE_DEVICE_TABLE(of, cdn_dp_dt_ids); + +static int cdn_dp_grf_write(struct cdn_dp_device *dp, + unsigned int reg, unsigned int val) +{ + int ret; + + ret = clk_prepare_enable(dp->grf_clk); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Failed to prepare_enable grf clock\n"); + return ret; + } + + ret = regmap_write(dp->grf, reg, val); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Could not write to GRF: %d\n", ret); + return ret; + } + + clk_disable_unprepare(dp->grf_clk); + + return 0; +} + +static int cdn_dp_clk_enable(struct cdn_dp_device *dp) +{ + int ret; + u32 rate; + + ret = clk_prepare_enable(dp->pclk); + if (ret < 0) { + DRM_DEV_ERROR(dp->dev, "cannot enable dp pclk %d\n", ret); + goto err_pclk; + } + + ret = clk_prepare_enable(dp->core_clk); + if (ret < 0) { + DRM_DEV_ERROR(dp->dev, "cannot enable core_clk %d\n", ret); + goto err_core_clk; + } + + ret = pm_runtime_get_sync(dp->dev); + if (ret < 0) { + DRM_DEV_ERROR(dp->dev, "cannot get pm runtime %d\n", ret); + goto err_pclk; + } + + reset_control_assert(dp->dptx_rst); + reset_control_assert(dp->apb_rst); + reset_control_deassert(dp->dptx_rst); + reset_control_deassert(dp->apb_rst); + + rate = clk_get_rate(dp->core_clk); + if (rate < 0) { + DRM_DEV_ERROR(dp->dev, "get clk rate failed: %d\n", rate); + goto err_set_rate; + } + + cdn_dp_set_fw_clk(dp, rate); + cdn_dp_clock_reset(dp); + + return 0; + +err_set_rate: + clk_disable_unprepare(dp->core_clk); +err_core_clk: + clk_disable_unprepare(dp->pclk); +err_pclk: + return ret; +} + +static void cdn_dp_clk_disable(struct cdn_dp_device *dp) +{ + pm_runtime_put_sync(dp->dev); + clk_disable_unprepare(dp->pclk); + clk_disable_unprepare(dp->core_clk); +} + +static int cdn_dp_get_port_lanes(struct cdn_dp_port *port) +{ + struct extcon_dev *edev = port->extcon; + union extcon_property_value property; + u8 lanes = 0; + int dptx; + + dptx = extcon_get_state(edev, EXTCON_DISP_DP); + if (dptx > 0) { + extcon_get_property(edev, EXTCON_DISP_DP, + EXTCON_PROP_USB_SS, &property); + if (property.intval) + lanes = 2; + else + lanes = 4; + } + + return lanes; +} + +static struct cdn_dp_port *cdn_dp_connected_port(struct cdn_dp_device *dp) +{ + struct cdn_dp_port *port; + int i, lanes; + + if (dp->no_sink) + return NULL; + + for (i = 0; i < dp->ports; i++) { + port = dp->port[i]; + lanes = cdn_dp_get_port_lanes(port); + if (lanes) + return port; + } + return NULL; +} + +static enum drm_connector_status +cdn_dp_connector_detect(struct drm_connector *connector, bool force) +{ + struct cdn_dp_device *dp = connector_to_dp(connector); + enum drm_connector_status status = connector_status_disconnected; + + mutex_lock(&dp->lock); + if (dp->active && dp->enabled) + status = connector_status_connected; + mutex_unlock(&dp->lock); + + return status; +} + +static void cdn_dp_connector_destroy(struct drm_connector *connector) +{ + drm_connector_unregister(connector); + drm_connector_cleanup(connector); +} + +static struct drm_connector_funcs cdn_dp_atomic_connector_funcs = { + .dpms = drm_atomic_helper_connector_dpms, + .detect = cdn_dp_connector_detect, + .destroy = cdn_dp_connector_destroy, + .fill_modes = drm_helper_probe_single_connector_modes, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int cdn_dp_connector_get_modes(struct drm_connector *connector) +{ + struct cdn_dp_device *dp = connector_to_dp(connector); + struct edid *edid; + int ret = 0; + + mutex_lock(&dp->lock); + if (WARN_ON(!dp->fw_loaded)) + goto out; + + edid = drm_do_get_edid(connector, cdn_dp_get_edid_block, dp); + if (edid) { + DRM_DEV_DEBUG_KMS(dp->dev, "got edid: width[%d] x height[%d]\n", + edid->width_cm, edid->height_cm); + + dp->sink_has_audio = drm_detect_monitor_audio(edid); + ret = drm_add_edid_modes(connector, edid); + if (ret) { + drm_mode_connector_update_edid_property(connector, + edid); + drm_edid_to_eld(connector, edid); + } + kfree(edid); + } + +out: + mutex_unlock(&dp->lock); + return ret; +} + +static struct drm_encoder * +cdn_dp_connector_best_encoder(struct drm_connector *connector) +{ + struct cdn_dp_device *dp = connector_to_dp(connector); + + return &dp->encoder; +} + +static int cdn_dp_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct cdn_dp_device *dp = connector_to_dp(connector); + struct drm_display_info *display_info = &dp->connector.display_info; + u32 requested, actual, rate, sink_max, source_max = 0; + u8 lanes, bpc, i; + + switch (display_info->bpc) { + case 16: + case 12: + case 10: + bpc = 10; + break; + case 6: + bpc = 6; + break; + default: + bpc = 8; + break; + } + + requested = mode->clock * bpc * 3 / 1000; + + /* find the running port */ + for (i = 0; i < dp->ports; i++) { + if (dp->port[i]->phy_enabled) { + source_max = dp->port[i]->lanes; + break; + } + } + + sink_max = drm_dp_max_lane_count(dp->dpcd); + lanes = min(source_max, sink_max); + + source_max = drm_dp_bw_code_to_link_rate(CDN_DP_MAX_LINK_RATE); + sink_max = drm_dp_max_link_rate(dp->dpcd); + rate = min(source_max, sink_max); + + actual = rate * lanes / 100; + + /* efficiency is about 0.8 */ + actual = actual * 8 / 10; + + if (requested > actual) { + DRM_DEV_DEBUG_KMS(dp->dev, + "requested=%d, actual=%d, clock=%d\n", + requested, actual, mode->clock); + return MODE_CLOCK_HIGH; + } + + return MODE_OK; +} + +static struct drm_connector_helper_funcs cdn_dp_connector_helper_funcs = { + .get_modes = cdn_dp_connector_get_modes, + .best_encoder = cdn_dp_connector_best_encoder, + .mode_valid = cdn_dp_connector_mode_valid, +}; + +static int cdn_dp_firmware_init(struct cdn_dp_device *dp) +{ + int ret; + const u32 *iram_data, *dram_data; + const struct firmware *fw = dp->fw; + const struct cdn_firmware_header *hdr; + + hdr = (struct cdn_firmware_header *)fw->data; + if (fw->size != le32_to_cpu(hdr->size_bytes)) { + DRM_DEV_ERROR(dp->dev, "firmware is invalid\n"); + return -EINVAL; + } + + iram_data = (const u32 *)(fw->data + hdr->header_size); + dram_data = (const u32 *)(fw->data + hdr->header_size + hdr->iram_size); + + ret = cdn_dp_load_firmware(dp, iram_data, hdr->iram_size, + dram_data, hdr->dram_size); + if (ret) + return ret; + + ret = cdn_dp_set_firmware_active(dp, true); + if (ret) { + DRM_DEV_ERROR(dp->dev, "active ucpu failed: %d\n", ret); + return ret; + } + + return cdn_dp_event_config(dp); +} + +static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp, + struct cdn_dp_port *port) +{ + u8 sink_count; + int ret; + unsigned long timeout = jiffies + msecs_to_jiffies(CDN_DPCD_TIMEOUT_MS); + + /* + * Attempt to read sink count & sink capability, retry in case the sink + * may not be ready. + * + * Sinks are *supposed* to come up within 1ms from an off state, but + * some docks need more time to power up. + */ + while (time_before(jiffies, timeout)) { + ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, &sink_count, 1); + if (!ret) { + DRM_DEV_DEBUG_KMS(dp->dev, "get dpcd success!\n"); + + sink_count = DP_GET_SINK_COUNT(sink_count); + if (!sink_count) { + DRM_DEV_ERROR(dp->dev, "Sink count is 0\n"); + return -ENODEV; + } + + ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, + DP_RECEIVER_CAP_SIZE); + if (ret) + continue; + + return 0; + + } else if (!extcon_get_state(port->extcon, EXTCON_DISP_DP)) { + break; + } + usleep_range(5000, 10000); + } + + dev_err(dp->dev, "get dpcd failed!\n"); + return -ETIMEDOUT; +} + +static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port) +{ + union extcon_property_value property; + int ret; + + ret = cdn_dp_grf_write(dp, GRF_SOC_CON26, + (port->id << UPHY_SEL_BIT) | UPHY_SEL_MASK); + if (ret) + return ret; + + if (!port->phy_enabled) { + ret = phy_power_on(port->phy); + if (ret) { + DRM_DEV_ERROR(dp->dev, "phy power on failed: %d\n", + ret); + goto err_phy; + } + port->phy_enabled = true; + } + + ret = cdn_dp_grf_write(dp, GRF_SOC_CON26, + DPTX_HPD_SEL_MASK | DPTX_HPD_SEL); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Failed to write HPD_SEL %d\n", ret); + goto err_power_on; + } + + ret = cdn_dp_get_hpd_status(dp); + if (ret <= 0) { + if (!ret) + DRM_DEV_ERROR(dp->dev, "hpd does not exist\n"); + goto err_power_on; + } + + ret = extcon_get_property(port->extcon, EXTCON_DISP_DP, + EXTCON_PROP_USB_TYPEC_POLARITY, &property); + if (ret) { + DRM_DEV_ERROR(dp->dev, "get property failed\n"); + goto err_power_on; + } + + port->lanes = cdn_dp_get_port_lanes(port); + ret = cdn_dp_set_host_cap(dp, port->lanes, property.intval); + if (ret) { + DRM_DEV_ERROR(dp->dev, "set host capabilities failed: %d\n", + ret); + goto err_power_on; + } + + return 0; + +err_power_on: + if (phy_power_off(port->phy)) + DRM_DEV_ERROR(dp->dev, "phy power off failed: %d", ret); + else + port->phy_enabled = false; + +err_phy: + cdn_dp_grf_write(dp, GRF_SOC_CON26, + DPTX_HPD_SEL_MASK | DPTX_HPD_DEL); + return ret; +} + +static int cdn_dp_disable_phy(struct cdn_dp_device *dp, + struct cdn_dp_port *port) +{ + int ret; + + if (port->phy_enabled) { + ret = phy_power_off(port->phy); + if (ret) { + DRM_DEV_ERROR(dp->dev, "phy power off failed: %d", ret); + return ret; + } + } + + port->phy_enabled = false; + port->lanes = 0; + return 0; +} + +static int cdn_dp_enable(struct cdn_dp_device *dp) +{ + int ret; + struct cdn_dp_port *port; + + if (dp->active) + return 0; + + port = cdn_dp_connected_port(dp); + if (!port) { + DRM_DEV_ERROR(dp->dev, "Can't enable without connection\n"); + return -ENODEV; + } + + ret = cdn_dp_clk_enable(dp); + if (ret) + return ret; + + ret = cdn_dp_firmware_init(dp); + if (ret) { + DRM_DEV_ERROR(dp->dev, "firmware init failed: %d", ret); + goto err_clk_disable; + } + + ret = cdn_dp_enable_phy(dp, port); + if (ret) + goto err_clk_disable; + + ret = cdn_dp_get_sink_capability(dp, port); + if (ret) + goto err_phy_disable; + + dp->active = true; + return 0; + +err_phy_disable: + cdn_dp_disable_phy(dp, port); +err_clk_disable: + cdn_dp_clk_disable(dp); + return ret; +} + +static int cdn_dp_disable(struct cdn_dp_device *dp) +{ + int ret, i; + + if (!dp->active) + return 0; + + for (i = 0; i < dp->ports; i++) { + if (cdn_dp_get_port_lanes(dp->port[i])) + cdn_dp_disable_phy(dp, dp->port[i]); + } + + ret = cdn_dp_grf_write(dp, GRF_SOC_CON26, + DPTX_HPD_SEL_MASK | DPTX_HPD_DEL); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Failed to clear hpd sel %d\n", + ret); + return ret; + } + + cdn_dp_set_firmware_active(dp, false); + cdn_dp_clk_disable(dp); + dp->active = false; + dp->no_sink = false; + return 0; +} + +static void cdn_dp_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted) +{ + struct cdn_dp_device *dp = encoder_to_dp(encoder); + struct drm_display_info *display_info = &dp->connector.display_info; + struct rockchip_crtc_state *state; + struct video_info *video = &dp->video_info; + int ret, val; + + switch (display_info->bpc) { + case 16: + case 12: + case 10: + video->color_depth = 10; + break; + case 6: + video->color_depth = 6; + break; + default: + video->color_depth = 8; + break; + } + + video->color_fmt = PXL_RGB; + + video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); + video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); + + ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder); + if (ret < 0) { + DRM_DEV_ERROR(dp->dev, "Could not get vop id, %d", ret); + return; + } + + DRM_DEV_DEBUG_KMS(dp->dev, "vop %s output to cdn-dp\n", + (ret) ? "LIT" : "BIG"); + state = to_rockchip_crtc_state(encoder->crtc->state); + if (ret) { + val = DP_SEL_VOP_LIT | (DP_SEL_VOP_LIT << 16); + state->output_mode = ROCKCHIP_OUT_MODE_P888; + } else { + val = DP_SEL_VOP_LIT << 16; + state->output_mode = ROCKCHIP_OUT_MODE_AAAA; + } + + ret = cdn_dp_grf_write(dp, GRF_SOC_CON9, val); + if (ret) + return; + + memcpy(&dp->mode, adjusted, sizeof(*mode)); +} + +static void cdn_dp_encoder_enable(struct drm_encoder *encoder) +{ + struct cdn_dp_device *dp = encoder_to_dp(encoder); + int ret; + + mutex_lock(&dp->lock); + if (!dp->active) { + ret = cdn_dp_enable(dp); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Failed to enable encoder %d\n", + ret); + } + } + + ret = cdn_dp_training_start(dp); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Failed to start training %d\n", ret); + goto out; + } + + ret = cdn_dp_get_training_status(dp); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Failed to get training stat %d\n", ret); + goto out; + } + + DRM_DEV_INFO(dp->dev, "rate:0x%x, lanes:%d\n", dp->link.rate, + dp->link.num_lanes); + + if (cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE)) { + DRM_DEV_ERROR(dp->dev, "Failed to idle video\n"); + goto out; + } + + if (cdn_dp_config_video(dp)) { + DRM_DEV_ERROR(dp->dev, "Failed to config video\n"); + goto out; + } + + if (cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID)) { + DRM_DEV_ERROR(dp->dev, "Failed to valid video\n"); + goto out; + } + +out: + mutex_unlock(&dp->lock); +} + +static void cdn_dp_encoder_disable(struct drm_encoder *encoder) +{ + struct cdn_dp_device *dp = encoder_to_dp(encoder); + int ret; + + mutex_lock(&dp->lock); + if (dp->active) { + ret = cdn_dp_disable(dp); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Failed to disable encoder %d\n", + ret); + } + } + mutex_unlock(&dp->lock); +} + +static int cdn_dp_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + + s->output_mode = ROCKCHIP_OUT_MODE_AAAA; + s->output_type = DRM_MODE_CONNECTOR_DisplayPort; + + return 0; +} + +static struct drm_encoder_helper_funcs cdn_dp_encoder_helper_funcs = { + .mode_set = cdn_dp_encoder_mode_set, + .enable = cdn_dp_encoder_enable, + .disable = cdn_dp_encoder_disable, + .atomic_check = cdn_dp_encoder_atomic_check, +}; + +static struct drm_encoder_funcs cdn_dp_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static int cdn_dp_parse_dt(struct cdn_dp_device *dp) +{ + struct device *dev = dp->dev; + struct device_node *np = dev->of_node; + struct platform_device *pdev = to_platform_device(dev); + struct resource *res; + + dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); + if (IS_ERR(dp->grf)) { + DRM_DEV_ERROR(dev, "cdn-dp needs rockchip,grf property\n"); + return PTR_ERR(dp->grf); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dp->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(dp->regs)) { + DRM_DEV_ERROR(dev, "ioremap reg failed\n"); + return PTR_ERR(dp->regs); + } + + dp->core_clk = devm_clk_get(dev, "core-clk"); + if (IS_ERR(dp->core_clk)) { + DRM_DEV_ERROR(dev, "cannot get core_clk_dp\n"); + return PTR_ERR(dp->core_clk); + } + + dp->pclk = devm_clk_get(dev, "pclk"); + if (IS_ERR(dp->pclk)) { + DRM_DEV_ERROR(dev, "cannot get pclk\n"); + return PTR_ERR(dp->pclk); + } + + dp->spdif_clk = devm_clk_get(dev, "spdif"); + if (IS_ERR(dp->spdif_clk)) { + DRM_DEV_ERROR(dev, "cannot get spdif_clk\n"); + return PTR_ERR(dp->spdif_clk); + } + + dp->grf_clk = devm_clk_get(dev, "grf"); + if (IS_ERR(dp->grf_clk)) { + DRM_DEV_ERROR(dev, "cannot get grf clk\n"); + return PTR_ERR(dp->grf_clk); + } + + dp->spdif_rst = devm_reset_control_get(dev, "spdif"); + if (IS_ERR(dp->spdif_rst)) { + DRM_DEV_ERROR(dev, "no spdif reset control found\n"); + return PTR_ERR(dp->spdif_rst); + } + + dp->dptx_rst = devm_reset_control_get(dev, "dptx"); + if (IS_ERR(dp->dptx_rst)) { + DRM_DEV_ERROR(dev, "no uphy reset control found\n"); + return PTR_ERR(dp->dptx_rst); + } + + dp->apb_rst = devm_reset_control_get(dev, "apb"); + if (IS_ERR(dp->apb_rst)) { + DRM_DEV_ERROR(dev, "no apb reset control found\n"); + return PTR_ERR(dp->apb_rst); + } + + return 0; +} + +static int cdn_dp_audio_hw_params(struct device *dev, void *data, + struct hdmi_codec_daifmt *daifmt, + struct hdmi_codec_params *params) +{ + struct cdn_dp_device *dp = dev_get_drvdata(dev); + struct audio_info audio = { + .sample_width = params->sample_width, + .sample_rate = params->sample_rate, + .channels = params->channels, + }; + int ret; + + if (!dp->encoder.crtc) + return -ENODEV; + + switch (daifmt->fmt) { + case HDMI_I2S: + audio.format = AFMT_I2S; + break; + case HDMI_SPDIF: + audio.format = AFMT_SPDIF; + break; + default: + DRM_DEV_ERROR(dev, "Invalid format %d\n", daifmt->fmt); + return -EINVAL; + } + + ret = cdn_dp_audio_config(dp, &audio); + if (!ret) + dp->audio_info = audio; + + return ret; +} + +static void cdn_dp_audio_shutdown(struct device *dev, void *data) +{ + struct cdn_dp_device *dp = dev_get_drvdata(dev); + int ret; + + if (!dp->encoder.crtc) + return; + + ret = cdn_dp_audio_stop(dp, &dp->audio_info); + if (!ret) + dp->audio_info.format = AFMT_UNUSED; +} + +static int cdn_dp_audio_digital_mute(struct device *dev, void *data, + bool enable) +{ + struct cdn_dp_device *dp = dev_get_drvdata(dev); + + if (!dp->encoder.crtc) + return -ENODEV; + + return cdn_dp_audio_mute(dp, enable); +} + +static int cdn_dp_audio_get_eld(struct device *dev, void *data, + u8 *buf, size_t len) +{ + struct cdn_dp_device *dp = dev_get_drvdata(dev); + + memcpy(buf, dp->connector.eld, min(sizeof(dp->connector.eld), len)); + + return 0; +} + +static const struct hdmi_codec_ops audio_codec_ops = { + .hw_params = cdn_dp_audio_hw_params, + .audio_shutdown = cdn_dp_audio_shutdown, + .digital_mute = cdn_dp_audio_digital_mute, + .get_eld = cdn_dp_audio_get_eld, +}; + +static int cdn_dp_audio_codec_init(struct cdn_dp_device *dp, + struct device *dev) +{ + struct hdmi_codec_pdata codec_data = { + .i2s = 1, + .spdif = 1, + .ops = &audio_codec_ops, + .max_i2s_channels = 8, + }; + + dp->audio_pdev = platform_device_register_data( + dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, + &codec_data, sizeof(codec_data)); + + return PTR_ERR_OR_ZERO(dp->audio_pdev); +} + +static int cdn_dp_request_firmware(struct cdn_dp_device *dp) +{ + int ret; + unsigned long timeout = jiffies + msecs_to_jiffies(CDN_FW_TIMEOUT_MS); + unsigned long sleep = 1000; + + WARN_ON(!mutex_is_locked(&dp->lock)); + + if (dp->fw_loaded) + return 0; + + /* Drop the lock before getting the firmware to avoid blocking boot */ + mutex_unlock(&dp->lock); + + while (time_before(jiffies, timeout)) { + ret = request_firmware(&dp->fw, CDN_DP_FIRMWARE, dp->dev); + if (ret == -ENOENT) { + msleep(sleep); + sleep *= 2; + continue; + } else if (ret) { + DRM_DEV_ERROR(dp->dev, + "failed to request firmware: %d\n", ret); + goto out; + } + + dp->fw_loaded = true; + ret = 0; + goto out; + } + + DRM_DEV_ERROR(dp->dev, "Timed out trying to load firmware\n"); + ret = -ETIMEDOUT; +out: + mutex_lock(&dp->lock); + return ret; +} + +static void cdn_dp_pd_event_work(struct work_struct *work) +{ + struct cdn_dp_device *dp = container_of(work, struct cdn_dp_device, + event_work); + union extcon_property_value property; + struct cdn_dp_port *port; + int ret, i, lanes; + bool hpd_event = false; + bool re_training = false; + u8 sink_count; + + DRM_DEV_INFO(dp->dev, "Received DP hotplug event\n"); + + mutex_lock(&dp->lock); + if (!dp->enabled) + goto out; + + ret = cdn_dp_request_firmware(dp); + if (ret) + goto out; + + /* We might need to notify userspace for everything below here */ + hpd_event = true; + + /* Disable any ports that have just become inactive */ + for (i = 0; i < dp->ports; i++) { + port = dp->port[i]; + lanes = cdn_dp_get_port_lanes(port); + if (lanes && dp->active) { + extcon_get_property(port->extcon, EXTCON_DISP_DP, + EXTCON_PROP_DISP_HPD, &property); + + ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, + &sink_count, 1); + if (ret || !sink_count) { + dp->no_sink = true; + lanes = 0; + } else if (property.intval) { + re_training = true; + goto out; + } + } + + if (!lanes && port->lanes) + cdn_dp_disable_phy(dp, port); + } + + /* Power on/off the block and ports */ + if (!cdn_dp_connected_port(dp)) { + ret = cdn_dp_disable(dp); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Disable dp failed %d\n", ret); + goto out; + } + + } else if (!dp->active) { + ret = cdn_dp_enable(dp); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Failed to enable dp %d\n", ret); + goto out; + } + } + +out: + mutex_unlock(&dp->lock); + + if (hpd_event) + drm_helper_hpd_irq_event(dp->drm_dev); + + if (re_training) + cdn_dp_encoder_enable(&dp->encoder); +} + +static int cdn_dp_pd_event(struct notifier_block *nb, + unsigned long event, void *priv) +{ + struct cdn_dp_port *port = container_of(nb, struct cdn_dp_port, + event_nb); + struct cdn_dp_device *dp = port->dp; + + /* + * It would be nice to be able to just do the work inline right here. + * However, we need to make a bunch of calls that might sleep in order + * to turn on the block/phy, so use a worker instead. + */ + schedule_work(&dp->event_work); + + return NOTIFY_DONE; +} + +static int cdn_dp_bind(struct device *dev, struct device *master, void *data) +{ + struct cdn_dp_device *dp = dev_get_drvdata(dev); + struct drm_encoder *encoder; + struct drm_connector *connector; + struct cdn_dp_port *port; + struct drm_device *drm_dev = data; + int ret, i; + + pm_runtime_enable(dev); + + ret = cdn_dp_parse_dt(dp); + if (ret < 0) + return ret; + + dp->drm_dev = drm_dev; + dp->enabled = true; + dp->active = false; + + mutex_init(&dp->lock); + INIT_WORK(&dp->event_work, cdn_dp_pd_event_work); + + encoder = &dp->encoder; + + encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev, + dev->of_node); + DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); + + ret = drm_encoder_init(drm_dev, encoder, &cdn_dp_encoder_funcs, + DRM_MODE_ENCODER_TMDS, NULL); + if (ret) { + DRM_ERROR("failed to initialize encoder with drm\n"); + return ret; + } + + drm_encoder_helper_add(encoder, &cdn_dp_encoder_helper_funcs); + + connector = &dp->connector; + connector->polled = DRM_CONNECTOR_POLL_HPD; + connector->dpms = DRM_MODE_DPMS_OFF; + + ret = drm_connector_init(drm_dev, connector, + &cdn_dp_atomic_connector_funcs, + DRM_MODE_CONNECTOR_DisplayPort); + if (ret) { + DRM_ERROR("failed to initialize connector with drm\n"); + goto err_free_encoder; + } + + drm_connector_helper_add(connector, &cdn_dp_connector_helper_funcs); + + ret = drm_mode_connector_attach_encoder(connector, encoder); + if (ret) { + DRM_ERROR("failed to attach connector and encoder\n"); + goto err_free_connector; + } + + cdn_dp_audio_codec_init(dp, dev); + + for (i = 0; i < dp->ports; i++) { + port = dp->port[i]; + + port->event_nb.notifier_call = cdn_dp_pd_event; + ret = devm_extcon_register_notifier(dp->dev, port->extcon, + EXTCON_DISP_DP, + &port->event_nb); + if (ret) { + DRM_DEV_ERROR(dev, + "register EXTCON_DISP_DP notifier err\n"); + goto err_free_connector; + } + + if (extcon_get_state(port->extcon, EXTCON_DISP_DP)) + schedule_work(&dp->event_work); + } + + return 0; + +err_free_connector: + drm_connector_cleanup(connector); +err_free_encoder: + drm_encoder_cleanup(encoder); + return ret; +} + +static void cdn_dp_unbind(struct device *dev, struct device *master, void *data) +{ + struct cdn_dp_device *dp = dev_get_drvdata(dev); + struct drm_encoder *encoder = &dp->encoder; + struct drm_connector *connector = &dp->connector; + + platform_device_unregister(dp->audio_pdev); + cdn_dp_encoder_disable(encoder); + encoder->funcs->destroy(encoder); + connector->funcs->destroy(connector); + + pm_runtime_disable(dev); + release_firmware(dp->fw); +} + +static const struct component_ops cdn_dp_component_ops = { + .bind = cdn_dp_bind, + .unbind = cdn_dp_unbind, +}; + +int cdn_dp_suspend(struct device *dev) +{ + struct cdn_dp_device *dp = dev_get_drvdata(dev); + + if (dp->active) + return cdn_dp_disable(dp); + + return 0; +} + +int cdn_dp_resume(struct device *dev) +{ + struct cdn_dp_device *dp = dev_get_drvdata(dev); + + schedule_work(&dp->event_work); + return 0; +} + +static int cdn_dp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *match; + struct cdn_dp_data *dp_data; + struct cdn_dp_port *port; + struct cdn_dp_device *dp; + struct extcon_dev *extcon; + struct phy *phy; + int i; + + dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); + if (!dp) + return -ENOMEM; + dp->dev = dev; + + match = of_match_node(cdn_dp_dt_ids, pdev->dev.of_node); + dp_data = (struct cdn_dp_data *)match->data; + + for (i = 0; i < dp_data->max_phy; i++) { + extcon = extcon_get_edev_by_phandle(dev, i); + phy = devm_of_phy_get_by_index(dev, dev->of_node, i); + + if (PTR_ERR(extcon) == -EPROBE_DEFER || + PTR_ERR(phy) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + if (IS_ERR(extcon) || IS_ERR(phy)) + continue; + + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!dp) + return -ENOMEM; + + port->extcon = extcon; + port->phy = phy; + port->dp = dp; + port->id = i; + dp->port[dp->ports++] = port; + } + + if (!dp->ports) { + DRM_DEV_ERROR(dev, "missing extcon or phy\n"); + return -EINVAL; + } + + dev_set_drvdata(dev, dp); + + return component_add(dev, &cdn_dp_component_ops); +} + +static int cdn_dp_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &cdn_dp_component_ops); + + return 0; +} + +static const struct dev_pm_ops cdn_dp_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(cdn_dp_suspend, + cdn_dp_resume) +}; + +static struct platform_driver cdn_dp_driver = { + .probe = cdn_dp_probe, + .remove = cdn_dp_remove, + .driver = { + .name = "cdn-dp", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(cdn_dp_dt_ids), + .pm = &cdn_dp_pm_ops, + }, +}; + +module_platform_driver(cdn_dp_driver); + +MODULE_AUTHOR("Chris Zhong "); +MODULE_DESCRIPTION("cdn DP Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h new file mode 100644 index 0000000..c0f7d04 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2016 Chris Zhong + * Copyright (C) 2016 ROCKCHIP, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CDN_DP_CORE_H +#define _CDN_DP_CORE_H + +#include +#include +#include +#include +#include "rockchip_drm_drv.h" + +#define MAX_PHY 2 + +enum audio_format { + AFMT_I2S = 0, + AFMT_SPDIF = 1, + AFMT_UNUSED, +}; + +struct audio_info { + enum audio_format format; + int sample_rate; + int channels; + int sample_width; +}; + +enum vic_pxl_encoding_format { + PXL_RGB = 0x1, + YCBCR_4_4_4 = 0x2, + YCBCR_4_2_2 = 0x4, + YCBCR_4_2_0 = 0x8, + Y_ONLY = 0x10, +}; + +struct video_info { + bool h_sync_polarity; + bool v_sync_polarity; + bool interlaced; + int color_depth; + enum vic_pxl_encoding_format color_fmt; +}; + +struct cdn_firmware_header { + u32 size_bytes; /* size of the entire header+image(s) in bytes */ + u32 header_size; /* size of just the header in bytes */ + u32 iram_size; /* size of iram */ + u32 dram_size; /* size of dram */ +}; + +struct cdn_dp_port { + struct cdn_dp_device *dp; + struct notifier_block event_nb; + struct extcon_dev *extcon; + struct phy *phy; + u8 lanes; + bool phy_enabled; + u8 id; +}; + +struct cdn_dp_device { + struct device *dev; + struct drm_device *drm_dev; + struct drm_connector connector; + struct drm_encoder encoder; + struct drm_display_mode mode; + struct platform_device *audio_pdev; + struct work_struct event_work; + + struct mutex lock; + bool enabled; + bool active; + + const struct firmware *fw; /* cdn dp firmware */ + unsigned int fw_version; /* cdn fw version */ + bool fw_loaded; + + void __iomem *regs; + struct regmap *grf; + struct clk *core_clk; + struct clk *pclk; + struct clk *spdif_clk; + struct clk *grf_clk; + struct reset_control *spdif_rst; + struct reset_control *dptx_rst; + struct reset_control *apb_rst; + struct audio_info audio_info; + struct video_info video_info; + struct drm_dp_link link; + struct cdn_dp_port *port[MAX_PHY]; + u8 ports; + + u8 dpcd[DP_RECEIVER_CAP_SIZE]; + bool sink_has_audio; + bool no_sink; +}; +#endif /* _CDN_DP_CORE_H */ diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c new file mode 100644 index 0000000..8d7d1c9 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -0,0 +1,956 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" + +#define CDN_DP_SPDIF_CLK 200000000 +#define FW_ALIVE_TIMEOUT_US 1000000 +#define MAILBOX_RETRY_US 1000 +#define MAILBOX_TIMEOUT_US 5000000 +#define LINK_TRAINING_RETRY_MS 20 +#define LINK_TRAINING_TIMEOUT_MS 500 + +void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, u32 clk) +{ + writel(clk / 1000000, dp->regs + SW_CLK_H); +} + +void cdn_dp_clock_reset(struct cdn_dp_device *dp) +{ + u32 val; + + val = DPTX_FRMR_DATA_CLK_RSTN_EN | + DPTX_FRMR_DATA_CLK_EN | + DPTX_PHY_DATA_RSTN_EN | + DPTX_PHY_DATA_CLK_EN | + DPTX_PHY_CHAR_RSTN_EN | + DPTX_PHY_CHAR_CLK_EN | + SOURCE_AUX_SYS_CLK_RSTN_EN | + SOURCE_AUX_SYS_CLK_EN | + DPTX_SYS_CLK_RSTN_EN | + DPTX_SYS_CLK_EN | + CFG_DPTX_VIF_CLK_RSTN_EN | + CFG_DPTX_VIF_CLK_EN; + writel(val, dp->regs + SOURCE_DPTX_CAR); + + val = SOURCE_PHY_RSTN_EN | SOURCE_PHY_CLK_EN; + writel(val, dp->regs + SOURCE_PHY_CAR); + + val = SOURCE_PKT_SYS_RSTN_EN | + SOURCE_PKT_SYS_CLK_EN | + SOURCE_PKT_DATA_RSTN_EN | + SOURCE_PKT_DATA_CLK_EN; + writel(val, dp->regs + SOURCE_PKT_CAR); + + val = SPDIF_CDR_CLK_RSTN_EN | + SPDIF_CDR_CLK_EN | + SOURCE_AIF_SYS_RSTN_EN | + SOURCE_AIF_SYS_CLK_EN | + SOURCE_AIF_CLK_RSTN_EN | + SOURCE_AIF_CLK_EN; + writel(val, dp->regs + SOURCE_AIF_CAR); + + val = SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN | + SOURCE_CIPHER_SYS_CLK_EN | + SOURCE_CIPHER_CHAR_CLK_RSTN_EN | + SOURCE_CIPHER_CHAR_CLK_EN; + writel(val, dp->regs + SOURCE_CIPHER_CAR); + + val = SOURCE_CRYPTO_SYS_CLK_RSTN_EN | + SOURCE_CRYPTO_SYS_CLK_EN; + writel(val, dp->regs + SOURCE_CRYPTO_CAR); + + val = ~(MAILBOX_INT_MASK_BIT | PIF_INT_MASK_BIT) & ALL_INT_MASK; + writel(val, dp->regs + APB_INT_MASK); +} + +static int cdn_dp_mailbox_read(struct cdn_dp_device *dp, bool force) +{ + int val, ret; + + ret = readx_poll_timeout(readl, dp->regs + MAILBOX_EMPTY_ADDR, + val, !val, MAILBOX_RETRY_US, + MAILBOX_TIMEOUT_US); + if (ret < 0) + return ret; + + return readl(dp->regs + MAILBOX0_RD_DATA) & 0xff; +} + +static int cdp_dp_mailbox_write(struct cdn_dp_device *dp, u8 val, bool force) +{ + int ret, full; + + ret = readx_poll_timeout(readl, dp->regs + MAILBOX_FULL_ADDR, + full, !full, MAILBOX_RETRY_US, + MAILBOX_TIMEOUT_US); + if (ret < 0) + return ret; + + writel(val, dp->regs + MAILBOX0_WR_DATA); + + return 0; +} + +static int cdn_dp_mailbox_validate_receive(struct cdn_dp_device *dp, + u8 module_id, u8 opcode, + u8 req_size) +{ + u32 mbox_size, i; + u8 header[4]; + int ret; + + /* read the header of the message */ + for (i = 0; i < 4; i++) { + ret = cdn_dp_mailbox_read(dp, 0); + if (ret < 0) + return ret; + + header[i] = ret; + } + + mbox_size = (header[2] << 8) | header[3]; + + if (opcode != header[0] || module_id != header[1] || + req_size != mbox_size) { + /* + * If the message in mailbox is not what we want, we need to + * clear the mailbox by reading its contents. + */ + for (i = 0; i < mbox_size; i++) + if (cdn_dp_mailbox_read(dp, 0) < 0) + break; + + return -EINVAL; + } + + return 0; +} + +static int cdn_dp_mailbox_read_receive(struct cdn_dp_device *dp, + u8 *buff, u8 buff_size) +{ + u32 i; + int ret; + + for (i = 0; i < buff_size; i++) { + ret = cdn_dp_mailbox_read(dp, 0); + if (ret < 0) + return ret; + + buff[i] = ret; + } + + return 0; +} + +static int cdn_dp_mailbox_send(struct cdn_dp_device *dp, u8 module_id, + u8 opcode, u16 size, u8 *message) +{ + u8 header[4]; + int ret, i; + + header[0] = opcode; + header[1] = module_id; + header[2] = (size >> 8) & 0xff; + header[3] = size & 0xff; + + for (i = 0; i < 4; i++) { + ret = cdp_dp_mailbox_write(dp, header[i], 0); + if (ret) + return ret; + } + + for (i = 0; i < size; i++) { + ret = cdp_dp_mailbox_write(dp, message[i], 0); + if (ret) + return ret; + } + + return 0; +} + +static int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val) +{ + u8 msg[6]; + + msg[0] = (addr >> 8) & 0xff; + msg[1] = addr & 0xff; + msg[2] = (val >> 24) & 0xff; + msg[3] = (val >> 16) & 0xff; + msg[4] = (val >> 8) & 0xff; + msg[5] = val & 0xff; + return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_REGISTER, + sizeof(msg), msg); +} + +static int cdn_dp_reg_write_bit(struct cdn_dp_device *dp, u16 addr, + u8 start_bit, u8 bits_no, u32 val) +{ + u8 field[8]; + + field[0] = (addr >> 8) & 0xff; + field[1] = addr & 0xff; + field[2] = start_bit; + field[3] = bits_no; + field[4] = (val >> 24) & 0xff; + field[5] = (val >> 16) & 0xff; + field[6] = (val >> 8) & 0xff; + field[7] = val & 0xff; + + return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_FIELD, + sizeof(field), field); +} + +int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len) +{ + u8 msg[5], reg[5]; + int ret; + + msg[0] = (len >> 8) & 0xff; + msg[1] = len & 0xff; + msg[2] = (addr >> 16) & 0xff; + msg[3] = (addr >> 8) & 0xff; + msg[4] = addr & 0xff; + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_DPCD, + sizeof(msg), msg); + if (ret) + goto err_dpcd_read; + + ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, + DPTX_READ_DPCD, + sizeof(reg) + len); + if (ret) + goto err_dpcd_read; + + ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg)); + if (ret) + goto err_dpcd_read; + + ret = cdn_dp_mailbox_read_receive(dp, data, len); + +err_dpcd_read: + return ret; +} + +int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value) +{ + u8 msg[6], reg[5]; + int ret; + + msg[0] = 0; + msg[1] = 1; + msg[2] = (addr >> 16) & 0xff; + msg[3] = (addr >> 8) & 0xff; + msg[4] = addr & 0xff; + msg[5] = value; + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_DPCD, + sizeof(msg), msg); + if (ret) + goto err_dpcd_write; + + ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, + DPTX_WRITE_DPCD, sizeof(reg)); + if (ret) + goto err_dpcd_write; + + ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg)); + if (ret) + goto err_dpcd_write; + + if (addr != (reg[2] << 16 | reg[3] << 8 | reg[4])) + ret = -EINVAL; + +err_dpcd_write: + if (ret) + DRM_DEV_ERROR(dp->dev, "dpcd write failed: %d\n", ret); + return ret; +} + +int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem, + u32 i_size, const u32 *d_mem, u32 d_size) +{ + u32 reg; + int i, ret; + + /* reset ucpu before load firmware*/ + writel(APB_IRAM_PATH | APB_DRAM_PATH | APB_XT_RESET, + dp->regs + APB_CTRL); + + for (i = 0; i < i_size; i += 4) + writel(*i_mem++, dp->regs + ADDR_IMEM + i); + + for (i = 0; i < d_size; i += 4) + writel(*d_mem++, dp->regs + ADDR_DMEM + i); + + /* un-reset ucpu */ + writel(0, dp->regs + APB_CTRL); + + /* check the keep alive register to make sure fw working */ + ret = readx_poll_timeout(readl, dp->regs + KEEP_ALIVE, + reg, reg, 2000, FW_ALIVE_TIMEOUT_US); + if (ret < 0) { + DRM_DEV_ERROR(dp->dev, "failed to loaded the FW reg = %x\n", + reg); + return -EINVAL; + } + + reg = readl(dp->regs + VER_L) & 0xff; + dp->fw_version = reg; + reg = readl(dp->regs + VER_H) & 0xff; + dp->fw_version |= reg << 8; + reg = readl(dp->regs + VER_LIB_L_ADDR) & 0xff; + dp->fw_version |= reg << 16; + reg = readl(dp->regs + VER_LIB_H_ADDR) & 0xff; + dp->fw_version |= reg << 24; + + dev_dbg(dp->dev, "firmware version: %x\n", dp->fw_version); + + return 0; +} + +int cdn_dp_set_firmware_active(struct cdn_dp_device *dp, bool enable) +{ + u8 msg[5]; + int ret, i; + + msg[0] = GENERAL_MAIN_CONTROL; + msg[1] = MB_MODULE_ID_GENERAL; + msg[2] = 0; + msg[3] = 1; + msg[4] = enable ? FW_ACTIVE : FW_STANDBY; + + for (i = 0; i < sizeof(msg); i++) { + ret = cdp_dp_mailbox_write(dp, msg[i], 1); + if (ret) + goto err_set_firmware_active; + } + + /* read the firmware state */ + for (i = 0; i < sizeof(msg); i++) { + ret = cdn_dp_mailbox_read(dp, 1); + if (ret < 0) + goto err_set_firmware_active; + + msg[i] = ret; + } + + ret = 0; + +err_set_firmware_active: + if (ret < 0) + DRM_DEV_ERROR(dp->dev, "set firmware active failed\n"); + return ret; +} + +int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip) +{ + u8 msg[8]; + int ret; + + msg[0] = CDN_DP_MAX_LINK_RATE; + msg[1] = lanes; + msg[2] = VOLTAGE_LEVEL_2; + msg[3] = PRE_EMPHASIS_LEVEL_3; + msg[4] = PTS1 | PTS2 | PTS3 | PTS4; + msg[5] = FAST_LT_NOT_SUPPORT; + msg[6] = flip ? LANE_MAPPING_FLIPPED : LANE_MAPPING_NORMAL; + msg[7] = ENHANCED; + + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, + DPTX_SET_HOST_CAPABILITIES, + sizeof(msg), msg); + if (ret) + goto err_set_host_cap; + + ret = cdn_dp_reg_write(dp, DP_AUX_SWAP_INVERSION_CONTROL, + AUX_HOST_INVERT); + +err_set_host_cap: + if (ret) + DRM_DEV_ERROR(dp->dev, "set host cap failed: %d\n", ret); + return ret; +} + +int cdn_dp_event_config(struct cdn_dp_device *dp) +{ + u8 msg[5]; + int ret; + + memset(msg, 0, sizeof(msg)); + + msg[0] = DPTX_EVENT_ENABLE_HPD | DPTX_EVENT_ENABLE_TRAINING; + + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_ENABLE_EVENT, + sizeof(msg), msg); + if (ret) + DRM_DEV_ERROR(dp->dev, "set event config failed: %d\n", ret); + + return ret; +} + +u32 cdn_dp_get_event(struct cdn_dp_device *dp) +{ + return readl(dp->regs + SW_EVENTS0); +} + +int cdn_dp_get_hpd_status(struct cdn_dp_device *dp) +{ + u8 status; + int ret; + + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_HPD_STATE, + 0, NULL); + if (ret) + goto err_get_hpd; + + ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, + DPTX_HPD_STATE, sizeof(status)); + if (ret) + goto err_get_hpd; + + ret = cdn_dp_mailbox_read_receive(dp, &status, sizeof(status)); + if (ret) + goto err_get_hpd; + + return status; + +err_get_hpd: + DRM_DEV_ERROR(dp->dev, "get hpd status failed: %d\n", ret); + return ret; +} + +int cdn_dp_get_edid_block(void *data, u8 *edid, + unsigned int block, size_t length) +{ + struct cdn_dp_device *dp = data; + u8 msg[2], reg[2], i; + int ret; + + for (i = 0; i < 4; i++) { + msg[0] = block / 2; + msg[1] = block % 2; + + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_GET_EDID, + sizeof(msg), msg); + if (ret) + continue; + + ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, + DPTX_GET_EDID, + sizeof(reg) + length); + if (ret) + continue; + + ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg)); + if (ret) + continue; + + ret = cdn_dp_mailbox_read_receive(dp, edid, length); + if (ret) + continue; + + if (reg[0] == length && reg[1] == block / 2) + break; + } + + if (ret) + DRM_DEV_ERROR(dp->dev, "get block[%d] edid failed: %d\n", block, + ret); + + return ret; +} + +int cdn_dp_training_start(struct cdn_dp_device *dp) +{ + unsigned long timeout; + u8 msg, event[2]; + int ret; + + msg = LINK_TRAINING_RUN; + + /* start training */ + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_TRAINING_CONTROL, + sizeof(msg), &msg); + if (ret) + goto err_training_start; + + timeout = jiffies + msecs_to_jiffies(LINK_TRAINING_TIMEOUT_MS); + while (time_before(jiffies, timeout)) { + msleep(LINK_TRAINING_RETRY_MS); + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, + DPTX_READ_EVENT, 0, NULL); + if (ret) + goto err_training_start; + + ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, + DPTX_READ_EVENT, + sizeof(event)); + if (ret) + goto err_training_start; + + ret = cdn_dp_mailbox_read_receive(dp, event, sizeof(event)); + if (ret) + goto err_training_start; + + if (event[1] & EQ_PHASE_FINISHED) + return 0; + } + + ret = -ETIMEDOUT; + +err_training_start: + DRM_DEV_ERROR(dp->dev, "training failed: %d\n", ret); + return ret; +} + +int cdn_dp_get_training_status(struct cdn_dp_device *dp) +{ + u8 status[10]; + int ret; + + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_LINK_STAT, + 0, NULL); + if (ret) + goto err_get_training_status; + + ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, + DPTX_READ_LINK_STAT, + sizeof(status)); + if (ret) + goto err_get_training_status; + + ret = cdn_dp_mailbox_read_receive(dp, status, sizeof(status)); + if (ret) + goto err_get_training_status; + + dp->link.rate = status[0]; + dp->link.num_lanes = status[1]; + +err_get_training_status: + if (ret) + DRM_DEV_ERROR(dp->dev, "get training status failed: %d\n", ret); + return ret; +} + +int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active) +{ + u8 msg; + int ret; + + msg = !!active; + + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_SET_VIDEO, + sizeof(msg), &msg); + if (ret) + DRM_DEV_ERROR(dp->dev, "set video status failed: %d\n", ret); + + return ret; +} + +static int cdn_dp_get_msa_misc(struct video_info *video, + struct drm_display_mode *mode) +{ + u32 msa_misc; + u8 val[2]; + + switch (video->color_fmt) { + case PXL_RGB: + case Y_ONLY: + val[0] = 0; + break; + /* set YUV default color space conversion to BT601 */ + case YCBCR_4_4_4: + val[0] = 6 + BT_601 * 8; + break; + case YCBCR_4_2_2: + val[0] = 5 + BT_601 * 8; + break; + case YCBCR_4_2_0: + val[0] = 5; + break; + }; + + switch (video->color_depth) { + case 6: + val[1] = 0; + break; + case 8: + val[1] = 1; + break; + case 10: + val[1] = 2; + break; + case 12: + val[1] = 3; + break; + case 16: + val[1] = 4; + break; + }; + + msa_misc = 2 * val[0] + 32 * val[1] + + ((video->color_fmt == Y_ONLY) ? (1 << 14) : 0); + + return msa_misc; +} + +int cdn_dp_config_video(struct cdn_dp_device *dp) +{ + struct video_info *video = &dp->video_info; + struct drm_display_mode *mode = &dp->mode; + u64 symbol, tmp; + u32 val, link_rate; + u8 bit_per_pix, tu_size_reg = TU_SIZE; + int ret; + + bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ? + (video->color_depth * 2) : (video->color_depth * 3); + + link_rate = drm_dp_bw_code_to_link_rate(dp->link.rate) / 1000; + + val = VIF_BYPASS_INTERLACE; + ret = cdn_dp_reg_write(dp, BND_HSYNC2VSYNC, val); + if (ret) + goto err_config_video; + + ret = cdn_dp_reg_write(dp, HSYNC2VSYNC_POL_CTRL, 0); + if (ret) + goto err_config_video; + + /* + * get a best tu_size and valid symbol: + * 1. chose Lclk freq(162Mhz, 270Mhz, 540Mhz), set TU to 32 + * 2. calculate VS(valid symbol) = TU * Pclk * Bpp / (Lclk * Lanes) + * 3. if VS > *.85 or VS < *.1 or VS < 2 or TU < VS + 4, then set + * TU += 2 and repeat 2nd step. + */ + do { + tu_size_reg += 2; + tmp = tu_size_reg * mode->clock * bit_per_pix; + tmp /= dp->link.num_lanes * link_rate * 8; + symbol = tmp / 1000; + } while ((symbol <= 1) || (tu_size_reg - symbol < 4) || + (tmp % 1000 > 850) || (tmp % 1000 < 100)); + + val = symbol + (tu_size_reg << 8); + ret = cdn_dp_reg_write(dp, DP_FRAMER_TU, val); + if (ret) + goto err_config_video; + + /* set the FIFO Buffer size */ + val = ((mode->clock * (symbol + 1) / 1000) + link_rate); + val /= (dp->link.num_lanes * link_rate); + val = 8 * (symbol + 1) / bit_per_pix - val; + val += 2; + ret = cdn_dp_reg_write(dp, DP_VC_TABLE(15), val); + + switch (video->color_depth) { + case 6: + val = BCS_6; + break; + case 8: + val = BCS_8; + break; + case 10: + val = BCS_10; + break; + case 12: + val = BCS_12; + break; + case 16: + val = BCS_16; + break; + }; + + val += video->color_fmt << 8; + ret = cdn_dp_reg_write(dp, DP_FRAMER_PXL_REPR, val); + if (ret) + goto err_config_video; + + val = video->h_sync_polarity ? DP_FRAMER_SP_HSP : 0; + val |= video->v_sync_polarity ? DP_FRAMER_SP_VSP : 0; + ret = cdn_dp_reg_write(dp, DP_FRAMER_SP, val); + if (ret) + goto err_config_video; + + val = (mode->hsync_start - mode->hdisplay) << 16; + val |= mode->htotal - mode->hsync_end; + ret = cdn_dp_reg_write(dp, DP_FRONT_BACK_PORCH, val); + if (ret) + goto err_config_video; + + val = mode->hdisplay * bit_per_pix / 8; + ret = cdn_dp_reg_write(dp, DP_BYTE_COUNT, val); + if (ret) + goto err_config_video; + + val = mode->htotal | ((mode->htotal - mode->hsync_start) << 16); + ret = cdn_dp_reg_write(dp, MSA_HORIZONTAL_0, val); + if (ret) + goto err_config_video; + + val = mode->hsync_end - mode->hsync_start; + val |= (mode->hdisplay << 16) | (video->h_sync_polarity << 15); + ret = cdn_dp_reg_write(dp, MSA_HORIZONTAL_1, val); + if (ret) + goto err_config_video; + + val = mode->vtotal; + val |= ((mode->vtotal - mode->vsync_start) << 16); + ret = cdn_dp_reg_write(dp, MSA_VERTICAL_0, val); + if (ret) + goto err_config_video; + + val = mode->vsync_end - mode->vsync_start; + val |= mode->vdisplay << 16 | (video->v_sync_polarity << 15); + ret = cdn_dp_reg_write(dp, MSA_VERTICAL_1, val); + if (ret) + goto err_config_video; + + val = cdn_dp_get_msa_misc(video, mode); + ret = cdn_dp_reg_write(dp, MSA_MISC, val); + if (ret) + goto err_config_video; + + ret = cdn_dp_reg_write(dp, STREAM_CONFIG, 1); + if (ret) + goto err_config_video; + + val = mode->hsync_end - mode->hsync_start; + val |= (mode->hdisplay << 16); + ret = cdn_dp_reg_write(dp, DP_HORIZONTAL, val); + if (ret) + goto err_config_video; + + val = mode->vtotal; + val -= (mode->vtotal - mode->vdisplay); + val |= (mode->vtotal - mode->vsync_start) << 16; + ret = cdn_dp_reg_write(dp, DP_VERTICAL_0, val); + if (ret) + goto err_config_video; + + val = mode->vtotal; + ret = cdn_dp_reg_write(dp, DP_VERTICAL_1, val); + if (ret) + goto err_config_video; + + val = 0; + ret = cdn_dp_reg_write_bit(dp, DP_VB_ID, 2, 1, val); + +err_config_video: + if (ret) + DRM_DEV_ERROR(dp->dev, "config video failed: %d\n", ret); + return ret; +} + +int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio) +{ + u32 val; + int ret; + + ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, 0); + if (ret) { + DRM_DEV_ERROR(dp->dev, "audio stop failed: %d\n", ret); + return ret; + } + + val = SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; + val |= SPDIF_FIFO_MID_RANGE(0xe0); + val |= SPDIF_JITTER_THRSH(0xe0); + val |= SPDIF_JITTER_AVG_WIN(7); + writel(val, dp->regs + SPDIF_CTRL_ADDR); + + /* clearn the audio config and reset */ + writel(0, dp->regs + AUDIO_SRC_CNTL); + writel(0, dp->regs + AUDIO_SRC_CNFG); + writel(AUDIO_SW_RST, dp->regs + AUDIO_SRC_CNTL); + writel(0, dp->regs + AUDIO_SRC_CNTL); + + /* reset smpl2pckt component */ + writel(0, dp->regs + SMPL2PKT_CNTL); + writel(AUDIO_SW_RST, dp->regs + SMPL2PKT_CNTL); + writel(0, dp->regs + SMPL2PKT_CNTL); + + /* reset FIFO */ + writel(AUDIO_SW_RST, dp->regs + FIFO_CNTL); + writel(0, dp->regs + FIFO_CNTL); + + if (audio->format == AFMT_SPDIF) + clk_disable_unprepare(dp->spdif_clk); + + return 0; +} + +int cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable) +{ + int ret; + + ret = cdn_dp_reg_write_bit(dp, DP_VB_ID, 4, 1, enable); + if (ret) + DRM_DEV_ERROR(dp->dev, "audio mute failed: %d\n", ret); + + return ret; +} + +static void cdn_dp_audio_config_i2s(struct cdn_dp_device *dp, + struct audio_info *audio) +{ + int sub_pckt_num = 1, i2s_port_en_val = 0xf, i; + u32 val; + + if (audio->channels == 2) { + if (dp->link.num_lanes == 1) + sub_pckt_num = 2; + else + sub_pckt_num = 4; + + i2s_port_en_val = 1; + } else if (audio->channels == 4) { + i2s_port_en_val = 3; + } + + writel(0x0, dp->regs + SPDIF_CTRL_ADDR); + + writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL); + + val = MAX_NUM_CH(audio->channels); + val |= NUM_OF_I2S_PORTS(audio->channels); + val |= AUDIO_TYPE_LPCM; + val |= CFG_SUB_PCKT_NUM(sub_pckt_num); + writel(val, dp->regs + SMPL2PKT_CNFG); + + if (audio->sample_width == 16) + val = 0; + else if (audio->sample_width == 24) + val = 1 << 9; + else + val = 2 << 9; + + val |= AUDIO_CH_NUM(audio->channels); + val |= I2S_DEC_PORT_EN(i2s_port_en_val); + val |= TRANS_SMPL_WIDTH_32; + writel(val, dp->regs + AUDIO_SRC_CNFG); + + for (i = 0; i < (audio->channels + 1) / 2; i++) { + if (audio->sample_width == 16) + val = (0x08 << 8) | (0x08 << 20); + else if (audio->sample_width == 24) + val = (0x0b << 8) | (0x0b << 20); + + val |= ((2 * i) << 4) | ((2 * i + 1) << 16); + writel(val, dp->regs + STTS_BIT_CH(i)); + } + + switch (audio->sample_rate) { + case 32000: + val = SAMPLING_FREQ(3) | + ORIGINAL_SAMP_FREQ(0xc); + break; + case 44100: + val = SAMPLING_FREQ(0) | + ORIGINAL_SAMP_FREQ(0xf); + break; + case 48000: + val = SAMPLING_FREQ(2) | + ORIGINAL_SAMP_FREQ(0xd); + break; + case 88200: + val = SAMPLING_FREQ(8) | + ORIGINAL_SAMP_FREQ(0x7); + break; + case 96000: + val = SAMPLING_FREQ(0xa) | + ORIGINAL_SAMP_FREQ(5); + break; + case 176400: + val = SAMPLING_FREQ(0xc) | + ORIGINAL_SAMP_FREQ(3); + break; + case 192000: + val = SAMPLING_FREQ(0xe) | + ORIGINAL_SAMP_FREQ(1); + break; + } + val |= 4; + writel(val, dp->regs + COM_CH_STTS_BITS); + + writel(SMPL2PKT_EN, dp->regs + SMPL2PKT_CNTL); + writel(I2S_DEC_START, dp->regs + AUDIO_SRC_CNTL); +} + +static void cdn_dp_audio_config_spdif(struct cdn_dp_device *dp) +{ + u32 val; + + val = SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; + val |= SPDIF_FIFO_MID_RANGE(0xe0); + val |= SPDIF_JITTER_THRSH(0xe0); + val |= SPDIF_JITTER_AVG_WIN(7); + writel(val, dp->regs + SPDIF_CTRL_ADDR); + + writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL); + + val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4); + writel(val, dp->regs + SMPL2PKT_CNFG); + writel(SMPL2PKT_EN, dp->regs + SMPL2PKT_CNTL); + + val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; + val |= SPDIF_FIFO_MID_RANGE(0xe0); + val |= SPDIF_JITTER_THRSH(0xe0); + val |= SPDIF_JITTER_AVG_WIN(7); + writel(val, dp->regs + SPDIF_CTRL_ADDR); + + clk_prepare_enable(dp->spdif_clk); + clk_set_rate(dp->spdif_clk, CDN_DP_SPDIF_CLK); +} + +int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio) +{ + int ret; + + /* reset the spdif clk before config */ + if (audio->format == AFMT_SPDIF) { + reset_control_assert(dp->spdif_rst); + reset_control_deassert(dp->spdif_rst); + } + + ret = cdn_dp_reg_write(dp, CM_LANE_CTRL, LANE_REF_CYC); + if (ret) + goto err_audio_config; + + ret = cdn_dp_reg_write(dp, CM_CTRL, 0); + if (ret) + goto err_audio_config; + + if (audio->format == AFMT_I2S) + cdn_dp_audio_config_i2s(dp, audio); + else if (audio->format == AFMT_SPDIF) + cdn_dp_audio_config_spdif(dp); + + ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN); + +err_audio_config: + if (ret) + DRM_DEV_ERROR(dp->dev, "audio config failed: %d\n", ret); + return ret; +} diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/drivers/gpu/drm/rockchip/cdn-dp-reg.h new file mode 100644 index 0000000..6ac3674 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.h @@ -0,0 +1,482 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CDN_DP_REG_H +#define _CDN_DP_REG_H + +#include + +#define ADDR_IMEM 0x10000 +#define ADDR_DMEM 0x20000 + +/* APB CFG addr */ +#define APB_CTRL 0 +#define XT_INT_CTRL 0x04 +#define MAILBOX_FULL_ADDR 0x08 +#define MAILBOX_EMPTY_ADDR 0x0c +#define MAILBOX0_WR_DATA 0x10 +#define MAILBOX0_RD_DATA 0x14 +#define KEEP_ALIVE 0x18 +#define VER_L 0x1c +#define VER_H 0x20 +#define VER_LIB_L_ADDR 0x24 +#define VER_LIB_H_ADDR 0x28 +#define SW_DEBUG_L 0x2c +#define SW_DEBUG_H 0x30 +#define MAILBOX_INT_MASK 0x34 +#define MAILBOX_INT_STATUS 0x38 +#define SW_CLK_L 0x3c +#define SW_CLK_H 0x40 +#define SW_EVENTS0 0x44 +#define SW_EVENTS1 0x48 +#define SW_EVENTS2 0x4c +#define SW_EVENTS3 0x50 +#define XT_OCD_CTRL 0x60 +#define APB_INT_MASK 0x6c +#define APB_STATUS_MASK 0x70 + +/* audio decoder addr */ +#define AUDIO_SRC_CNTL 0x30000 +#define AUDIO_SRC_CNFG 0x30004 +#define COM_CH_STTS_BITS 0x30008 +#define STTS_BIT_CH(x) (0x3000c + ((x) << 2)) +#define SPDIF_CTRL_ADDR 0x3004c +#define SPDIF_CH1_CS_3100_ADDR 0x30050 +#define SPDIF_CH1_CS_6332_ADDR 0x30054 +#define SPDIF_CH1_CS_9564_ADDR 0x30058 +#define SPDIF_CH1_CS_12796_ADDR 0x3005c +#define SPDIF_CH1_CS_159128_ADDR 0x30060 +#define SPDIF_CH1_CS_191160_ADDR 0x30064 +#define SPDIF_CH2_CS_3100_ADDR 0x30068 +#define SPDIF_CH2_CS_6332_ADDR 0x3006c +#define SPDIF_CH2_CS_9564_ADDR 0x30070 +#define SPDIF_CH2_CS_12796_ADDR 0x30074 +#define SPDIF_CH2_CS_159128_ADDR 0x30078 +#define SPDIF_CH2_CS_191160_ADDR 0x3007c +#define SMPL2PKT_CNTL 0x30080 +#define SMPL2PKT_CNFG 0x30084 +#define FIFO_CNTL 0x30088 +#define FIFO_STTS 0x3008c + +/* source pif addr */ +#define SOURCE_PIF_WR_ADDR 0x30800 +#define SOURCE_PIF_WR_REQ 0x30804 +#define SOURCE_PIF_RD_ADDR 0x30808 +#define SOURCE_PIF_RD_REQ 0x3080c +#define SOURCE_PIF_DATA_WR 0x30810 +#define SOURCE_PIF_DATA_RD 0x30814 +#define SOURCE_PIF_FIFO1_FLUSH 0x30818 +#define SOURCE_PIF_FIFO2_FLUSH 0x3081c +#define SOURCE_PIF_STATUS 0x30820 +#define SOURCE_PIF_INTERRUPT_SOURCE 0x30824 +#define SOURCE_PIF_INTERRUPT_MASK 0x30828 +#define SOURCE_PIF_PKT_ALLOC_REG 0x3082c +#define SOURCE_PIF_PKT_ALLOC_WR_EN 0x30830 +#define SOURCE_PIF_SW_RESET 0x30834 + +/* bellow registers need access by mailbox */ +/* source car addr */ +#define SOURCE_HDTX_CAR 0x0900 +#define SOURCE_DPTX_CAR 0x0904 +#define SOURCE_PHY_CAR 0x0908 +#define SOURCE_CEC_CAR 0x090c +#define SOURCE_CBUS_CAR 0x0910 +#define SOURCE_PKT_CAR 0x0918 +#define SOURCE_AIF_CAR 0x091c +#define SOURCE_CIPHER_CAR 0x0920 +#define SOURCE_CRYPTO_CAR 0x0924 + +/* clock meters addr */ +#define CM_CTRL 0x0a00 +#define CM_I2S_CTRL 0x0a04 +#define CM_SPDIF_CTRL 0x0a08 +#define CM_VID_CTRL 0x0a0c +#define CM_LANE_CTRL 0x0a10 +#define I2S_NM_STABLE 0x0a14 +#define I2S_NCTS_STABLE 0x0a18 +#define SPDIF_NM_STABLE 0x0a1c +#define SPDIF_NCTS_STABLE 0x0a20 +#define NMVID_MEAS_STABLE 0x0a24 +#define I2S_MEAS 0x0a40 +#define SPDIF_MEAS 0x0a80 +#define NMVID_MEAS 0x0ac0 + +/* source vif addr */ +#define BND_HSYNC2VSYNC 0x0b00 +#define HSYNC2VSYNC_F1_L1 0x0b04 +#define HSYNC2VSYNC_F2_L1 0x0b08 +#define HSYNC2VSYNC_STATUS 0x0b0c +#define HSYNC2VSYNC_POL_CTRL 0x0b10 + +/* dptx phy addr */ +#define DP_TX_PHY_CONFIG_REG 0x2000 +#define DP_TX_PHY_STATUS_REG 0x2004 +#define DP_TX_PHY_SW_RESET 0x2008 +#define DP_TX_PHY_SCRAMBLER_SEED 0x200c +#define DP_TX_PHY_TRAINING_01_04 0x2010 +#define DP_TX_PHY_TRAINING_05_08 0x2014 +#define DP_TX_PHY_TRAINING_09_10 0x2018 +#define TEST_COR 0x23fc + +/* dptx hpd addr */ +#define HPD_IRQ_DET_MIN_TIMER 0x2100 +#define HPD_IRQ_DET_MAX_TIMER 0x2104 +#define HPD_UNPLGED_DET_MIN_TIMER 0x2108 +#define HPD_STABLE_TIMER 0x210c +#define HPD_FILTER_TIMER 0x2110 +#define HPD_EVENT_MASK 0x211c +#define HPD_EVENT_DET 0x2120 + +/* dpyx framer addr */ +#define DP_FRAMER_GLOBAL_CONFIG 0x2200 +#define DP_SW_RESET 0x2204 +#define DP_FRAMER_TU 0x2208 +#define DP_FRAMER_PXL_REPR 0x220c +#define DP_FRAMER_SP 0x2210 +#define AUDIO_PACK_CONTROL 0x2214 +#define DP_VC_TABLE(x) (0x2218 + ((x) << 2)) +#define DP_VB_ID 0x2258 +#define DP_MTPH_LVP_CONTROL 0x225c +#define DP_MTPH_SYMBOL_VALUES 0x2260 +#define DP_MTPH_ECF_CONTROL 0x2264 +#define DP_MTPH_ACT_CONTROL 0x2268 +#define DP_MTPH_STATUS 0x226c +#define DP_INTERRUPT_SOURCE 0x2270 +#define DP_INTERRUPT_MASK 0x2274 +#define DP_FRONT_BACK_PORCH 0x2278 +#define DP_BYTE_COUNT 0x227c + +/* dptx stream addr */ +#define MSA_HORIZONTAL_0 0x2280 +#define MSA_HORIZONTAL_1 0x2284 +#define MSA_VERTICAL_0 0x2288 +#define MSA_VERTICAL_1 0x228c +#define MSA_MISC 0x2290 +#define STREAM_CONFIG 0x2294 +#define AUDIO_PACK_STATUS 0x2298 +#define VIF_STATUS 0x229c +#define PCK_STUFF_STATUS_0 0x22a0 +#define PCK_STUFF_STATUS_1 0x22a4 +#define INFO_PACK_STATUS 0x22a8 +#define RATE_GOVERNOR_STATUS 0x22ac +#define DP_HORIZONTAL 0x22b0 +#define DP_VERTICAL_0 0x22b4 +#define DP_VERTICAL_1 0x22b8 +#define DP_BLOCK_SDP 0x22bc + +/* dptx glbl addr */ +#define DPTX_LANE_EN 0x2300 +#define DPTX_ENHNCD 0x2304 +#define DPTX_INT_MASK 0x2308 +#define DPTX_INT_STATUS 0x230c + +/* dp aux addr */ +#define DP_AUX_HOST_CONTROL 0x2800 +#define DP_AUX_INTERRUPT_SOURCE 0x2804 +#define DP_AUX_INTERRUPT_MASK 0x2808 +#define DP_AUX_SWAP_INVERSION_CONTROL 0x280c +#define DP_AUX_SEND_NACK_TRANSACTION 0x2810 +#define DP_AUX_CLEAR_RX 0x2814 +#define DP_AUX_CLEAR_TX 0x2818 +#define DP_AUX_TIMER_STOP 0x281c +#define DP_AUX_TIMER_CLEAR 0x2820 +#define DP_AUX_RESET_SW 0x2824 +#define DP_AUX_DIVIDE_2M 0x2828 +#define DP_AUX_TX_PREACHARGE_LENGTH 0x282c +#define DP_AUX_FREQUENCY_1M_MAX 0x2830 +#define DP_AUX_FREQUENCY_1M_MIN 0x2834 +#define DP_AUX_RX_PRE_MIN 0x2838 +#define DP_AUX_RX_PRE_MAX 0x283c +#define DP_AUX_TIMER_PRESET 0x2840 +#define DP_AUX_NACK_FORMAT 0x2844 +#define DP_AUX_TX_DATA 0x2848 +#define DP_AUX_RX_DATA 0x284c +#define DP_AUX_TX_STATUS 0x2850 +#define DP_AUX_RX_STATUS 0x2854 +#define DP_AUX_RX_CYCLE_COUNTER 0x2858 +#define DP_AUX_MAIN_STATES 0x285c +#define DP_AUX_MAIN_TIMER 0x2860 +#define DP_AUX_AFE_OUT 0x2864 + +/* crypto addr */ +#define CRYPTO_HDCP_REVISION 0x5800 +#define HDCP_CRYPTO_CONFIG 0x5804 +#define CRYPTO_INTERRUPT_SOURCE 0x5808 +#define CRYPTO_INTERRUPT_MASK 0x580c +#define CRYPTO22_CONFIG 0x5818 +#define CRYPTO22_STATUS 0x581c +#define SHA_256_DATA_IN 0x583c +#define SHA_256_DATA_OUT_(x) (0x5850 + ((x) << 2)) +#define AES_32_KEY_(x) (0x5870 + ((x) << 2)) +#define AES_32_DATA_IN 0x5880 +#define AES_32_DATA_OUT_(x) (0x5884 + ((x) << 2)) +#define CRYPTO14_CONFIG 0x58a0 +#define CRYPTO14_STATUS 0x58a4 +#define CRYPTO14_PRNM_OUT 0x58a8 +#define CRYPTO14_KM_0 0x58ac +#define CRYPTO14_KM_1 0x58b0 +#define CRYPTO14_AN_0 0x58b4 +#define CRYPTO14_AN_1 0x58b8 +#define CRYPTO14_YOUR_KSV_0 0x58bc +#define CRYPTO14_YOUR_KSV_1 0x58c0 +#define CRYPTO14_MI_0 0x58c4 +#define CRYPTO14_MI_1 0x58c8 +#define CRYPTO14_TI_0 0x58cc +#define CRYPTO14_KI_0 0x58d0 +#define CRYPTO14_KI_1 0x58d4 +#define CRYPTO14_BLOCKS_NUM 0x58d8 +#define CRYPTO14_KEY_MEM_DATA_0 0x58dc +#define CRYPTO14_KEY_MEM_DATA_1 0x58e0 +#define CRYPTO14_SHA1_MSG_DATA 0x58e4 +#define CRYPTO14_SHA1_V_VALUE_(x) (0x58e8 + ((x) << 2)) +#define TRNG_CTRL 0x58fc +#define TRNG_DATA_RDY 0x5900 +#define TRNG_DATA 0x5904 + +/* cipher addr */ +#define HDCP_REVISION 0x60000 +#define INTERRUPT_SOURCE 0x60004 +#define INTERRUPT_MASK 0x60008 +#define HDCP_CIPHER_CONFIG 0x6000c +#define AES_128_KEY_0 0x60010 +#define AES_128_KEY_1 0x60014 +#define AES_128_KEY_2 0x60018 +#define AES_128_KEY_3 0x6001c +#define AES_128_RANDOM_0 0x60020 +#define AES_128_RANDOM_1 0x60024 +#define CIPHER14_KM_0 0x60028 +#define CIPHER14_KM_1 0x6002c +#define CIPHER14_STATUS 0x60030 +#define CIPHER14_RI_PJ_STATUS 0x60034 +#define CIPHER_MODE 0x60038 +#define CIPHER14_AN_0 0x6003c +#define CIPHER14_AN_1 0x60040 +#define CIPHER22_AUTH 0x60044 +#define CIPHER14_R0_DP_STATUS 0x60048 +#define CIPHER14_BOOTSTRAP 0x6004c + +#define DPTX_FRMR_DATA_CLK_RSTN_EN BIT(11) +#define DPTX_FRMR_DATA_CLK_EN BIT(10) +#define DPTX_PHY_DATA_RSTN_EN BIT(9) +#define DPTX_PHY_DATA_CLK_EN BIT(8) +#define DPTX_PHY_CHAR_RSTN_EN BIT(7) +#define DPTX_PHY_CHAR_CLK_EN BIT(6) +#define SOURCE_AUX_SYS_CLK_RSTN_EN BIT(5) +#define SOURCE_AUX_SYS_CLK_EN BIT(4) +#define DPTX_SYS_CLK_RSTN_EN BIT(3) +#define DPTX_SYS_CLK_EN BIT(2) +#define CFG_DPTX_VIF_CLK_RSTN_EN BIT(1) +#define CFG_DPTX_VIF_CLK_EN BIT(0) + +#define SOURCE_PHY_RSTN_EN BIT(1) +#define SOURCE_PHY_CLK_EN BIT(0) + +#define SOURCE_PKT_SYS_RSTN_EN BIT(3) +#define SOURCE_PKT_SYS_CLK_EN BIT(2) +#define SOURCE_PKT_DATA_RSTN_EN BIT(1) +#define SOURCE_PKT_DATA_CLK_EN BIT(0) + +#define SPDIF_CDR_CLK_RSTN_EN BIT(5) +#define SPDIF_CDR_CLK_EN BIT(4) +#define SOURCE_AIF_SYS_RSTN_EN BIT(3) +#define SOURCE_AIF_SYS_CLK_EN BIT(2) +#define SOURCE_AIF_CLK_RSTN_EN BIT(1) +#define SOURCE_AIF_CLK_EN BIT(0) + +#define SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN BIT(3) +#define SOURCE_CIPHER_SYS_CLK_EN BIT(2) +#define SOURCE_CIPHER_CHAR_CLK_RSTN_EN BIT(1) +#define SOURCE_CIPHER_CHAR_CLK_EN BIT(0) + +#define SOURCE_CRYPTO_SYS_CLK_RSTN_EN BIT(1) +#define SOURCE_CRYPTO_SYS_CLK_EN BIT(0) + +#define APB_IRAM_PATH BIT(2) +#define APB_DRAM_PATH BIT(1) +#define APB_XT_RESET BIT(0) + +#define MAILBOX_INT_MASK_BIT BIT(1) +#define PIF_INT_MASK_BIT BIT(0) +#define ALL_INT_MASK 3 + +/* mailbox */ +#define MB_OPCODE_ID 0 +#define MB_MODULE_ID 1 +#define MB_SIZE_MSB_ID 2 +#define MB_SIZE_LSB_ID 3 +#define MB_DATA_ID 4 + +#define MB_MODULE_ID_DP_TX 0x01 +#define MB_MODULE_ID_HDCP_TX 0x07 +#define MB_MODULE_ID_HDCP_RX 0x08 +#define MB_MODULE_ID_HDCP_GENERAL 0x09 +#define MB_MODULE_ID_GENERAL 0x0a + +/* general opcode */ +#define GENERAL_MAIN_CONTROL 0x01 +#define GENERAL_TEST_ECHO 0x02 +#define GENERAL_BUS_SETTINGS 0x03 +#define GENERAL_TEST_ACCESS 0x04 + +#define DPTX_SET_POWER_MNG 0x00 +#define DPTX_SET_HOST_CAPABILITIES 0x01 +#define DPTX_GET_EDID 0x02 +#define DPTX_READ_DPCD 0x03 +#define DPTX_WRITE_DPCD 0x04 +#define DPTX_ENABLE_EVENT 0x05 +#define DPTX_WRITE_REGISTER 0x06 +#define DPTX_READ_REGISTER 0x07 +#define DPTX_WRITE_FIELD 0x08 +#define DPTX_TRAINING_CONTROL 0x09 +#define DPTX_READ_EVENT 0x0a +#define DPTX_READ_LINK_STAT 0x0b +#define DPTX_SET_VIDEO 0x0c +#define DPTX_SET_AUDIO 0x0d +#define DPTX_GET_LAST_AUX_STAUS 0x0e +#define DPTX_SET_LINK_BREAK_POINT 0x0f +#define DPTX_FORCE_LANES 0x10 +#define DPTX_HPD_STATE 0x11 + +#define FW_STANDBY 0 +#define FW_ACTIVE 1 + +#define DPTX_EVENT_ENABLE_HPD BIT(0) +#define DPTX_EVENT_ENABLE_TRAINING BIT(1) + +#define LINK_TRAINING_NOT_ACTIVE 0 +#define LINK_TRAINING_RUN 1 +#define LINK_TRAINING_RESTART 2 + +#define CONTROL_VIDEO_IDLE 0 +#define CONTROL_VIDEO_VALID 1 + +#define VIF_BYPASS_INTERLACE BIT(13) +#define INTERLACE_FMT_DET BIT(12) +#define INTERLACE_DTCT_WIN 0x20 + +#define DP_FRAMER_SP_INTERLACE_EN BIT(2) +#define DP_FRAMER_SP_HSP BIT(1) +#define DP_FRAMER_SP_VSP BIT(0) + +/* capability */ +#define AUX_HOST_INVERT 3 +#define FAST_LT_SUPPORT 1 +#define FAST_LT_NOT_SUPPORT 0 +#define LANE_MAPPING_NORMAL 0x1b +#define LANE_MAPPING_FLIPPED 0xe4 +#define ENHANCED 1 + +#define FULL_LT_STARTED BIT(0) +#define FASE_LT_STARTED BIT(1) +#define CLK_RECOVERY_FINISHED BIT(2) +#define EQ_PHASE_FINISHED BIT(3) +#define FASE_LT_START_FINISHED BIT(4) +#define CLK_RECOVERY_FAILED BIT(5) +#define EQ_PHASE_FAILED BIT(6) +#define FASE_LT_FAILED BIT(7) + +#define DPTX_HPD_EVENT BIT(0) +#define DPTX_TRAINING_EVENT BIT(1) +#define HDCP_TX_STATUS_EVENT BIT(4) +#define HDCP2_TX_IS_KM_STORED_EVENT BIT(5) +#define HDCP2_TX_STORE_KM_EVENT BIT(6) +#define HDCP_TX_IS_RECEIVER_ID_VALID_EVENT BIT(7) + +#define TU_SIZE 30 +#define CDN_DP_MAX_LINK_RATE DP_LINK_BW_5_4 + +/* audio */ +#define AUDIO_PACK_EN BIT(8) +#define SAMPLING_FREQ(x) (((x) & 0xf) << 16) +#define ORIGINAL_SAMP_FREQ(x) (((x) & 0xf) << 24) +#define SYNC_WR_TO_CH_ZERO BIT(1) +#define I2S_DEC_START BIT(1) +#define AUDIO_SW_RST BIT(0) +#define SMPL2PKT_EN BIT(1) +#define MAX_NUM_CH(x) (((x) & 0x1f) - 1) +#define NUM_OF_I2S_PORTS(x) ((((x) / 2 - 1) & 0x3) << 5) +#define AUDIO_TYPE_LPCM (2 << 7) +#define CFG_SUB_PCKT_NUM(x) ((((x) - 1) & 0x7) << 11) +#define AUDIO_CH_NUM(x) ((((x) - 1) & 0x1f) << 2) +#define TRANS_SMPL_WIDTH_16 0 +#define TRANS_SMPL_WIDTH_24 BIT(11) +#define TRANS_SMPL_WIDTH_32 (2 << 11) +#define I2S_DEC_PORT_EN(x) (((x) & 0xf) << 17) +#define SPDIF_ENABLE BIT(21) +#define SPDIF_AVG_SEL BIT(20) +#define SPDIF_JITTER_BYPASS BIT(19) +#define SPDIF_FIFO_MID_RANGE(x) (((x) & 0xff) << 11) +#define SPDIF_JITTER_THRSH(x) (((x) & 0xff) << 3) +#define SPDIF_JITTER_AVG_WIN(x) ((x) & 0x7) + +/* Refernce cycles when using lane clock as refernce */ +#define LANE_REF_CYC 0x8000 + +enum voltage_swing_level { + VOLTAGE_LEVEL_0, + VOLTAGE_LEVEL_1, + VOLTAGE_LEVEL_2, + VOLTAGE_LEVEL_3, +}; + +enum pre_emphasis_level { + PRE_EMPHASIS_LEVEL_0, + PRE_EMPHASIS_LEVEL_1, + PRE_EMPHASIS_LEVEL_2, + PRE_EMPHASIS_LEVEL_3, +}; + +enum pattern_set { + PTS1 = BIT(0), + PTS2 = BIT(1), + PTS3 = BIT(2), + PTS4 = BIT(3), + DP_NONE = BIT(4) +}; + +enum vic_color_depth { + BCS_6 = 0x1, + BCS_8 = 0x2, + BCS_10 = 0x4, + BCS_12 = 0x8, + BCS_16 = 0x10, +}; + +enum vic_bt_type { + BT_601 = 0x0, + BT_709 = 0x1, +}; + +void cdn_dp_clock_reset(struct cdn_dp_device *dp); + +void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, u32 clk); +int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem, + u32 i_size, const u32 *d_mem, u32 d_size); +int cdn_dp_set_firmware_active(struct cdn_dp_device *dp, bool enable); +int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip); +int cdn_dp_event_config(struct cdn_dp_device *dp); +u32 cdn_dp_get_event(struct cdn_dp_device *dp); +int cdn_dp_get_hpd_status(struct cdn_dp_device *dp); +int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value); +int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len); +int cdn_dp_get_edid_block(void *dp, u8 *edid, + unsigned int block, size_t length); +int cdn_dp_training_start(struct cdn_dp_device *dp); +int cdn_dp_get_training_status(struct cdn_dp_device *dp); +int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active); +int cdn_dp_config_video(struct cdn_dp_device *dp); +int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio); +int cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable); +int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio); +#endif /* _CDN_DP_REG_H */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index a711589..cc73d56 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1048,9 +1048,11 @@ static void vop_crtc_enable(struct drm_crtc *crtc) vop_dsp_hold_valid_irq_disable(vop); } - pin_pol = 0x8; - pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1; - pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : (1 << 1); + pin_pol = BIT(DCLK_INVERT); + pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? + 0 : BIT(HSYNC_POSITIVE); + pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? + 0 : BIT(VSYNC_POSITIVE); VOP_CTRL_SET(vop, pin_pol, pin_pol); switch (s->output_type) { @@ -1070,6 +1072,11 @@ static void vop_crtc_enable(struct drm_crtc *crtc) VOP_CTRL_SET(vop, mipi_pin_pol, pin_pol); VOP_CTRL_SET(vop, mipi_en, 1); break; + case DRM_MODE_CONNECTOR_DisplayPort: + pin_pol &= ~BIT(DCLK_INVERT); + VOP_CTRL_SET(vop, dp_pin_pol, pin_pol); + VOP_CTRL_SET(vop, dp_en, 1); + break; default: DRM_DEV_ERROR(vop->dev, "unsupported connector_type [%d]\n", s->output_type); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 1dbc526..5a4faa85 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -45,6 +45,7 @@ struct vop_ctrl { struct vop_reg edp_en; struct vop_reg hdmi_en; struct vop_reg mipi_en; + struct vop_reg dp_en; struct vop_reg out_mode; struct vop_reg dither_down; struct vop_reg dither_up; @@ -53,6 +54,7 @@ struct vop_ctrl { struct vop_reg hdmi_pin_pol; struct vop_reg edp_pin_pol; struct vop_reg mipi_pin_pol; + struct vop_reg dp_pin_pol; struct vop_reg htotal_pw; struct vop_reg hact_st_end; @@ -244,6 +246,13 @@ enum scale_down_mode { SCALE_DOWN_AVG = 0x1 }; +enum vop_pol { + HSYNC_POSITIVE = 0, + VSYNC_POSITIVE = 1, + DEN_NEGATIVE = 2, + DCLK_INVERT = 3 +}; + #define FRAC_16_16(mult, div) (((mult) << 16) / (div)) #define SCL_FT_DEFAULT_FIXPOINT_SHIFT 12 #define SCL_MAX_VSKIPLINES 4 diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index eea8427..aaede6b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -283,6 +283,7 @@ static const struct vop_data rk3288_vop = { static const struct vop_ctrl rk3399_ctrl_data = { .standby = VOP_REG(RK3399_SYS_CTRL, 0x1, 22), .gate_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 23), + .dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11), .rgb_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 12), .hdmi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 13), .edp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 14), @@ -292,6 +293,7 @@ static const struct vop_ctrl rk3399_ctrl_data = { .data_blank = VOP_REG(RK3399_DSP_CTRL0, 0x1, 19), .out_mode = VOP_REG(RK3399_DSP_CTRL0, 0xf, 0), .rgb_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16), + .dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16), .hdmi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 20), .edp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 24), .mipi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 28), -- 1.9.1