From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S965379AbcHBMqq (ORCPT ); Tue, 2 Aug 2016 08:46:46 -0400 Received: from mail-pf0-f193.google.com ([209.85.192.193]:36135 "EHLO mail-pf0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S965132AbcHBMqF (ORCPT ); Tue, 2 Aug 2016 08:46:05 -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 Cc: linux-rockchip@lists.infradead.org, Chris Zhong , Mark Yao , David Airlie , linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org Subject: [v9 PATCH 6/6] drm/rockchip: cdn-dp: add cdn DP support for rk3399 Date: Tue, 2 Aug 2016 20:45:13 +0800 Message-Id: <1470141913-1082-7-git-send-email-zyw@rock-chips.com> X-Mailer: git-send-email 2.6.3 In-Reply-To: <1470141913-1082-1-git-send-email-zyw@rock-chips.com> References: <1470141913-1082-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 Reviewed-by: Sean Paul Acked-by: Mark Yao --- 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 | 860 +++++++++++++++++++++++++ drivers/gpu/drm/rockchip/cdn-dp-core.h | 103 +++ drivers/gpu/drm/rockchip/cdn-dp-reg.c | 959 ++++++++++++++++++++++++++++ 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, 2436 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 05d0713..abdecd5 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..e1a9670 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -0,0 +1,860 @@ +/* + * 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) + +/* dp grf register offset */ +#define DP_VOP_SEL 0x6224 +#define DP_SEL_VOP_LIT BIT(12) +#define MAX_FW_WAIT_SECS 64 +#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_clk_enable(struct cdn_dp_device *dp) +{ + int ret; + u32 rate; + + ret = clk_prepare_enable(dp->pclk); + if (ret < 0) { + dev_err(dp->dev, "cannot enable dp pclk %d\n", ret); + goto err_pclk; + } + + ret = clk_prepare_enable(dp->core_clk); + if (ret < 0) { + dev_err(dp->dev, "cannot enable core_clk %d\n", ret); + goto err_core_clk; + } + + rate = clk_get_rate(dp->core_clk); + if (rate < 0) { + dev_err(dp->dev, "get clk rate failed: %d\n", rate); + goto err_set_rate; + } + + cdn_dp_set_fw_clk(dp, rate); + + return 0; + +err_set_rate: + clk_disable_unprepare(dp->core_clk); +err_core_clk: + clk_disable_unprepare(dp->pclk); +err_pclk: + return ret; +} + +static enum drm_connector_status +cdn_dp_connector_detect(struct drm_connector *connector, bool force) +{ + struct cdn_dp_device *dp = connector_to_dp(connector); + + return dp->hpd_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; + + edid = drm_do_get_edid(connector, cdn_dp_get_edid_block, dp); + if (edid) { + dev_dbg(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); + } + + 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 = mode->clock * display_info->bpc * 3 / 1000; + u32 actual, rate, sink_max, source_max = 0; + u8 lanes, i; + + /* find the running port */ + for (i = 0; i < dp->ports; i++) { + if (dp->port[i]->phy_status) { + source_max = dp->port[i]->cap_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) { + dev_dbg(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 void cdn_dp_commit(struct drm_encoder *encoder) +{ + struct cdn_dp_device *dp = encoder_to_dp(encoder); + int ret; + + ret = cdn_dp_training_start(dp); + if (ret) + return; + + ret = cdn_dp_get_training_status(dp); + if (ret) + return; + + 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)) + return; + + if (cdn_dp_config_video(dp)) + return; + + if (cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID)) + return; + + dp->dpms_mode = DRM_MODE_DPMS_ON; +} + +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) { + dev_err(dp->dev, "Could not get vop id, %d", ret); + return; + } + + dev_dbg(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 = regmap_write(dp->grf, DP_VOP_SEL, val); + if (ret != 0) + dev_err(dp->dev, "Could not write to GRF: %d\n", ret); + + 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); + + if (dp->dpms_mode != DRM_MODE_DPMS_ON) + cdn_dp_commit(encoder); +} + +static void cdn_dp_encoder_disable(struct drm_encoder *encoder) +{ + struct cdn_dp_device *dp = encoder_to_dp(encoder); + + dp->dpms_mode = DRM_MODE_DPMS_OFF; +} + +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_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)) { + dev_err(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) { + dev_err(dp->dev, "active ucpu failed: %d\n", ret); + return ret; + } + + dp->fw_loaded = 1; + + return cdn_dp_event_config(dp); +} + +static int cdn_dp_init(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; + int ret; + + dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); + if (IS_ERR(dp->grf)) { + dev_err(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)) { + dev_err(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)) { + dev_err(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)) { + dev_err(dev, "cannot get pclk\n"); + return PTR_ERR(dp->pclk); + } + + dp->spdif_clk = devm_clk_get(dev, "spdif"); + if (IS_ERR(dp->spdif_clk)) { + dev_err(dev, "cannot get spdif_clk\n"); + return PTR_ERR(dp->spdif_clk); + } + + dp->spdif_rst = devm_reset_control_get(dev, "spdif"); + if (IS_ERR(dp->spdif_rst)) { + dev_err(dev, "no spdif reset control found\n"); + return PTR_ERR(dp->spdif_rst); + } + + dp->dpms_mode = DRM_MODE_DPMS_OFF; + + ret = cdn_dp_clk_enable(dp); + if (ret < 0) + return ret; + + cdn_dp_clock_reset(dp); + + 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: + dev_err(dev, "%s: Invalid format %d\n", __func__, 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); + struct drm_mode_config *config = &dp->encoder.dev->mode_config; + struct drm_connector *connector; + int ret = -ENODEV; + + mutex_lock(&config->mutex); + list_for_each_entry(connector, &config->connector_list, head) { + if (&dp->encoder == connector->encoder) { + memcpy(buf, connector->eld, + min(sizeof(connector->eld), len)); + ret = 0; + } + } + mutex_unlock(&config->mutex); + + return ret; +} + +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_get_cap_lanes(struct cdn_dp_device *dp, + struct extcon_dev *edev) +{ + bool dfp, dptx; + u8 lanes; + + dfp = extcon_get_state(edev, EXTCON_USB_HOST); + dptx = extcon_get_state(edev, EXTCON_DISP_DP); + + if (dfp && dptx) + lanes = 2; + else if (dptx) + lanes = 4; + else + lanes = 0; + + return lanes; +} + +static int cdn_dp_pd_event(struct notifier_block *nb, + unsigned long event, void *priv) +{ + struct cdn_dp_port *port; + + port = container_of(nb, struct cdn_dp_port, event_nb); + + schedule_delayed_work(&port->event_wq, 0); + + return 0; +} + +static void cdn_dp_pd_event_wq(struct work_struct *work) +{ + struct cdn_dp_port *port = container_of(work, struct cdn_dp_port, + event_wq.work); + union extcon_property_value property; + struct cdn_dp_device *dp = port->dp; + u8 new_cap_lanes, i; + int ret; + + new_cap_lanes = cdn_dp_get_cap_lanes(dp, port->extcon); + + if (new_cap_lanes == port->cap_lanes) { + dev_dbg(dp->dev, "lanes count does not change: %d\n", + new_cap_lanes); + return; + } + + if (!new_cap_lanes) { + ret = phy_power_off(port->phy); + if (ret) { + dev_err(dp->dev, "phy power off failed: %d", ret); + return; + } + port->phy_status = false; + port->cap_lanes = new_cap_lanes; + for (i = 0; i < dp->ports; i++) { + if (dp->port[i]->phy_status) + return; + } + + dp->hpd_status = connector_status_disconnected; + drm_helper_hpd_irq_event(dp->drm_dev); + cdn_dp_set_firmware_active(dp, false); + return; + } + + /* if other phy is running, do not touch the hpd_status, and return */ + for (i = 0; i < dp->ports; i++) { + if (dp->port[i]->phy_status) { + dev_warn(dp->dev, "busy, phy[%d] is running", + dp->port[i]->id); + return; + } + } + + if (!dp->fw_loaded) { + ret = request_firmware(&dp->fw, CDN_DP_FIRMWARE, dp->dev); + if (ret == -ENOENT && dp->fw_wait <= MAX_FW_WAIT_SECS) { + unsigned long time = msecs_to_jiffies(dp->fw_wait * HZ); + + /* + * If can not find the file, retry to load the firmware + * in several seconds, if still failed after 1 minute, + * give up. + */ + schedule_delayed_work(&port->event_wq, time); + dp->fw_wait *= 2; + return; + } else if (ret) { + dev_err(dp->dev, "failed to request firmware: %d\n", + ret); + return; + } + } + + if (dp->fw_loaded) + cdn_dp_set_firmware_active(dp, true); + + ret = phy_power_on(port->phy); + if (ret) { + if (!dp->fw_loaded) + release_firmware(dp->fw); + dev_err(dp->dev, "phy power on failed: %d\n", ret); + return; + } + + port->phy_status = true; + + if (!dp->fw_loaded) { + ret = cdn_dp_firmware_init(dp); + release_firmware(dp->fw); + if (ret) { + dev_err(dp->dev, "firmware init failed: %d", ret); + goto err_firmware; + } + } + + ret = cdn_dp_get_hpd_status(dp); + if (ret <= 0) { + if (!ret) + dev_err(dp->dev, "hpd does not exist\n"); + goto err_firmware; + } + + ret = extcon_get_property(port->extcon, EXTCON_DISP_DP, + EXTCON_PROP_USB_TYPEC_POLARITY, &property); + if (ret) { + dev_err(dp->dev, "get property failed\n"); + goto err_firmware; + } + + ret = cdn_dp_set_host_cap(dp, new_cap_lanes, property.intval); + if (ret) { + dev_err(dp->dev, "set host capabilities failed: %d\n", ret); + goto err_firmware; + } + + /* + * Native read with retry for link status and receiver capability reads + * for cases where the sink may still not be ready. + * + * Sinks are *supposed* to come up within 1ms from an off state, but + * some DOCKs need about 5 seconds to power up, so read the dpcd every + * 100ms, if can not get a good dpcd in 10 seconds, give up. + */ + for (i = 1; i < 100; i++) { + ret = cdn_dp_dpcd_read(dp, 0x000, dp->dpcd, + DP_RECEIVER_CAP_SIZE); + if (!ret) { + dev_dbg(dp->dev, "get dpcd success!\n"); + port->cap_lanes = new_cap_lanes; + dp->hpd_status = connector_status_connected; + drm_helper_hpd_irq_event(dp->drm_dev); + return; + } else if (!extcon_get_state(port->extcon, EXTCON_DISP_DP)) { + break; + } + msleep(100); + } + + dev_err(dp->dev, "get dpcd failed!\n"); + +err_firmware: + ret = phy_power_off(port->phy); + if (ret) + dev_err(dp->dev, "phy power off failed: %d", ret); + else + port->phy_status = false; + + if (dp->fw_loaded) + cdn_dp_set_firmware_active(dp, false); +} + +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; + + ret = cdn_dp_init(dp); + if (ret < 0) + return ret; + + dp->drm_dev = drm_dev; + dp->hpd_status = connector_status_disconnected; + dp->fw_wait = 1; + + 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; + INIT_DELAYED_WORK(&port->event_wq, cdn_dp_pd_event_wq); + ret = extcon_register_notifier(port->extcon, EXTCON_DISP_DP, + &port->event_nb); + if (ret) { + dev_err(dev, "register EXTCON_DISP_DP notifier err\n"); + return ret; + } + + if (extcon_get_state(port->extcon, EXTCON_DISP_DP)) + schedule_delayed_work(&port->event_wq, 0); + } + + 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; + struct cdn_dp_port *port; + int i; + + platform_device_unregister(dp->audio_pdev); + cdn_dp_encoder_disable(encoder); + encoder->funcs->destroy(encoder); + connector->funcs->destroy(connector); + + for (i = 0; i < dp->ports; i++) { + port = dp->port[i]; + extcon_unregister_notifier(port->extcon, EXTCON_DISP_DP, + &port->event_nb); + } +} + +static const struct component_ops cdn_dp_component_ops = { + .bind = cdn_dp_bind, + .unbind = cdn_dp_unbind, +}; + +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) { + dev_err(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 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), + }, +}; + +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..78424f9 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -0,0 +1,103 @@ +/* + * 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 delayed_work event_wq; + struct extcon_dev *extcon; + struct phy *phy; + u8 cap_lanes; + bool phy_status; + 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; + + const struct firmware *fw; /* cdn dp firmware */ + unsigned int fw_version; /* cdn fw version */ + u32 fw_wait; + bool fw_loaded; + bool fw_actived; + void __iomem *regs; + struct regmap *grf; + struct clk *core_clk; + struct clk *pclk; + struct clk *spdif_clk; + struct reset_control *spdif_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]; + enum drm_connector_status hpd_status; + int dpms_mode; + bool sink_has_audio; +}; +#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..2ea702d --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -0,0 +1,959 @@ +/* + * 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; + + if (!dp->fw_actived && !force) + return -EPERM; + + 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; + + if (!dp->fw_actived && !force) + return -EPERM; + + 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 read. + */ + 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) + dev_err(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) { + dev_err(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; + } + + dp->fw_actived = (msg[4] == FW_ACTIVE); + ret = 0; + +err_set_firmware_active: + if (ret < 0) + dev_err(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) + dev_err(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) + dev_err(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: + dev_err(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]; + int ret; + + 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) + goto err_get_edid; + + ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, + DPTX_GET_EDID, + sizeof(reg) + length); + if (ret) + goto err_get_edid; + + ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg)); + if (ret) + goto err_get_edid; + + ret = cdn_dp_mailbox_read_receive(dp, edid, length); + if (ret) + goto err_get_edid; + + if (reg[0] != length || reg[1] != block / 2) + ret = -EINVAL; + +err_get_edid: + if (ret) + dev_err(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: + dev_err(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) + dev_err(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) + dev_err(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) + dev_err(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) { + dev_err(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) + dev_err(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 + cdn_dp_audio_config_spdif(dp); + + ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN); + +err_audio_config: + if (ret) + dev_err(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 edd7ec2..d723d8e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -969,9 +969,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) { @@ -991,6 +993,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_ERROR("unsupport 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 ff4f52e..4820a8b 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; @@ -242,6 +244,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 5b1ae1f..dcf172e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -281,6 +281,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), @@ -290,6 +291,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), -- 2.6.3 From mboxrd@z Thu Jan 1 00:00:00 1970 From: Chris Zhong Subject: [v9 PATCH 6/6] drm/rockchip: cdn-dp: add cdn DP support for rk3399 Date: Tue, 2 Aug 2016 20:45:13 +0800 Message-ID: <1470141913-1082-7-git-send-email-zyw@rock-chips.com> References: <1470141913-1082-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: <1470141913-1082-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 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+ClJldmlld2VkLWJ5OiBTZWFuIFBhdWwgPHNlYW5wYXVsQGNocm9taXVt Lm9yZz4KQWNrZWQtYnk6IE1hcmsgWWFvIDxtYXJrLnlhb0Byb2NrLWNoaXBzLmNvbT4KCi0tLQoK Q2hhbmdlcyBpbiB2OToKLSBkbyBub3QgbmVlZCByZXNldCB0aGUgcGh5IGJlZm9yZSBwb3dlcl9v bgotIGFkZCBhIG9yaWVudGF0aW9uIGluZm9ybWF0aW9uIGZvciBzZXRfY2FwYWJpbGl0eQotIHJl dHJ5IHRvIHJlYWQgZHBjZCBpbiAxMCBzZWNvbmRzCgpDaGFuZ2VzIGluIHY4OgotIG9wdGltaXph dGlvbiB0aGUgZXJyIGxvZwoKQ2hhbmdlcyBpbiB2NzoKLSBzdXBwb3J0IGZpcm13YXJlIHN0YW5k Ynkgd2hlbiBubyBkcHR4IGNvbm5lY3Rpb24KLSBvcHRpbWl6YXRpb24gdGhlIGNhbGN1bGF0aW9u IG9mIHR1IHNpemUgYW5kIHZhbGlkIHN5bWJvbAoKQ2hhbmdlcyBpbiB2NjoKLSBhZGQgYSBwb3J0 IHN0cnVjdAotIHNlbGVjdCBTTkRfU09DX0hETUlfQ09ERUMKLSBmb3JjZSByZXNldCB0aGUgcGh5 IHdoZW4gaHBkIGRldGVjdGVkCgpDaGFuZ2VzIGluIHY1OgotIGFscGhhYmV0aWNhbCBvcmRlcgot IGRvIG5vdCB1c2UgbG9uZywgdXNlIHUzMiBvciB1NjQKLSByZXR1cm4gTU9ERV9DTE9DS19ISUdI IHdoZW4gcmVxdWVzdGVkID4gYWN0dWFsCi0gT3B0aW1pemVkIENvZGluZyBTdHlsZQotIGFkZCBh IGZvcm11bGEgdG8gZ2V0IGJldHRlciB0dSBzaXplIGFuZCBzeW1ib2wgdmFsdWUuCi0gbW9kaWZ5 IGFjY29yZGluZyB0byBTZWFuIFBhdWwncyBjb21tZW50cwotIGZpeGVkIHRoZSBmd193YWl0IGFs d2F5cyAwCgpDaGFuZ2VzIGluIHY0OgotIHVzZSBwaHkgZnJhbWV3b3JrIHRvIGNvbnRyb2wgRFAg cGh5Ci0gc3VwcG9ydCAyIHBoeXMKCkNoYW5nZXMgaW4gdjM6Ci0gdXNlIEVYVENPTl9ESVNQX0RQ IGFuZCBFWFRDT05fRElTUF9EUF9BTFQgY2FibGUgdG8gZ2V0IGRwIHBvcnQgc3RhdGUuCi0gcmVz ZXQgc3BkaWYgYmVmb3JlIGNvbmZpZyBpdAotIG1vZGlmeSB0aGUgZmlybXdhcmUgY2xrIHRvIDEw ME1oegotIHJldHJ5IGxvYWQgZmlybXdhcmUgaWYgZncgZmlsZSBpcyByZXF1ZXN0ZWQgdG9vIGVh cmx5CgpDaGFuZ2VzIGluIHYyOgotIEFscGhhYmV0aWMgb3JkZXIKLSByZW1vdmUgZXhjZXNzIGVy cm9yIG1lc3NhZ2UKLSB1c2UgZGVmaW5lIGNsa19yYXRlCi0gY2hlY2sgYWxsIHJldHVybiB2YWx1 ZQotIHJlbW92ZSBkZXZfc2V0X25hbWUoZHAtPmRldiwgImNkbi1kcCIpOwotIHVzZSBzY2hlZHVs ZV9kZWxheWVkX3dvcmsKLSByZW1vdmUgbmV2ZXItY2FsbGVkIGZ1bmN0aW9ucwotIHJlbW92ZSBz b21lIHVubmVjZXNzYXJ5ICgpCgpDaGFuZ2VzIGluIHYxOgotIHVzZSBleHRjb24gQVBJCi0gdXNl IGhkbWktY29kZWMgZm9yIHRoZSBEUCBBc29jCi0gZG8gbm90IGluaXRpYWxpemUgdGhlICJyZXQi Ci0gcHJpbnRrIGEgZXJyIGxvZyB3aGVuIGRybV9vZl9lbmNvZGVyX2FjdGl2ZV9lbmRwb2ludF9p ZAotIG1vZGlmeSB0aGUgZGNsayBwaW5fcG9sIHRvIGEgc2luZ2xlIGxpbmUKCiBkcml2ZXJzL2dw dS9kcm0vcm9ja2NoaXAvS2NvbmZpZyAgICAgICAgICAgIHwgIDEwICsKIGRyaXZlcnMvZ3B1L2Ry bS9yb2NrY2hpcC9NYWtlZmlsZSAgICAgICAgICAgfCAgIDEgKwogZHJpdmVycy9ncHUvZHJtL3Jv Y2tjaGlwL2Nkbi1kcC1jb3JlLmMgICAgICB8IDg2MCArKysrKysrKysrKysrKysrKysrKysrKysr CiBkcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvY2RuLWRwLWNvcmUuaCAgICAgIHwgMTAzICsrKwog ZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL2Nkbi1kcC1yZWcuYyAgICAgICB8IDk1OSArKysrKysr KysrKysrKysrKysrKysrKysrKysrCiBkcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvY2RuLWRwLXJl Zy5oICAgICAgIHwgNDgyICsrKysrKysrKysrKysrCiBkcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAv cm9ja2NoaXBfZHJtX3ZvcC5jIHwgIDEzICstCiBkcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvcm9j a2NoaXBfZHJtX3ZvcC5oIHwgICA5ICsKIGRyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9yb2NrY2hp cF92b3BfcmVnLmMgfCAgIDIgKwogOSBmaWxlcyBjaGFuZ2VkLCAyNDM2IGluc2VydGlvbnMoKyks IDMgZGVsZXRpb25zKC0pCiBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9ncHUvZHJtL3JvY2tj aGlwL2Nkbi1kcC1jb3JlLmMKIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL2dwdS9kcm0vcm9j a2NoaXAvY2RuLWRwLWNvcmUuaAogY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvZ3B1L2RybS9y b2NrY2hpcC9jZG4tZHAtcmVnLmMKIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL2dwdS9kcm0v cm9ja2NoaXAvY2RuLWRwLXJlZy5oCgpkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJtL3JvY2tj aGlwL0tjb25maWcgYi9kcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvS2NvbmZpZwppbmRleCBkMzBi ZGMzLi4yMGFhYWZlIDEwMDY0NAotLS0gYS9kcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvS2NvbmZp ZworKysgYi9kcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvS2NvbmZpZwpAQCAtMjUsNiArMjUsMTYg QEAgY29uZmlnIFJPQ0tDSElQX0FOQUxPR0lYX0RQCiAJICBmb3IgdGhlIEFuYWxvZ2l4IENvcmUg RFAgZHJpdmVyLiBJZiB5b3Ugd2FudCB0byBlbmFibGUgRFAKIAkgIG9uIFJLMzI4OCBiYXNlZCBT b0MsIHlvdSBzaG91bGQgc2VsZXQgdGhpcyBvcHRpb24uCiAKK2NvbmZpZyBST0NLQ0hJUF9DRE5f RFAKKyAgICAgICAgdHJpc3RhdGUgIlJvY2tjaGlwIGNkbiBEUCIKKyAgICAgICAgZGVwZW5kcyBv biBEUk1fUk9DS0NISVAKKwlzZWxlY3QgU05EX1NPQ19IRE1JX0NPREVDIGlmIFNORF9TT0MKKyAg ICAgICAgaGVscAorCSAgVGhpcyBzZWxlY3RzIHN1cHBvcnQgZm9yIFJvY2tjaGlwIFNvQyBzcGVj aWZpYyBleHRlbnNpb25zCisJICBmb3IgdGhlIGNkbiBEUCBkcml2ZXIuIElmIHlvdSB3YW50IHRv IGVuYWJsZSBEcCBvbgorCSAgUkszMzk5IGJhc2VkIFNvQywgeW91IHNob3VsZCBzZWxlY3QgdGhp cworCSAgb3B0aW9uLgorCiBjb25maWcgUk9DS0NISVBfRFdfSERNSQogICAgICAgICB0cmlzdGF0 ZSAiUm9ja2NoaXAgc3BlY2lmaWMgZXh0ZW5zaW9ucyBmb3IgU3lub3BzeXMgRFcgSERNSSIKICAg ICAgICAgZGVwZW5kcyBvbiBEUk1fUk9DS0NISVAKZGlmZiAtLWdpdCBhL2RyaXZlcnMvZ3B1L2Ry bS9yb2NrY2hpcC9NYWtlZmlsZSBiL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9NYWtlZmlsZQpp bmRleCAwNWQwNzEzLi5hYmRlY2Q1IDEwMDY0NAotLS0gYS9kcml2ZXJzL2dwdS9kcm0vcm9ja2No aXAvTWFrZWZpbGUKKysrIGIvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL01ha2VmaWxlCkBAIC03 LDYgKzcsNyBAQCByb2NrY2hpcGRybS15IDo9IHJvY2tjaGlwX2RybV9kcnYubyByb2NrY2hpcF9k cm1fZmIubyBcCiByb2NrY2hpcGRybS0kKENPTkZJR19EUk1fRkJERVZfRU1VTEFUSU9OKSArPSBy b2NrY2hpcF9kcm1fZmJkZXYubwogCiBvYmotJChDT05GSUdfUk9DS0NISVBfQU5BTE9HSVhfRFAp ICs9IGFuYWxvZ2l4X2RwLXJvY2tjaGlwLm8KK29iai0kKENPTkZJR19ST0NLQ0hJUF9DRE5fRFAp ICs9IGNkbi1kcC1jb3JlLm8gY2RuLWRwLXJlZy5vCiBvYmotJChDT05GSUdfUk9DS0NISVBfRFdf SERNSSkgKz0gZHdfaGRtaS1yb2NrY2hpcC5vCiBvYmotJChDT05GSUdfUk9DS0NISVBfRFdfTUlQ SV9EU0kpICs9IGR3LW1pcGktZHNpLm8KIG9iai0kKENPTkZJR19ST0NLQ0hJUF9JTk5PX0hETUkp ICs9IGlubm9faGRtaS5vCmRpZmYgLS1naXQgYS9kcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvY2Ru LWRwLWNvcmUuYyBiL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9jZG4tZHAtY29yZS5jCm5ldyBm aWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAuLmUxYTk2NzAKLS0tIC9kZXYvbnVsbAorKysg Yi9kcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvY2RuLWRwLWNvcmUuYwpAQCAtMCwwICsxLDg2MCBA QAorLyoKKyAqIENvcHlyaWdodCAoQykgRnV6aG91IFJvY2tjaGlwIEVsZWN0cm9uaWNzIENvLkx0 ZAorICogQXV0aG9yOiBDaHJpcyBaaG9uZyA8enl3QHJvY2stY2hpcHMuY29tPgorICoKKyAqIFRo aXMgc29mdHdhcmUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJh bCBQdWJsaWMKKyAqIExpY2Vuc2UgdmVyc2lvbiAyLCBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUg U29mdHdhcmUgRm91bmRhdGlvbiwgYW5kCisgKiBtYXkgYmUgY29waWVkLCBkaXN0cmlidXRlZCwg YW5kIG1vZGlmaWVkIHVuZGVyIHRob3NlIHRlcm1zLgorICoKKyAqIFRoaXMgcHJvZ3JhbSBpcyBk aXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLAorICogYnV0IFdJ VEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YK KyAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4g IFNlZSB0aGUKKyAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMu CisgKi8KKworI2luY2x1ZGUgPGRybS9kcm1QLmg+CisjaW5jbHVkZSA8ZHJtL2RybV9hdG9taWNf aGVscGVyLmg+CisjaW5jbHVkZSA8ZHJtL2RybV9jcnRjX2hlbHBlci5oPgorI2luY2x1ZGUgPGRy bS9kcm1fZHBfaGVscGVyLmg+CisjaW5jbHVkZSA8ZHJtL2RybV9lZGlkLmg+CisjaW5jbHVkZSA8 ZHJtL2RybV9vZi5oPgorCisjaW5jbHVkZSA8bGludXgvY2xrLmg+CisjaW5jbHVkZSA8bGludXgv Y29tcG9uZW50Lmg+CisjaW5jbHVkZSA8bGludXgvZXh0Y29uLmg+CisjaW5jbHVkZSA8bGludXgv ZmlybXdhcmUuaD4KKyNpbmNsdWRlIDxsaW51eC9yZWdtYXAuaD4KKyNpbmNsdWRlIDxsaW51eC9y ZXNldC5oPgorCisjaW5jbHVkZSA8bGludXgvbWZkL3N5c2Nvbi5oPgorI2luY2x1ZGUgPGxpbnV4 L3BoeS9waHkuaD4KKworI2luY2x1ZGUgPHNvdW5kL2hkbWktY29kZWMuaD4KKworI2luY2x1ZGUg ImNkbi1kcC1jb3JlLmgiCisjaW5jbHVkZSAiY2RuLWRwLXJlZy5oIgorI2luY2x1ZGUgInJvY2tj aGlwX2RybV92b3AuaCIKKworI2RlZmluZSBjb25uZWN0b3JfdG9fZHAoYykgXAorCQljb250YWlu ZXJfb2YoYywgc3RydWN0IGNkbl9kcF9kZXZpY2UsIGNvbm5lY3RvcikKKworI2RlZmluZSBlbmNv ZGVyX3RvX2RwKGMpIFwKKwkJY29udGFpbmVyX29mKGMsIHN0cnVjdCBjZG5fZHBfZGV2aWNlLCBl bmNvZGVyKQorCisvKiBkcCBncmYgcmVnaXN0ZXIgb2Zmc2V0ICovCisjZGVmaW5lIERQX1ZPUF9T RUwJCTB4NjIyNAorI2RlZmluZSBEUF9TRUxfVk9QX0xJVAkJQklUKDEyKQorI2RlZmluZSBNQVhf RldfV0FJVF9TRUNTCTY0CisjZGVmaW5lIENETl9EUF9GSVJNV0FSRQkJInJvY2tjaGlwL2RwdHgu YmluIgorCitzdHJ1Y3QgY2RuX2RwX2RhdGEgeworCXU4IG1heF9waHk7Cit9OworCitzdHJ1Y3Qg Y2RuX2RwX2RhdGEgcmszMzk5X2Nkbl9kcCA9IHsKKwkubWF4X3BoeSA9IDIsCit9OworCitzdGF0 aWMgY29uc3Qgc3RydWN0IG9mX2RldmljZV9pZCBjZG5fZHBfZHRfaWRzW10gPSB7CisJeyAuY29t cGF0aWJsZSA9ICJyb2NrY2hpcCxyazMzOTktY2RuLWRwIiwKKwkJLmRhdGEgPSAodm9pZCAqKSZy azMzOTlfY2RuX2RwIH0sCisJe30KK307CisKK01PRFVMRV9ERVZJQ0VfVEFCTEUob2YsIGNkbl9k cF9kdF9pZHMpOworCitzdGF0aWMgaW50IGNkbl9kcF9jbGtfZW5hYmxlKHN0cnVjdCBjZG5fZHBf ZGV2aWNlICpkcCkKK3sKKwlpbnQgcmV0OworCXUzMiByYXRlOworCisJcmV0ID0gY2xrX3ByZXBh cmVfZW5hYmxlKGRwLT5wY2xrKTsKKwlpZiAocmV0IDwgMCkgeworCQlkZXZfZXJyKGRwLT5kZXYs ICJjYW5ub3QgZW5hYmxlIGRwIHBjbGsgJWRcbiIsIHJldCk7CisJCWdvdG8gZXJyX3BjbGs7CisJ fQorCisJcmV0ID0gY2xrX3ByZXBhcmVfZW5hYmxlKGRwLT5jb3JlX2Nsayk7CisJaWYgKHJldCA8 IDApIHsKKwkJZGV2X2VycihkcC0+ZGV2LCAiY2Fubm90IGVuYWJsZSBjb3JlX2NsayAlZFxuIiwg cmV0KTsKKwkJZ290byBlcnJfY29yZV9jbGs7CisJfQorCisJcmF0ZSA9IGNsa19nZXRfcmF0ZShk cC0+Y29yZV9jbGspOworCWlmIChyYXRlIDwgMCkgeworCQlkZXZfZXJyKGRwLT5kZXYsICJnZXQg Y2xrIHJhdGUgZmFpbGVkOiAlZFxuIiwgcmF0ZSk7CisJCWdvdG8gZXJyX3NldF9yYXRlOworCX0K KworCWNkbl9kcF9zZXRfZndfY2xrKGRwLCByYXRlKTsKKworCXJldHVybiAwOworCitlcnJfc2V0 X3JhdGU6CisJY2xrX2Rpc2FibGVfdW5wcmVwYXJlKGRwLT5jb3JlX2Nsayk7CitlcnJfY29yZV9j bGs6CisJY2xrX2Rpc2FibGVfdW5wcmVwYXJlKGRwLT5wY2xrKTsKK2Vycl9wY2xrOgorCXJldHVy biByZXQ7Cit9CisKK3N0YXRpYyBlbnVtIGRybV9jb25uZWN0b3Jfc3RhdHVzCitjZG5fZHBfY29u bmVjdG9yX2RldGVjdChzdHJ1Y3QgZHJtX2Nvbm5lY3RvciAqY29ubmVjdG9yLCBib29sIGZvcmNl KQoreworCXN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCA9IGNvbm5lY3Rvcl90b19kcChjb25uZWN0 b3IpOworCisJcmV0dXJuIGRwLT5ocGRfc3RhdHVzOworfQorCitzdGF0aWMgdm9pZCBjZG5fZHBf Y29ubmVjdG9yX2Rlc3Ryb3koc3RydWN0IGRybV9jb25uZWN0b3IgKmNvbm5lY3RvcikKK3sKKwlk cm1fY29ubmVjdG9yX3VucmVnaXN0ZXIoY29ubmVjdG9yKTsKKwlkcm1fY29ubmVjdG9yX2NsZWFu dXAoY29ubmVjdG9yKTsKK30KKworc3RhdGljIHN0cnVjdCBkcm1fY29ubmVjdG9yX2Z1bmNzIGNk bl9kcF9hdG9taWNfY29ubmVjdG9yX2Z1bmNzID0geworCS5kcG1zID0gZHJtX2F0b21pY19oZWxw ZXJfY29ubmVjdG9yX2RwbXMsCisJLmRldGVjdCA9IGNkbl9kcF9jb25uZWN0b3JfZGV0ZWN0LAor CS5kZXN0cm95ID0gY2RuX2RwX2Nvbm5lY3Rvcl9kZXN0cm95LAorCS5maWxsX21vZGVzID0gZHJt X2hlbHBlcl9wcm9iZV9zaW5nbGVfY29ubmVjdG9yX21vZGVzLAorCS5yZXNldCA9IGRybV9hdG9t aWNfaGVscGVyX2Nvbm5lY3Rvcl9yZXNldCwKKwkuYXRvbWljX2R1cGxpY2F0ZV9zdGF0ZSA9IGRy bV9hdG9taWNfaGVscGVyX2Nvbm5lY3Rvcl9kdXBsaWNhdGVfc3RhdGUsCisJLmF0b21pY19kZXN0 cm95X3N0YXRlID0gZHJtX2F0b21pY19oZWxwZXJfY29ubmVjdG9yX2Rlc3Ryb3lfc3RhdGUsCit9 OworCitzdGF0aWMgaW50IGNkbl9kcF9jb25uZWN0b3JfZ2V0X21vZGVzKHN0cnVjdCBkcm1fY29u bmVjdG9yICpjb25uZWN0b3IpCit7CisJc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwID0gY29ubmVj dG9yX3RvX2RwKGNvbm5lY3Rvcik7CisJc3RydWN0IGVkaWQgKmVkaWQ7CisJaW50IHJldCA9IDA7 CisKKwllZGlkID0gZHJtX2RvX2dldF9lZGlkKGNvbm5lY3RvciwgY2RuX2RwX2dldF9lZGlkX2Js b2NrLCBkcCk7CisJaWYgKGVkaWQpIHsKKwkJZGV2X2RiZyhkcC0+ZGV2LCAiZ290IGVkaWQ6IHdp ZHRoWyVkXSB4IGhlaWdodFslZF1cbiIsCisJCQllZGlkLT53aWR0aF9jbSwgZWRpZC0+aGVpZ2h0 X2NtKTsKKworCQlkcC0+c2lua19oYXNfYXVkaW8gPSBkcm1fZGV0ZWN0X21vbml0b3JfYXVkaW8o ZWRpZCk7CisJCXJldCA9IGRybV9hZGRfZWRpZF9tb2Rlcyhjb25uZWN0b3IsIGVkaWQpOworCQlp ZiAocmV0KSB7CisJCQlkcm1fbW9kZV9jb25uZWN0b3JfdXBkYXRlX2VkaWRfcHJvcGVydHkoY29u bmVjdG9yLAorCQkJCQkJCQllZGlkKTsKKwkJCWRybV9lZGlkX3RvX2VsZChjb25uZWN0b3IsIGVk aWQpOworCQl9CisJCWtmcmVlKGVkaWQpOworCX0KKworCXJldHVybiByZXQ7Cit9CisKK3N0YXRp YyBzdHJ1Y3QgZHJtX2VuY29kZXIgKgorCWNkbl9kcF9jb25uZWN0b3JfYmVzdF9lbmNvZGVyKHN0 cnVjdCBkcm1fY29ubmVjdG9yICpjb25uZWN0b3IpCit7CisJc3RydWN0IGNkbl9kcF9kZXZpY2Ug KmRwID0gY29ubmVjdG9yX3RvX2RwKGNvbm5lY3Rvcik7CisKKwlyZXR1cm4gJmRwLT5lbmNvZGVy OworfQorCitzdGF0aWMgaW50IGNkbl9kcF9jb25uZWN0b3JfbW9kZV92YWxpZChzdHJ1Y3QgZHJt X2Nvbm5lY3RvciAqY29ubmVjdG9yLAorCQkJCSAgICAgICBzdHJ1Y3QgZHJtX2Rpc3BsYXlfbW9k ZSAqbW9kZSkKK3sKKwlzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAgPSBjb25uZWN0b3JfdG9fZHAo Y29ubmVjdG9yKTsKKwlzdHJ1Y3QgZHJtX2Rpc3BsYXlfaW5mbyAqZGlzcGxheV9pbmZvID0gJmRw LT5jb25uZWN0b3IuZGlzcGxheV9pbmZvOworCXUzMiByZXF1ZXN0ZWQgPSBtb2RlLT5jbG9jayAq IGRpc3BsYXlfaW5mby0+YnBjICogMyAvIDEwMDA7CisJdTMyIGFjdHVhbCwgcmF0ZSwgc2lua19t YXgsIHNvdXJjZV9tYXggPSAwOworCXU4IGxhbmVzLCBpOworCisJLyogZmluZCB0aGUgcnVubmlu ZyBwb3J0ICovCisJZm9yIChpID0gMDsgaSA8IGRwLT5wb3J0czsgaSsrKSB7CisJCWlmIChkcC0+ cG9ydFtpXS0+cGh5X3N0YXR1cykgeworCQkJc291cmNlX21heCA9IGRwLT5wb3J0W2ldLT5jYXBf bGFuZXM7CisJCQlicmVhazsKKwkJfQorCX0KKworCXNpbmtfbWF4ID0gZHJtX2RwX21heF9sYW5l X2NvdW50KGRwLT5kcGNkKTsKKwlsYW5lcyA9IG1pbihzb3VyY2VfbWF4LCBzaW5rX21heCk7CisK Kwlzb3VyY2VfbWF4ID0gZHJtX2RwX2J3X2NvZGVfdG9fbGlua19yYXRlKENETl9EUF9NQVhfTElO S19SQVRFKTsKKwlzaW5rX21heCA9IGRybV9kcF9tYXhfbGlua19yYXRlKGRwLT5kcGNkKTsKKwly YXRlID0gbWluKHNvdXJjZV9tYXgsIHNpbmtfbWF4KTsKKworCWFjdHVhbCA9IHJhdGUgKiBsYW5l cyAvIDEwMDsKKworCS8qIGVmZmljaWVuY3kgaXMgYWJvdXQgMC44ICovCisJYWN0dWFsID0gYWN0 dWFsICogOCAvIDEwOworCisJaWYgKHJlcXVlc3RlZCA+IGFjdHVhbCkgeworCQlkZXZfZGJnKGRw LT5kZXYsICJyZXF1ZXN0ZWQ9JWQsIGFjdHVhbD0lZCwgY2xvY2s9JWRcbiIsCisJCQlyZXF1ZXN0 ZWQsIGFjdHVhbCwgbW9kZS0+Y2xvY2spOworCQlyZXR1cm4gTU9ERV9DTE9DS19ISUdIOworCX0K KworCXJldHVybiBNT0RFX09LOworfQorCitzdGF0aWMgc3RydWN0IGRybV9jb25uZWN0b3JfaGVs cGVyX2Z1bmNzIGNkbl9kcF9jb25uZWN0b3JfaGVscGVyX2Z1bmNzID0geworCS5nZXRfbW9kZXMg PSBjZG5fZHBfY29ubmVjdG9yX2dldF9tb2RlcywKKwkuYmVzdF9lbmNvZGVyID0gY2RuX2RwX2Nv bm5lY3Rvcl9iZXN0X2VuY29kZXIsCisJLm1vZGVfdmFsaWQgPSBjZG5fZHBfY29ubmVjdG9yX21v ZGVfdmFsaWQsCit9OworCitzdGF0aWMgdm9pZCBjZG5fZHBfY29tbWl0KHN0cnVjdCBkcm1fZW5j b2RlciAqZW5jb2RlcikKK3sKKwlzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAgPSBlbmNvZGVyX3Rv X2RwKGVuY29kZXIpOworCWludCByZXQ7CisKKwlyZXQgPSBjZG5fZHBfdHJhaW5pbmdfc3RhcnQo ZHApOworCWlmIChyZXQpCisJCXJldHVybjsKKworCXJldCA9IGNkbl9kcF9nZXRfdHJhaW5pbmdf c3RhdHVzKGRwKTsKKwlpZiAocmV0KQorCQlyZXR1cm47CisKKwlkZXZfaW5mbyhkcC0+ZGV2LCAi cmF0ZToweCV4LCBsYW5lczolZFxuIiwKKwkJIGRwLT5saW5rLnJhdGUsIGRwLT5saW5rLm51bV9s YW5lcyk7CisKKwlpZiAoY2RuX2RwX3NldF92aWRlb19zdGF0dXMoZHAsIENPTlRST0xfVklERU9f SURMRSkpCisJCXJldHVybjsKKworCWlmIChjZG5fZHBfY29uZmlnX3ZpZGVvKGRwKSkKKwkJcmV0 dXJuOworCisJaWYgKGNkbl9kcF9zZXRfdmlkZW9fc3RhdHVzKGRwLCBDT05UUk9MX1ZJREVPX1ZB TElEKSkKKwkJcmV0dXJuOworCisJZHAtPmRwbXNfbW9kZSA9IERSTV9NT0RFX0RQTVNfT047Cit9 CisKK3N0YXRpYyB2b2lkIGNkbl9kcF9lbmNvZGVyX21vZGVfc2V0KHN0cnVjdCBkcm1fZW5jb2Rl ciAqZW5jb2RlciwKKwkJCQkgICAgc3RydWN0IGRybV9kaXNwbGF5X21vZGUgKm1vZGUsCisJCQkJ ICAgIHN0cnVjdCBkcm1fZGlzcGxheV9tb2RlICphZGp1c3RlZCkKK3sKKwlzdHJ1Y3QgY2RuX2Rw X2RldmljZSAqZHAgPSBlbmNvZGVyX3RvX2RwKGVuY29kZXIpOworCXN0cnVjdCBkcm1fZGlzcGxh eV9pbmZvICpkaXNwbGF5X2luZm8gPSAmZHAtPmNvbm5lY3Rvci5kaXNwbGF5X2luZm87CisJc3Ry dWN0IHJvY2tjaGlwX2NydGNfc3RhdGUgKnN0YXRlOworCXN0cnVjdCB2aWRlb19pbmZvICp2aWRl byA9ICZkcC0+dmlkZW9faW5mbzsKKwlpbnQgcmV0LCB2YWw7CisKKwlzd2l0Y2ggKGRpc3BsYXlf aW5mby0+YnBjKSB7CisJY2FzZSAxNjoKKwljYXNlIDEyOgorCWNhc2UgMTA6CisJCXZpZGVvLT5j b2xvcl9kZXB0aCA9IDEwOworCQlicmVhazsKKwljYXNlIDY6CisJCXZpZGVvLT5jb2xvcl9kZXB0 aCA9IDY7CisJCWJyZWFrOworCWRlZmF1bHQ6CisJCXZpZGVvLT5jb2xvcl9kZXB0aCA9IDg7CisJ CWJyZWFrOworCX0KKworCXZpZGVvLT5jb2xvcl9mbXQgPSBQWExfUkdCOworCisJdmlkZW8tPnZf c3luY19wb2xhcml0eSA9ICEhKG1vZGUtPmZsYWdzICYgRFJNX01PREVfRkxBR19OVlNZTkMpOwor CXZpZGVvLT5oX3N5bmNfcG9sYXJpdHkgPSAhIShtb2RlLT5mbGFncyAmIERSTV9NT0RFX0ZMQUdf TkhTWU5DKTsKKworCXJldCA9IGRybV9vZl9lbmNvZGVyX2FjdGl2ZV9lbmRwb2ludF9pZChkcC0+ ZGV2LT5vZl9ub2RlLCBlbmNvZGVyKTsKKwlpZiAocmV0IDwgMCkgeworCQlkZXZfZXJyKGRwLT5k ZXYsICJDb3VsZCBub3QgZ2V0IHZvcCBpZCwgJWQiLCByZXQpOworCQlyZXR1cm47CisJfQorCisJ ZGV2X2RiZyhkcC0+ZGV2LCAidm9wICVzIG91dHB1dCB0byBjZG4tZHBcbiIsIChyZXQpID8gIkxJ VCIgOiAiQklHIik7CisJc3RhdGUgPSB0b19yb2NrY2hpcF9jcnRjX3N0YXRlKGVuY29kZXItPmNy dGMtPnN0YXRlKTsKKwlpZiAocmV0KSB7CisJCXZhbCA9IERQX1NFTF9WT1BfTElUIHwgKERQX1NF TF9WT1BfTElUIDw8IDE2KTsKKwkJc3RhdGUtPm91dHB1dF9tb2RlID0gUk9DS0NISVBfT1VUX01P REVfUDg4ODsKKwl9IGVsc2UgeworCQl2YWwgPSBEUF9TRUxfVk9QX0xJVCA8PCAxNjsKKwkJc3Rh dGUtPm91dHB1dF9tb2RlID0gUk9DS0NISVBfT1VUX01PREVfQUFBQTsKKwl9CisJcmV0ID0gcmVn bWFwX3dyaXRlKGRwLT5ncmYsIERQX1ZPUF9TRUwsIHZhbCk7CisJaWYgKHJldCAhPSAwKQorCQlk ZXZfZXJyKGRwLT5kZXYsICJDb3VsZCBub3Qgd3JpdGUgdG8gR1JGOiAlZFxuIiwgcmV0KTsKKwor CW1lbWNweSgmZHAtPm1vZGUsIGFkanVzdGVkLCBzaXplb2YoKm1vZGUpKTsKK30KKworc3RhdGlj IHZvaWQgY2RuX2RwX2VuY29kZXJfZW5hYmxlKHN0cnVjdCBkcm1fZW5jb2RlciAqZW5jb2RlcikK K3sKKwlzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAgPSBlbmNvZGVyX3RvX2RwKGVuY29kZXIpOwor CisJaWYgKGRwLT5kcG1zX21vZGUgIT0gRFJNX01PREVfRFBNU19PTikKKwkJY2RuX2RwX2NvbW1p dChlbmNvZGVyKTsKK30KKworc3RhdGljIHZvaWQgY2RuX2RwX2VuY29kZXJfZGlzYWJsZShzdHJ1 Y3QgZHJtX2VuY29kZXIgKmVuY29kZXIpCit7CisJc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwID0g ZW5jb2Rlcl90b19kcChlbmNvZGVyKTsKKworCWRwLT5kcG1zX21vZGUgPSBEUk1fTU9ERV9EUE1T X09GRjsKK30KKworc3RhdGljIGludAorY2RuX2RwX2VuY29kZXJfYXRvbWljX2NoZWNrKHN0cnVj dCBkcm1fZW5jb2RlciAqZW5jb2RlciwKKwkJCSAgICBzdHJ1Y3QgZHJtX2NydGNfc3RhdGUgKmNy dGNfc3RhdGUsCisJCQkgICAgc3RydWN0IGRybV9jb25uZWN0b3Jfc3RhdGUgKmNvbm5fc3RhdGUp Cit7CisJc3RydWN0IHJvY2tjaGlwX2NydGNfc3RhdGUgKnMgPSB0b19yb2NrY2hpcF9jcnRjX3N0 YXRlKGNydGNfc3RhdGUpOworCisJcy0+b3V0cHV0X21vZGUgPSBST0NLQ0hJUF9PVVRfTU9ERV9B QUFBOworCXMtPm91dHB1dF90eXBlID0gRFJNX01PREVfQ09OTkVDVE9SX0Rpc3BsYXlQb3J0Owor CisJcmV0dXJuIDA7Cit9CisKK3N0YXRpYyBzdHJ1Y3QgZHJtX2VuY29kZXJfaGVscGVyX2Z1bmNz IGNkbl9kcF9lbmNvZGVyX2hlbHBlcl9mdW5jcyA9IHsKKwkubW9kZV9zZXQgPSBjZG5fZHBfZW5j b2Rlcl9tb2RlX3NldCwKKwkuZW5hYmxlID0gY2RuX2RwX2VuY29kZXJfZW5hYmxlLAorCS5kaXNh YmxlID0gY2RuX2RwX2VuY29kZXJfZGlzYWJsZSwKKwkuYXRvbWljX2NoZWNrID0gY2RuX2RwX2Vu Y29kZXJfYXRvbWljX2NoZWNrLAorfTsKKworc3RhdGljIHN0cnVjdCBkcm1fZW5jb2Rlcl9mdW5j cyBjZG5fZHBfZW5jb2Rlcl9mdW5jcyA9IHsKKwkuZGVzdHJveSA9IGRybV9lbmNvZGVyX2NsZWFu dXAsCit9OworCitzdGF0aWMgaW50IGNkbl9kcF9maXJtd2FyZV9pbml0KHN0cnVjdCBjZG5fZHBf ZGV2aWNlICpkcCkKK3sKKwlpbnQgcmV0OworCWNvbnN0IHUzMiAqaXJhbV9kYXRhLCAqZHJhbV9k YXRhOworCWNvbnN0IHN0cnVjdCBmaXJtd2FyZSAqZncgPSBkcC0+Znc7CisJY29uc3Qgc3RydWN0 IGNkbl9maXJtd2FyZV9oZWFkZXIgKmhkcjsKKworCWhkciA9IChzdHJ1Y3QgY2RuX2Zpcm13YXJl X2hlYWRlciAqKWZ3LT5kYXRhOworCWlmIChmdy0+c2l6ZSAhPSBsZTMyX3RvX2NwdShoZHItPnNp emVfYnl0ZXMpKSB7CisJCWRldl9lcnIoZHAtPmRldiwgImZpcm13YXJlIGlzIGludmFsaWRcbiIp OworCQlyZXR1cm4gLUVJTlZBTDsKKwl9CisKKwlpcmFtX2RhdGEgPSAoY29uc3QgdTMyICopKGZ3 LT5kYXRhICsgaGRyLT5oZWFkZXJfc2l6ZSk7CisJZHJhbV9kYXRhID0gKGNvbnN0IHUzMiAqKShm dy0+ZGF0YSArIGhkci0+aGVhZGVyX3NpemUgKyBoZHItPmlyYW1fc2l6ZSk7CisKKwlyZXQgPSBj ZG5fZHBfbG9hZF9maXJtd2FyZShkcCwgaXJhbV9kYXRhLCBoZHItPmlyYW1fc2l6ZSwKKwkJCQkg ICBkcmFtX2RhdGEsIGhkci0+ZHJhbV9zaXplKTsKKwlpZiAocmV0KQorCQlyZXR1cm4gcmV0Owor CisJcmV0ID0gY2RuX2RwX3NldF9maXJtd2FyZV9hY3RpdmUoZHAsIHRydWUpOworCWlmIChyZXQp IHsKKwkJZGV2X2VycihkcC0+ZGV2LCAiYWN0aXZlIHVjcHUgZmFpbGVkOiAlZFxuIiwgcmV0KTsK KwkJcmV0dXJuIHJldDsKKwl9CisKKwlkcC0+ZndfbG9hZGVkID0gMTsKKworCXJldHVybiBjZG5f ZHBfZXZlbnRfY29uZmlnKGRwKTsKK30KKworc3RhdGljIGludCBjZG5fZHBfaW5pdChzdHJ1Y3Qg Y2RuX2RwX2RldmljZSAqZHApCit7CisJc3RydWN0IGRldmljZSAqZGV2ID0gZHAtPmRldjsKKwlz dHJ1Y3QgZGV2aWNlX25vZGUgKm5wID0gZGV2LT5vZl9ub2RlOworCXN0cnVjdCBwbGF0Zm9ybV9k ZXZpY2UgKnBkZXYgPSB0b19wbGF0Zm9ybV9kZXZpY2UoZGV2KTsKKwlzdHJ1Y3QgcmVzb3VyY2Ug KnJlczsKKwlpbnQgcmV0OworCisJZHAtPmdyZiA9IHN5c2Nvbl9yZWdtYXBfbG9va3VwX2J5X3Bo YW5kbGUobnAsICJyb2NrY2hpcCxncmYiKTsKKwlpZiAoSVNfRVJSKGRwLT5ncmYpKSB7CisJCWRl dl9lcnIoZGV2LCAiY2RuLWRwIG5lZWRzIHJvY2tjaGlwLGdyZiBwcm9wZXJ0eVxuIik7CisJCXJl dHVybiBQVFJfRVJSKGRwLT5ncmYpOworCX0KKworCXJlcyA9IHBsYXRmb3JtX2dldF9yZXNvdXJj ZShwZGV2LCBJT1JFU09VUkNFX01FTSwgMCk7CisJZHAtPnJlZ3MgPSBkZXZtX2lvcmVtYXBfcmVz b3VyY2UoZGV2LCByZXMpOworCWlmIChJU19FUlIoZHAtPnJlZ3MpKSB7CisJCWRldl9lcnIoZGV2 LCAiaW9yZW1hcCByZWcgZmFpbGVkXG4iKTsKKwkJcmV0dXJuIFBUUl9FUlIoZHAtPnJlZ3MpOwor CX0KKworCWRwLT5jb3JlX2NsayA9IGRldm1fY2xrX2dldChkZXYsICJjb3JlLWNsayIpOworCWlm IChJU19FUlIoZHAtPmNvcmVfY2xrKSkgeworCQlkZXZfZXJyKGRldiwgImNhbm5vdCBnZXQgY29y ZV9jbGtfZHBcbiIpOworCQlyZXR1cm4gUFRSX0VSUihkcC0+Y29yZV9jbGspOworCX0KKworCWRw LT5wY2xrID0gZGV2bV9jbGtfZ2V0KGRldiwgInBjbGsiKTsKKwlpZiAoSVNfRVJSKGRwLT5wY2xr KSkgeworCQlkZXZfZXJyKGRldiwgImNhbm5vdCBnZXQgcGNsa1xuIik7CisJCXJldHVybiBQVFJf RVJSKGRwLT5wY2xrKTsKKwl9CisKKwlkcC0+c3BkaWZfY2xrID0gZGV2bV9jbGtfZ2V0KGRldiwg InNwZGlmIik7CisJaWYgKElTX0VSUihkcC0+c3BkaWZfY2xrKSkgeworCQlkZXZfZXJyKGRldiwg ImNhbm5vdCBnZXQgc3BkaWZfY2xrXG4iKTsKKwkJcmV0dXJuIFBUUl9FUlIoZHAtPnNwZGlmX2Ns ayk7CisJfQorCisJZHAtPnNwZGlmX3JzdCA9IGRldm1fcmVzZXRfY29udHJvbF9nZXQoZGV2LCAi c3BkaWYiKTsKKwlpZiAoSVNfRVJSKGRwLT5zcGRpZl9yc3QpKSB7CisJCWRldl9lcnIoZGV2LCAi bm8gc3BkaWYgcmVzZXQgY29udHJvbCBmb3VuZFxuIik7CisJCXJldHVybiBQVFJfRVJSKGRwLT5z cGRpZl9yc3QpOworCX0KKworCWRwLT5kcG1zX21vZGUgPSBEUk1fTU9ERV9EUE1TX09GRjsKKwor CXJldCA9IGNkbl9kcF9jbGtfZW5hYmxlKGRwKTsKKwlpZiAocmV0IDwgMCkKKwkJcmV0dXJuIHJl dDsKKworCWNkbl9kcF9jbG9ja19yZXNldChkcCk7CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGlj IGludCBjZG5fZHBfYXVkaW9faHdfcGFyYW1zKHN0cnVjdCBkZXZpY2UgKmRldiwgIHZvaWQgKmRh dGEsCisJCQkJICBzdHJ1Y3QgaGRtaV9jb2RlY19kYWlmbXQgKmRhaWZtdCwKKwkJCQkgIHN0cnVj dCBoZG1pX2NvZGVjX3BhcmFtcyAqcGFyYW1zKQoreworCXN0cnVjdCBjZG5fZHBfZGV2aWNlICpk cCA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOworCXN0cnVjdCBhdWRpb19pbmZvIGF1ZGlvID0gewor CQkuc2FtcGxlX3dpZHRoID0gcGFyYW1zLT5zYW1wbGVfd2lkdGgsCisJCS5zYW1wbGVfcmF0ZSA9 IHBhcmFtcy0+c2FtcGxlX3JhdGUsCisJCS5jaGFubmVscyA9IHBhcmFtcy0+Y2hhbm5lbHMsCisJ fTsKKwlpbnQgcmV0OworCisJaWYgKCFkcC0+ZW5jb2Rlci5jcnRjKQorCQlyZXR1cm4gLUVOT0RF VjsKKworCXN3aXRjaCAoZGFpZm10LT5mbXQpIHsKKwljYXNlIEhETUlfSTJTOgorCQlhdWRpby5m b3JtYXQgPSBBRk1UX0kyUzsKKwkJYnJlYWs7CisJY2FzZSBIRE1JX1NQRElGOgorCQlhdWRpby5m b3JtYXQgPSBBRk1UX1NQRElGOworCQlicmVhazsKKwlkZWZhdWx0OgorCQlkZXZfZXJyKGRldiwg IiVzOiBJbnZhbGlkIGZvcm1hdCAlZFxuIiwgX19mdW5jX18sIGRhaWZtdC0+Zm10KTsKKwkJcmV0 dXJuIC1FSU5WQUw7CisJfQorCisJcmV0ID0gY2RuX2RwX2F1ZGlvX2NvbmZpZyhkcCwgJmF1ZGlv KTsKKwlpZiAoIXJldCkKKwkJZHAtPmF1ZGlvX2luZm8gPSBhdWRpbzsKKworCXJldHVybiByZXQ7 Cit9CisKK3N0YXRpYyB2b2lkIGNkbl9kcF9hdWRpb19zaHV0ZG93bihzdHJ1Y3QgZGV2aWNlICpk ZXYsIHZvaWQgKmRhdGEpCit7CisJc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwID0gZGV2X2dldF9k cnZkYXRhKGRldik7CisJaW50IHJldDsKKworCWlmICghZHAtPmVuY29kZXIuY3J0YykKKwkJcmV0 dXJuOworCisJcmV0ID0gY2RuX2RwX2F1ZGlvX3N0b3AoZHAsICZkcC0+YXVkaW9faW5mbyk7CisJ aWYgKCFyZXQpCisJCWRwLT5hdWRpb19pbmZvLmZvcm1hdCA9IEFGTVRfVU5VU0VEOworfQorCitz dGF0aWMgaW50IGNkbl9kcF9hdWRpb19kaWdpdGFsX211dGUoc3RydWN0IGRldmljZSAqZGV2LCB2 b2lkICpkYXRhLAorCQkJCSAgICAgYm9vbCBlbmFibGUpCit7CisJc3RydWN0IGNkbl9kcF9kZXZp Y2UgKmRwID0gZGV2X2dldF9kcnZkYXRhKGRldik7CisKKwlpZiAoIWRwLT5lbmNvZGVyLmNydGMp CisJCXJldHVybiAtRU5PREVWOworCisJcmV0dXJuIGNkbl9kcF9hdWRpb19tdXRlKGRwLCBlbmFi bGUpOworfQorCitzdGF0aWMgaW50IGNkbl9kcF9hdWRpb19nZXRfZWxkKHN0cnVjdCBkZXZpY2Ug KmRldiwgdm9pZCAqZGF0YSwKKwkJCQl1OCAqYnVmLCBzaXplX3QgbGVuKQoreworCXN0cnVjdCBj ZG5fZHBfZGV2aWNlICpkcCA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOworCXN0cnVjdCBkcm1fbW9k ZV9jb25maWcgKmNvbmZpZyA9ICZkcC0+ZW5jb2Rlci5kZXYtPm1vZGVfY29uZmlnOworCXN0cnVj dCBkcm1fY29ubmVjdG9yICpjb25uZWN0b3I7CisJaW50IHJldCA9IC1FTk9ERVY7CisKKwltdXRl eF9sb2NrKCZjb25maWctPm11dGV4KTsKKwlsaXN0X2Zvcl9lYWNoX2VudHJ5KGNvbm5lY3Rvciwg JmNvbmZpZy0+Y29ubmVjdG9yX2xpc3QsIGhlYWQpIHsKKwkJaWYgKCZkcC0+ZW5jb2RlciA9PSBj b25uZWN0b3ItPmVuY29kZXIpIHsKKwkJCW1lbWNweShidWYsIGNvbm5lY3Rvci0+ZWxkLAorCQkJ ICAgICAgIG1pbihzaXplb2YoY29ubmVjdG9yLT5lbGQpLCBsZW4pKTsKKwkJCXJldCA9IDA7CisJ CX0KKwl9CisJbXV0ZXhfdW5sb2NrKCZjb25maWctPm11dGV4KTsKKworCXJldHVybiByZXQ7Cit9 CisKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgaGRtaV9jb2RlY19vcHMgYXVkaW9fY29kZWNfb3BzID0g eworCS5od19wYXJhbXMgPSBjZG5fZHBfYXVkaW9faHdfcGFyYW1zLAorCS5hdWRpb19zaHV0ZG93 biA9IGNkbl9kcF9hdWRpb19zaHV0ZG93biwKKwkuZGlnaXRhbF9tdXRlID0gY2RuX2RwX2F1ZGlv X2RpZ2l0YWxfbXV0ZSwKKwkuZ2V0X2VsZCA9IGNkbl9kcF9hdWRpb19nZXRfZWxkLAorfTsKKwor c3RhdGljIGludCBjZG5fZHBfYXVkaW9fY29kZWNfaW5pdChzdHJ1Y3QgY2RuX2RwX2RldmljZSAq ZHAsCisJCQkJICAgc3RydWN0IGRldmljZSAqZGV2KQoreworCXN0cnVjdCBoZG1pX2NvZGVjX3Bk YXRhIGNvZGVjX2RhdGEgPSB7CisJCS5pMnMgPSAxLAorCQkuc3BkaWYgPSAxLAorCQkub3BzID0g JmF1ZGlvX2NvZGVjX29wcywKKwkJLm1heF9pMnNfY2hhbm5lbHMgPSA4LAorCX07CisKKwlkcC0+ YXVkaW9fcGRldiA9IHBsYXRmb3JtX2RldmljZV9yZWdpc3Rlcl9kYXRhKAorCQkJIGRldiwgSERN SV9DT0RFQ19EUlZfTkFNRSwgUExBVEZPUk1fREVWSURfQVVUTywKKwkJCSAmY29kZWNfZGF0YSwg c2l6ZW9mKGNvZGVjX2RhdGEpKTsKKworCXJldHVybiBQVFJfRVJSX09SX1pFUk8oZHAtPmF1ZGlv X3BkZXYpOworfQorCitzdGF0aWMgaW50IGNkbl9kcF9nZXRfY2FwX2xhbmVzKHN0cnVjdCBjZG5f ZHBfZGV2aWNlICpkcCwKKwkJCQlzdHJ1Y3QgZXh0Y29uX2RldiAqZWRldikKK3sKKwlib29sIGRm cCwgZHB0eDsKKwl1OCBsYW5lczsKKworCWRmcCA9IGV4dGNvbl9nZXRfc3RhdGUoZWRldiwgRVhU Q09OX1VTQl9IT1NUKTsKKwlkcHR4ID0gZXh0Y29uX2dldF9zdGF0ZShlZGV2LCBFWFRDT05fRElT UF9EUCk7CisKKwlpZiAoZGZwICYmIGRwdHgpCisJCWxhbmVzID0gMjsKKwllbHNlIGlmIChkcHR4 KQorCQlsYW5lcyA9IDQ7CisJZWxzZQorCQlsYW5lcyA9IDA7CisKKwlyZXR1cm4gbGFuZXM7Cit9 CisKK3N0YXRpYyBpbnQgY2RuX2RwX3BkX2V2ZW50KHN0cnVjdCBub3RpZmllcl9ibG9jayAqbmIs CisJCQkgICB1bnNpZ25lZCBsb25nIGV2ZW50LCB2b2lkICpwcml2KQoreworCXN0cnVjdCBjZG5f ZHBfcG9ydCAqcG9ydDsKKworCXBvcnQgPSBjb250YWluZXJfb2YobmIsIHN0cnVjdCBjZG5fZHBf cG9ydCwgZXZlbnRfbmIpOworCisJc2NoZWR1bGVfZGVsYXllZF93b3JrKCZwb3J0LT5ldmVudF93 cSwgMCk7CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIHZvaWQgY2RuX2RwX3BkX2V2ZW50X3dx KHN0cnVjdCB3b3JrX3N0cnVjdCAqd29yaykKK3sKKwlzdHJ1Y3QgY2RuX2RwX3BvcnQgKnBvcnQg PSBjb250YWluZXJfb2Yod29yaywgc3RydWN0IGNkbl9kcF9wb3J0LAorCQkJCQkJZXZlbnRfd3Eu d29yayk7CisJdW5pb24gZXh0Y29uX3Byb3BlcnR5X3ZhbHVlIHByb3BlcnR5OworCXN0cnVjdCBj ZG5fZHBfZGV2aWNlICpkcCA9IHBvcnQtPmRwOworCXU4IG5ld19jYXBfbGFuZXMsIGk7CisJaW50 IHJldDsKKworCW5ld19jYXBfbGFuZXMgPSBjZG5fZHBfZ2V0X2NhcF9sYW5lcyhkcCwgcG9ydC0+ ZXh0Y29uKTsKKworCWlmIChuZXdfY2FwX2xhbmVzID09IHBvcnQtPmNhcF9sYW5lcykgeworCQlk ZXZfZGJnKGRwLT5kZXYsICJsYW5lcyBjb3VudCBkb2VzIG5vdCBjaGFuZ2U6ICVkXG4iLAorCQkJ bmV3X2NhcF9sYW5lcyk7CisJCXJldHVybjsKKwl9CisKKwlpZiAoIW5ld19jYXBfbGFuZXMpIHsK KwkJcmV0ID0gcGh5X3Bvd2VyX29mZihwb3J0LT5waHkpOworCQlpZiAocmV0KSB7CisJCQlkZXZf ZXJyKGRwLT5kZXYsICJwaHkgcG93ZXIgb2ZmIGZhaWxlZDogJWQiLCByZXQpOworCQkJcmV0dXJu OworCQl9CisJCXBvcnQtPnBoeV9zdGF0dXMgPSBmYWxzZTsKKwkJcG9ydC0+Y2FwX2xhbmVzID0g bmV3X2NhcF9sYW5lczsKKwkJZm9yIChpID0gMDsgaSA8IGRwLT5wb3J0czsgaSsrKSB7CisJCQlp ZiAoZHAtPnBvcnRbaV0tPnBoeV9zdGF0dXMpCisJCQkJcmV0dXJuOworCQl9CisKKwkJZHAtPmhw ZF9zdGF0dXMgPSBjb25uZWN0b3Jfc3RhdHVzX2Rpc2Nvbm5lY3RlZDsKKwkJZHJtX2hlbHBlcl9o cGRfaXJxX2V2ZW50KGRwLT5kcm1fZGV2KTsKKwkJY2RuX2RwX3NldF9maXJtd2FyZV9hY3RpdmUo ZHAsIGZhbHNlKTsKKwkJcmV0dXJuOworCX0KKworCS8qIGlmIG90aGVyIHBoeSBpcyBydW5uaW5n LCBkbyBub3QgdG91Y2ggdGhlIGhwZF9zdGF0dXMsIGFuZCByZXR1cm4gKi8KKwlmb3IgKGkgPSAw OyBpIDwgZHAtPnBvcnRzOyBpKyspIHsKKwkJaWYgKGRwLT5wb3J0W2ldLT5waHlfc3RhdHVzKSB7 CisJCQlkZXZfd2FybihkcC0+ZGV2LCAiYnVzeSwgcGh5WyVkXSBpcyBydW5uaW5nIiwKKwkJCQkg ZHAtPnBvcnRbaV0tPmlkKTsKKwkJCXJldHVybjsKKwkJfQorCX0KKworCWlmICghZHAtPmZ3X2xv YWRlZCkgeworCQlyZXQgPSByZXF1ZXN0X2Zpcm13YXJlKCZkcC0+ZncsIENETl9EUF9GSVJNV0FS RSwgZHAtPmRldik7CisJCWlmIChyZXQgPT0gLUVOT0VOVCAmJiBkcC0+Zndfd2FpdCA8PSBNQVhf RldfV0FJVF9TRUNTKSB7CisJCQl1bnNpZ25lZCBsb25nIHRpbWUgPSBtc2Vjc190b19qaWZmaWVz KGRwLT5md193YWl0ICogSFopOworCisJCQkvKgorCQkJICogSWYgY2FuIG5vdCBmaW5kIHRoZSBm aWxlLCByZXRyeSB0byBsb2FkIHRoZSBmaXJtd2FyZQorCQkJICogaW4gc2V2ZXJhbCBzZWNvbmRz LCBpZiBzdGlsbCBmYWlsZWQgYWZ0ZXIgMSBtaW51dGUsCisJCQkgKiBnaXZlIHVwLgorCQkJICov CisJCQlzY2hlZHVsZV9kZWxheWVkX3dvcmsoJnBvcnQtPmV2ZW50X3dxLCB0aW1lKTsKKwkJCWRw LT5md193YWl0ICo9IDI7CisJCQlyZXR1cm47CisJCX0gZWxzZSBpZiAocmV0KSB7CisJCQlkZXZf ZXJyKGRwLT5kZXYsICJmYWlsZWQgdG8gcmVxdWVzdCBmaXJtd2FyZTogJWRcbiIsCisJCQkJcmV0 KTsKKwkJCXJldHVybjsKKwkJfQorCX0KKworCWlmIChkcC0+ZndfbG9hZGVkKQorCQljZG5fZHBf c2V0X2Zpcm13YXJlX2FjdGl2ZShkcCwgdHJ1ZSk7CisKKwlyZXQgPSBwaHlfcG93ZXJfb24ocG9y dC0+cGh5KTsKKwlpZiAocmV0KSB7CisJCWlmICghZHAtPmZ3X2xvYWRlZCkKKwkJCXJlbGVhc2Vf ZmlybXdhcmUoZHAtPmZ3KTsKKwkJZGV2X2VycihkcC0+ZGV2LCAicGh5IHBvd2VyIG9uIGZhaWxl ZDogJWRcbiIsIHJldCk7CisJCXJldHVybjsKKwl9CisKKwlwb3J0LT5waHlfc3RhdHVzID0gdHJ1 ZTsKKworCWlmICghZHAtPmZ3X2xvYWRlZCkgeworCQlyZXQgPSBjZG5fZHBfZmlybXdhcmVfaW5p dChkcCk7CisJCXJlbGVhc2VfZmlybXdhcmUoZHAtPmZ3KTsKKwkJaWYgKHJldCkgeworCQkJZGV2 X2VycihkcC0+ZGV2LCAiZmlybXdhcmUgaW5pdCBmYWlsZWQ6ICVkIiwgcmV0KTsKKwkJCWdvdG8g ZXJyX2Zpcm13YXJlOworCQl9CisJfQorCisJcmV0ID0gY2RuX2RwX2dldF9ocGRfc3RhdHVzKGRw KTsKKwlpZiAocmV0IDw9IDApIHsKKwkJaWYgKCFyZXQpCisJCQlkZXZfZXJyKGRwLT5kZXYsICJo cGQgZG9lcyBub3QgZXhpc3RcbiIpOworCQlnb3RvIGVycl9maXJtd2FyZTsKKwl9CisKKwlyZXQg PSBleHRjb25fZ2V0X3Byb3BlcnR5KHBvcnQtPmV4dGNvbiwgRVhUQ09OX0RJU1BfRFAsCisJCQkJ ICBFWFRDT05fUFJPUF9VU0JfVFlQRUNfUE9MQVJJVFksICZwcm9wZXJ0eSk7CisJaWYgKHJldCkg eworCQlkZXZfZXJyKGRwLT5kZXYsICJnZXQgcHJvcGVydHkgZmFpbGVkXG4iKTsKKwkJZ290byBl cnJfZmlybXdhcmU7CisJfQorCisJcmV0ID0gY2RuX2RwX3NldF9ob3N0X2NhcChkcCwgbmV3X2Nh cF9sYW5lcywgcHJvcGVydHkuaW50dmFsKTsKKwlpZiAocmV0KSB7CisJCWRldl9lcnIoZHAtPmRl diwgInNldCBob3N0IGNhcGFiaWxpdGllcyBmYWlsZWQ6ICVkXG4iLCByZXQpOworCQlnb3RvIGVy cl9maXJtd2FyZTsKKwl9CisKKwkvKgorCSAqIE5hdGl2ZSByZWFkIHdpdGggcmV0cnkgZm9yIGxp bmsgc3RhdHVzIGFuZCByZWNlaXZlciBjYXBhYmlsaXR5IHJlYWRzCisJICogZm9yIGNhc2VzIHdo ZXJlIHRoZSBzaW5rIG1heSBzdGlsbCBub3QgYmUgcmVhZHkuCisJICoKKwkgKiBTaW5rcyBhcmUg KnN1cHBvc2VkKiB0byBjb21lIHVwIHdpdGhpbiAxbXMgZnJvbSBhbiBvZmYgc3RhdGUsIGJ1dAor CSAqIHNvbWUgRE9DS3MgbmVlZCBhYm91dCA1IHNlY29uZHMgdG8gcG93ZXIgdXAsIHNvIHJlYWQg dGhlIGRwY2QgZXZlcnkKKwkgKiAxMDBtcywgaWYgY2FuIG5vdCBnZXQgYSBnb29kIGRwY2QgaW4g MTAgc2Vjb25kcywgZ2l2ZSB1cC4KKwkgKi8KKwlmb3IgKGkgPSAxOyBpIDwgMTAwOyBpKyspIHsK KwkJcmV0ID0gY2RuX2RwX2RwY2RfcmVhZChkcCwgMHgwMDAsIGRwLT5kcGNkLAorCQkJCSAgICAg ICBEUF9SRUNFSVZFUl9DQVBfU0laRSk7CisJCWlmICghcmV0KSB7CisJCQlkZXZfZGJnKGRwLT5k ZXYsICJnZXQgZHBjZCBzdWNjZXNzIVxuIik7CisJCQlwb3J0LT5jYXBfbGFuZXMgPSBuZXdfY2Fw X2xhbmVzOworCQkJZHAtPmhwZF9zdGF0dXMgPSBjb25uZWN0b3Jfc3RhdHVzX2Nvbm5lY3RlZDsK KwkJCWRybV9oZWxwZXJfaHBkX2lycV9ldmVudChkcC0+ZHJtX2Rldik7CisJCQlyZXR1cm47CisJ CX0gZWxzZSBpZiAoIWV4dGNvbl9nZXRfc3RhdGUocG9ydC0+ZXh0Y29uLCBFWFRDT05fRElTUF9E UCkpIHsKKwkJCWJyZWFrOworCQl9CisJCW1zbGVlcCgxMDApOworCX0KKworCWRldl9lcnIoZHAt PmRldiwgImdldCBkcGNkIGZhaWxlZCFcbiIpOworCitlcnJfZmlybXdhcmU6CisJcmV0ID0gcGh5 X3Bvd2VyX29mZihwb3J0LT5waHkpOworCWlmIChyZXQpCisJCWRldl9lcnIoZHAtPmRldiwgInBo eSBwb3dlciBvZmYgZmFpbGVkOiAlZCIsIHJldCk7CisJZWxzZQorCQlwb3J0LT5waHlfc3RhdHVz ID0gZmFsc2U7CisKKwlpZiAoZHAtPmZ3X2xvYWRlZCkKKwkJY2RuX2RwX3NldF9maXJtd2FyZV9h Y3RpdmUoZHAsIGZhbHNlKTsKK30KKworc3RhdGljIGludCBjZG5fZHBfYmluZChzdHJ1Y3QgZGV2 aWNlICpkZXYsIHN0cnVjdCBkZXZpY2UgKm1hc3Rlciwgdm9pZCAqZGF0YSkKK3sKKwlzdHJ1Y3Qg Y2RuX2RwX2RldmljZSAqZHAgPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsKKwlzdHJ1Y3QgZHJtX2Vu Y29kZXIgKmVuY29kZXI7CisJc3RydWN0IGRybV9jb25uZWN0b3IgKmNvbm5lY3RvcjsKKwlzdHJ1 Y3QgY2RuX2RwX3BvcnQgKnBvcnQ7CisJc3RydWN0IGRybV9kZXZpY2UgKmRybV9kZXYgPSBkYXRh OworCWludCByZXQsIGk7CisKKwlyZXQgPSBjZG5fZHBfaW5pdChkcCk7CisJaWYgKHJldCA8IDAp CisJCXJldHVybiByZXQ7CisKKwlkcC0+ZHJtX2RldiA9IGRybV9kZXY7CisJZHAtPmhwZF9zdGF0 dXMgPSBjb25uZWN0b3Jfc3RhdHVzX2Rpc2Nvbm5lY3RlZDsKKwlkcC0+Zndfd2FpdCA9IDE7CisK KwllbmNvZGVyID0gJmRwLT5lbmNvZGVyOworCisJZW5jb2Rlci0+cG9zc2libGVfY3J0Y3MgPSBk cm1fb2ZfZmluZF9wb3NzaWJsZV9jcnRjcyhkcm1fZGV2LAorCQkJCQkJCSAgICAgZGV2LT5vZl9u b2RlKTsKKwlEUk1fREVCVUdfS01TKCJwb3NzaWJsZV9jcnRjcyA9IDB4JXhcbiIsIGVuY29kZXIt PnBvc3NpYmxlX2NydGNzKTsKKworCXJldCA9IGRybV9lbmNvZGVyX2luaXQoZHJtX2RldiwgZW5j b2RlciwgJmNkbl9kcF9lbmNvZGVyX2Z1bmNzLAorCQkJICAgICAgIERSTV9NT0RFX0VOQ09ERVJf VE1EUywgTlVMTCk7CisJaWYgKHJldCkgeworCQlEUk1fRVJST1IoImZhaWxlZCB0byBpbml0aWFs aXplIGVuY29kZXIgd2l0aCBkcm1cbiIpOworCQlyZXR1cm4gcmV0OworCX0KKworCWRybV9lbmNv ZGVyX2hlbHBlcl9hZGQoZW5jb2RlciwgJmNkbl9kcF9lbmNvZGVyX2hlbHBlcl9mdW5jcyk7CisK Kwljb25uZWN0b3IgPSAmZHAtPmNvbm5lY3RvcjsKKwljb25uZWN0b3ItPnBvbGxlZCA9IERSTV9D T05ORUNUT1JfUE9MTF9IUEQ7CisJY29ubmVjdG9yLT5kcG1zID0gRFJNX01PREVfRFBNU19PRkY7 CisKKwlyZXQgPSBkcm1fY29ubmVjdG9yX2luaXQoZHJtX2RldiwgY29ubmVjdG9yLAorCQkJCSAm Y2RuX2RwX2F0b21pY19jb25uZWN0b3JfZnVuY3MsCisJCQkJIERSTV9NT0RFX0NPTk5FQ1RPUl9E aXNwbGF5UG9ydCk7CisJaWYgKHJldCkgeworCQlEUk1fRVJST1IoImZhaWxlZCB0byBpbml0aWFs aXplIGNvbm5lY3RvciB3aXRoIGRybVxuIik7CisJCWdvdG8gZXJyX2ZyZWVfZW5jb2RlcjsKKwl9 CisKKwlkcm1fY29ubmVjdG9yX2hlbHBlcl9hZGQoY29ubmVjdG9yLCAmY2RuX2RwX2Nvbm5lY3Rv cl9oZWxwZXJfZnVuY3MpOworCisJcmV0ID0gZHJtX21vZGVfY29ubmVjdG9yX2F0dGFjaF9lbmNv ZGVyKGNvbm5lY3RvciwgZW5jb2Rlcik7CisJaWYgKHJldCkgeworCQlEUk1fRVJST1IoImZhaWxl ZCB0byBhdHRhY2ggY29ubmVjdG9yIGFuZCBlbmNvZGVyXG4iKTsKKwkJZ290byBlcnJfZnJlZV9j b25uZWN0b3I7CisJfQorCisJY2RuX2RwX2F1ZGlvX2NvZGVjX2luaXQoZHAsIGRldik7CisKKwlm b3IgKGkgPSAwOyBpIDwgZHAtPnBvcnRzOyBpKyspIHsKKwkJcG9ydCA9IGRwLT5wb3J0W2ldOwor CisJCXBvcnQtPmV2ZW50X25iLm5vdGlmaWVyX2NhbGwgPSBjZG5fZHBfcGRfZXZlbnQ7CisJCUlO SVRfREVMQVlFRF9XT1JLKCZwb3J0LT5ldmVudF93cSwgY2RuX2RwX3BkX2V2ZW50X3dxKTsKKwkJ cmV0ID0gZXh0Y29uX3JlZ2lzdGVyX25vdGlmaWVyKHBvcnQtPmV4dGNvbiwgRVhUQ09OX0RJU1Bf RFAsCisJCQkJCSAgICAgICAmcG9ydC0+ZXZlbnRfbmIpOworCQlpZiAocmV0KSB7CisJCQlkZXZf ZXJyKGRldiwgInJlZ2lzdGVyIEVYVENPTl9ESVNQX0RQIG5vdGlmaWVyIGVyclxuIik7CisJCQly ZXR1cm4gcmV0OworCQl9CisKKwkJaWYgKGV4dGNvbl9nZXRfc3RhdGUocG9ydC0+ZXh0Y29uLCBF WFRDT05fRElTUF9EUCkpCisJCQlzY2hlZHVsZV9kZWxheWVkX3dvcmsoJnBvcnQtPmV2ZW50X3dx LCAwKTsKKwl9CisKKwlyZXR1cm4gMDsKKworZXJyX2ZyZWVfY29ubmVjdG9yOgorCWRybV9jb25u ZWN0b3JfY2xlYW51cChjb25uZWN0b3IpOworZXJyX2ZyZWVfZW5jb2RlcjoKKwlkcm1fZW5jb2Rl cl9jbGVhbnVwKGVuY29kZXIpOworCXJldHVybiByZXQ7Cit9CisKK3N0YXRpYyB2b2lkIGNkbl9k cF91bmJpbmQoc3RydWN0IGRldmljZSAqZGV2LCBzdHJ1Y3QgZGV2aWNlICptYXN0ZXIsIHZvaWQg KmRhdGEpCit7CisJc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwID0gZGV2X2dldF9kcnZkYXRhKGRl dik7CisJc3RydWN0IGRybV9lbmNvZGVyICplbmNvZGVyID0gJmRwLT5lbmNvZGVyOworCXN0cnVj dCBkcm1fY29ubmVjdG9yICpjb25uZWN0b3IgPSAmZHAtPmNvbm5lY3RvcjsKKwlzdHJ1Y3QgY2Ru X2RwX3BvcnQgKnBvcnQ7CisJaW50IGk7CisKKwlwbGF0Zm9ybV9kZXZpY2VfdW5yZWdpc3Rlcihk cC0+YXVkaW9fcGRldik7CisJY2RuX2RwX2VuY29kZXJfZGlzYWJsZShlbmNvZGVyKTsKKwllbmNv ZGVyLT5mdW5jcy0+ZGVzdHJveShlbmNvZGVyKTsKKwljb25uZWN0b3ItPmZ1bmNzLT5kZXN0cm95 KGNvbm5lY3Rvcik7CisKKwlmb3IgKGkgPSAwOyBpIDwgZHAtPnBvcnRzOyBpKyspIHsKKwkJcG9y dCA9IGRwLT5wb3J0W2ldOworCQlleHRjb25fdW5yZWdpc3Rlcl9ub3RpZmllcihwb3J0LT5leHRj b24sIEVYVENPTl9ESVNQX0RQLAorCQkJCQkgICAmcG9ydC0+ZXZlbnRfbmIpOworCX0KK30KKwor c3RhdGljIGNvbnN0IHN0cnVjdCBjb21wb25lbnRfb3BzIGNkbl9kcF9jb21wb25lbnRfb3BzID0g eworCS5iaW5kID0gY2RuX2RwX2JpbmQsCisJLnVuYmluZCA9IGNkbl9kcF91bmJpbmQsCit9Owor CitzdGF0aWMgaW50IGNkbl9kcF9wcm9iZShzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2KQor eworCXN0cnVjdCBkZXZpY2UgKmRldiA9ICZwZGV2LT5kZXY7CisJY29uc3Qgc3RydWN0IG9mX2Rl dmljZV9pZCAqbWF0Y2g7CisJc3RydWN0IGNkbl9kcF9kYXRhICpkcF9kYXRhOworCXN0cnVjdCBj ZG5fZHBfcG9ydCAqcG9ydDsKKwlzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHA7CisJc3RydWN0IGV4 dGNvbl9kZXYgKmV4dGNvbjsKKwlzdHJ1Y3QgcGh5ICpwaHk7CisJaW50IGk7CisKKwlkcCA9IGRl dm1fa3phbGxvYyhkZXYsIHNpemVvZigqZHApLCBHRlBfS0VSTkVMKTsKKwlpZiAoIWRwKQorCQly ZXR1cm4gLUVOT01FTTsKKwlkcC0+ZGV2ID0gZGV2OworCisJbWF0Y2ggPSBvZl9tYXRjaF9ub2Rl KGNkbl9kcF9kdF9pZHMsIHBkZXYtPmRldi5vZl9ub2RlKTsKKwlkcF9kYXRhID0gKHN0cnVjdCBj ZG5fZHBfZGF0YSAqKW1hdGNoLT5kYXRhOworCisJZm9yIChpID0gMDsgaSA8IGRwX2RhdGEtPm1h eF9waHk7IGkrKykgeworCQlleHRjb24gPSBleHRjb25fZ2V0X2VkZXZfYnlfcGhhbmRsZShkZXYs IGkpOworCQlwaHkgPSBkZXZtX29mX3BoeV9nZXRfYnlfaW5kZXgoZGV2LCBkZXYtPm9mX25vZGUs IGkpOworCisJCWlmIChQVFJfRVJSKGV4dGNvbikgPT0gLUVQUk9CRV9ERUZFUiB8fAorCQkgICAg UFRSX0VSUihwaHkpID09IC1FUFJPQkVfREVGRVIpCisJCQlyZXR1cm4gLUVQUk9CRV9ERUZFUjsK KworCQlpZiAoSVNfRVJSKGV4dGNvbikgfHwgSVNfRVJSKHBoeSkpCisJCQljb250aW51ZTsKKwor CQlwb3J0ID0gZGV2bV9remFsbG9jKGRldiwgc2l6ZW9mKCpwb3J0KSwgR0ZQX0tFUk5FTCk7CisJ CWlmICghZHApCisJCQlyZXR1cm4gLUVOT01FTTsKKworCQlwb3J0LT5leHRjb24gPSBleHRjb247 CisJCXBvcnQtPnBoeSA9IHBoeTsKKwkJcG9ydC0+ZHAgPSBkcDsKKwkJcG9ydC0+aWQgPSBpOwor CQlkcC0+cG9ydFtkcC0+cG9ydHMrK10gPSBwb3J0OworCX0KKworCWlmICghZHAtPnBvcnRzKSB7 CisJCWRldl9lcnIoZGV2LCAibWlzc2luZyBleHRjb24gb3IgcGh5XG4iKTsKKwkJcmV0dXJuIC1F SU5WQUw7CisJfQorCisJZGV2X3NldF9kcnZkYXRhKGRldiwgZHApOworCisJcmV0dXJuIGNvbXBv bmVudF9hZGQoZGV2LCAmY2RuX2RwX2NvbXBvbmVudF9vcHMpOworfQorCitzdGF0aWMgaW50IGNk bl9kcF9yZW1vdmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldikKK3sKKwljb21wb25lbnRf ZGVsKCZwZGV2LT5kZXYsICZjZG5fZHBfY29tcG9uZW50X29wcyk7CisKKwlyZXR1cm4gMDsKK30K Kworc3RhdGljIHN0cnVjdCBwbGF0Zm9ybV9kcml2ZXIgY2RuX2RwX2RyaXZlciA9IHsKKwkucHJv YmUgPSBjZG5fZHBfcHJvYmUsCisJLnJlbW92ZSA9IGNkbl9kcF9yZW1vdmUsCisJLmRyaXZlciA9 IHsKKwkJICAgLm5hbWUgPSAiY2RuLWRwIiwKKwkJICAgLm93bmVyID0gVEhJU19NT0RVTEUsCisJ CSAgIC5vZl9tYXRjaF90YWJsZSA9IG9mX21hdGNoX3B0cihjZG5fZHBfZHRfaWRzKSwKKwl9LAor fTsKKworbW9kdWxlX3BsYXRmb3JtX2RyaXZlcihjZG5fZHBfZHJpdmVyKTsKKworTU9EVUxFX0FV VEhPUigiQ2hyaXMgWmhvbmcgPHp5d0Byb2NrLWNoaXBzLmNvbT4iKTsKK01PRFVMRV9ERVNDUklQ VElPTigiY2RuIERQIERyaXZlciIpOworTU9EVUxFX0xJQ0VOU0UoIkdQTCB2MiIpOwpkaWZmIC0t Z2l0IGEvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL2Nkbi1kcC1jb3JlLmggYi9kcml2ZXJzL2dw dS9kcm0vcm9ja2NoaXAvY2RuLWRwLWNvcmUuaApuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAw MDAwMDAwLi43ODQyNGY5Ci0tLSAvZGV2L251bGwKKysrIGIvZHJpdmVycy9ncHUvZHJtL3JvY2tj aGlwL2Nkbi1kcC1jb3JlLmgKQEAgLTAsMCArMSwxMDMgQEAKKy8qCisgKiBDb3B5cmlnaHQgKEMp 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 c3RydWN0IG5vdGlmaWVyX2Jsb2NrIGV2ZW50X25iOworCXN0cnVjdCBkZWxheWVkX3dvcmsgZXZl bnRfd3E7CisJc3RydWN0IGV4dGNvbl9kZXYgKmV4dGNvbjsKKwlzdHJ1Y3QgcGh5ICpwaHk7CisJ dTggY2FwX2xhbmVzOworCWJvb2wgcGh5X3N0YXR1czsKKwl1OCBpZDsKK307CisKK3N0cnVjdCBj ZG5fZHBfZGV2aWNlIHsKKwlzdHJ1Y3QgZGV2aWNlICpkZXY7CisJc3RydWN0IGRybV9kZXZpY2Ug KmRybV9kZXY7CisJc3RydWN0IGRybV9jb25uZWN0b3IgY29ubmVjdG9yOworCXN0cnVjdCBkcm1f ZW5jb2RlciBlbmNvZGVyOworCXN0cnVjdCBkcm1fZGlzcGxheV9tb2RlIG1vZGU7CisJc3RydWN0 IHBsYXRmb3JtX2RldmljZSAqYXVkaW9fcGRldjsKKworCWNvbnN0IHN0cnVjdCBmaXJtd2FyZSAq Znc7CS8qIGNkbiBkcCBmaXJtd2FyZSAqLworCXVuc2lnbmVkIGludCBmd192ZXJzaW9uOwkvKiBj ZG4gZncgdmVyc2lvbiAqLworCXUzMiBmd193YWl0OworCWJvb2wgZndfbG9hZGVkOworCWJvb2wg ZndfYWN0aXZlZDsKKwl2b2lkIF9faW9tZW0gKnJlZ3M7CisJc3RydWN0IHJlZ21hcCAqZ3JmOwor CXN0cnVjdCBjbGsgKmNvcmVfY2xrOworCXN0cnVjdCBjbGsgKnBjbGs7CisJc3RydWN0IGNsayAq c3BkaWZfY2xrOworCXN0cnVjdCByZXNldF9jb250cm9sICpzcGRpZl9yc3Q7CisJc3RydWN0IGF1 ZGlvX2luZm8gYXVkaW9faW5mbzsKKwlzdHJ1Y3QgdmlkZW9faW5mbyB2aWRlb19pbmZvOworCXN0 cnVjdCBkcm1fZHBfbGluayBsaW5rOworCXN0cnVjdCBjZG5fZHBfcG9ydCAqcG9ydFtNQVhfUEhZ XTsKKwl1OCBwb3J0czsKKworCXU4IGRwY2RbRFBfUkVDRUlWRVJfQ0FQX1NJWkVdOworCWVudW0g ZHJtX2Nvbm5lY3Rvcl9zdGF0dXMgaHBkX3N0YXR1czsKKwlpbnQgZHBtc19tb2RlOworCWJvb2wg c2lua19oYXNfYXVkaW87Cit9OworI2VuZGlmICAvKiBfQ0ROX0RQX0NPUkVfSCAqLwpkaWZmIC0t Z2l0IGEvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL2Nkbi1kcC1yZWcuYyBiL2RyaXZlcnMvZ3B1 L2RybS9yb2NrY2hpcC9jZG4tZHAtcmVnLmMKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAw MDAwMC4uMmVhNzAyZAotLS0gL2Rldi9udWxsCisrKyBiL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hp cC9jZG4tZHAtcmVnLmMKQEAgLTAsMCArMSw5NTkgQEAKKy8qCisgKiBDb3B5cmlnaHQgKEMpIEZ1 emhvdSBSb2NrY2hpcCBFbGVjdHJvbmljcyBDby5MdGQKKyAqIEF1dGhvcjogQ2hyaXMgWmhvbmcg PHp5d0Byb2NrLWNoaXBzLmNvbT4KKyAqCisgKiBUaGlzIHNvZnR3YXJlIGlzIGxpY2Vuc2VkIHVu ZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljCisgKiBMaWNlbnNlIHZlcnNp b24gMiwgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGFuZAor ICogbWF5IGJlIGNvcGllZCwgZGlzdHJpYnV0ZWQsIGFuZCBtb2RpZmllZCB1bmRlciB0aG9zZSB0 ZXJtcy4KKyAqCisgKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhh dCBpdCB3aWxsIGJlIHVzZWZ1bCwKKyAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91 dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mCisgKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklU TkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlCisgKiBHTlUgR2VuZXJhbCBQ dWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLgorICovCisKKyNpbmNsdWRlIDxsaW51eC9j bGsuaD4KKyNpbmNsdWRlIDxsaW51eC9kZXZpY2UuaD4KKyNpbmNsdWRlIDxsaW51eC9kZWxheS5o PgorI2luY2x1ZGUgPGxpbnV4L2lvLmg+CisjaW5jbHVkZSA8bGludXgvaW9wb2xsLmg+CisjaW5j bHVkZSA8bGludXgvcmVzZXQuaD4KKworI2luY2x1ZGUgImNkbi1kcC1jb3JlLmgiCisjaW5jbHVk ZSAiY2RuLWRwLXJlZy5oIgorCisjZGVmaW5lIENETl9EUF9TUERJRl9DTEsJCTIwMDAwMDAwMAor I2RlZmluZSBGV19BTElWRV9USU1FT1VUX1VTCQkxMDAwMDAwCisjZGVmaW5lIE1BSUxCT1hfUkVU UllfVVMJCTEwMDAKKyNkZWZpbmUgTUFJTEJPWF9USU1FT1VUX1VTCQk1MDAwMDAwCisjZGVmaW5l IExJTktfVFJBSU5JTkdfUkVUUllfTVMJCTIwCisjZGVmaW5lIExJTktfVFJBSU5JTkdfVElNRU9V VF9NUwk1MDAKKwordm9pZCBjZG5fZHBfc2V0X2Z3X2NsayhzdHJ1Y3QgY2RuX2RwX2RldmljZSAq ZHAsIHUzMiBjbGspCit7CisJd3JpdGVsKGNsayAvIDEwMDAwMDAsIGRwLT5yZWdzICsgU1dfQ0xL X0gpOworfQorCit2b2lkIGNkbl9kcF9jbG9ja19yZXNldChzdHJ1Y3QgY2RuX2RwX2RldmljZSAq ZHApCit7CisJdTMyIHZhbDsKKworCXZhbCA9IERQVFhfRlJNUl9EQVRBX0NMS19SU1ROX0VOIHwK KwkgICAgICBEUFRYX0ZSTVJfREFUQV9DTEtfRU4gfAorCSAgICAgIERQVFhfUEhZX0RBVEFfUlNU Tl9FTiB8CisJICAgICAgRFBUWF9QSFlfREFUQV9DTEtfRU4gfAorCSAgICAgIERQVFhfUEhZX0NI QVJfUlNUTl9FTiB8CisJICAgICAgRFBUWF9QSFlfQ0hBUl9DTEtfRU4gfAorCSAgICAgIFNPVVJD RV9BVVhfU1lTX0NMS19SU1ROX0VOIHwKKwkgICAgICBTT1VSQ0VfQVVYX1NZU19DTEtfRU4gfAor CSAgICAgIERQVFhfU1lTX0NMS19SU1ROX0VOIHwKKwkgICAgICBEUFRYX1NZU19DTEtfRU4gfAor CSAgICAgIENGR19EUFRYX1ZJRl9DTEtfUlNUTl9FTiB8CisJICAgICAgQ0ZHX0RQVFhfVklGX0NM S19FTjsKKwl3cml0ZWwodmFsLCBkcC0+cmVncyArIFNPVVJDRV9EUFRYX0NBUik7CisKKwl2YWwg PSBTT1VSQ0VfUEhZX1JTVE5fRU4gfCBTT1VSQ0VfUEhZX0NMS19FTjsKKwl3cml0ZWwodmFsLCBk cC0+cmVncyArIFNPVVJDRV9QSFlfQ0FSKTsKKworCXZhbCA9IFNPVVJDRV9QS1RfU1lTX1JTVE5f RU4gfAorCSAgICAgIFNPVVJDRV9QS1RfU1lTX0NMS19FTiB8CisJICAgICAgU09VUkNFX1BLVF9E QVRBX1JTVE5fRU4gfAorCSAgICAgIFNPVVJDRV9QS1RfREFUQV9DTEtfRU47CisJd3JpdGVsKHZh bCwgZHAtPnJlZ3MgKyBTT1VSQ0VfUEtUX0NBUik7CisKKwl2YWwgPSBTUERJRl9DRFJfQ0xLX1JT VE5fRU4gfAorCSAgICAgIFNQRElGX0NEUl9DTEtfRU4gfAorCSAgICAgIFNPVVJDRV9BSUZfU1lT X1JTVE5fRU4gfAorCSAgICAgIFNPVVJDRV9BSUZfU1lTX0NMS19FTiB8CisJICAgICAgU09VUkNF X0FJRl9DTEtfUlNUTl9FTiB8CisJICAgICAgU09VUkNFX0FJRl9DTEtfRU47CisJd3JpdGVsKHZh bCwgZHAtPnJlZ3MgKyBTT1VSQ0VfQUlGX0NBUik7CisKKwl2YWwgPSBTT1VSQ0VfQ0lQSEVSX1NZ U1RFTV9DTEtfUlNUTl9FTiB8CisJICAgICAgU09VUkNFX0NJUEhFUl9TWVNfQ0xLX0VOIHwKKwkg ICAgICBTT1VSQ0VfQ0lQSEVSX0NIQVJfQ0xLX1JTVE5fRU4gfAorCSAgICAgIFNPVVJDRV9DSVBI RVJfQ0hBUl9DTEtfRU47CisJd3JpdGVsKHZhbCwgZHAtPnJlZ3MgKyBTT1VSQ0VfQ0lQSEVSX0NB Uik7CisKKwl2YWwgPSBTT1VSQ0VfQ1JZUFRPX1NZU19DTEtfUlNUTl9FTiB8CisJICAgICAgU09V UkNFX0NSWVBUT19TWVNfQ0xLX0VOOworCXdyaXRlbCh2YWwsIGRwLT5yZWdzICsgU09VUkNFX0NS WVBUT19DQVIpOworCisJdmFsID0gfihNQUlMQk9YX0lOVF9NQVNLX0JJVCB8IFBJRl9JTlRfTUFT S19CSVQpICYgQUxMX0lOVF9NQVNLOworCXdyaXRlbCh2YWwsIGRwLT5yZWdzICsgQVBCX0lOVF9N QVNLKTsKK30KKworc3RhdGljIGludCBjZG5fZHBfbWFpbGJveF9yZWFkKHN0cnVjdCBjZG5fZHBf ZGV2aWNlICpkcCwgYm9vbCBmb3JjZSkKK3sKKwlpbnQgdmFsLCByZXQ7CisKKwlpZiAoIWRwLT5m d19hY3RpdmVkICYmICFmb3JjZSkKKwkJcmV0dXJuIC1FUEVSTTsKKworCXJldCA9IHJlYWR4X3Bv bGxfdGltZW91dChyZWFkbCwgZHAtPnJlZ3MgKyBNQUlMQk9YX0VNUFRZX0FERFIsCisJCQkJIHZh bCwgIXZhbCwgTUFJTEJPWF9SRVRSWV9VUywKKwkJCQkgTUFJTEJPWF9USU1FT1VUX1VTKTsKKwlp ZiAocmV0IDwgMCkKKwkJcmV0dXJuIHJldDsKKworCXJldHVybiByZWFkbChkcC0+cmVncyArIE1B SUxCT1gwX1JEX0RBVEEpICYgMHhmZjsKK30KKworc3RhdGljIGludCBjZHBfZHBfbWFpbGJveF93 cml0ZShzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAsIHU4IHZhbCwgYm9vbCBmb3JjZSkKK3sKKwlp bnQgcmV0LCBmdWxsOworCisJaWYgKCFkcC0+ZndfYWN0aXZlZCAmJiAhZm9yY2UpCisJCXJldHVy biAtRVBFUk07CisKKwlyZXQgPSByZWFkeF9wb2xsX3RpbWVvdXQocmVhZGwsIGRwLT5yZWdzICsg TUFJTEJPWF9GVUxMX0FERFIsCisJCQkJIGZ1bGwsICFmdWxsLCBNQUlMQk9YX1JFVFJZX1VTLAor CQkJCSBNQUlMQk9YX1RJTUVPVVRfVVMpOworCWlmIChyZXQgPCAwKQorCQlyZXR1cm4gcmV0Owor CisJd3JpdGVsKHZhbCwgZHAtPnJlZ3MgKyBNQUlMQk9YMF9XUl9EQVRBKTsKKworCXJldHVybiAw OworfQorCitzdGF0aWMgaW50IGNkbl9kcF9tYWlsYm94X3ZhbGlkYXRlX3JlY2VpdmUoc3RydWN0 IGNkbl9kcF9kZXZpY2UgKmRwLAorCQkJCQkgICB1OCBtb2R1bGVfaWQsIHU4IG9wY29kZSwKKwkJ CQkJICAgdTggcmVxX3NpemUpCit7CisJdTMyIG1ib3hfc2l6ZSwgaTsKKwl1OCBoZWFkZXJbNF07 CisJaW50IHJldDsKKworCS8qIHJlYWQgdGhlIGhlYWRlciBvZiB0aGUgbWVzc2FnZSAqLworCWZv ciAoaSA9IDA7IGkgPCA0OyBpKyspIHsKKwkJcmV0ID0gY2RuX2RwX21haWxib3hfcmVhZChkcCwg MCk7CisJCWlmIChyZXQgPCAwKQorCQkJcmV0dXJuIHJldDsKKworCQloZWFkZXJbaV0gPSByZXQ7 CisJfQorCisJbWJveF9zaXplID0gKGhlYWRlclsyXSA8PCA4KSB8IGhlYWRlclszXTsKKworCWlm IChvcGNvZGUgIT0gaGVhZGVyWzBdIHx8IG1vZHVsZV9pZCAhPSBoZWFkZXJbMV0gfHwKKwkgICAg cmVxX3NpemUgIT0gbWJveF9zaXplKSB7CisJCS8qCisJCSAqIElmIHRoZSBtZXNzYWdlIGluIG1h aWxib3ggaXMgbm90IHdoYXQgd2Ugd2FudCwgd2UgbmVlZCB0bworCQkgKiBjbGVhciB0aGUgbWFp bGJveCBieSByZWFkLgorCQkgKi8KKwkJZm9yIChpID0gMDsgaSA8IG1ib3hfc2l6ZTsgaSsrKQor CQkJaWYgKGNkbl9kcF9tYWlsYm94X3JlYWQoZHAsIDApIDwgMCkKKwkJCQlicmVhazsKKworCQly ZXR1cm4gLUVJTlZBTDsKKwl9CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGludCBjZG5fZHBf bWFpbGJveF9yZWFkX3JlY2VpdmUoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLAorCQkJCSAgICAg ICB1OCAqYnVmZiwgdTggYnVmZl9zaXplKQoreworCXUzMiBpOworCWludCByZXQ7CisKKwlmb3Ig KGkgPSAwOyBpIDwgYnVmZl9zaXplOyBpKyspIHsKKwkJcmV0ID0gY2RuX2RwX21haWxib3hfcmVh ZChkcCwgMCk7CisJCWlmIChyZXQgPCAwKQorCQkJcmV0dXJuIHJldDsKKworCQlidWZmW2ldID0g cmV0OworCX0KKworCXJldHVybiAwOworfQorCitzdGF0aWMgaW50IGNkbl9kcF9tYWlsYm94X3Nl bmQoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLCB1OCBtb2R1bGVfaWQsCisJCQkgICAgICAgdTgg b3Bjb2RlLCB1MTYgc2l6ZSwgdTggKm1lc3NhZ2UpCit7CisJdTggaGVhZGVyWzRdOworCWludCBy ZXQsIGk7CisKKwloZWFkZXJbMF0gPSBvcGNvZGU7CisJaGVhZGVyWzFdID0gbW9kdWxlX2lkOwor CWhlYWRlclsyXSA9IChzaXplID4+IDgpICYgMHhmZjsKKwloZWFkZXJbM10gPSBzaXplICYgMHhm ZjsKKworCWZvciAoaSA9IDA7IGkgPCA0OyBpKyspIHsKKwkJcmV0ID0gY2RwX2RwX21haWxib3hf d3JpdGUoZHAsIGhlYWRlcltpXSwgMCk7CisJCWlmIChyZXQpCisJCQlyZXR1cm4gcmV0OworCX0K KworCWZvciAoaSA9IDA7IGkgPCBzaXplOyBpKyspIHsKKwkJcmV0ID0gY2RwX2RwX21haWxib3hf d3JpdGUoZHAsIG1lc3NhZ2VbaV0sIDApOworCQlpZiAocmV0KQorCQkJcmV0dXJuIHJldDsKKwl9 CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGludCBjZG5fZHBfcmVnX3dyaXRlKHN0cnVjdCBj ZG5fZHBfZGV2aWNlICpkcCwgdTE2IGFkZHIsIHUzMiB2YWwpCit7CisJdTggbXNnWzZdOworCisJ bXNnWzBdID0gKGFkZHIgPj4gOCkgJiAweGZmOworCW1zZ1sxXSA9IGFkZHIgJiAweGZmOworCW1z Z1syXSA9ICh2YWwgPj4gMjQpICYgMHhmZjsKKwltc2dbM10gPSAodmFsID4+IDE2KSAmIDB4ZmY7 CisJbXNnWzRdID0gKHZhbCA+PiA4KSAmIDB4ZmY7CisJbXNnWzVdID0gdmFsICYgMHhmZjsKKwly ZXR1cm4gY2RuX2RwX21haWxib3hfc2VuZChkcCwgTUJfTU9EVUxFX0lEX0RQX1RYLCBEUFRYX1dS SVRFX1JFR0lTVEVSLAorCQkJCSAgIHNpemVvZihtc2cpLCBtc2cpOworfQorCitzdGF0aWMgaW50 IGNkbl9kcF9yZWdfd3JpdGVfYml0KHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCwgdTE2IGFkZHIs CisJCQkJdTggc3RhcnRfYml0LCB1OCBiaXRzX25vLCB1MzIgdmFsKQoreworCXU4IGZpZWxkWzhd OworCisJZmllbGRbMF0gPSAoYWRkciA+PiA4KSAmIDB4ZmY7CisJZmllbGRbMV0gPSBhZGRyICYg MHhmZjsKKwlmaWVsZFsyXSA9IHN0YXJ0X2JpdDsKKwlmaWVsZFszXSA9IGJpdHNfbm87CisJZmll bGRbNF0gPSAodmFsID4+IDI0KSAmIDB4ZmY7CisJZmllbGRbNV0gPSAodmFsID4+IDE2KSAmIDB4 ZmY7CisJZmllbGRbNl0gPSAodmFsID4+IDgpICYgMHhmZjsKKwlmaWVsZFs3XSA9IHZhbCAmIDB4 ZmY7CisKKwlyZXR1cm4gY2RuX2RwX21haWxib3hfc2VuZChkcCwgTUJfTU9EVUxFX0lEX0RQX1RY LCBEUFRYX1dSSVRFX0ZJRUxELAorCQkJCSAgIHNpemVvZihmaWVsZCksIGZpZWxkKTsKK30KKwor aW50IGNkbl9kcF9kcGNkX3JlYWQoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLCB1MzIgYWRkciwg dTggKmRhdGEsIHUxNiBsZW4pCit7CisJdTggbXNnWzVdLCByZWdbNV07CisJaW50IHJldDsKKwor CW1zZ1swXSA9IChsZW4gPj4gOCkgJiAweGZmOworCW1zZ1sxXSA9IGxlbiAmIDB4ZmY7CisJbXNn WzJdID0gKGFkZHIgPj4gMTYpICYgMHhmZjsKKwltc2dbM10gPSAoYWRkciA+PiA4KSAmIDB4ZmY7 CisJbXNnWzRdID0gYWRkciAmIDB4ZmY7CisJcmV0ID0gY2RuX2RwX21haWxib3hfc2VuZChkcCwg TUJfTU9EVUxFX0lEX0RQX1RYLCBEUFRYX1JFQURfRFBDRCwKKwkJCQkgIHNpemVvZihtc2cpLCBt c2cpOworCWlmIChyZXQpCisJCWdvdG8gZXJyX2RwY2RfcmVhZDsKKworCXJldCA9IGNkbl9kcF9t YWlsYm94X3ZhbGlkYXRlX3JlY2VpdmUoZHAsIE1CX01PRFVMRV9JRF9EUF9UWCwKKwkJCQkJICAg ICAgRFBUWF9SRUFEX0RQQ0QsCisJCQkJCSAgICAgIHNpemVvZihyZWcpICsgbGVuKTsKKwlpZiAo cmV0KQorCQlnb3RvIGVycl9kcGNkX3JlYWQ7CisKKwlyZXQgPSBjZG5fZHBfbWFpbGJveF9yZWFk X3JlY2VpdmUoZHAsIHJlZywgc2l6ZW9mKHJlZykpOworCWlmIChyZXQpCisJCWdvdG8gZXJyX2Rw Y2RfcmVhZDsKKworCXJldCA9IGNkbl9kcF9tYWlsYm94X3JlYWRfcmVjZWl2ZShkcCwgZGF0YSwg bGVuKTsKKworZXJyX2RwY2RfcmVhZDoKKwlyZXR1cm4gcmV0OworfQorCitpbnQgY2RuX2RwX2Rw Y2Rfd3JpdGUoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLCB1MzIgYWRkciwgdTggdmFsdWUpCit7 CisJdTggbXNnWzZdLCByZWdbNV07CisJaW50IHJldDsKKworCW1zZ1swXSA9IDA7CisJbXNnWzFd ID0gMTsKKwltc2dbMl0gPSAoYWRkciA+PiAxNikgJiAweGZmOworCW1zZ1szXSA9IChhZGRyID4+ IDgpICYgMHhmZjsKKwltc2dbNF0gPSBhZGRyICYgMHhmZjsKKwltc2dbNV0gPSB2YWx1ZTsKKwly ZXQgPSBjZG5fZHBfbWFpbGJveF9zZW5kKGRwLCBNQl9NT0RVTEVfSURfRFBfVFgsIERQVFhfV1JJ VEVfRFBDRCwKKwkJCQkgIHNpemVvZihtc2cpLCBtc2cpOworCWlmIChyZXQpCisJCWdvdG8gZXJy X2RwY2Rfd3JpdGU7CisKKwlyZXQgPSBjZG5fZHBfbWFpbGJveF92YWxpZGF0ZV9yZWNlaXZlKGRw LCBNQl9NT0RVTEVfSURfRFBfVFgsCisJCQkJCSAgICAgIERQVFhfV1JJVEVfRFBDRCwgc2l6ZW9m KHJlZykpOworCWlmIChyZXQpCisJCWdvdG8gZXJyX2RwY2Rfd3JpdGU7CisKKwlyZXQgPSBjZG5f ZHBfbWFpbGJveF9yZWFkX3JlY2VpdmUoZHAsIHJlZywgc2l6ZW9mKHJlZykpOworCWlmIChyZXQp CisJCWdvdG8gZXJyX2RwY2Rfd3JpdGU7CisKKwlpZiAoYWRkciAhPSAocmVnWzJdIDw8IDE2IHwg cmVnWzNdIDw8IDggfCByZWdbNF0pKQorCQlyZXQgPSAtRUlOVkFMOworCitlcnJfZHBjZF93cml0 ZToKKwlpZiAocmV0KQorCQlkZXZfZXJyKGRwLT5kZXYsICJkcGNkIHdyaXRlIGZhaWxlZDogJWRc biIsIHJldCk7CisJcmV0dXJuIHJldDsKK30KKworaW50IGNkbl9kcF9sb2FkX2Zpcm13YXJlKHN0 cnVjdCBjZG5fZHBfZGV2aWNlICpkcCwgY29uc3QgdTMyICppX21lbSwKKwkJCSB1MzIgaV9zaXpl LCBjb25zdCB1MzIgKmRfbWVtLCB1MzIgZF9zaXplKQoreworCXUzMiByZWc7CisJaW50IGksIHJl dDsKKworCS8qIHJlc2V0IHVjcHUgYmVmb3JlIGxvYWQgZmlybXdhcmUqLworCXdyaXRlbChBUEJf SVJBTV9QQVRIIHwgQVBCX0RSQU1fUEFUSCB8IEFQQl9YVF9SRVNFVCwKKwkgICAgICAgZHAtPnJl Z3MgKyBBUEJfQ1RSTCk7CisKKwlmb3IgKGkgPSAwOyBpIDwgaV9zaXplOyBpICs9IDQpCisJCXdy aXRlbCgqaV9tZW0rKywgZHAtPnJlZ3MgKyBBRERSX0lNRU0gKyBpKTsKKworCWZvciAoaSA9IDA7 IGkgPCBkX3NpemU7IGkgKz0gNCkKKwkJd3JpdGVsKCpkX21lbSsrLCBkcC0+cmVncyArIEFERFJf RE1FTSArIGkpOworCisJLyogdW4tcmVzZXQgdWNwdSAqLworCXdyaXRlbCgwLCBkcC0+cmVncyAr IEFQQl9DVFJMKTsKKworCS8qIGNoZWNrIHRoZSBrZWVwIGFsaXZlIHJlZ2lzdGVyIHRvIG1ha2Ug c3VyZSBmdyB3b3JraW5nICovCisJcmV0ID0gcmVhZHhfcG9sbF90aW1lb3V0KHJlYWRsLCBkcC0+ cmVncyArIEtFRVBfQUxJVkUsCisJCQkJIHJlZywgcmVnLCAyMDAwLCBGV19BTElWRV9USU1FT1VU X1VTKTsKKwlpZiAocmV0IDwgMCkgeworCQlkZXZfZXJyKGRwLT5kZXYsICJmYWlsZWQgdG8gbG9h ZGVkIHRoZSBGVyByZWcgPSAleFxuIiwgcmVnKTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCisJ cmVnID0gcmVhZGwoZHAtPnJlZ3MgKyBWRVJfTCkgJiAweGZmOworCWRwLT5md192ZXJzaW9uID0g cmVnOworCXJlZyA9IHJlYWRsKGRwLT5yZWdzICsgVkVSX0gpICYgMHhmZjsKKwlkcC0+ZndfdmVy c2lvbiB8PSByZWcgPDwgODsKKwlyZWcgPSByZWFkbChkcC0+cmVncyArIFZFUl9MSUJfTF9BRERS KSAmIDB4ZmY7CisJZHAtPmZ3X3ZlcnNpb24gfD0gcmVnIDw8IDE2OworCXJlZyA9IHJlYWRsKGRw LT5yZWdzICsgVkVSX0xJQl9IX0FERFIpICYgMHhmZjsKKwlkcC0+ZndfdmVyc2lvbiB8PSByZWcg PDwgMjQ7CisKKwlkZXZfZGJnKGRwLT5kZXYsICJmaXJtd2FyZSB2ZXJzaW9uOiAleFxuIiwgZHAt PmZ3X3ZlcnNpb24pOworCisJcmV0dXJuIDA7Cit9CisKK2ludCBjZG5fZHBfc2V0X2Zpcm13YXJl X2FjdGl2ZShzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAsIGJvb2wgZW5hYmxlKQoreworCXU4IG1z Z1s1XTsKKwlpbnQgcmV0LCBpOworCisJbXNnWzBdID0gR0VORVJBTF9NQUlOX0NPTlRST0w7CisJ bXNnWzFdID0gTUJfTU9EVUxFX0lEX0dFTkVSQUw7CisJbXNnWzJdID0gMDsKKwltc2dbM10gPSAx OworCW1zZ1s0XSA9IGVuYWJsZSA/IEZXX0FDVElWRSA6IEZXX1NUQU5EQlk7CisKKwlmb3IgKGkg PSAwOyBpIDwgc2l6ZW9mKG1zZyk7IGkrKykgeworCQlyZXQgPSBjZHBfZHBfbWFpbGJveF93cml0 ZShkcCwgbXNnW2ldLCAxKTsKKwkJaWYgKHJldCkKKwkJCWdvdG8gZXJyX3NldF9maXJtd2FyZV9h Y3RpdmU7CisJfQorCisJLyogcmVhZCB0aGUgZmlybXdhcmUgc3RhdGUgKi8KKwlmb3IgKGkgPSAw OyBpIDwgc2l6ZW9mKG1zZyk7IGkrKykgIHsKKwkJcmV0ID0gY2RuX2RwX21haWxib3hfcmVhZChk cCwgMSk7CisJCWlmIChyZXQgPCAwKQorCQkJZ290byBlcnJfc2V0X2Zpcm13YXJlX2FjdGl2ZTsK KworCQltc2dbaV0gPSByZXQ7CisJfQorCisJZHAtPmZ3X2FjdGl2ZWQgPSAobXNnWzRdID09IEZX X0FDVElWRSk7CisJcmV0ID0gMDsKKworZXJyX3NldF9maXJtd2FyZV9hY3RpdmU6CisJaWYgKHJl dCA8IDApCisJCWRldl9lcnIoZHAtPmRldiwgInNldCBmaXJtd2FyZSBhY3RpdmUgZmFpbGVkXG4i KTsKKwlyZXR1cm4gcmV0OworfQorCitpbnQgY2RuX2RwX3NldF9ob3N0X2NhcChzdHJ1Y3QgY2Ru X2RwX2RldmljZSAqZHAsIHU4IGxhbmVzLCBib29sIGZsaXApCit7CisJdTggbXNnWzhdOworCWlu dCByZXQ7CisKKwltc2dbMF0gPSBDRE5fRFBfTUFYX0xJTktfUkFURTsKKwltc2dbMV0gPSBsYW5l czsKKwltc2dbMl0gPSBWT0xUQUdFX0xFVkVMXzI7CisJbXNnWzNdID0gUFJFX0VNUEhBU0lTX0xF VkVMXzM7CisJbXNnWzRdID0gUFRTMSB8IFBUUzIgfCBQVFMzIHwgUFRTNDsKKwltc2dbNV0gPSBG QVNUX0xUX05PVF9TVVBQT1JUOworCW1zZ1s2XSA9IGZsaXAgPyBMQU5FX01BUFBJTkdfRkxJUFBF RCA6IExBTkVfTUFQUElOR19OT1JNQUw7CisJbXNnWzddID0gRU5IQU5DRUQ7CisKKwlyZXQgPSBj ZG5fZHBfbWFpbGJveF9zZW5kKGRwLCBNQl9NT0RVTEVfSURfRFBfVFgsCisJCQkJICBEUFRYX1NF VF9IT1NUX0NBUEFCSUxJVElFUywKKwkJCQkgIHNpemVvZihtc2cpLCBtc2cpOworCWlmIChyZXQp CisJCWdvdG8gZXJyX3NldF9ob3N0X2NhcDsKKworCXJldCA9IGNkbl9kcF9yZWdfd3JpdGUoZHAs IERQX0FVWF9TV0FQX0lOVkVSU0lPTl9DT05UUk9MLAorCQkJICAgICAgIEFVWF9IT1NUX0lOVkVS VCk7CisKK2Vycl9zZXRfaG9zdF9jYXA6CisJaWYgKHJldCkKKwkJZGV2X2VycihkcC0+ZGV2LCAi c2V0IGhvc3QgY2FwIGZhaWxlZDogJWRcbiIsIHJldCk7CisJcmV0dXJuIHJldDsKK30KKworaW50 IGNkbl9kcF9ldmVudF9jb25maWcoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwKQoreworCXU4IG1z Z1s1XTsKKwlpbnQgcmV0OworCisJbWVtc2V0KG1zZywgMCwgc2l6ZW9mKG1zZykpOworCisJbXNn WzBdID0gRFBUWF9FVkVOVF9FTkFCTEVfSFBEIHwgRFBUWF9FVkVOVF9FTkFCTEVfVFJBSU5JTkc7 CisKKwlyZXQgPSBjZG5fZHBfbWFpbGJveF9zZW5kKGRwLCBNQl9NT0RVTEVfSURfRFBfVFgsIERQ VFhfRU5BQkxFX0VWRU5ULAorCQkJCSAgc2l6ZW9mKG1zZyksIG1zZyk7CisJaWYgKHJldCkKKwkJ ZGV2X2VycihkcC0+ZGV2LCAic2V0IGV2ZW50IGNvbmZpZyBmYWlsZWQ6ICVkXG4iLCByZXQpOwor CisJcmV0dXJuIHJldDsKK30KKwordTMyIGNkbl9kcF9nZXRfZXZlbnQoc3RydWN0IGNkbl9kcF9k ZXZpY2UgKmRwKQoreworCXJldHVybiByZWFkbChkcC0+cmVncyArIFNXX0VWRU5UUzApOworfQor CitpbnQgY2RuX2RwX2dldF9ocGRfc3RhdHVzKHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCkKK3sK Kwl1OCBzdGF0dXM7CisJaW50IHJldDsKKworCXJldCA9IGNkbl9kcF9tYWlsYm94X3NlbmQoZHAs IE1CX01PRFVMRV9JRF9EUF9UWCwgRFBUWF9IUERfU1RBVEUsCisJCQkJICAwLCBOVUxMKTsKKwlp ZiAocmV0KQorCQlnb3RvIGVycl9nZXRfaHBkOworCisJcmV0ID0gY2RuX2RwX21haWxib3hfdmFs aWRhdGVfcmVjZWl2ZShkcCwgTUJfTU9EVUxFX0lEX0RQX1RYLAorCQkJCQkgICAgICBEUFRYX0hQ RF9TVEFURSwgc2l6ZW9mKHN0YXR1cykpOworCWlmIChyZXQpCisJCWdvdG8gZXJyX2dldF9ocGQ7 CisKKwlyZXQgPSBjZG5fZHBfbWFpbGJveF9yZWFkX3JlY2VpdmUoZHAsICZzdGF0dXMsIHNpemVv ZihzdGF0dXMpKTsKKwlpZiAocmV0KQorCQlnb3RvIGVycl9nZXRfaHBkOworCisJcmV0dXJuIHN0 YXR1czsKKworZXJyX2dldF9ocGQ6CisJZGV2X2VycihkcC0+ZGV2LCAiZ2V0IGhwZCBzdGF0dXMg ZmFpbGVkOiAlZFxuIiwgcmV0KTsKKwlyZXR1cm4gcmV0OworfQorCitpbnQgY2RuX2RwX2dldF9l ZGlkX2Jsb2NrKHZvaWQgKmRhdGEsIHU4ICplZGlkLAorCQkJICB1bnNpZ25lZCBpbnQgYmxvY2ss IHNpemVfdCBsZW5ndGgpCit7CisJc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwID0gZGF0YTsKKwl1 OCBtc2dbMl0sIHJlZ1syXTsKKwlpbnQgcmV0OworCisJbXNnWzBdID0gYmxvY2sgLyAyOworCW1z Z1sxXSA9IGJsb2NrICUgMjsKKworCXJldCA9IGNkbl9kcF9tYWlsYm94X3NlbmQoZHAsIE1CX01P RFVMRV9JRF9EUF9UWCwgRFBUWF9HRVRfRURJRCwKKwkJCQkgIHNpemVvZihtc2cpLCBtc2cpOwor CWlmIChyZXQpCisJCWdvdG8gZXJyX2dldF9lZGlkOworCisJcmV0ID0gY2RuX2RwX21haWxib3hf dmFsaWRhdGVfcmVjZWl2ZShkcCwgTUJfTU9EVUxFX0lEX0RQX1RYLAorCQkJCQkgICAgICBEUFRY X0dFVF9FRElELAorCQkJCQkgICAgICBzaXplb2YocmVnKSArIGxlbmd0aCk7CisJaWYgKHJldCkK KwkJZ290byBlcnJfZ2V0X2VkaWQ7CisKKwlyZXQgPSBjZG5fZHBfbWFpbGJveF9yZWFkX3JlY2Vp dmUoZHAsIHJlZywgc2l6ZW9mKHJlZykpOworCWlmIChyZXQpCisJCWdvdG8gZXJyX2dldF9lZGlk OworCisJcmV0ID0gY2RuX2RwX21haWxib3hfcmVhZF9yZWNlaXZlKGRwLCBlZGlkLCBsZW5ndGgp OworCWlmIChyZXQpCisJCWdvdG8gZXJyX2dldF9lZGlkOworCisJaWYgKHJlZ1swXSAhPSBsZW5n dGggfHwgcmVnWzFdICE9IGJsb2NrIC8gMikKKwkJcmV0ID0gLUVJTlZBTDsKKworZXJyX2dldF9l ZGlkOgorCWlmIChyZXQpCisJCWRldl9lcnIoZHAtPmRldiwgImdldCBibG9ja1slZF0gZWRpZCBm YWlsZWQ6ICVkXG4iLCBibG9jaywgcmV0KTsKKwlyZXR1cm4gcmV0OworfQorCitpbnQgY2RuX2Rw X3RyYWluaW5nX3N0YXJ0KHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCkKK3sKKwl1bnNpZ25lZCBs b25nIHRpbWVvdXQ7CisJdTggbXNnLCBldmVudFsyXTsKKwlpbnQgcmV0OworCisJbXNnID0gTElO S19UUkFJTklOR19SVU47CisKKwkvKiBzdGFydCB0cmFpbmluZyAqLworCXJldCA9IGNkbl9kcF9t YWlsYm94X3NlbmQoZHAsIE1CX01PRFVMRV9JRF9EUF9UWCwgRFBUWF9UUkFJTklOR19DT05UUk9M LAorCQkJCSAgc2l6ZW9mKG1zZyksICZtc2cpOworCWlmIChyZXQpCisJCWdvdG8gZXJyX3RyYWlu aW5nX3N0YXJ0OworCisJdGltZW91dCA9IGppZmZpZXMgKyBtc2Vjc190b19qaWZmaWVzKExJTktf VFJBSU5JTkdfVElNRU9VVF9NUyk7CisJd2hpbGUgKHRpbWVfYmVmb3JlKGppZmZpZXMsIHRpbWVv dXQpKSB7CisJCW1zbGVlcChMSU5LX1RSQUlOSU5HX1JFVFJZX01TKTsKKwkJcmV0ID0gY2RuX2Rw X21haWxib3hfc2VuZChkcCwgTUJfTU9EVUxFX0lEX0RQX1RYLAorCQkJCQkgIERQVFhfUkVBRF9F VkVOVCwgMCwgTlVMTCk7CisJCWlmIChyZXQpCisJCQlnb3RvIGVycl90cmFpbmluZ19zdGFydDsK KworCQlyZXQgPSBjZG5fZHBfbWFpbGJveF92YWxpZGF0ZV9yZWNlaXZlKGRwLCBNQl9NT0RVTEVf SURfRFBfVFgsCisJCQkJCQkgICAgICBEUFRYX1JFQURfRVZFTlQsCisJCQkJCQkgICAgICBzaXpl b2YoZXZlbnQpKTsKKwkJaWYgKHJldCkKKwkJCWdvdG8gZXJyX3RyYWluaW5nX3N0YXJ0OworCisJ CXJldCA9IGNkbl9kcF9tYWlsYm94X3JlYWRfcmVjZWl2ZShkcCwgZXZlbnQsIHNpemVvZihldmVu dCkpOworCQlpZiAocmV0KQorCQkJZ290byBlcnJfdHJhaW5pbmdfc3RhcnQ7CisKKwkJaWYgKGV2 ZW50WzFdICYgRVFfUEhBU0VfRklOSVNIRUQpCisJCQlyZXR1cm4gMDsKKwl9CisKKwlyZXQgPSAt RVRJTUVET1VUOworCitlcnJfdHJhaW5pbmdfc3RhcnQ6CisJZGV2X2VycihkcC0+ZGV2LCAidHJh aW5pbmcgZmFpbGVkOiAlZFxuIiwgcmV0KTsKKwlyZXR1cm4gcmV0OworfQorCitpbnQgY2RuX2Rw X2dldF90cmFpbmluZ19zdGF0dXMoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwKQoreworCXU4IHN0 YXR1c1sxMF07CisJaW50IHJldDsKKworCXJldCA9IGNkbl9kcF9tYWlsYm94X3NlbmQoZHAsIE1C X01PRFVMRV9JRF9EUF9UWCwgRFBUWF9SRUFEX0xJTktfU1RBVCwKKwkJCQkgIDAsIE5VTEwpOwor CWlmIChyZXQpCisJCWdvdG8gZXJyX2dldF90cmFpbmluZ19zdGF0dXM7CisKKwlyZXQgPSBjZG5f ZHBfbWFpbGJveF92YWxpZGF0ZV9yZWNlaXZlKGRwLCBNQl9NT0RVTEVfSURfRFBfVFgsCisJCQkJ CSAgICAgIERQVFhfUkVBRF9MSU5LX1NUQVQsCisJCQkJCSAgICAgIHNpemVvZihzdGF0dXMpKTsK KwlpZiAocmV0KQorCQlnb3RvIGVycl9nZXRfdHJhaW5pbmdfc3RhdHVzOworCisJcmV0ID0gY2Ru X2RwX21haWxib3hfcmVhZF9yZWNlaXZlKGRwLCBzdGF0dXMsIHNpemVvZihzdGF0dXMpKTsKKwlp ZiAocmV0KQorCQlnb3RvIGVycl9nZXRfdHJhaW5pbmdfc3RhdHVzOworCisJZHAtPmxpbmsucmF0 ZSA9IHN0YXR1c1swXTsKKwlkcC0+bGluay5udW1fbGFuZXMgPSBzdGF0dXNbMV07CisKK2Vycl9n ZXRfdHJhaW5pbmdfc3RhdHVzOgorCWlmIChyZXQpCisJCWRldl9lcnIoZHAtPmRldiwgImdldCB0 cmFpbmluZyBzdGF0dXMgZmFpbGVkOiAlZFxuIiwgcmV0KTsKKwlyZXR1cm4gcmV0OworfQorCitp bnQgY2RuX2RwX3NldF92aWRlb19zdGF0dXMoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLCBpbnQg YWN0aXZlKQoreworCXU4IG1zZzsKKwlpbnQgcmV0OworCisJbXNnID0gISFhY3RpdmU7CisKKwly ZXQgPSBjZG5fZHBfbWFpbGJveF9zZW5kKGRwLCBNQl9NT0RVTEVfSURfRFBfVFgsIERQVFhfU0VU X1ZJREVPLAorCQkJCSAgc2l6ZW9mKG1zZyksICZtc2cpOworCWlmIChyZXQpCisJCWRldl9lcnIo ZHAtPmRldiwgInNldCB2aWRlbyBzdGF0dXMgZmFpbGVkOiAlZFxuIiwgcmV0KTsKKworCXJldHVy biByZXQ7Cit9CisKK3N0YXRpYyBpbnQgY2RuX2RwX2dldF9tc2FfbWlzYyhzdHJ1Y3QgdmlkZW9f aW5mbyAqdmlkZW8sCisJCQkgICAgICAgc3RydWN0IGRybV9kaXNwbGF5X21vZGUgKm1vZGUpCit7 CisJdTMyIG1zYV9taXNjOworCXU4IHZhbFsyXTsKKworCXN3aXRjaCAodmlkZW8tPmNvbG9yX2Zt dCkgeworCWNhc2UgUFhMX1JHQjoKKwljYXNlIFlfT05MWToKKwkJdmFsWzBdID0gMDsKKwkJYnJl YWs7CisJLyogc2V0IFlVViBkZWZhdWx0IGNvbG9yIHNwYWNlIGNvbnZlcnNpb24gdG8gQlQ2MDEg Ki8KKwljYXNlIFlDQkNSXzRfNF80OgorCQl2YWxbMF0gPSA2ICsgQlRfNjAxICogODsKKwkJYnJl YWs7CisJY2FzZSBZQ0JDUl80XzJfMjoKKwkJdmFsWzBdID0gNSArIEJUXzYwMSAqIDg7CisJCWJy ZWFrOworCWNhc2UgWUNCQ1JfNF8yXzA6CisJCXZhbFswXSA9IDU7CisJCWJyZWFrOworCX07CisK Kwlzd2l0Y2ggKHZpZGVvLT5jb2xvcl9kZXB0aCkgeworCWNhc2UgNjoKKwkJdmFsWzFdID0gMDsK KwkJYnJlYWs7CisJY2FzZSA4OgorCQl2YWxbMV0gPSAxOworCQlicmVhazsKKwljYXNlIDEwOgor CQl2YWxbMV0gPSAyOworCQlicmVhazsKKwljYXNlIDEyOgorCQl2YWxbMV0gPSAzOworCQlicmVh azsKKwljYXNlIDE2OgorCQl2YWxbMV0gPSA0OworCQlicmVhazsKKwl9OworCisJbXNhX21pc2Mg PSAyICogdmFsWzBdICsgMzIgKiB2YWxbMV0gKworCQkgICAoKHZpZGVvLT5jb2xvcl9mbXQgPT0g WV9PTkxZKSA/ICgxIDw8IDE0KSA6IDApOworCisJcmV0dXJuIG1zYV9taXNjOworfQorCitpbnQg Y2RuX2RwX2NvbmZpZ192aWRlbyhzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHApCit7CisJc3RydWN0 IHZpZGVvX2luZm8gKnZpZGVvID0gJmRwLT52aWRlb19pbmZvOworCXN0cnVjdCBkcm1fZGlzcGxh eV9tb2RlICptb2RlID0gJmRwLT5tb2RlOworCXU2NCBzeW1ib2wsIHRtcDsKKwl1MzIgdmFsLCBs aW5rX3JhdGU7CisJdTggYml0X3Blcl9waXgsIHR1X3NpemVfcmVnID0gVFVfU0laRTsKKwlpbnQg cmV0OworCisJYml0X3Blcl9waXggPSAodmlkZW8tPmNvbG9yX2ZtdCA9PSBZQ0JDUl80XzJfMikg PworCQkgICAgICAodmlkZW8tPmNvbG9yX2RlcHRoICogMikgOiAodmlkZW8tPmNvbG9yX2RlcHRo ICogMyk7CisKKwlsaW5rX3JhdGUgPSBkcm1fZHBfYndfY29kZV90b19saW5rX3JhdGUoZHAtPmxp bmsucmF0ZSkgLyAxMDAwOworCisJdmFsID0gVklGX0JZUEFTU19JTlRFUkxBQ0U7CisJcmV0ID0g Y2RuX2RwX3JlZ193cml0ZShkcCwgQk5EX0hTWU5DMlZTWU5DLCB2YWwpOworCWlmIChyZXQpCisJ CWdvdG8gZXJyX2NvbmZpZ192aWRlbzsKKworCXJldCA9IGNkbl9kcF9yZWdfd3JpdGUoZHAsIEhT WU5DMlZTWU5DX1BPTF9DVFJMLCAwKTsKKwlpZiAocmV0KQorCQlnb3RvIGVycl9jb25maWdfdmlk ZW87CisKKwkvKgorCSAqIGdldCBhIGJlc3QgdHVfc2l6ZSBhbmQgdmFsaWQgc3ltYm9sOgorCSAq IDEuIGNob3NlIExjbGsgZnJlcSgxNjJNaHosIDI3ME1oeiwgNTQwTWh6KSwgc2V0IFRVIHRvIDMy CisJICogMi4gY2FsY3VsYXRlIFZTKHZhbGlkIHN5bWJvbCkgPSBUVSAqIFBjbGsgKiBCcHAgLyAo TGNsayAqIExhbmVzKQorCSAqIDMuIGlmIFZTID4gKi44NSBvciBWUyA8ICouMSBvciBWUyA8IDIg b3IgVFUgPCBWUyArIDQsIHRoZW4gc2V0CisJICogICAgVFUgKz0gMiBhbmQgcmVwZWF0IDJuZCBz dGVwLgorCSAqLworCWRvIHsKKwkJdHVfc2l6ZV9yZWcgKz0gMjsKKwkJdG1wID0gdHVfc2l6ZV9y ZWcgKiBtb2RlLT5jbG9jayAqIGJpdF9wZXJfcGl4OworCQl0bXAgLz0gZHAtPmxpbmsubnVtX2xh bmVzICogbGlua19yYXRlICogODsKKwkJc3ltYm9sID0gdG1wIC8gMTAwMDsKKwl9IHdoaWxlICgo c3ltYm9sIDw9IDEpIHx8ICh0dV9zaXplX3JlZyAtIHN5bWJvbCA8IDQpIHx8CisJCSAodG1wICUg MTAwMCA+IDg1MCkgfHwgKHRtcCAlIDEwMDAgPCAxMDApKTsKKworCXZhbCA9IHN5bWJvbCArICh0 dV9zaXplX3JlZyA8PCA4KTsKKwlyZXQgPSBjZG5fZHBfcmVnX3dyaXRlKGRwLCBEUF9GUkFNRVJf VFUsIHZhbCk7CisJaWYgKHJldCkKKwkJZ290byBlcnJfY29uZmlnX3ZpZGVvOworCisJLyogc2V0 IHRoZSBGSUZPIEJ1ZmZlciBzaXplICovCisJdmFsID0gKChtb2RlLT5jbG9jayAqIChzeW1ib2wg KyAxKSAvIDEwMDApICsgbGlua19yYXRlKTsKKwl2YWwgLz0gKGRwLT5saW5rLm51bV9sYW5lcyAq IGxpbmtfcmF0ZSk7CisJdmFsID0gOCAqIChzeW1ib2wgKyAxKSAvIGJpdF9wZXJfcGl4IC0gdmFs OworCXZhbCArPSAyOworCXJldCA9IGNkbl9kcF9yZWdfd3JpdGUoZHAsIERQX1ZDX1RBQkxFKDE1 KSwgdmFsKTsKKworCXN3aXRjaCAodmlkZW8tPmNvbG9yX2RlcHRoKSB7CisJY2FzZSA2OgorCQl2 YWwgPSBCQ1NfNjsKKwkJYnJlYWs7CisJY2FzZSA4OgorCQl2YWwgPSBCQ1NfODsKKwkJYnJlYWs7 CisJY2FzZSAxMDoKKwkJdmFsID0gQkNTXzEwOworCQlicmVhazsKKwljYXNlIDEyOgorCQl2YWwg PSBCQ1NfMTI7CisJCWJyZWFrOworCWNhc2UgMTY6CisJCXZhbCA9IEJDU18xNjsKKwkJYnJlYWs7 CisJfTsKKworCXZhbCArPSB2aWRlby0+Y29sb3JfZm10IDw8IDg7CisJcmV0ID0gY2RuX2RwX3Jl Z193cml0ZShkcCwgRFBfRlJBTUVSX1BYTF9SRVBSLCB2YWwpOworCWlmIChyZXQpCisJCWdvdG8g ZXJyX2NvbmZpZ192aWRlbzsKKworCXZhbCA9IHZpZGVvLT5oX3N5bmNfcG9sYXJpdHkgPyBEUF9G UkFNRVJfU1BfSFNQIDogMDsKKwl2YWwgfD0gdmlkZW8tPnZfc3luY19wb2xhcml0eSA/IERQX0ZS QU1FUl9TUF9WU1AgOiAwOworCXJldCA9IGNkbl9kcF9yZWdfd3JpdGUoZHAsIERQX0ZSQU1FUl9T UCwgdmFsKTsKKwlpZiAocmV0KQorCQlnb3RvIGVycl9jb25maWdfdmlkZW87CisKKwl2YWwgPSAo bW9kZS0+aHN5bmNfc3RhcnQgLSBtb2RlLT5oZGlzcGxheSkgPDwgMTY7CisJdmFsIHw9IG1vZGUt Pmh0b3RhbCAtIG1vZGUtPmhzeW5jX2VuZDsKKwlyZXQgPSBjZG5fZHBfcmVnX3dyaXRlKGRwLCBE UF9GUk9OVF9CQUNLX1BPUkNILCB2YWwpOworCWlmIChyZXQpCisJCWdvdG8gZXJyX2NvbmZpZ192 aWRlbzsKKworCXZhbCA9IG1vZGUtPmhkaXNwbGF5ICogYml0X3Blcl9waXggLyA4OworCXJldCA9 IGNkbl9kcF9yZWdfd3JpdGUoZHAsIERQX0JZVEVfQ09VTlQsIHZhbCk7CisJaWYgKHJldCkKKwkJ Z290byBlcnJfY29uZmlnX3ZpZGVvOworCisJdmFsID0gbW9kZS0+aHRvdGFsIHwgKChtb2RlLT5o dG90YWwgLSBtb2RlLT5oc3luY19zdGFydCkgPDwgMTYpOworCXJldCA9IGNkbl9kcF9yZWdfd3Jp dGUoZHAsIE1TQV9IT1JJWk9OVEFMXzAsIHZhbCk7CisJaWYgKHJldCkKKwkJZ290byBlcnJfY29u ZmlnX3ZpZGVvOworCisJdmFsID0gbW9kZS0+aHN5bmNfZW5kIC0gbW9kZS0+aHN5bmNfc3RhcnQ7 CisJdmFsIHw9IChtb2RlLT5oZGlzcGxheSA8PCAxNikgfCAodmlkZW8tPmhfc3luY19wb2xhcml0 eSA8PCAxNSk7CisJcmV0ID0gY2RuX2RwX3JlZ193cml0ZShkcCwgTVNBX0hPUklaT05UQUxfMSwg dmFsKTsKKwlpZiAocmV0KQorCQlnb3RvIGVycl9jb25maWdfdmlkZW87CisKKwl2YWwgPSBtb2Rl LT52dG90YWw7CisJdmFsIHw9ICgobW9kZS0+dnRvdGFsIC0gbW9kZS0+dnN5bmNfc3RhcnQpIDw8 IDE2KTsKKwlyZXQgPSBjZG5fZHBfcmVnX3dyaXRlKGRwLCBNU0FfVkVSVElDQUxfMCwgdmFsKTsK KwlpZiAocmV0KQorCQlnb3RvIGVycl9jb25maWdfdmlkZW87CisKKwl2YWwgPSBtb2RlLT52c3lu Y19lbmQgLSBtb2RlLT52c3luY19zdGFydDsKKwl2YWwgfD0gbW9kZS0+dmRpc3BsYXkgPDwgMTYg fCAodmlkZW8tPnZfc3luY19wb2xhcml0eSA8PCAxNSk7CisJcmV0ID0gY2RuX2RwX3JlZ193cml0 ZShkcCwgTVNBX1ZFUlRJQ0FMXzEsIHZhbCk7CisJaWYgKHJldCkKKwkJZ290byBlcnJfY29uZmln X3ZpZGVvOworCisJdmFsID0gY2RuX2RwX2dldF9tc2FfbWlzYyh2aWRlbywgbW9kZSk7CisJcmV0 ID0gY2RuX2RwX3JlZ193cml0ZShkcCwgTVNBX01JU0MsIHZhbCk7CisJaWYgKHJldCkKKwkJZ290 byBlcnJfY29uZmlnX3ZpZGVvOworCisJcmV0ID0gY2RuX2RwX3JlZ193cml0ZShkcCwgU1RSRUFN X0NPTkZJRywgMSk7CisJaWYgKHJldCkKKwkJZ290byBlcnJfY29uZmlnX3ZpZGVvOworCisJdmFs ID0gbW9kZS0+aHN5bmNfZW5kIC0gbW9kZS0+aHN5bmNfc3RhcnQ7CisJdmFsIHw9IChtb2RlLT5o ZGlzcGxheSA8PCAxNik7CisJcmV0ID0gY2RuX2RwX3JlZ193cml0ZShkcCwgRFBfSE9SSVpPTlRB TCwgdmFsKTsKKwlpZiAocmV0KQorCQlnb3RvIGVycl9jb25maWdfdmlkZW87CisKKwl2YWwgPSBt b2RlLT52dG90YWw7CisJdmFsIC09IChtb2RlLT52dG90YWwgLSBtb2RlLT52ZGlzcGxheSk7CisJ dmFsIHw9IChtb2RlLT52dG90YWwgLSBtb2RlLT52c3luY19zdGFydCkgPDwgMTY7CisJcmV0ID0g Y2RuX2RwX3JlZ193cml0ZShkcCwgRFBfVkVSVElDQUxfMCwgdmFsKTsKKwlpZiAocmV0KQorCQln b3RvIGVycl9jb25maWdfdmlkZW87CisKKwl2YWwgPSBtb2RlLT52dG90YWw7CisJcmV0ID0gY2Ru X2RwX3JlZ193cml0ZShkcCwgRFBfVkVSVElDQUxfMSwgdmFsKTsKKwlpZiAocmV0KQorCQlnb3Rv IGVycl9jb25maWdfdmlkZW87CisKKwl2YWwgPSAgMDsKKwlyZXQgPSBjZG5fZHBfcmVnX3dyaXRl X2JpdChkcCwgRFBfVkJfSUQsIDIsIDEsIHZhbCk7CisKK2Vycl9jb25maWdfdmlkZW86CisJaWYg KHJldCkKKwkJZGV2X2VycihkcC0+ZGV2LCAiY29uZmlnIHZpZGVvIGZhaWxlZDogJWRcbiIsIHJl dCk7CisJcmV0dXJuIHJldDsKK30KKworaW50IGNkbl9kcF9hdWRpb19zdG9wKHN0cnVjdCBjZG5f ZHBfZGV2aWNlICpkcCwgc3RydWN0IGF1ZGlvX2luZm8gKmF1ZGlvKQoreworCXUzMiB2YWw7CisJ aW50IHJldDsKKworCXJldCA9IGNkbl9kcF9yZWdfd3JpdGUoZHAsIEFVRElPX1BBQ0tfQ09OVFJP TCwgMCk7CisJaWYgKHJldCkgeworCQlkZXZfZXJyKGRwLT5kZXYsICJhdWRpbyBzdG9wIGZhaWxl ZDogJWRcbiIsIHJldCk7CisJCXJldHVybiByZXQ7CisJfQorCisJdmFsID0gU1BESUZfQVZHX1NF TCB8IFNQRElGX0pJVFRFUl9CWVBBU1M7CisJdmFsIHw9IFNQRElGX0ZJRk9fTUlEX1JBTkdFKDB4 ZTApOworCXZhbCB8PSBTUERJRl9KSVRURVJfVEhSU0goMHhlMCk7CisJdmFsIHw9IFNQRElGX0pJ VFRFUl9BVkdfV0lOKDcpOworCXdyaXRlbCh2YWwsIGRwLT5yZWdzICsgU1BESUZfQ1RSTF9BRERS KTsKKworCS8qIGNsZWFybiB0aGUgYXVkaW8gY29uZmlnIGFuZCByZXNldCAqLworCXdyaXRlbCgw LCBkcC0+cmVncyArIEFVRElPX1NSQ19DTlRMKTsKKwl3cml0ZWwoMCwgZHAtPnJlZ3MgKyBBVURJ T19TUkNfQ05GRyk7CisJd3JpdGVsKEFVRElPX1NXX1JTVCwgZHAtPnJlZ3MgKyBBVURJT19TUkNf Q05UTCk7CisJd3JpdGVsKDAsIGRwLT5yZWdzICsgQVVESU9fU1JDX0NOVEwpOworCisJLyogcmVz ZXQgc21wbDJwY2t0IGNvbXBvbmVudCAgKi8KKwl3cml0ZWwoMCwgZHAtPnJlZ3MgKyBTTVBMMlBL VF9DTlRMKTsKKwl3cml0ZWwoQVVESU9fU1dfUlNULCBkcC0+cmVncyArIFNNUEwyUEtUX0NOVEwp OworCXdyaXRlbCgwLCBkcC0+cmVncyArIFNNUEwyUEtUX0NOVEwpOworCisJLyogcmVzZXQgRklG TyAqLworCXdyaXRlbChBVURJT19TV19SU1QsIGRwLT5yZWdzICsgRklGT19DTlRMKTsKKwl3cml0 ZWwoMCwgZHAtPnJlZ3MgKyBGSUZPX0NOVEwpOworCisJaWYgKGF1ZGlvLT5mb3JtYXQgPT0gQUZN VF9TUERJRikKKwkJY2xrX2Rpc2FibGVfdW5wcmVwYXJlKGRwLT5zcGRpZl9jbGspOworCisJcmV0 dXJuIDA7Cit9CisKK2ludCBjZG5fZHBfYXVkaW9fbXV0ZShzdHJ1Y3QgY2RuX2RwX2RldmljZSAq ZHAsIGJvb2wgZW5hYmxlKQoreworCWludCByZXQ7CisKKwlyZXQgPSBjZG5fZHBfcmVnX3dyaXRl X2JpdChkcCwgRFBfVkJfSUQsIDQsIDEsIGVuYWJsZSk7CisJaWYgKHJldCkKKwkJZGV2X2Vycihk cC0+ZGV2LCAiYXVkaW8gbXV0ZSBmYWlsZWQ6ICVkXG4iLCByZXQpOworCisJcmV0dXJuIHJldDsK K30KKworc3RhdGljIHZvaWQgY2RuX2RwX2F1ZGlvX2NvbmZpZ19pMnMoc3RydWN0IGNkbl9kcF9k ZXZpY2UgKmRwLAorCQkJCSAgICBzdHJ1Y3QgYXVkaW9faW5mbyAqYXVkaW8pCit7CisJaW50IHN1 Yl9wY2t0X251bSA9IDEsIGkyc19wb3J0X2VuX3ZhbCA9IDB4ZiwgaTsKKwl1MzIgdmFsOworCisJ aWYgKGF1ZGlvLT5jaGFubmVscyA9PSAyKSB7CisJCWlmIChkcC0+bGluay5udW1fbGFuZXMgPT0g MSkKKwkJCXN1Yl9wY2t0X251bSA9IDI7CisJCWVsc2UKKwkJCXN1Yl9wY2t0X251bSA9IDQ7CisK KwkJaTJzX3BvcnRfZW5fdmFsID0gMTsKKwl9IGVsc2UgaWYgKGF1ZGlvLT5jaGFubmVscyA9PSA0 KSB7CisJCWkyc19wb3J0X2VuX3ZhbCA9IDM7CisJfQorCisJd3JpdGVsKDB4MCwgZHAtPnJlZ3Mg KyBTUERJRl9DVFJMX0FERFIpOworCisJd3JpdGVsKFNZTkNfV1JfVE9fQ0hfWkVSTywgZHAtPnJl Z3MgKyBGSUZPX0NOVEwpOworCisJdmFsID0gTUFYX05VTV9DSChhdWRpby0+Y2hhbm5lbHMpOwor CXZhbCB8PSBOVU1fT0ZfSTJTX1BPUlRTKGF1ZGlvLT5jaGFubmVscyk7CisJdmFsIHw9IEFVRElP X1RZUEVfTFBDTTsKKwl2YWwgfD0gQ0ZHX1NVQl9QQ0tUX05VTShzdWJfcGNrdF9udW0pOworCXdy aXRlbCh2YWwsIGRwLT5yZWdzICsgU01QTDJQS1RfQ05GRyk7CisKKwlpZiAoYXVkaW8tPnNhbXBs ZV93aWR0aCA9PSAxNikKKwkJdmFsID0gMDsKKwllbHNlIGlmIChhdWRpby0+c2FtcGxlX3dpZHRo ID09IDI0KQorCQl2YWwgPSAxIDw8IDk7CisJZWxzZQorCQl2YWwgPSAyIDw8IDk7CisKKwl2YWwg fD0gQVVESU9fQ0hfTlVNKGF1ZGlvLT5jaGFubmVscyk7CisJdmFsIHw9IEkyU19ERUNfUE9SVF9F TihpMnNfcG9ydF9lbl92YWwpOworCXZhbCB8PSBUUkFOU19TTVBMX1dJRFRIXzMyOworCXdyaXRl bCh2YWwsIGRwLT5yZWdzICsgQVVESU9fU1JDX0NORkcpOworCisJZm9yIChpID0gMDsgaSA8IChh dWRpby0+Y2hhbm5lbHMgKyAxKSAvIDI7IGkrKykgeworCQlpZiAoYXVkaW8tPnNhbXBsZV93aWR0 aCA9PSAxNikKKwkJCXZhbCA9ICgweDA4IDw8IDgpIHwgKDB4MDggPDwgMjApOworCQllbHNlIGlm IChhdWRpby0+c2FtcGxlX3dpZHRoID09IDI0KQorCQkJdmFsID0gKDB4MGIgPDwgOCkgfCAoMHgw YiA8PCAyMCk7CisKKwkJdmFsIHw9ICgoMiAqIGkpIDw8IDQpIHwgKCgyICogaSArIDEpIDw8IDE2 KTsKKwkJd3JpdGVsKHZhbCwgZHAtPnJlZ3MgKyBTVFRTX0JJVF9DSChpKSk7CisJfQorCisJc3dp dGNoIChhdWRpby0+c2FtcGxlX3JhdGUpIHsKKwljYXNlIDMyMDAwOgorCQl2YWwgPSBTQU1QTElO R19GUkVRKDMpIHwKKwkJICAgICAgT1JJR0lOQUxfU0FNUF9GUkVRKDB4Yyk7CisJCWJyZWFrOwor CWNhc2UgNDQxMDA6CisJCXZhbCA9IFNBTVBMSU5HX0ZSRVEoMCkgfAorCQkgICAgICBPUklHSU5B TF9TQU1QX0ZSRVEoMHhmKTsKKwkJYnJlYWs7CisJY2FzZSA0ODAwMDoKKwkJdmFsID0gU0FNUExJ TkdfRlJFUSgyKSB8CisJCSAgICAgIE9SSUdJTkFMX1NBTVBfRlJFUSgweGQpOworCQlicmVhazsK KwljYXNlIDg4MjAwOgorCQl2YWwgPSBTQU1QTElOR19GUkVRKDgpIHwKKwkJICAgICAgT1JJR0lO QUxfU0FNUF9GUkVRKDB4Nyk7CisJCWJyZWFrOworCWNhc2UgOTYwMDA6CisJCXZhbCA9IFNBTVBM SU5HX0ZSRVEoMHhhKSB8CisJCSAgICAgIE9SSUdJTkFMX1NBTVBfRlJFUSg1KTsKKwkJYnJlYWs7 CisJY2FzZSAxNzY0MDA6CisJCXZhbCA9IFNBTVBMSU5HX0ZSRVEoMHhjKSB8CisJCSAgICAgIE9S SUdJTkFMX1NBTVBfRlJFUSgzKTsKKwkJYnJlYWs7CisJY2FzZSAxOTIwMDA6CisJCXZhbCA9IFNB TVBMSU5HX0ZSRVEoMHhlKSB8CisJCSAgICAgIE9SSUdJTkFMX1NBTVBfRlJFUSgxKTsKKwkJYnJl YWs7CisJfQorCXZhbCB8PSA0OworCXdyaXRlbCh2YWwsIGRwLT5yZWdzICsgQ09NX0NIX1NUVFNf QklUUyk7CisKKwl3cml0ZWwoU01QTDJQS1RfRU4sIGRwLT5yZWdzICsgU01QTDJQS1RfQ05UTCk7 CisJd3JpdGVsKEkyU19ERUNfU1RBUlQsIGRwLT5yZWdzICsgQVVESU9fU1JDX0NOVEwpOworfQor CitzdGF0aWMgdm9pZCBjZG5fZHBfYXVkaW9fY29uZmlnX3NwZGlmKHN0cnVjdCBjZG5fZHBfZGV2 aWNlICpkcCkKK3sKKwl1MzIgdmFsOworCisJdmFsID0gU1BESUZfQVZHX1NFTCB8IFNQRElGX0pJ VFRFUl9CWVBBU1M7CisJdmFsIHw9IFNQRElGX0ZJRk9fTUlEX1JBTkdFKDB4ZTApOworCXZhbCB8 PSBTUERJRl9KSVRURVJfVEhSU0goMHhlMCk7CisJdmFsIHw9IFNQRElGX0pJVFRFUl9BVkdfV0lO KDcpOworCXdyaXRlbCh2YWwsIGRwLT5yZWdzICsgU1BESUZfQ1RSTF9BRERSKTsKKworCXdyaXRl bChTWU5DX1dSX1RPX0NIX1pFUk8sIGRwLT5yZWdzICsgRklGT19DTlRMKTsKKworCXZhbCA9IE1B WF9OVU1fQ0goMikgfCBBVURJT19UWVBFX0xQQ00gfCBDRkdfU1VCX1BDS1RfTlVNKDQpOworCXdy aXRlbCh2YWwsIGRwLT5yZWdzICsgU01QTDJQS1RfQ05GRyk7CisJd3JpdGVsKFNNUEwyUEtUX0VO LCBkcC0+cmVncyArIFNNUEwyUEtUX0NOVEwpOworCisJdmFsID0gU1BESUZfRU5BQkxFIHwgU1BE SUZfQVZHX1NFTCB8IFNQRElGX0pJVFRFUl9CWVBBU1M7CisJdmFsIHw9IFNQRElGX0ZJRk9fTUlE X1JBTkdFKDB4ZTApOworCXZhbCB8PSBTUERJRl9KSVRURVJfVEhSU0goMHhlMCk7CisJdmFsIHw9 IFNQRElGX0pJVFRFUl9BVkdfV0lOKDcpOworCXdyaXRlbCh2YWwsIGRwLT5yZWdzICsgU1BESUZf Q1RSTF9BRERSKTsKKworCWNsa19wcmVwYXJlX2VuYWJsZShkcC0+c3BkaWZfY2xrKTsKKwljbGtf c2V0X3JhdGUoZHAtPnNwZGlmX2NsaywgQ0ROX0RQX1NQRElGX0NMSyk7Cit9CisKK2ludCBjZG5f ZHBfYXVkaW9fY29uZmlnKHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCwgc3RydWN0IGF1ZGlvX2lu Zm8gKmF1ZGlvKQoreworCWludCByZXQ7CisKKwkvKiByZXNldCB0aGUgc3BkaWYgY2xrIGJlZm9y ZSBjb25maWcgKi8KKwlpZiAoYXVkaW8tPmZvcm1hdCA9PSBBRk1UX1NQRElGKSB7CisJCXJlc2V0 X2NvbnRyb2xfYXNzZXJ0KGRwLT5zcGRpZl9yc3QpOworCQlyZXNldF9jb250cm9sX2RlYXNzZXJ0 KGRwLT5zcGRpZl9yc3QpOworCX0KKworCXJldCA9IGNkbl9kcF9yZWdfd3JpdGUoZHAsIENNX0xB TkVfQ1RSTCwgTEFORV9SRUZfQ1lDKTsKKwlpZiAocmV0KQorCQlnb3RvIGVycl9hdWRpb19jb25m aWc7CisKKwlyZXQgPSBjZG5fZHBfcmVnX3dyaXRlKGRwLCBDTV9DVFJMLCAwKTsKKwlpZiAocmV0 KQorCQlnb3RvIGVycl9hdWRpb19jb25maWc7CisKKwlpZiAoYXVkaW8tPmZvcm1hdCA9PSBBRk1U X0kyUykKKwkJY2RuX2RwX2F1ZGlvX2NvbmZpZ19pMnMoZHAsIGF1ZGlvKTsKKwllbHNlCisJCWNk bl9kcF9hdWRpb19jb25maWdfc3BkaWYoZHApOworCisJcmV0ID0gY2RuX2RwX3JlZ193cml0ZShk cCwgQVVESU9fUEFDS19DT05UUk9MLCBBVURJT19QQUNLX0VOKTsKKworZXJyX2F1ZGlvX2NvbmZp ZzoKKwlpZiAocmV0KQorCQlkZXZfZXJyKGRwLT5kZXYsICJhdWRpbyBjb25maWcgZmFpbGVkOiAl ZFxuIiwgcmV0KTsKKwlyZXR1cm4gcmV0OworfQpkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJt L3JvY2tjaGlwL2Nkbi1kcC1yZWcuaCBiL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9jZG4tZHAt cmVnLmgKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMC4uNmFjMzY3NAotLS0gL2Rl di9udWxsCisrKyBiL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9jZG4tZHAtcmVnLmgKQEAgLTAs MCArMSw0ODIgQEAKKy8qCisgKiBDb3B5cmlnaHQgKEMpIEZ1emhvdSBSb2NrY2hpcCBFbGVjdHJv bmljcyBDby5MdGQKKyAqIEF1dGhvcjogQ2hyaXMgWmhvbmcgPHp5d0Byb2NrLWNoaXBzLmNvbT4K KyAqCisgKiBUaGlzIHNvZnR3YXJlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUg R05VIEdlbmVyYWwgUHVibGljCisgKiBMaWNlbnNlIHZlcnNpb24gMiwgYXMgcHVibGlzaGVkIGJ5 IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGFuZAorICogbWF5IGJlIGNvcGllZCwgZGlz dHJpYnV0ZWQsIGFuZCBtb2RpZmllZCB1bmRlciB0aG9zZSB0ZXJtcy4KKyAqCisgKiBUaGlzIHBy b2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwK KyAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdh cnJhbnR5IG9mCisgKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFS IFBVUlBPU0UuICBTZWUgdGhlCisgKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9y ZSBkZXRhaWxzLgorICovCisKKyNpZm5kZWYgX0NETl9EUF9SRUdfSAorI2RlZmluZSBfQ0ROX0RQ X1JFR19ICisKKyNpbmNsdWRlIDxsaW51eC9iaXRvcHMuaD4KKworI2RlZmluZSBBRERSX0lNRU0J CTB4MTAwMDAKKyNkZWZpbmUgQUREUl9ETUVNCQkweDIwMDAwCisKKy8qIEFQQiBDRkcgYWRkciAq LworI2RlZmluZSBBUEJfQ1RSTAkJCTAKKyNkZWZpbmUgWFRfSU5UX0NUUkwJCQkweDA0CisjZGVm aW5lIE1BSUxCT1hfRlVMTF9BRERSCQkweDA4CisjZGVmaW5lIE1BSUxCT1hfRU1QVFlfQUREUgkJ MHgwYworI2RlZmluZSBNQUlMQk9YMF9XUl9EQVRBCQkweDEwCisjZGVmaW5lIE1BSUxCT1gwX1JE X0RBVEEJCTB4MTQKKyNkZWZpbmUgS0VFUF9BTElWRQkJCTB4MTgKKyNkZWZpbmUgVkVSX0wJCQkJ MHgxYworI2RlZmluZSBWRVJfSAkJCQkweDIwCisjZGVmaW5lIFZFUl9MSUJfTF9BRERSCQkJMHgy NAorI2RlZmluZSBWRVJfTElCX0hfQUREUgkJCTB4MjgKKyNkZWZpbmUgU1dfREVCVUdfTAkJCTB4 MmMKKyNkZWZpbmUgU1dfREVCVUdfSAkJCTB4MzAKKyNkZWZpbmUgTUFJTEJPWF9JTlRfTUFTSwkJ MHgzNAorI2RlZmluZSBNQUlMQk9YX0lOVF9TVEFUVVMJCTB4MzgKKyNkZWZpbmUgU1dfQ0xLX0wJ CQkweDNjCisjZGVmaW5lIFNXX0NMS19ICQkJMHg0MAorI2RlZmluZSBTV19FVkVOVFMwCQkJMHg0 NAorI2RlZmluZSBTV19FVkVOVFMxCQkJMHg0OAorI2RlZmluZSBTV19FVkVOVFMyCQkJMHg0Ywor I2RlZmluZSBTV19FVkVOVFMzCQkJMHg1MAorI2RlZmluZSBYVF9PQ0RfQ1RSTAkJCTB4NjAKKyNk ZWZpbmUgQVBCX0lOVF9NQVNLCQkJMHg2YworI2RlZmluZSBBUEJfU1RBVFVTX01BU0sJCQkweDcw CisKKy8qIGF1ZGlvIGRlY29kZXIgYWRkciAqLworI2RlZmluZSBBVURJT19TUkNfQ05UTAkJCTB4 MzAwMDAKKyNkZWZpbmUgQVVESU9fU1JDX0NORkcJCQkweDMwMDA0CisjZGVmaW5lIENPTV9DSF9T VFRTX0JJVFMJCTB4MzAwMDgKKyNkZWZpbmUgU1RUU19CSVRfQ0goeCkJCQkoMHgzMDAwYyArICgo eCkgPDwgMikpCisjZGVmaW5lIFNQRElGX0NUUkxfQUREUgkJCTB4MzAwNGMKKyNkZWZpbmUgU1BE SUZfQ0gxX0NTXzMxMDBfQUREUgkJMHgzMDA1MAorI2RlZmluZSBTUERJRl9DSDFfQ1NfNjMzMl9B RERSCQkweDMwMDU0CisjZGVmaW5lIFNQRElGX0NIMV9DU185NTY0X0FERFIJCTB4MzAwNTgKKyNk ZWZpbmUgU1BESUZfQ0gxX0NTXzEyNzk2X0FERFIJCTB4MzAwNWMKKyNkZWZpbmUgU1BESUZfQ0gx X0NTXzE1OTEyOF9BRERSCTB4MzAwNjAKKyNkZWZpbmUgU1BESUZfQ0gxX0NTXzE5MTE2MF9BRERS CTB4MzAwNjQKKyNkZWZpbmUgU1BESUZfQ0gyX0NTXzMxMDBfQUREUgkJMHgzMDA2OAorI2RlZmlu ZSBTUERJRl9DSDJfQ1NfNjMzMl9BRERSCQkweDMwMDZjCisjZGVmaW5lIFNQRElGX0NIMl9DU185 NTY0X0FERFIJCTB4MzAwNzAKKyNkZWZpbmUgU1BESUZfQ0gyX0NTXzEyNzk2X0FERFIJCTB4MzAw NzQKKyNkZWZpbmUgU1BESUZfQ0gyX0NTXzE1OTEyOF9BRERSCTB4MzAwNzgKKyNkZWZpbmUgU1BE SUZfQ0gyX0NTXzE5MTE2MF9BRERSCTB4MzAwN2MKKyNkZWZpbmUgU01QTDJQS1RfQ05UTAkJCTB4 MzAwODAKKyNkZWZpbmUgU01QTDJQS1RfQ05GRwkJCTB4MzAwODQKKyNkZWZpbmUgRklGT19DTlRM CQkJMHgzMDA4OAorI2RlZmluZSBGSUZPX1NUVFMJCQkweDMwMDhjCisKKy8qIHNvdXJjZSBwaWYg YWRkciAqLworI2RlZmluZSBTT1VSQ0VfUElGX1dSX0FERFIJCTB4MzA4MDAKKyNkZWZpbmUgU09V UkNFX1BJRl9XUl9SRVEJCTB4MzA4MDQKKyNkZWZpbmUgU09VUkNFX1BJRl9SRF9BRERSCQkweDMw ODA4CisjZGVmaW5lIFNPVVJDRV9QSUZfUkRfUkVRCQkweDMwODBjCisjZGVmaW5lIFNPVVJDRV9Q SUZfREFUQV9XUgkJMHgzMDgxMAorI2RlZmluZSBTT1VSQ0VfUElGX0RBVEFfUkQJCTB4MzA4MTQK KyNkZWZpbmUgU09VUkNFX1BJRl9GSUZPMV9GTFVTSAkJMHgzMDgxOAorI2RlZmluZSBTT1VSQ0Vf UElGX0ZJRk8yX0ZMVVNICQkweDMwODFjCisjZGVmaW5lIFNPVVJDRV9QSUZfU1RBVFVTCQkweDMw ODIwCisjZGVmaW5lIFNPVVJDRV9QSUZfSU5URVJSVVBUX1NPVVJDRQkweDMwODI0CisjZGVmaW5l IFNPVVJDRV9QSUZfSU5URVJSVVBUX01BU0sJMHgzMDgyOAorI2RlZmluZSBTT1VSQ0VfUElGX1BL VF9BTExPQ19SRUcJMHgzMDgyYworI2RlZmluZSBTT1VSQ0VfUElGX1BLVF9BTExPQ19XUl9FTgkw eDMwODMwCisjZGVmaW5lIFNPVVJDRV9QSUZfU1dfUkVTRVQJCTB4MzA4MzQKKworLyogYmVsbG93 IHJlZ2lzdGVycyBuZWVkIGFjY2VzcyBieSBtYWlsYm94ICovCisvKiBzb3VyY2UgY2FyIGFkZHIg Ki8KKyNkZWZpbmUgU09VUkNFX0hEVFhfQ0FSCQkJMHgwOTAwCisjZGVmaW5lIFNPVVJDRV9EUFRY X0NBUgkJCTB4MDkwNAorI2RlZmluZSBTT1VSQ0VfUEhZX0NBUgkJCTB4MDkwOAorI2RlZmluZSBT T1VSQ0VfQ0VDX0NBUgkJCTB4MDkwYworI2RlZmluZSBTT1VSQ0VfQ0JVU19DQVIJCQkweDA5MTAK KyNkZWZpbmUgU09VUkNFX1BLVF9DQVIJCQkweDA5MTgKKyNkZWZpbmUgU09VUkNFX0FJRl9DQVIJ CQkweDA5MWMKKyNkZWZpbmUgU09VUkNFX0NJUEhFUl9DQVIJCTB4MDkyMAorI2RlZmluZSBTT1VS Q0VfQ1JZUFRPX0NBUgkJMHgwOTI0CisKKy8qIGNsb2NrIG1ldGVycyBhZGRyICovCisjZGVmaW5l IENNX0NUUkwJCQkJMHgwYTAwCisjZGVmaW5lIENNX0kyU19DVFJMCQkJMHgwYTA0CisjZGVmaW5l IENNX1NQRElGX0NUUkwJCQkweDBhMDgKKyNkZWZpbmUgQ01fVklEX0NUUkwJCQkweDBhMGMKKyNk ZWZpbmUgQ01fTEFORV9DVFJMCQkJMHgwYTEwCisjZGVmaW5lIEkyU19OTV9TVEFCTEUJCQkweDBh MTQKKyNkZWZpbmUgSTJTX05DVFNfU1RBQkxFCQkJMHgwYTE4CisjZGVmaW5lIFNQRElGX05NX1NU QUJMRQkJCTB4MGExYworI2RlZmluZSBTUERJRl9OQ1RTX1NUQUJMRQkJMHgwYTIwCisjZGVmaW5l IE5NVklEX01FQVNfU1RBQkxFCQkweDBhMjQKKyNkZWZpbmUgSTJTX01FQVMJCQkweDBhNDAKKyNk ZWZpbmUgU1BESUZfTUVBUwkJCTB4MGE4MAorI2RlZmluZSBOTVZJRF9NRUFTCQkJMHgwYWMwCisK Ky8qIHNvdXJjZSB2aWYgYWRkciAqLworI2RlZmluZSBCTkRfSFNZTkMyVlNZTkMJCQkweDBiMDAK KyNkZWZpbmUgSFNZTkMyVlNZTkNfRjFfTDEJCTB4MGIwNAorI2RlZmluZSBIU1lOQzJWU1lOQ19G Ml9MMQkJMHgwYjA4CisjZGVmaW5lIEhTWU5DMlZTWU5DX1NUQVRVUwkJMHgwYjBjCisjZGVmaW5l IEhTWU5DMlZTWU5DX1BPTF9DVFJMCQkweDBiMTAKKworLyogZHB0eCBwaHkgYWRkciAqLworI2Rl ZmluZSBEUF9UWF9QSFlfQ09ORklHX1JFRwkJMHgyMDAwCisjZGVmaW5lIERQX1RYX1BIWV9TVEFU VVNfUkVHCQkweDIwMDQKKyNkZWZpbmUgRFBfVFhfUEhZX1NXX1JFU0VUCQkweDIwMDgKKyNkZWZp bmUgRFBfVFhfUEhZX1NDUkFNQkxFUl9TRUVECTB4MjAwYworI2RlZmluZSBEUF9UWF9QSFlfVFJB SU5JTkdfMDFfMDQJMHgyMDEwCisjZGVmaW5lIERQX1RYX1BIWV9UUkFJTklOR18wNV8wOAkweDIw MTQKKyNkZWZpbmUgRFBfVFhfUEhZX1RSQUlOSU5HXzA5XzEwCTB4MjAxOAorI2RlZmluZSBURVNU X0NPUgkJCTB4MjNmYworCisvKiBkcHR4IGhwZCBhZGRyICovCisjZGVmaW5lIEhQRF9JUlFfREVU X01JTl9USU1FUgkJMHgyMTAwCisjZGVmaW5lIEhQRF9JUlFfREVUX01BWF9USU1FUgkJMHgyMTA0 CisjZGVmaW5lIEhQRF9VTlBMR0VEX0RFVF9NSU5fVElNRVIJMHgyMTA4CisjZGVmaW5lIEhQRF9T VEFCTEVfVElNRVIJCTB4MjEwYworI2RlZmluZSBIUERfRklMVEVSX1RJTUVSCQkweDIxMTAKKyNk ZWZpbmUgSFBEX0VWRU5UX01BU0sJCQkweDIxMWMKKyNkZWZpbmUgSFBEX0VWRU5UX0RFVAkJCTB4 MjEyMAorCisvKiBkcHl4IGZyYW1lciBhZGRyICovCisjZGVmaW5lIERQX0ZSQU1FUl9HTE9CQUxf Q09ORklHCQkweDIyMDAKKyNkZWZpbmUgRFBfU1dfUkVTRVQJCQkweDIyMDQKKyNkZWZpbmUgRFBf RlJBTUVSX1RVCQkJMHgyMjA4CisjZGVmaW5lIERQX0ZSQU1FUl9QWExfUkVQUgkJMHgyMjBjCisj ZGVmaW5lIERQX0ZSQU1FUl9TUAkJCTB4MjIxMAorI2RlZmluZSBBVURJT19QQUNLX0NPTlRST0wJ CTB4MjIxNAorI2RlZmluZSBEUF9WQ19UQUJMRSh4KQkJCSgweDIyMTggKyAoKHgpIDw8IDIpKQor I2RlZmluZSBEUF9WQl9JRAkJCTB4MjI1OAorI2RlZmluZSBEUF9NVFBIX0xWUF9DT05UUk9MCQkw eDIyNWMKKyNkZWZpbmUgRFBfTVRQSF9TWU1CT0xfVkFMVUVTCQkweDIyNjAKKyNkZWZpbmUgRFBf TVRQSF9FQ0ZfQ09OVFJPTAkJMHgyMjY0CisjZGVmaW5lIERQX01UUEhfQUNUX0NPTlRST0wJCTB4 MjI2OAorI2RlZmluZSBEUF9NVFBIX1NUQVRVUwkJCTB4MjI2YworI2RlZmluZSBEUF9JTlRFUlJV UFRfU09VUkNFCQkweDIyNzAKKyNkZWZpbmUgRFBfSU5URVJSVVBUX01BU0sJCTB4MjI3NAorI2Rl ZmluZSBEUF9GUk9OVF9CQUNLX1BPUkNICQkweDIyNzgKKyNkZWZpbmUgRFBfQllURV9DT1VOVAkJ CTB4MjI3YworCisvKiBkcHR4IHN0cmVhbSBhZGRyICovCisjZGVmaW5lIE1TQV9IT1JJWk9OVEFM XzAJCTB4MjI4MAorI2RlZmluZSBNU0FfSE9SSVpPTlRBTF8xCQkweDIyODQKKyNkZWZpbmUgTVNB X1ZFUlRJQ0FMXzAJCQkweDIyODgKKyNkZWZpbmUgTVNBX1ZFUlRJQ0FMXzEJCQkweDIyOGMKKyNk ZWZpbmUgTVNBX01JU0MJCQkweDIyOTAKKyNkZWZpbmUgU1RSRUFNX0NPTkZJRwkJCTB4MjI5NAor I2RlZmluZSBBVURJT19QQUNLX1NUQVRVUwkJMHgyMjk4CisjZGVmaW5lIFZJRl9TVEFUVVMJCQkw eDIyOWMKKyNkZWZpbmUgUENLX1NUVUZGX1NUQVRVU18wCQkweDIyYTAKKyNkZWZpbmUgUENLX1NU VUZGX1NUQVRVU18xCQkweDIyYTQKKyNkZWZpbmUgSU5GT19QQUNLX1NUQVRVUwkJMHgyMmE4Cisj ZGVmaW5lIFJBVEVfR09WRVJOT1JfU1RBVFVTCQkweDIyYWMKKyNkZWZpbmUgRFBfSE9SSVpPTlRB TAkJCTB4MjJiMAorI2RlZmluZSBEUF9WRVJUSUNBTF8wCQkJMHgyMmI0CisjZGVmaW5lIERQX1ZF UlRJQ0FMXzEJCQkweDIyYjgKKyNkZWZpbmUgRFBfQkxPQ0tfU0RQCQkJMHgyMmJjCisKKy8qIGRw dHggZ2xibCBhZGRyICovCisjZGVmaW5lIERQVFhfTEFORV9FTgkJCTB4MjMwMAorI2RlZmluZSBE UFRYX0VOSE5DRAkJCTB4MjMwNAorI2RlZmluZSBEUFRYX0lOVF9NQVNLCQkJMHgyMzA4CisjZGVm aW5lIERQVFhfSU5UX1NUQVRVUwkJCTB4MjMwYworCisvKiBkcCBhdXggYWRkciAqLworI2RlZmlu ZSBEUF9BVVhfSE9TVF9DT05UUk9MCQkweDI4MDAKKyNkZWZpbmUgRFBfQVVYX0lOVEVSUlVQVF9T T1VSQ0UJCTB4MjgwNAorI2RlZmluZSBEUF9BVVhfSU5URVJSVVBUX01BU0sJCTB4MjgwOAorI2Rl ZmluZSBEUF9BVVhfU1dBUF9JTlZFUlNJT05fQ09OVFJPTAkweDI4MGMKKyNkZWZpbmUgRFBfQVVY X1NFTkRfTkFDS19UUkFOU0FDVElPTgkweDI4MTAKKyNkZWZpbmUgRFBfQVVYX0NMRUFSX1JYCQkJ MHgyODE0CisjZGVmaW5lIERQX0FVWF9DTEVBUl9UWAkJCTB4MjgxOAorI2RlZmluZSBEUF9BVVhf VElNRVJfU1RPUAkJMHgyODFjCisjZGVmaW5lIERQX0FVWF9USU1FUl9DTEVBUgkJMHgyODIwCisj ZGVmaW5lIERQX0FVWF9SRVNFVF9TVwkJCTB4MjgyNAorI2RlZmluZSBEUF9BVVhfRElWSURFXzJN CQkweDI4MjgKKyNkZWZpbmUgRFBfQVVYX1RYX1BSRUFDSEFSR0VfTEVOR1RICTB4MjgyYworI2Rl ZmluZSBEUF9BVVhfRlJFUVVFTkNZXzFNX01BWAkJMHgyODMwCisjZGVmaW5lIERQX0FVWF9GUkVR VUVOQ1lfMU1fTUlOCQkweDI4MzQKKyNkZWZpbmUgRFBfQVVYX1JYX1BSRV9NSU4JCTB4MjgzOAor I2RlZmluZSBEUF9BVVhfUlhfUFJFX01BWAkJMHgyODNjCisjZGVmaW5lIERQX0FVWF9USU1FUl9Q UkVTRVQJCTB4Mjg0MAorI2RlZmluZSBEUF9BVVhfTkFDS19GT1JNQVQJCTB4Mjg0NAorI2RlZmlu ZSBEUF9BVVhfVFhfREFUQQkJCTB4Mjg0OAorI2RlZmluZSBEUF9BVVhfUlhfREFUQQkJCTB4Mjg0 YworI2RlZmluZSBEUF9BVVhfVFhfU1RBVFVTCQkweDI4NTAKKyNkZWZpbmUgRFBfQVVYX1JYX1NU QVRVUwkJMHgyODU0CisjZGVmaW5lIERQX0FVWF9SWF9DWUNMRV9DT1VOVEVSCQkweDI4NTgKKyNk ZWZpbmUgRFBfQVVYX01BSU5fU1RBVEVTCQkweDI4NWMKKyNkZWZpbmUgRFBfQVVYX01BSU5fVElN RVIJCTB4Mjg2MAorI2RlZmluZSBEUF9BVVhfQUZFX09VVAkJCTB4Mjg2NAorCisvKiBjcnlwdG8g YWRkciAqLworI2RlZmluZSBDUllQVE9fSERDUF9SRVZJU0lPTgkJMHg1ODAwCisjZGVmaW5lIEhE Q1BfQ1JZUFRPX0NPTkZJRwkJMHg1ODA0CisjZGVmaW5lIENSWVBUT19JTlRFUlJVUFRfU09VUkNF CQkweDU4MDgKKyNkZWZpbmUgQ1JZUFRPX0lOVEVSUlVQVF9NQVNLCQkweDU4MGMKKyNkZWZpbmUg Q1JZUFRPMjJfQ09ORklHCQkJMHg1ODE4CisjZGVmaW5lIENSWVBUTzIyX1NUQVRVUwkJCTB4NTgx YworI2RlZmluZSBTSEFfMjU2X0RBVEFfSU4JCQkweDU4M2MKKyNkZWZpbmUgU0hBXzI1Nl9EQVRB X09VVF8oeCkJCSgweDU4NTAgKyAoKHgpIDw8IDIpKQorI2RlZmluZSBBRVNfMzJfS0VZXyh4KQkJ CSgweDU4NzAgKyAoKHgpIDw8IDIpKQorI2RlZmluZSBBRVNfMzJfREFUQV9JTgkJCTB4NTg4MAor I2RlZmluZSBBRVNfMzJfREFUQV9PVVRfKHgpCQkoMHg1ODg0ICsgKCh4KSA8PCAyKSkKKyNkZWZp bmUgQ1JZUFRPMTRfQ09ORklHCQkJMHg1OGEwCisjZGVmaW5lIENSWVBUTzE0X1NUQVRVUwkJCTB4 NThhNAorI2RlZmluZSBDUllQVE8xNF9QUk5NX09VVAkJMHg1OGE4CisjZGVmaW5lIENSWVBUTzE0 X0tNXzAJCQkweDU4YWMKKyNkZWZpbmUgQ1JZUFRPMTRfS01fMQkJCTB4NThiMAorI2RlZmluZSBD UllQVE8xNF9BTl8wCQkJMHg1OGI0CisjZGVmaW5lIENSWVBUTzE0X0FOXzEJCQkweDU4YjgKKyNk ZWZpbmUgQ1JZUFRPMTRfWU9VUl9LU1ZfMAkJMHg1OGJjCisjZGVmaW5lIENSWVBUTzE0X1lPVVJf S1NWXzEJCTB4NThjMAorI2RlZmluZSBDUllQVE8xNF9NSV8wCQkJMHg1OGM0CisjZGVmaW5lIENS WVBUTzE0X01JXzEJCQkweDU4YzgKKyNkZWZpbmUgQ1JZUFRPMTRfVElfMAkJCTB4NThjYworI2Rl ZmluZSBDUllQVE8xNF9LSV8wCQkJMHg1OGQwCisjZGVmaW5lIENSWVBUTzE0X0tJXzEJCQkweDU4 ZDQKKyNkZWZpbmUgQ1JZUFRPMTRfQkxPQ0tTX05VTQkJMHg1OGQ4CisjZGVmaW5lIENSWVBUTzE0 X0tFWV9NRU1fREFUQV8wCQkweDU4ZGMKKyNkZWZpbmUgQ1JZUFRPMTRfS0VZX01FTV9EQVRBXzEJ CTB4NThlMAorI2RlZmluZSBDUllQVE8xNF9TSEExX01TR19EQVRBCQkweDU4ZTQKKyNkZWZpbmUg Q1JZUFRPMTRfU0hBMV9WX1ZBTFVFXyh4KQkoMHg1OGU4ICsgKCh4KSA8PCAyKSkKKyNkZWZpbmUg VFJOR19DVFJMCQkJMHg1OGZjCisjZGVmaW5lIFRSTkdfREFUQV9SRFkJCQkweDU5MDAKKyNkZWZp bmUgVFJOR19EQVRBCQkJMHg1OTA0CisKKy8qIGNpcGhlciBhZGRyICovCisjZGVmaW5lIEhEQ1Bf UkVWSVNJT04JCQkweDYwMDAwCisjZGVmaW5lIElOVEVSUlVQVF9TT1VSQ0UJCTB4NjAwMDQKKyNk ZWZpbmUgSU5URVJSVVBUX01BU0sJCQkweDYwMDA4CisjZGVmaW5lIEhEQ1BfQ0lQSEVSX0NPTkZJ RwkJMHg2MDAwYworI2RlZmluZSBBRVNfMTI4X0tFWV8wCQkJMHg2MDAxMAorI2RlZmluZSBBRVNf MTI4X0tFWV8xCQkJMHg2MDAxNAorI2RlZmluZSBBRVNfMTI4X0tFWV8yCQkJMHg2MDAxOAorI2Rl ZmluZSBBRVNfMTI4X0tFWV8zCQkJMHg2MDAxYworI2RlZmluZSBBRVNfMTI4X1JBTkRPTV8wCQkw eDYwMDIwCisjZGVmaW5lIEFFU18xMjhfUkFORE9NXzEJCTB4NjAwMjQKKyNkZWZpbmUgQ0lQSEVS MTRfS01fMAkJCTB4NjAwMjgKKyNkZWZpbmUgQ0lQSEVSMTRfS01fMQkJCTB4NjAwMmMKKyNkZWZp bmUgQ0lQSEVSMTRfU1RBVFVTCQkJMHg2MDAzMAorI2RlZmluZSBDSVBIRVIxNF9SSV9QSl9TVEFU VVMJCTB4NjAwMzQKKyNkZWZpbmUgQ0lQSEVSX01PREUJCQkweDYwMDM4CisjZGVmaW5lIENJUEhF UjE0X0FOXzAJCQkweDYwMDNjCisjZGVmaW5lIENJUEhFUjE0X0FOXzEJCQkweDYwMDQwCisjZGVm aW5lIENJUEhFUjIyX0FVVEgJCQkweDYwMDQ0CisjZGVmaW5lIENJUEhFUjE0X1IwX0RQX1NUQVRV UwkJMHg2MDA0OAorI2RlZmluZSBDSVBIRVIxNF9CT09UU1RSQVAJCTB4NjAwNGMKKworI2RlZmlu ZSBEUFRYX0ZSTVJfREFUQV9DTEtfUlNUTl9FTglCSVQoMTEpCisjZGVmaW5lIERQVFhfRlJNUl9E QVRBX0NMS19FTgkJQklUKDEwKQorI2RlZmluZSBEUFRYX1BIWV9EQVRBX1JTVE5fRU4JCUJJVCg5 KQorI2RlZmluZSBEUFRYX1BIWV9EQVRBX0NMS19FTgkJQklUKDgpCisjZGVmaW5lIERQVFhfUEhZ X0NIQVJfUlNUTl9FTgkJQklUKDcpCisjZGVmaW5lIERQVFhfUEhZX0NIQVJfQ0xLX0VOCQlCSVQo NikKKyNkZWZpbmUgU09VUkNFX0FVWF9TWVNfQ0xLX1JTVE5fRU4JQklUKDUpCisjZGVmaW5lIFNP VVJDRV9BVVhfU1lTX0NMS19FTgkJQklUKDQpCisjZGVmaW5lIERQVFhfU1lTX0NMS19SU1ROX0VO CQlCSVQoMykKKyNkZWZpbmUgRFBUWF9TWVNfQ0xLX0VOCQkJQklUKDIpCisjZGVmaW5lIENGR19E UFRYX1ZJRl9DTEtfUlNUTl9FTglCSVQoMSkKKyNkZWZpbmUgQ0ZHX0RQVFhfVklGX0NMS19FTgkJ QklUKDApCisKKyNkZWZpbmUgU09VUkNFX1BIWV9SU1ROX0VOCQlCSVQoMSkKKyNkZWZpbmUgU09V UkNFX1BIWV9DTEtfRU4JCUJJVCgwKQorCisjZGVmaW5lIFNPVVJDRV9QS1RfU1lTX1JTVE5fRU4J CUJJVCgzKQorI2RlZmluZSBTT1VSQ0VfUEtUX1NZU19DTEtfRU4JCUJJVCgyKQorI2RlZmluZSBT T1VSQ0VfUEtUX0RBVEFfUlNUTl9FTgkJQklUKDEpCisjZGVmaW5lIFNPVVJDRV9QS1RfREFUQV9D TEtfRU4JCUJJVCgwKQorCisjZGVmaW5lIFNQRElGX0NEUl9DTEtfUlNUTl9FTgkJQklUKDUpCisj ZGVmaW5lIFNQRElGX0NEUl9DTEtfRU4JCUJJVCg0KQorI2RlZmluZSBTT1VSQ0VfQUlGX1NZU19S U1ROX0VOCQlCSVQoMykKKyNkZWZpbmUgU09VUkNFX0FJRl9TWVNfQ0xLX0VOCQlCSVQoMikKKyNk ZWZpbmUgU09VUkNFX0FJRl9DTEtfUlNUTl9FTgkJQklUKDEpCisjZGVmaW5lIFNPVVJDRV9BSUZf Q0xLX0VOCQlCSVQoMCkKKworI2RlZmluZSBTT1VSQ0VfQ0lQSEVSX1NZU1RFTV9DTEtfUlNUTl9F TglCSVQoMykKKyNkZWZpbmUgU09VUkNFX0NJUEhFUl9TWVNfQ0xLX0VOCQlCSVQoMikKKyNkZWZp bmUgU09VUkNFX0NJUEhFUl9DSEFSX0NMS19SU1ROX0VOCQlCSVQoMSkKKyNkZWZpbmUgU09VUkNF X0NJUEhFUl9DSEFSX0NMS19FTgkJQklUKDApCisKKyNkZWZpbmUgU09VUkNFX0NSWVBUT19TWVNf Q0xLX1JTVE5fRU4JQklUKDEpCisjZGVmaW5lIFNPVVJDRV9DUllQVE9fU1lTX0NMS19FTglCSVQo MCkKKworI2RlZmluZSBBUEJfSVJBTV9QQVRICQkJQklUKDIpCisjZGVmaW5lIEFQQl9EUkFNX1BB VEgJCQlCSVQoMSkKKyNkZWZpbmUgQVBCX1hUX1JFU0VUCQkJQklUKDApCisKKyNkZWZpbmUgTUFJ TEJPWF9JTlRfTUFTS19CSVQJCUJJVCgxKQorI2RlZmluZSBQSUZfSU5UX01BU0tfQklUCQlCSVQo MCkKKyNkZWZpbmUgQUxMX0lOVF9NQVNLCQkJMworCisvKiBtYWlsYm94ICovCisjZGVmaW5lIE1C X09QQ09ERV9JRAkJCTAKKyNkZWZpbmUgTUJfTU9EVUxFX0lECQkJMQorI2RlZmluZSBNQl9TSVpF X01TQl9JRAkJCTIKKyNkZWZpbmUgTUJfU0laRV9MU0JfSUQJCQkzCisjZGVmaW5lIE1CX0RBVEFf SUQJCQk0CisKKyNkZWZpbmUgTUJfTU9EVUxFX0lEX0RQX1RYCQkweDAxCisjZGVmaW5lIE1CX01P RFVMRV9JRF9IRENQX1RYCQkweDA3CisjZGVmaW5lIE1CX01PRFVMRV9JRF9IRENQX1JYCQkweDA4 CisjZGVmaW5lIE1CX01PRFVMRV9JRF9IRENQX0dFTkVSQUwJMHgwOQorI2RlZmluZSBNQl9NT0RV TEVfSURfR0VORVJBTAkJMHgwYQorCisvKiBnZW5lcmFsIG9wY29kZSAqLworI2RlZmluZSBHRU5F UkFMX01BSU5fQ09OVFJPTCAgICAgICAgICAgIDB4MDEKKyNkZWZpbmUgR0VORVJBTF9URVNUX0VD SE8gICAgICAgICAgICAgICAweDAyCisjZGVmaW5lIEdFTkVSQUxfQlVTX1NFVFRJTkdTICAgICAg ICAgICAgMHgwMworI2RlZmluZSBHRU5FUkFMX1RFU1RfQUNDRVNTICAgICAgICAgICAgIDB4MDQK KworI2RlZmluZSBEUFRYX1NFVF9QT1dFUl9NTkcJCQkweDAwCisjZGVmaW5lIERQVFhfU0VUX0hP U1RfQ0FQQUJJTElUSUVTCQkweDAxCisjZGVmaW5lIERQVFhfR0VUX0VESUQJCQkJMHgwMgorI2Rl ZmluZSBEUFRYX1JFQURfRFBDRAkJCQkweDAzCisjZGVmaW5lIERQVFhfV1JJVEVfRFBDRAkJCQkw eDA0CisjZGVmaW5lIERQVFhfRU5BQkxFX0VWRU5UCQkJMHgwNQorI2RlZmluZSBEUFRYX1dSSVRF X1JFR0lTVEVSCQkJMHgwNgorI2RlZmluZSBEUFRYX1JFQURfUkVHSVNURVIJCQkweDA3CisjZGVm aW5lIERQVFhfV1JJVEVfRklFTEQJCQkweDA4CisjZGVmaW5lIERQVFhfVFJBSU5JTkdfQ09OVFJP TAkJCTB4MDkKKyNkZWZpbmUgRFBUWF9SRUFEX0VWRU5UCQkJCTB4MGEKKyNkZWZpbmUgRFBUWF9S RUFEX0xJTktfU1RBVAkJCTB4MGIKKyNkZWZpbmUgRFBUWF9TRVRfVklERU8JCQkJMHgwYworI2Rl ZmluZSBEUFRYX1NFVF9BVURJTwkJCQkweDBkCisjZGVmaW5lIERQVFhfR0VUX0xBU1RfQVVYX1NU QVVTCQkJMHgwZQorI2RlZmluZSBEUFRYX1NFVF9MSU5LX0JSRUFLX1BPSU5UCQkweDBmCisjZGVm aW5lIERQVFhfRk9SQ0VfTEFORVMJCQkweDEwCisjZGVmaW5lIERQVFhfSFBEX1NUQVRFCQkJCTB4 MTEKKworI2RlZmluZSBGV19TVEFOREJZCQkJCTAKKyNkZWZpbmUgRldfQUNUSVZFCQkJCTEKKwor I2RlZmluZSBEUFRYX0VWRU5UX0VOQUJMRV9IUEQJCQlCSVQoMCkKKyNkZWZpbmUgRFBUWF9FVkVO VF9FTkFCTEVfVFJBSU5JTkcJCUJJVCgxKQorCisjZGVmaW5lIExJTktfVFJBSU5JTkdfTk9UX0FD VElWRQkJMAorI2RlZmluZSBMSU5LX1RSQUlOSU5HX1JVTgkJCTEKKyNkZWZpbmUgTElOS19UUkFJ TklOR19SRVNUQVJUCQkJMgorCisjZGVmaW5lIENPTlRST0xfVklERU9fSURMRQkJCTAKKyNkZWZp bmUgQ09OVFJPTF9WSURFT19WQUxJRAkJCTEKKworI2RlZmluZSBWSUZfQllQQVNTX0lOVEVSTEFD RQkJCUJJVCgxMykKKyNkZWZpbmUgSU5URVJMQUNFX0ZNVF9ERVQJCQlCSVQoMTIpCisjZGVmaW5l IElOVEVSTEFDRV9EVENUX1dJTgkJCTB4MjAKKworI2RlZmluZSBEUF9GUkFNRVJfU1BfSU5URVJM QUNFX0VOCQlCSVQoMikKKyNkZWZpbmUgRFBfRlJBTUVSX1NQX0hTUAkJCUJJVCgxKQorI2RlZmlu ZSBEUF9GUkFNRVJfU1BfVlNQCQkJQklUKDApCisKKy8qIGNhcGFiaWxpdHkgKi8KKyNkZWZpbmUg QVVYX0hPU1RfSU5WRVJUCQkJCTMKKyNkZWZpbmUJRkFTVF9MVF9TVVBQT1JUCQkJCTEKKyNkZWZp bmUgRkFTVF9MVF9OT1RfU1VQUE9SVAkJCTAKKyNkZWZpbmUgTEFORV9NQVBQSU5HX05PUk1BTAkJ CTB4MWIKKyNkZWZpbmUgTEFORV9NQVBQSU5HX0ZMSVBQRUQJCQkweGU0CisjZGVmaW5lIEVOSEFO Q0VECQkJCTEKKworI2RlZmluZQlGVUxMX0xUX1NUQVJURUQJCQkJQklUKDApCisjZGVmaW5lIEZB U0VfTFRfU1RBUlRFRAkJCQlCSVQoMSkKKyNkZWZpbmUgQ0xLX1JFQ09WRVJZX0ZJTklTSEVECQkJ QklUKDIpCisjZGVmaW5lIEVRX1BIQVNFX0ZJTklTSEVECQkJQklUKDMpCisjZGVmaW5lIEZBU0Vf TFRfU1RBUlRfRklOSVNIRUQJCQlCSVQoNCkKKyNkZWZpbmUgQ0xLX1JFQ09WRVJZX0ZBSUxFRAkJ CUJJVCg1KQorI2RlZmluZSBFUV9QSEFTRV9GQUlMRUQJCQkJQklUKDYpCisjZGVmaW5lIEZBU0Vf TFRfRkFJTEVECQkJCUJJVCg3KQorCisjZGVmaW5lIERQVFhfSFBEX0VWRU5UCQkJCUJJVCgwKQor I2RlZmluZSBEUFRYX1RSQUlOSU5HX0VWRU5UCQkJQklUKDEpCisjZGVmaW5lIEhEQ1BfVFhfU1RB VFVTX0VWRU5UCQkJQklUKDQpCisjZGVmaW5lIEhEQ1AyX1RYX0lTX0tNX1NUT1JFRF9FVkVOVAkJ QklUKDUpCisjZGVmaW5lIEhEQ1AyX1RYX1NUT1JFX0tNX0VWRU5UCQkJQklUKDYpCisjZGVmaW5l IEhEQ1BfVFhfSVNfUkVDRUlWRVJfSURfVkFMSURfRVZFTlQJQklUKDcpCisKKyNkZWZpbmUgVFVf U0laRQkJCQkJMzAKKyNkZWZpbmUgQ0ROX0RQX01BWF9MSU5LX1JBVEUJCQlEUF9MSU5LX0JXXzVf NAorCisvKiBhdWRpbyAqLworI2RlZmluZSBBVURJT19QQUNLX0VOCQkJCUJJVCg4KQorI2RlZmlu ZSBTQU1QTElOR19GUkVRKHgpCQkJKCgoeCkgJiAweGYpIDw8IDE2KQorI2RlZmluZSBPUklHSU5B TF9TQU1QX0ZSRVEoeCkJCQkoKCh4KSAmIDB4ZikgPDwgMjQpCisjZGVmaW5lIFNZTkNfV1JfVE9f Q0hfWkVSTwkJCUJJVCgxKQorI2RlZmluZSBJMlNfREVDX1NUQVJUCQkJCUJJVCgxKQorI2RlZmlu ZSBBVURJT19TV19SU1QJCQkJQklUKDApCisjZGVmaW5lIFNNUEwyUEtUX0VOCQkJCUJJVCgxKQor I2RlZmluZSBNQVhfTlVNX0NIKHgpCQkJCSgoKHgpICYgMHgxZikgLSAxKQorI2RlZmluZSBOVU1f T0ZfSTJTX1BPUlRTKHgpCQkJKCgoKHgpIC8gMiAtIDEpICYgMHgzKSA8PCA1KQorI2RlZmluZSBB VURJT19UWVBFX0xQQ00JCQkJKDIgPDwgNykKKyNkZWZpbmUgQ0ZHX1NVQl9QQ0tUX05VTSh4KQkJ CSgoKCh4KSAtIDEpICYgMHg3KSA8PCAxMSkKKyNkZWZpbmUgQVVESU9fQ0hfTlVNKHgpCQkJCSgo KCh4KSAtIDEpICYgMHgxZikgPDwgMikKKyNkZWZpbmUgVFJBTlNfU01QTF9XSURUSF8xNgkJCTAK KyNkZWZpbmUgVFJBTlNfU01QTF9XSURUSF8yNAkJCUJJVCgxMSkKKyNkZWZpbmUgVFJBTlNfU01Q TF9XSURUSF8zMgkJCSgyIDw8IDExKQorI2RlZmluZSBJMlNfREVDX1BPUlRfRU4oeCkJCQkoKCh4 KSAmIDB4ZikgPDwgMTcpCisjZGVmaW5lIFNQRElGX0VOQUJMRQkJCQlCSVQoMjEpCisjZGVmaW5l IFNQRElGX0FWR19TRUwJCQkJQklUKDIwKQorI2RlZmluZSBTUERJRl9KSVRURVJfQllQQVNTCQkJ QklUKDE5KQorI2RlZmluZSBTUERJRl9GSUZPX01JRF9SQU5HRSh4KQkJCSgoKHgpICYgMHhmZikg PDwgMTEpCisjZGVmaW5lIFNQRElGX0pJVFRFUl9USFJTSCh4KQkJCSgoKHgpICYgMHhmZikgPDwg MykKKyNkZWZpbmUgU1BESUZfSklUVEVSX0FWR19XSU4oeCkJCQkoKHgpICYgMHg3KQorCisvKiBS ZWZlcm5jZSBjeWNsZXMgd2hlbiB1c2luZyBsYW5lIGNsb2NrIGFzIHJlZmVybmNlICovCisjZGVm aW5lIExBTkVfUkVGX0NZQwkJCQkweDgwMDAKKworZW51bSB2b2x0YWdlX3N3aW5nX2xldmVsIHsK KwlWT0xUQUdFX0xFVkVMXzAsCisJVk9MVEFHRV9MRVZFTF8xLAorCVZPTFRBR0VfTEVWRUxfMiwK KwlWT0xUQUdFX0xFVkVMXzMsCit9OworCitlbnVtIHByZV9lbXBoYXNpc19sZXZlbCB7CisJUFJF X0VNUEhBU0lTX0xFVkVMXzAsCisJUFJFX0VNUEhBU0lTX0xFVkVMXzEsCisJUFJFX0VNUEhBU0lT X0xFVkVMXzIsCisJUFJFX0VNUEhBU0lTX0xFVkVMXzMsCit9OworCitlbnVtIHBhdHRlcm5fc2V0 IHsKKwlQVFMxCQk9IEJJVCgwKSwKKwlQVFMyCQk9IEJJVCgxKSwKKwlQVFMzCQk9IEJJVCgyKSwK KwlQVFM0CQk9IEJJVCgzKSwKKwlEUF9OT05FCQk9IEJJVCg0KQorfTsKKworZW51bSB2aWNfY29s b3JfZGVwdGggeworCUJDU182ID0gMHgxLAorCUJDU184ID0gMHgyLAorCUJDU18xMCA9IDB4NCwK KwlCQ1NfMTIgPSAweDgsCisJQkNTXzE2ID0gMHgxMCwKK307CisKK2VudW0gdmljX2J0X3R5cGUg eworCUJUXzYwMSA9IDB4MCwKKwlCVF83MDkgPSAweDEsCit9OworCit2b2lkIGNkbl9kcF9jbG9j a19yZXNldChzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHApOworCit2b2lkIGNkbl9kcF9zZXRfZndf Y2xrKHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCwgdTMyIGNsayk7CitpbnQgY2RuX2RwX2xvYWRf ZmlybXdhcmUoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLCBjb25zdCB1MzIgKmlfbWVtLAorCQkJ IHUzMiBpX3NpemUsIGNvbnN0IHUzMiAqZF9tZW0sIHUzMiBkX3NpemUpOworaW50IGNkbl9kcF9z ZXRfZmlybXdhcmVfYWN0aXZlKHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCwgYm9vbCBlbmFibGUp OworaW50IGNkbl9kcF9zZXRfaG9zdF9jYXAoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLCB1OCBs YW5lcywgYm9vbCBmbGlwKTsKK2ludCBjZG5fZHBfZXZlbnRfY29uZmlnKHN0cnVjdCBjZG5fZHBf ZGV2aWNlICpkcCk7Cit1MzIgY2RuX2RwX2dldF9ldmVudChzdHJ1Y3QgY2RuX2RwX2RldmljZSAq ZHApOworaW50IGNkbl9kcF9nZXRfaHBkX3N0YXR1cyhzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAp OworaW50IGNkbl9kcF9kcGNkX3dyaXRlKHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCwgdTMyIGFk ZHIsIHU4IHZhbHVlKTsKK2ludCBjZG5fZHBfZHBjZF9yZWFkKHN0cnVjdCBjZG5fZHBfZGV2aWNl ICpkcCwgdTMyIGFkZHIsIHU4ICpkYXRhLCB1MTYgbGVuKTsKK2ludCBjZG5fZHBfZ2V0X2VkaWRf YmxvY2sodm9pZCAqZHAsIHU4ICplZGlkLAorCQkJICB1bnNpZ25lZCBpbnQgYmxvY2ssIHNpemVf dCBsZW5ndGgpOworaW50IGNkbl9kcF90cmFpbmluZ19zdGFydChzdHJ1Y3QgY2RuX2RwX2Rldmlj ZSAqZHApOworaW50IGNkbl9kcF9nZXRfdHJhaW5pbmdfc3RhdHVzKHN0cnVjdCBjZG5fZHBfZGV2 aWNlICpkcCk7CitpbnQgY2RuX2RwX3NldF92aWRlb19zdGF0dXMoc3RydWN0IGNkbl9kcF9kZXZp Y2UgKmRwLCBpbnQgYWN0aXZlKTsKK2ludCBjZG5fZHBfY29uZmlnX3ZpZGVvKHN0cnVjdCBjZG5f ZHBfZGV2aWNlICpkcCk7CitpbnQgY2RuX2RwX2F1ZGlvX3N0b3Aoc3RydWN0IGNkbl9kcF9kZXZp Y2UgKmRwLCBzdHJ1Y3QgYXVkaW9faW5mbyAqYXVkaW8pOworaW50IGNkbl9kcF9hdWRpb19tdXRl KHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCwgYm9vbCBlbmFibGUpOworaW50IGNkbl9kcF9hdWRp b19jb25maWcoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLCBzdHJ1Y3QgYXVkaW9faW5mbyAqYXVk aW8pOworI2VuZGlmIC8qIF9DRE5fRFBfUkVHX0ggKi8KZGlmZiAtLWdpdCBhL2RyaXZlcnMvZ3B1 L2RybS9yb2NrY2hpcC9yb2NrY2hpcF9kcm1fdm9wLmMgYi9kcml2ZXJzL2dwdS9kcm0vcm9ja2No aXAvcm9ja2NoaXBfZHJtX3ZvcC5jCmluZGV4IGVkZDdlYzIuLmQ3MjNkOGUgMTAwNjQ0Ci0tLSBh L2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9yb2NrY2hpcF9kcm1fdm9wLmMKKysrIGIvZHJpdmVy cy9ncHUvZHJtL3JvY2tjaGlwL3JvY2tjaGlwX2RybV92b3AuYwpAQCAtOTY5LDkgKzk2OSwxMSBA QCBzdGF0aWMgdm9pZCB2b3BfY3J0Y19lbmFibGUoc3RydWN0IGRybV9jcnRjICpjcnRjKQogCQl2 b3BfZHNwX2hvbGRfdmFsaWRfaXJxX2Rpc2FibGUodm9wKTsKIAl9CiAKLQlwaW5fcG9sID0gMHg4 OwotCXBpbl9wb2wgfD0gKGFkanVzdGVkX21vZGUtPmZsYWdzICYgRFJNX01PREVfRkxBR19OSFNZ TkMpID8gMCA6IDE7Ci0JcGluX3BvbCB8PSAoYWRqdXN0ZWRfbW9kZS0+ZmxhZ3MgJiBEUk1fTU9E RV9GTEFHX05WU1lOQykgPyAwIDogKDEgPDwgMSk7CisJcGluX3BvbCA9IEJJVChEQ0xLX0lOVkVS VCk7CisJcGluX3BvbCB8PSAoYWRqdXN0ZWRfbW9kZS0+ZmxhZ3MgJiBEUk1fTU9ERV9GTEFHX05I U1lOQykgPworCQkgICAwIDogQklUKEhTWU5DX1BPU0lUSVZFKTsKKwlwaW5fcG9sIHw9IChhZGp1 c3RlZF9tb2RlLT5mbGFncyAmIERSTV9NT0RFX0ZMQUdfTlZTWU5DKSA/CisJCSAgIDAgOiBCSVQo VlNZTkNfUE9TSVRJVkUpOwogCVZPUF9DVFJMX1NFVCh2b3AsIHBpbl9wb2wsIHBpbl9wb2wpOwog CiAJc3dpdGNoIChzLT5vdXRwdXRfdHlwZSkgewpAQCAtOTkxLDYgKzk5MywxMSBAQCBzdGF0aWMg dm9pZCB2b3BfY3J0Y19lbmFibGUoc3RydWN0IGRybV9jcnRjICpjcnRjKQogCQlWT1BfQ1RSTF9T RVQodm9wLCBtaXBpX3Bpbl9wb2wsIHBpbl9wb2wpOwogCQlWT1BfQ1RSTF9TRVQodm9wLCBtaXBp X2VuLCAxKTsKIAkJYnJlYWs7CisJY2FzZSBEUk1fTU9ERV9DT05ORUNUT1JfRGlzcGxheVBvcnQ6 CisJCXBpbl9wb2wgJj0gfkJJVChEQ0xLX0lOVkVSVCk7CisJCVZPUF9DVFJMX1NFVCh2b3AsIGRw X3Bpbl9wb2wsIHBpbl9wb2wpOworCQlWT1BfQ1RSTF9TRVQodm9wLCBkcF9lbiwgMSk7CisJCWJy ZWFrOwogCWRlZmF1bHQ6CiAJCURSTV9FUlJPUigidW5zdXBwb3J0IGNvbm5lY3Rvcl90eXBlWyVk XVxuIiwgcy0+b3V0cHV0X3R5cGUpOwogCX0KZGlmZiAtLWdpdCBhL2RyaXZlcnMvZ3B1L2RybS9y b2NrY2hpcC9yb2NrY2hpcF9kcm1fdm9wLmggYi9kcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvcm9j a2NoaXBfZHJtX3ZvcC5oCmluZGV4IGZmNGY1MmUuLjQ4MjBhOGIgMTAwNjQ0Ci0tLSBhL2RyaXZl cnMvZ3B1L2RybS9yb2NrY2hpcC9yb2NrY2hpcF9kcm1fdm9wLmgKKysrIGIvZHJpdmVycy9ncHUv ZHJtL3JvY2tjaGlwL3JvY2tjaGlwX2RybV92b3AuaApAQCAtNDUsNiArNDUsNyBAQCBzdHJ1Y3Qg dm9wX2N0cmwgewogCXN0cnVjdCB2b3BfcmVnIGVkcF9lbjsKIAlzdHJ1Y3Qgdm9wX3JlZyBoZG1p X2VuOwogCXN0cnVjdCB2b3BfcmVnIG1pcGlfZW47CisJc3RydWN0IHZvcF9yZWcgZHBfZW47CiAJ c3RydWN0IHZvcF9yZWcgb3V0X21vZGU7CiAJc3RydWN0IHZvcF9yZWcgZGl0aGVyX2Rvd247CiAJ c3RydWN0IHZvcF9yZWcgZGl0aGVyX3VwOwpAQCAtNTMsNiArNTQsNyBAQCBzdHJ1Y3Qgdm9wX2N0 cmwgewogCXN0cnVjdCB2b3BfcmVnIGhkbWlfcGluX3BvbDsKIAlzdHJ1Y3Qgdm9wX3JlZyBlZHBf cGluX3BvbDsKIAlzdHJ1Y3Qgdm9wX3JlZyBtaXBpX3Bpbl9wb2w7CisJc3RydWN0IHZvcF9yZWcg ZHBfcGluX3BvbDsKIAogCXN0cnVjdCB2b3BfcmVnIGh0b3RhbF9wdzsKIAlzdHJ1Y3Qgdm9wX3Jl ZyBoYWN0X3N0X2VuZDsKQEAgLTI0Miw2ICsyNDQsMTMgQEAgZW51bSBzY2FsZV9kb3duX21vZGUg ewogCVNDQUxFX0RPV05fQVZHID0gMHgxCiB9OwogCitlbnVtIHZvcF9wb2wgeworCUhTWU5DX1BP U0lUSVZFID0gMCwKKwlWU1lOQ19QT1NJVElWRSA9IDEsCisJREVOX05FR0FUSVZFICAgPSAyLAor CURDTEtfSU5WRVJUICAgID0gMworfTsKKwogI2RlZmluZSBGUkFDXzE2XzE2KG11bHQsIGRpdikg ICAgKCgobXVsdCkgPDwgMTYpIC8gKGRpdikpCiAjZGVmaW5lIFNDTF9GVF9ERUZBVUxUX0ZJWFBP SU5UX1NISUZUCTEyCiAjZGVmaW5lIFNDTF9NQVhfVlNLSVBMSU5FUwkJNApkaWZmIC0tZ2l0IGEv ZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL3JvY2tjaGlwX3ZvcF9yZWcuYyBiL2RyaXZlcnMvZ3B1 L2RybS9yb2NrY2hpcC9yb2NrY2hpcF92b3BfcmVnLmMKaW5kZXggNWIxYWUxZi4uZGNmMTcyZSAx MDA2NDQKLS0tIGEvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL3JvY2tjaGlwX3ZvcF9yZWcuYwor KysgYi9kcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvcm9ja2NoaXBfdm9wX3JlZy5jCkBAIC0yODEs NiArMjgxLDcgQEAgc3RhdGljIGNvbnN0IHN0cnVjdCB2b3BfZGF0YSByazMyODhfdm9wID0gewog c3RhdGljIGNvbnN0IHN0cnVjdCB2b3BfY3RybCByazMzOTlfY3RybF9kYXRhID0gewogCS5zdGFu ZGJ5ID0gVk9QX1JFRyhSSzMzOTlfU1lTX0NUUkwsIDB4MSwgMjIpLAogCS5nYXRlX2VuID0gVk9Q X1JFRyhSSzMzOTlfU1lTX0NUUkwsIDB4MSwgMjMpLAorCS5kcF9lbiA9IFZPUF9SRUcoUkszMzk5 X1NZU19DVFJMLCAweDEsIDExKSwKIAkucmdiX2VuID0gVk9QX1JFRyhSSzMzOTlfU1lTX0NUUkws IDB4MSwgMTIpLAogCS5oZG1pX2VuID0gVk9QX1JFRyhSSzMzOTlfU1lTX0NUUkwsIDB4MSwgMTMp LAogCS5lZHBfZW4gPSBWT1BfUkVHKFJLMzM5OV9TWVNfQ1RSTCwgMHgxLCAxNCksCkBAIC0yOTAs NiArMjkxLDcgQEAgc3RhdGljIGNvbnN0IHN0cnVjdCB2b3BfY3RybCByazMzOTlfY3RybF9kYXRh ID0gewogCS5kYXRhX2JsYW5rID0gVk9QX1JFRyhSSzMzOTlfRFNQX0NUUkwwLCAweDEsIDE5KSwK IAkub3V0X21vZGUgPSBWT1BfUkVHKFJLMzM5OV9EU1BfQ1RSTDAsIDB4ZiwgMCksCiAJLnJnYl9w aW5fcG9sID0gVk9QX1JFRyhSSzMzOTlfRFNQX0NUUkwxLCAweGYsIDE2KSwKKwkuZHBfcGluX3Bv bCA9IFZPUF9SRUcoUkszMzk5X0RTUF9DVFJMMSwgMHhmLCAxNiksCiAJLmhkbWlfcGluX3BvbCA9 IFZPUF9SRUcoUkszMzk5X0RTUF9DVFJMMSwgMHhmLCAyMCksCiAJLmVkcF9waW5fcG9sID0gVk9Q X1JFRyhSSzMzOTlfRFNQX0NUUkwxLCAweGYsIDI0KSwKIAkubWlwaV9waW5fcG9sID0gVk9QX1JF RyhSSzMzOTlfRFNQX0NUUkwxLCAweGYsIDI4KSwKLS0gCjIuNi4zCgpfX19fX19fX19fX19fX19f X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXwpkcmktZGV2ZWwgbWFpbGluZyBsaXN0CmRy aS1kZXZlbEBsaXN0cy5mcmVlZGVza3RvcC5vcmcKaHR0cHM6Ly9saXN0cy5mcmVlZGVza3RvcC5v cmcvbWFpbG1hbi9saXN0aW5mby9kcmktZGV2ZWwK From mboxrd@z Thu Jan 1 00:00:00 1970 From: zyw@rock-chips.com (Chris Zhong) Date: Tue, 2 Aug 2016 20:45:13 +0800 Subject: [v9 PATCH 6/6] drm/rockchip: cdn-dp: add cdn DP support for rk3399 In-Reply-To: <1470141913-1082-1-git-send-email-zyw@rock-chips.com> References: <1470141913-1082-1-git-send-email-zyw@rock-chips.com> Message-ID: <1470141913-1082-7-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 Reviewed-by: Sean Paul Acked-by: Mark Yao --- 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 | 860 +++++++++++++++++++++++++ drivers/gpu/drm/rockchip/cdn-dp-core.h | 103 +++ drivers/gpu/drm/rockchip/cdn-dp-reg.c | 959 ++++++++++++++++++++++++++++ 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, 2436 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 05d0713..abdecd5 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..e1a9670 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -0,0 +1,860 @@ +/* + * 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) + +/* dp grf register offset */ +#define DP_VOP_SEL 0x6224 +#define DP_SEL_VOP_LIT BIT(12) +#define MAX_FW_WAIT_SECS 64 +#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_clk_enable(struct cdn_dp_device *dp) +{ + int ret; + u32 rate; + + ret = clk_prepare_enable(dp->pclk); + if (ret < 0) { + dev_err(dp->dev, "cannot enable dp pclk %d\n", ret); + goto err_pclk; + } + + ret = clk_prepare_enable(dp->core_clk); + if (ret < 0) { + dev_err(dp->dev, "cannot enable core_clk %d\n", ret); + goto err_core_clk; + } + + rate = clk_get_rate(dp->core_clk); + if (rate < 0) { + dev_err(dp->dev, "get clk rate failed: %d\n", rate); + goto err_set_rate; + } + + cdn_dp_set_fw_clk(dp, rate); + + return 0; + +err_set_rate: + clk_disable_unprepare(dp->core_clk); +err_core_clk: + clk_disable_unprepare(dp->pclk); +err_pclk: + return ret; +} + +static enum drm_connector_status +cdn_dp_connector_detect(struct drm_connector *connector, bool force) +{ + struct cdn_dp_device *dp = connector_to_dp(connector); + + return dp->hpd_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; + + edid = drm_do_get_edid(connector, cdn_dp_get_edid_block, dp); + if (edid) { + dev_dbg(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); + } + + 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 = mode->clock * display_info->bpc * 3 / 1000; + u32 actual, rate, sink_max, source_max = 0; + u8 lanes, i; + + /* find the running port */ + for (i = 0; i < dp->ports; i++) { + if (dp->port[i]->phy_status) { + source_max = dp->port[i]->cap_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) { + dev_dbg(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 void cdn_dp_commit(struct drm_encoder *encoder) +{ + struct cdn_dp_device *dp = encoder_to_dp(encoder); + int ret; + + ret = cdn_dp_training_start(dp); + if (ret) + return; + + ret = cdn_dp_get_training_status(dp); + if (ret) + return; + + 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)) + return; + + if (cdn_dp_config_video(dp)) + return; + + if (cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID)) + return; + + dp->dpms_mode = DRM_MODE_DPMS_ON; +} + +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) { + dev_err(dp->dev, "Could not get vop id, %d", ret); + return; + } + + dev_dbg(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 = regmap_write(dp->grf, DP_VOP_SEL, val); + if (ret != 0) + dev_err(dp->dev, "Could not write to GRF: %d\n", ret); + + 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); + + if (dp->dpms_mode != DRM_MODE_DPMS_ON) + cdn_dp_commit(encoder); +} + +static void cdn_dp_encoder_disable(struct drm_encoder *encoder) +{ + struct cdn_dp_device *dp = encoder_to_dp(encoder); + + dp->dpms_mode = DRM_MODE_DPMS_OFF; +} + +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_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)) { + dev_err(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) { + dev_err(dp->dev, "active ucpu failed: %d\n", ret); + return ret; + } + + dp->fw_loaded = 1; + + return cdn_dp_event_config(dp); +} + +static int cdn_dp_init(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; + int ret; + + dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); + if (IS_ERR(dp->grf)) { + dev_err(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)) { + dev_err(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)) { + dev_err(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)) { + dev_err(dev, "cannot get pclk\n"); + return PTR_ERR(dp->pclk); + } + + dp->spdif_clk = devm_clk_get(dev, "spdif"); + if (IS_ERR(dp->spdif_clk)) { + dev_err(dev, "cannot get spdif_clk\n"); + return PTR_ERR(dp->spdif_clk); + } + + dp->spdif_rst = devm_reset_control_get(dev, "spdif"); + if (IS_ERR(dp->spdif_rst)) { + dev_err(dev, "no spdif reset control found\n"); + return PTR_ERR(dp->spdif_rst); + } + + dp->dpms_mode = DRM_MODE_DPMS_OFF; + + ret = cdn_dp_clk_enable(dp); + if (ret < 0) + return ret; + + cdn_dp_clock_reset(dp); + + 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: + dev_err(dev, "%s: Invalid format %d\n", __func__, 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); + struct drm_mode_config *config = &dp->encoder.dev->mode_config; + struct drm_connector *connector; + int ret = -ENODEV; + + mutex_lock(&config->mutex); + list_for_each_entry(connector, &config->connector_list, head) { + if (&dp->encoder == connector->encoder) { + memcpy(buf, connector->eld, + min(sizeof(connector->eld), len)); + ret = 0; + } + } + mutex_unlock(&config->mutex); + + return ret; +} + +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_get_cap_lanes(struct cdn_dp_device *dp, + struct extcon_dev *edev) +{ + bool dfp, dptx; + u8 lanes; + + dfp = extcon_get_state(edev, EXTCON_USB_HOST); + dptx = extcon_get_state(edev, EXTCON_DISP_DP); + + if (dfp && dptx) + lanes = 2; + else if (dptx) + lanes = 4; + else + lanes = 0; + + return lanes; +} + +static int cdn_dp_pd_event(struct notifier_block *nb, + unsigned long event, void *priv) +{ + struct cdn_dp_port *port; + + port = container_of(nb, struct cdn_dp_port, event_nb); + + schedule_delayed_work(&port->event_wq, 0); + + return 0; +} + +static void cdn_dp_pd_event_wq(struct work_struct *work) +{ + struct cdn_dp_port *port = container_of(work, struct cdn_dp_port, + event_wq.work); + union extcon_property_value property; + struct cdn_dp_device *dp = port->dp; + u8 new_cap_lanes, i; + int ret; + + new_cap_lanes = cdn_dp_get_cap_lanes(dp, port->extcon); + + if (new_cap_lanes == port->cap_lanes) { + dev_dbg(dp->dev, "lanes count does not change: %d\n", + new_cap_lanes); + return; + } + + if (!new_cap_lanes) { + ret = phy_power_off(port->phy); + if (ret) { + dev_err(dp->dev, "phy power off failed: %d", ret); + return; + } + port->phy_status = false; + port->cap_lanes = new_cap_lanes; + for (i = 0; i < dp->ports; i++) { + if (dp->port[i]->phy_status) + return; + } + + dp->hpd_status = connector_status_disconnected; + drm_helper_hpd_irq_event(dp->drm_dev); + cdn_dp_set_firmware_active(dp, false); + return; + } + + /* if other phy is running, do not touch the hpd_status, and return */ + for (i = 0; i < dp->ports; i++) { + if (dp->port[i]->phy_status) { + dev_warn(dp->dev, "busy, phy[%d] is running", + dp->port[i]->id); + return; + } + } + + if (!dp->fw_loaded) { + ret = request_firmware(&dp->fw, CDN_DP_FIRMWARE, dp->dev); + if (ret == -ENOENT && dp->fw_wait <= MAX_FW_WAIT_SECS) { + unsigned long time = msecs_to_jiffies(dp->fw_wait * HZ); + + /* + * If can not find the file, retry to load the firmware + * in several seconds, if still failed after 1 minute, + * give up. + */ + schedule_delayed_work(&port->event_wq, time); + dp->fw_wait *= 2; + return; + } else if (ret) { + dev_err(dp->dev, "failed to request firmware: %d\n", + ret); + return; + } + } + + if (dp->fw_loaded) + cdn_dp_set_firmware_active(dp, true); + + ret = phy_power_on(port->phy); + if (ret) { + if (!dp->fw_loaded) + release_firmware(dp->fw); + dev_err(dp->dev, "phy power on failed: %d\n", ret); + return; + } + + port->phy_status = true; + + if (!dp->fw_loaded) { + ret = cdn_dp_firmware_init(dp); + release_firmware(dp->fw); + if (ret) { + dev_err(dp->dev, "firmware init failed: %d", ret); + goto err_firmware; + } + } + + ret = cdn_dp_get_hpd_status(dp); + if (ret <= 0) { + if (!ret) + dev_err(dp->dev, "hpd does not exist\n"); + goto err_firmware; + } + + ret = extcon_get_property(port->extcon, EXTCON_DISP_DP, + EXTCON_PROP_USB_TYPEC_POLARITY, &property); + if (ret) { + dev_err(dp->dev, "get property failed\n"); + goto err_firmware; + } + + ret = cdn_dp_set_host_cap(dp, new_cap_lanes, property.intval); + if (ret) { + dev_err(dp->dev, "set host capabilities failed: %d\n", ret); + goto err_firmware; + } + + /* + * Native read with retry for link status and receiver capability reads + * for cases where the sink may still not be ready. + * + * Sinks are *supposed* to come up within 1ms from an off state, but + * some DOCKs need about 5 seconds to power up, so read the dpcd every + * 100ms, if can not get a good dpcd in 10 seconds, give up. + */ + for (i = 1; i < 100; i++) { + ret = cdn_dp_dpcd_read(dp, 0x000, dp->dpcd, + DP_RECEIVER_CAP_SIZE); + if (!ret) { + dev_dbg(dp->dev, "get dpcd success!\n"); + port->cap_lanes = new_cap_lanes; + dp->hpd_status = connector_status_connected; + drm_helper_hpd_irq_event(dp->drm_dev); + return; + } else if (!extcon_get_state(port->extcon, EXTCON_DISP_DP)) { + break; + } + msleep(100); + } + + dev_err(dp->dev, "get dpcd failed!\n"); + +err_firmware: + ret = phy_power_off(port->phy); + if (ret) + dev_err(dp->dev, "phy power off failed: %d", ret); + else + port->phy_status = false; + + if (dp->fw_loaded) + cdn_dp_set_firmware_active(dp, false); +} + +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; + + ret = cdn_dp_init(dp); + if (ret < 0) + return ret; + + dp->drm_dev = drm_dev; + dp->hpd_status = connector_status_disconnected; + dp->fw_wait = 1; + + 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; + INIT_DELAYED_WORK(&port->event_wq, cdn_dp_pd_event_wq); + ret = extcon_register_notifier(port->extcon, EXTCON_DISP_DP, + &port->event_nb); + if (ret) { + dev_err(dev, "register EXTCON_DISP_DP notifier err\n"); + return ret; + } + + if (extcon_get_state(port->extcon, EXTCON_DISP_DP)) + schedule_delayed_work(&port->event_wq, 0); + } + + 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; + struct cdn_dp_port *port; + int i; + + platform_device_unregister(dp->audio_pdev); + cdn_dp_encoder_disable(encoder); + encoder->funcs->destroy(encoder); + connector->funcs->destroy(connector); + + for (i = 0; i < dp->ports; i++) { + port = dp->port[i]; + extcon_unregister_notifier(port->extcon, EXTCON_DISP_DP, + &port->event_nb); + } +} + +static const struct component_ops cdn_dp_component_ops = { + .bind = cdn_dp_bind, + .unbind = cdn_dp_unbind, +}; + +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) { + dev_err(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 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), + }, +}; + +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..78424f9 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -0,0 +1,103 @@ +/* + * 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 delayed_work event_wq; + struct extcon_dev *extcon; + struct phy *phy; + u8 cap_lanes; + bool phy_status; + 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; + + const struct firmware *fw; /* cdn dp firmware */ + unsigned int fw_version; /* cdn fw version */ + u32 fw_wait; + bool fw_loaded; + bool fw_actived; + void __iomem *regs; + struct regmap *grf; + struct clk *core_clk; + struct clk *pclk; + struct clk *spdif_clk; + struct reset_control *spdif_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]; + enum drm_connector_status hpd_status; + int dpms_mode; + bool sink_has_audio; +}; +#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..2ea702d --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -0,0 +1,959 @@ +/* + * 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; + + if (!dp->fw_actived && !force) + return -EPERM; + + 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; + + if (!dp->fw_actived && !force) + return -EPERM; + + 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 read. + */ + 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) + dev_err(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) { + dev_err(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; + } + + dp->fw_actived = (msg[4] == FW_ACTIVE); + ret = 0; + +err_set_firmware_active: + if (ret < 0) + dev_err(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) + dev_err(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) + dev_err(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: + dev_err(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]; + int ret; + + 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) + goto err_get_edid; + + ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, + DPTX_GET_EDID, + sizeof(reg) + length); + if (ret) + goto err_get_edid; + + ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg)); + if (ret) + goto err_get_edid; + + ret = cdn_dp_mailbox_read_receive(dp, edid, length); + if (ret) + goto err_get_edid; + + if (reg[0] != length || reg[1] != block / 2) + ret = -EINVAL; + +err_get_edid: + if (ret) + dev_err(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: + dev_err(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) + dev_err(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) + dev_err(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) + dev_err(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) { + dev_err(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) + dev_err(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 + cdn_dp_audio_config_spdif(dp); + + ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN); + +err_audio_config: + if (ret) + dev_err(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 edd7ec2..d723d8e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -969,9 +969,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) { @@ -991,6 +993,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_ERROR("unsupport 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 ff4f52e..4820a8b 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; @@ -242,6 +244,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 5b1ae1f..dcf172e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -281,6 +281,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), @@ -290,6 +291,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), -- 2.6.3