From mboxrd@z Thu Jan 1 00:00:00 1970 From: Russell King Date: Fri, 12 Aug 2016 14:15:10 +0000 Subject: [PATCH RFC 4/5] drm/bridge: add dw-hdmi cec driver using Hans Verkil's CEC code Message-Id: List-Id: References: <20160812141421.GB1041@n2100.armlinux.org.uk> In-Reply-To: <20160812141421.GB1041@n2100.armlinux.org.uk> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: David Airlie , Jean-Christophe Plagniol-Villard , Tomi Valkeinen , Hans Verkuil Cc: linux-fbdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org, dri-devel@lists.freedesktop.org Add a CEC driver for the dw-hdmi hardware using Hans Verkil's CEC implementation. Signed-off-by: Russell King --- drivers/gpu/drm/bridge/Kconfig | 7 + drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/dw-hdmi-cec.c | 344 ++++++++++++++++++++++++++++++ drivers/gpu/drm/bridge/dw-hdmi.c | 64 +++++- include/linux/platform_data/dw_hdmi-cec.h | 16 ++ 5 files changed, 421 insertions(+), 11 deletions(-) create mode 100644 drivers/gpu/drm/bridge/dw-hdmi-cec.c create mode 100644 include/linux/platform_data/dw_hdmi-cec.h diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 6d97d9f2b164..3ad19d16f4ca 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -33,6 +33,13 @@ config DRM_DW_HDMI_AHB_AUDIO Designware HDMI block. This is used in conjunction with the i.MX6 HDMI driver. +config DRM_DW_HDMI_CEC + tristate "Synopsis Designware CEC interface" + depends on DRM_DW_HDMI && MEDIA_CEC + help + Support the CE interface which is part of the Synopsis + Designware HDMI block. + config DRM_NXP_PTN3460 tristate "NXP PTN3460 DP/LVDS bridge" depends on OF diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 96b13b30e6ab..4869441d35f4 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -3,6 +3,7 @@ ccflags-y := -Iinclude/drm obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o +obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/ diff --git a/drivers/gpu/drm/bridge/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/dw-hdmi-cec.c new file mode 100644 index 000000000000..9d6b8daa584d --- /dev/null +++ b/drivers/gpu/drm/bridge/dw-hdmi-cec.c @@ -0,0 +1,344 @@ +/* http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/ + * tree/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c?h=imx_3.0.35_4.1.0 */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#define DEV_NAME "mxc_hdmi_cec" + +enum { + HDMI_IH_CEC_STAT0 = 0x0106, + HDMI_IH_MUTE_CEC_STAT0 = 0x0186, + + HDMI_CEC_CTRL = 0x7d00, + CEC_CTRL_START = BIT(0), + CEC_CTRL_NORMAL = 1 << 1, + + HDMI_CEC_STAT = 0x7d01, + CEC_STAT_DONE = BIT(0), + CEC_STAT_EOM = BIT(1), + CEC_STAT_NACK = BIT(2), + CEC_STAT_ARBLOST = BIT(3), + CEC_STAT_ERROR_INIT = BIT(4), + CEC_STAT_ERROR_FOLL = BIT(5), + CEC_STAT_WAKEUP = BIT(6), + + HDMI_CEC_MASK = 0x7d02, + HDMI_CEC_POLARITY = 0x7d03, + HDMI_CEC_INT = 0x7d04, + HDMI_CEC_ADDR_L = 0x7d05, + HDMI_CEC_ADDR_H = 0x7d06, + HDMI_CEC_TX_CNT = 0x7d07, + HDMI_CEC_RX_CNT = 0x7d08, + HDMI_CEC_TX_DATA0 = 0x7d10, + HDMI_CEC_RX_DATA0 = 0x7d20, + HDMI_CEC_LOCK = 0x7d30, + HDMI_CEC_WKUPCTRL = 0x7d31, +}; + +struct dw_hdmi_cec { + void __iomem *base; + u32 addresses; + struct cec_adapter *adap; + struct cec_msg rx_msg; + unsigned int tx_status; + bool tx_done; + bool rx_done; + const struct dw_hdmi_cec_ops *ops; + void *ops_data; + int retries; + int irq; + struct notifier_block nb; +}; + +static int dw_hdmi_cec_log_addr(struct cec_adapter *adap, u8 logical_addr) +{ + struct dw_hdmi_cec *cec = adap->priv; + u32 addresses; + + if (logical_addr = CEC_LOG_ADDR_INVALID) + addresses = cec->addresses = BIT(15); + else + addresses = cec->addresses |= BIT(logical_addr); + + writeb_relaxed(addresses & 255, cec->base + HDMI_CEC_ADDR_L); + writeb_relaxed(addresses >> 8, cec->base + HDMI_CEC_ADDR_H); + + return 0; +} + +static int dw_hdmi_cec_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg) +{ + struct dw_hdmi_cec *cec = adap->priv; + unsigned i; + + cec->retries = attempts; + + for (i = 0; i < msg->len; i++) + writeb_relaxed(msg->msg[i], cec->base + HDMI_CEC_TX_DATA0 + i); + + writeb_relaxed(msg->len, cec->base + HDMI_CEC_TX_CNT); + writeb_relaxed(CEC_CTRL_NORMAL | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL); + + return 0; +} + +static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) +{ + struct cec_adapter *adap = data; + struct dw_hdmi_cec *cec = adap->priv; + unsigned stat = readb_relaxed(cec->base + HDMI_IH_CEC_STAT0); + irqreturn_t ret = IRQ_HANDLED; + + if (stat = 0) + return IRQ_NONE; + + writeb_relaxed(stat, cec->base + HDMI_IH_CEC_STAT0); + + if (stat & CEC_STAT_ERROR_INIT) { + if (cec->retries) { + unsigned v = readb_relaxed(cec->base + HDMI_CEC_CTRL); + writeb_relaxed(v | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL); + cec->retries -= 1; + } else { + cec->tx_status = CEC_TX_STATUS_MAX_RETRIES; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; + } + } else if (stat & CEC_STAT_DONE) { + cec->tx_status = CEC_TX_STATUS_OK; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; + } else if (stat & CEC_STAT_NACK) { + cec->tx_status = CEC_TX_STATUS_NACK; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; + } + + if (stat & CEC_STAT_EOM) { + unsigned len, i; + void *base = cec->base; + + len = readb_relaxed(base + HDMI_CEC_RX_CNT); + if (len > sizeof(cec->rx_msg.msg)) + len = sizeof(cec->rx_msg.msg); + + for (i = 0; i < len; i++) + cec->rx_msg.msg[i] + readb_relaxed(base + HDMI_CEC_RX_DATA0 + i); + + writeb_relaxed(0, base + HDMI_CEC_LOCK); + + cec->rx_msg.len = len; + smp_wmb(); + cec->rx_done = true; + + ret = IRQ_WAKE_THREAD; + } + + return ret; +} + +static irqreturn_t dw_hdmi_cec_thread(int irq, void *data) +{ + struct cec_adapter *adap = data; + struct dw_hdmi_cec *cec = adap->priv; + + if (cec->tx_done) { + cec->tx_done = false; + cec_transmit_done(adap, cec->tx_status, 0, 0, 0, 0); + } + if (cec->rx_done) { + cec->rx_done = false; + smp_rmb(); + cec_received_msg(adap, &cec->rx_msg); + } + return IRQ_HANDLED; +} + +static int dw_hdmi_cec_enable(struct cec_adapter *adap, bool enable) +{ + struct dw_hdmi_cec *cec = adap->priv; + + if (!enable) { + writeb_relaxed(~0, cec->base + HDMI_CEC_MASK); + writeb_relaxed(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0); + writeb_relaxed(0, cec->base + HDMI_CEC_POLARITY); + + cec->ops->disable(cec->ops_data); + } else { + unsigned irqs; + + writeb_relaxed(0, cec->base + HDMI_CEC_CTRL); + writeb_relaxed(~0, cec->base + HDMI_IH_CEC_STAT0); + writeb_relaxed(0, cec->base + HDMI_CEC_LOCK); + + dw_hdmi_cec_log_addr(cec->adap, CEC_LOG_ADDR_INVALID); + + cec->ops->enable(cec->ops_data); + + irqs = CEC_STAT_ERROR_INIT | CEC_STAT_NACK | CEC_STAT_EOM | + CEC_STAT_DONE; + writeb_relaxed(irqs, cec->base + HDMI_CEC_POLARITY); + writeb_relaxed(~irqs, cec->base + HDMI_CEC_MASK); + writeb_relaxed(~irqs, cec->base + HDMI_IH_MUTE_CEC_STAT0); + } + return 0; +} + +static const struct cec_adap_ops dw_hdmi_cec_ops = { + .adap_enable = dw_hdmi_cec_enable, + .adap_log_addr = dw_hdmi_cec_log_addr, + .adap_transmit = dw_hdmi_cec_transmit, +}; + +static unsigned int parse_hdmi_addr(const struct edid *edid) +{ + if (!edid || edid->extensions = 0) + return (u16)~0; + + return cec_get_edid_phys_addr((u8 *)edid, + EDID_LENGTH * (edid->extensions + 1), NULL); +} + +static int dw_hdmi_cec_notify(struct notifier_block *nb, unsigned long event, + void *data) +{ + struct dw_hdmi_cec *cec = container_of(nb, struct dw_hdmi_cec, nb); + union hdmi_event *event_block = data; + unsigned int phys; + + dev_info(event_block->base.source, "event %lu\n", event); + + if (event_block->base.source != cec->adap->devnode.parent) + return NOTIFY_OK; + + switch (event) { + case HDMI_CONNECTED: + break; + + case HDMI_DISCONNECTED: + cec_s_phys_addr(cec->adap, CEC_PHYS_ADDR_INVALID, false); + break; + + case HDMI_NEW_EDID: + phys = parse_hdmi_addr(event_block->edid.edid); + cec_s_phys_addr(cec->adap, phys, false); + break; + } + + return NOTIFY_OK; +} + +static void dw_hdmi_cec_del(void *data) +{ + struct dw_hdmi_cec *cec = data; + + cec_delete_adapter(cec->adap); +} + +static int dw_hdmi_cec_probe(struct platform_device *pdev) +{ + struct dw_hdmi_cec_data *data = dev_get_platdata(&pdev->dev); + struct dw_hdmi_cec *cec; + int ret; + + if (!data) + return -ENXIO; + + /* + * Our device is just a convenience - we want to link to the real + * hardware device here, so that userspace can see the association + * between the HDMI hardware and its associated CEC chardev. + */ + cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL); + if (!cec) + return -ENOMEM; + + cec->base = data->base; + cec->irq = data->irq; + cec->ops = data->ops; + cec->ops_data = data->ops_data; + cec->nb.notifier_call = dw_hdmi_cec_notify; + + platform_set_drvdata(pdev, cec); + + writeb_relaxed(0, cec->base + HDMI_CEC_TX_CNT); + writeb_relaxed(~0, cec->base + HDMI_CEC_MASK); + writeb_relaxed(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0); + writeb_relaxed(0, cec->base + HDMI_CEC_POLARITY); + + cec->adap = cec_allocate_adapter(&dw_hdmi_cec_ops, cec, "dw_hdmi", + CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | + CEC_CAP_RC, CEC_MAX_LOG_ADDRS, + pdev->dev.parent); + if (IS_ERR(cec->adap)) + return PTR_ERR(cec->adap); + + /* override the module pointer */ + cec->adap->owner = THIS_MODULE; + + ret = devm_add_action(&pdev->dev, dw_hdmi_cec_del, cec); + if (ret) { + cec_delete_adapter(cec->adap); + return ret; + } + + ret = devm_request_threaded_irq(&pdev->dev, cec->irq, + dw_hdmi_cec_hardirq, + dw_hdmi_cec_thread, IRQF_SHARED, + DEV_NAME, cec->adap); + if (ret < 0) + return ret; + + ret = cec_register_adapter(cec->adap); + if (ret < 0) + return ret; + + /* + * CEC documentation says we must not call cec_delete_adapter + * after a successful call to cec_register_adapter(). + */ + devm_remove_action(&pdev->dev, dw_hdmi_cec_del, cec); + + hdmi_register_notifier(&cec->nb); + + return 0; +} + +static int dw_hdmi_cec_remove(struct platform_device *pdev) +{ + struct dw_hdmi_cec *cec = platform_get_drvdata(pdev); + + hdmi_unregister_notifier(&cec->nb); + cec_unregister_adapter(cec->adap); + + return 0; +} + +static struct platform_driver dw_hdmi_cec_driver = { + .probe = dw_hdmi_cec_probe, + .remove = dw_hdmi_cec_remove, + .driver = { + .name = "dw-hdmi-cec", + .owner = THIS_MODULE, + }, +}; +module_platform_driver(dw_hdmi_cec_driver); + +MODULE_AUTHOR("Russell King "); +MODULE_DESCRIPTION("Synopsis Designware HDMI CEC driver for i.MX"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS(PLATFORM_MODULE_PREFIX "dw-hdmi-cec"); diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index cb6e03efbebf..1ad58e37c0b3 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -108,6 +109,7 @@ struct dw_hdmi { struct drm_bridge *bridge; struct platform_device *audio; + struct platform_device *cec; enum dw_hdmi_devtype dev_type; struct device *dev; struct clk *isfr_clk; @@ -119,6 +121,7 @@ struct dw_hdmi { int vic; u8 edid[HDMI_EDID_LEN]; + u8 mc_clkdis; bool cable_plugin; bool phy_enabled; @@ -1108,8 +1111,6 @@ static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi) /* HDMI Initialization Step B.4 */ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi) { - u8 clkdis; - /* control period minimum duration */ hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR); hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR); @@ -1121,23 +1122,28 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi) hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM); /* Enable pixel clock and tmds data path */ - clkdis = 0x7F; - clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE; - hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); + hdmi->mc_clkdis |= HDMI_MC_CLKDIS_HDCPCLK_DISABLE | + HDMI_MC_CLKDIS_CSCCLK_DISABLE | + HDMI_MC_CLKDIS_AUDCLK_DISABLE | + HDMI_MC_CLKDIS_PREPCLK_DISABLE | + HDMI_MC_CLKDIS_TMDSCLK_DISABLE; + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE; + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); - clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE; - hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE; + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); /* Enable csc path */ if (is_color_space_conversion(hdmi)) { - clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE; - hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE; + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); } } static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi) { - hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS); + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE; + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); } /* Workaround to clear the overflow condition */ @@ -1297,7 +1303,6 @@ static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi) hdmi_writeb(hdmi, 0xff, HDMI_AUD_HBR_MASK); hdmi_writeb(hdmi, 0xff, HDMI_GP_MASK); hdmi_writeb(hdmi, 0xff, HDMI_A_APIINTMSK); - hdmi_writeb(hdmi, 0xff, HDMI_CEC_MASK); hdmi_writeb(hdmi, 0xff, HDMI_I2CM_INT); hdmi_writeb(hdmi, 0xff, HDMI_I2CM_CTLINT); @@ -1666,6 +1671,27 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi) return 0; } +static void dw_hdmi_cec_enable(void *data) +{ + struct dw_hdmi *hdmi = data; + + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CECCLK_DISABLE; + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); +} + +static void dw_hdmi_cec_disable(void *data) +{ + struct dw_hdmi *hdmi = data; + + hdmi->mc_clkdis |= HDMI_MC_CLKDIS_CECCLK_DISABLE; + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); +} + +static const struct dw_hdmi_cec_ops dw_hdmi_cec_ops = { + .enable = dw_hdmi_cec_enable, + .disable = dw_hdmi_cec_disable, +}; + int dw_hdmi_bind(struct device *dev, struct device *master, void *data, struct drm_encoder *encoder, struct resource *iores, int irq, @@ -1676,6 +1702,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master, struct platform_device_info pdevinfo; struct device_node *ddc_node; struct dw_hdmi_audio_data audio; + struct dw_hdmi_cec_data cec; struct dw_hdmi *hdmi; int ret; u32 val = 1; @@ -1694,6 +1721,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master, hdmi->disabled = true; hdmi->rxsense = true; hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE); + hdmi->mc_clkdis = 0x7f; mutex_init(&hdmi->mutex); mutex_init(&hdmi->audio_mutex); @@ -1820,6 +1848,18 @@ int dw_hdmi_bind(struct device *dev, struct device *master, hdmi->audio = platform_device_register_full(&pdevinfo); } + cec.base = hdmi->regs; + cec.irq = irq; + cec.ops = &dw_hdmi_cec_ops; + cec.ops_data = hdmi; + + pdevinfo.name = "dw-hdmi-cec"; + pdevinfo.data = &cec; + pdevinfo.size_data = sizeof(cec); + pdevinfo.dma_mask = 0; + + hdmi->cec = platform_device_register_full(&pdevinfo); + dev_set_drvdata(dev, hdmi); return 0; @@ -1839,6 +1879,8 @@ void dw_hdmi_unbind(struct device *dev, struct device *master, void *data) if (hdmi->audio && !IS_ERR(hdmi->audio)) platform_device_unregister(hdmi->audio); + if (!IS_ERR(hdmi->cec)) + platform_device_unregister(hdmi->cec); /* Disable all interrupts */ hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0); diff --git a/include/linux/platform_data/dw_hdmi-cec.h b/include/linux/platform_data/dw_hdmi-cec.h new file mode 100644 index 000000000000..5ff40cc237a8 --- /dev/null +++ b/include/linux/platform_data/dw_hdmi-cec.h @@ -0,0 +1,16 @@ +#ifndef DW_HDMI_CEC_H +#define DW_HDMI_CEC_H + +struct dw_hdmi_cec_ops { + void (*enable)(void *); + void (*disable)(void *); +}; + +struct dw_hdmi_cec_data { + void __iomem *base; + int irq; + const struct dw_hdmi_cec_ops *ops; + void *ops_data; +}; + +#endif -- 2.1.0 From mboxrd@z Thu Jan 1 00:00:00 1970 From: rmk+kernel@arm.linux.org.uk (Russell King) Date: Fri, 12 Aug 2016 15:15:10 +0100 Subject: [PATCH RFC 4/5] drm/bridge: add dw-hdmi cec driver using Hans Verkil's CEC code In-Reply-To: <20160812141421.GB1041@n2100.armlinux.org.uk> References: <20160812141421.GB1041@n2100.armlinux.org.uk> Message-ID: To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Add a CEC driver for the dw-hdmi hardware using Hans Verkil's CEC implementation. Signed-off-by: Russell King --- drivers/gpu/drm/bridge/Kconfig | 7 + drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/dw-hdmi-cec.c | 344 ++++++++++++++++++++++++++++++ drivers/gpu/drm/bridge/dw-hdmi.c | 64 +++++- include/linux/platform_data/dw_hdmi-cec.h | 16 ++ 5 files changed, 421 insertions(+), 11 deletions(-) create mode 100644 drivers/gpu/drm/bridge/dw-hdmi-cec.c create mode 100644 include/linux/platform_data/dw_hdmi-cec.h diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 6d97d9f2b164..3ad19d16f4ca 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -33,6 +33,13 @@ config DRM_DW_HDMI_AHB_AUDIO Designware HDMI block. This is used in conjunction with the i.MX6 HDMI driver. +config DRM_DW_HDMI_CEC + tristate "Synopsis Designware CEC interface" + depends on DRM_DW_HDMI && MEDIA_CEC + help + Support the CE interface which is part of the Synopsis + Designware HDMI block. + config DRM_NXP_PTN3460 tristate "NXP PTN3460 DP/LVDS bridge" depends on OF diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 96b13b30e6ab..4869441d35f4 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -3,6 +3,7 @@ ccflags-y := -Iinclude/drm obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o +obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/ diff --git a/drivers/gpu/drm/bridge/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/dw-hdmi-cec.c new file mode 100644 index 000000000000..9d6b8daa584d --- /dev/null +++ b/drivers/gpu/drm/bridge/dw-hdmi-cec.c @@ -0,0 +1,344 @@ +/* http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/ + * tree/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c?h=imx_3.0.35_4.1.0 */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#define DEV_NAME "mxc_hdmi_cec" + +enum { + HDMI_IH_CEC_STAT0 = 0x0106, + HDMI_IH_MUTE_CEC_STAT0 = 0x0186, + + HDMI_CEC_CTRL = 0x7d00, + CEC_CTRL_START = BIT(0), + CEC_CTRL_NORMAL = 1 << 1, + + HDMI_CEC_STAT = 0x7d01, + CEC_STAT_DONE = BIT(0), + CEC_STAT_EOM = BIT(1), + CEC_STAT_NACK = BIT(2), + CEC_STAT_ARBLOST = BIT(3), + CEC_STAT_ERROR_INIT = BIT(4), + CEC_STAT_ERROR_FOLL = BIT(5), + CEC_STAT_WAKEUP = BIT(6), + + HDMI_CEC_MASK = 0x7d02, + HDMI_CEC_POLARITY = 0x7d03, + HDMI_CEC_INT = 0x7d04, + HDMI_CEC_ADDR_L = 0x7d05, + HDMI_CEC_ADDR_H = 0x7d06, + HDMI_CEC_TX_CNT = 0x7d07, + HDMI_CEC_RX_CNT = 0x7d08, + HDMI_CEC_TX_DATA0 = 0x7d10, + HDMI_CEC_RX_DATA0 = 0x7d20, + HDMI_CEC_LOCK = 0x7d30, + HDMI_CEC_WKUPCTRL = 0x7d31, +}; + +struct dw_hdmi_cec { + void __iomem *base; + u32 addresses; + struct cec_adapter *adap; + struct cec_msg rx_msg; + unsigned int tx_status; + bool tx_done; + bool rx_done; + const struct dw_hdmi_cec_ops *ops; + void *ops_data; + int retries; + int irq; + struct notifier_block nb; +}; + +static int dw_hdmi_cec_log_addr(struct cec_adapter *adap, u8 logical_addr) +{ + struct dw_hdmi_cec *cec = adap->priv; + u32 addresses; + + if (logical_addr == CEC_LOG_ADDR_INVALID) + addresses = cec->addresses = BIT(15); + else + addresses = cec->addresses |= BIT(logical_addr); + + writeb_relaxed(addresses & 255, cec->base + HDMI_CEC_ADDR_L); + writeb_relaxed(addresses >> 8, cec->base + HDMI_CEC_ADDR_H); + + return 0; +} + +static int dw_hdmi_cec_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg) +{ + struct dw_hdmi_cec *cec = adap->priv; + unsigned i; + + cec->retries = attempts; + + for (i = 0; i < msg->len; i++) + writeb_relaxed(msg->msg[i], cec->base + HDMI_CEC_TX_DATA0 + i); + + writeb_relaxed(msg->len, cec->base + HDMI_CEC_TX_CNT); + writeb_relaxed(CEC_CTRL_NORMAL | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL); + + return 0; +} + +static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) +{ + struct cec_adapter *adap = data; + struct dw_hdmi_cec *cec = adap->priv; + unsigned stat = readb_relaxed(cec->base + HDMI_IH_CEC_STAT0); + irqreturn_t ret = IRQ_HANDLED; + + if (stat == 0) + return IRQ_NONE; + + writeb_relaxed(stat, cec->base + HDMI_IH_CEC_STAT0); + + if (stat & CEC_STAT_ERROR_INIT) { + if (cec->retries) { + unsigned v = readb_relaxed(cec->base + HDMI_CEC_CTRL); + writeb_relaxed(v | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL); + cec->retries -= 1; + } else { + cec->tx_status = CEC_TX_STATUS_MAX_RETRIES; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; + } + } else if (stat & CEC_STAT_DONE) { + cec->tx_status = CEC_TX_STATUS_OK; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; + } else if (stat & CEC_STAT_NACK) { + cec->tx_status = CEC_TX_STATUS_NACK; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; + } + + if (stat & CEC_STAT_EOM) { + unsigned len, i; + void *base = cec->base; + + len = readb_relaxed(base + HDMI_CEC_RX_CNT); + if (len > sizeof(cec->rx_msg.msg)) + len = sizeof(cec->rx_msg.msg); + + for (i = 0; i < len; i++) + cec->rx_msg.msg[i] = + readb_relaxed(base + HDMI_CEC_RX_DATA0 + i); + + writeb_relaxed(0, base + HDMI_CEC_LOCK); + + cec->rx_msg.len = len; + smp_wmb(); + cec->rx_done = true; + + ret = IRQ_WAKE_THREAD; + } + + return ret; +} + +static irqreturn_t dw_hdmi_cec_thread(int irq, void *data) +{ + struct cec_adapter *adap = data; + struct dw_hdmi_cec *cec = adap->priv; + + if (cec->tx_done) { + cec->tx_done = false; + cec_transmit_done(adap, cec->tx_status, 0, 0, 0, 0); + } + if (cec->rx_done) { + cec->rx_done = false; + smp_rmb(); + cec_received_msg(adap, &cec->rx_msg); + } + return IRQ_HANDLED; +} + +static int dw_hdmi_cec_enable(struct cec_adapter *adap, bool enable) +{ + struct dw_hdmi_cec *cec = adap->priv; + + if (!enable) { + writeb_relaxed(~0, cec->base + HDMI_CEC_MASK); + writeb_relaxed(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0); + writeb_relaxed(0, cec->base + HDMI_CEC_POLARITY); + + cec->ops->disable(cec->ops_data); + } else { + unsigned irqs; + + writeb_relaxed(0, cec->base + HDMI_CEC_CTRL); + writeb_relaxed(~0, cec->base + HDMI_IH_CEC_STAT0); + writeb_relaxed(0, cec->base + HDMI_CEC_LOCK); + + dw_hdmi_cec_log_addr(cec->adap, CEC_LOG_ADDR_INVALID); + + cec->ops->enable(cec->ops_data); + + irqs = CEC_STAT_ERROR_INIT | CEC_STAT_NACK | CEC_STAT_EOM | + CEC_STAT_DONE; + writeb_relaxed(irqs, cec->base + HDMI_CEC_POLARITY); + writeb_relaxed(~irqs, cec->base + HDMI_CEC_MASK); + writeb_relaxed(~irqs, cec->base + HDMI_IH_MUTE_CEC_STAT0); + } + return 0; +} + +static const struct cec_adap_ops dw_hdmi_cec_ops = { + .adap_enable = dw_hdmi_cec_enable, + .adap_log_addr = dw_hdmi_cec_log_addr, + .adap_transmit = dw_hdmi_cec_transmit, +}; + +static unsigned int parse_hdmi_addr(const struct edid *edid) +{ + if (!edid || edid->extensions == 0) + return (u16)~0; + + return cec_get_edid_phys_addr((u8 *)edid, + EDID_LENGTH * (edid->extensions + 1), NULL); +} + +static int dw_hdmi_cec_notify(struct notifier_block *nb, unsigned long event, + void *data) +{ + struct dw_hdmi_cec *cec = container_of(nb, struct dw_hdmi_cec, nb); + union hdmi_event *event_block = data; + unsigned int phys; + + dev_info(event_block->base.source, "event %lu\n", event); + + if (event_block->base.source != cec->adap->devnode.parent) + return NOTIFY_OK; + + switch (event) { + case HDMI_CONNECTED: + break; + + case HDMI_DISCONNECTED: + cec_s_phys_addr(cec->adap, CEC_PHYS_ADDR_INVALID, false); + break; + + case HDMI_NEW_EDID: + phys = parse_hdmi_addr(event_block->edid.edid); + cec_s_phys_addr(cec->adap, phys, false); + break; + } + + return NOTIFY_OK; +} + +static void dw_hdmi_cec_del(void *data) +{ + struct dw_hdmi_cec *cec = data; + + cec_delete_adapter(cec->adap); +} + +static int dw_hdmi_cec_probe(struct platform_device *pdev) +{ + struct dw_hdmi_cec_data *data = dev_get_platdata(&pdev->dev); + struct dw_hdmi_cec *cec; + int ret; + + if (!data) + return -ENXIO; + + /* + * Our device is just a convenience - we want to link to the real + * hardware device here, so that userspace can see the association + * between the HDMI hardware and its associated CEC chardev. + */ + cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL); + if (!cec) + return -ENOMEM; + + cec->base = data->base; + cec->irq = data->irq; + cec->ops = data->ops; + cec->ops_data = data->ops_data; + cec->nb.notifier_call = dw_hdmi_cec_notify; + + platform_set_drvdata(pdev, cec); + + writeb_relaxed(0, cec->base + HDMI_CEC_TX_CNT); + writeb_relaxed(~0, cec->base + HDMI_CEC_MASK); + writeb_relaxed(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0); + writeb_relaxed(0, cec->base + HDMI_CEC_POLARITY); + + cec->adap = cec_allocate_adapter(&dw_hdmi_cec_ops, cec, "dw_hdmi", + CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | + CEC_CAP_RC, CEC_MAX_LOG_ADDRS, + pdev->dev.parent); + if (IS_ERR(cec->adap)) + return PTR_ERR(cec->adap); + + /* override the module pointer */ + cec->adap->owner = THIS_MODULE; + + ret = devm_add_action(&pdev->dev, dw_hdmi_cec_del, cec); + if (ret) { + cec_delete_adapter(cec->adap); + return ret; + } + + ret = devm_request_threaded_irq(&pdev->dev, cec->irq, + dw_hdmi_cec_hardirq, + dw_hdmi_cec_thread, IRQF_SHARED, + DEV_NAME, cec->adap); + if (ret < 0) + return ret; + + ret = cec_register_adapter(cec->adap); + if (ret < 0) + return ret; + + /* + * CEC documentation says we must not call cec_delete_adapter + * after a successful call to cec_register_adapter(). + */ + devm_remove_action(&pdev->dev, dw_hdmi_cec_del, cec); + + hdmi_register_notifier(&cec->nb); + + return 0; +} + +static int dw_hdmi_cec_remove(struct platform_device *pdev) +{ + struct dw_hdmi_cec *cec = platform_get_drvdata(pdev); + + hdmi_unregister_notifier(&cec->nb); + cec_unregister_adapter(cec->adap); + + return 0; +} + +static struct platform_driver dw_hdmi_cec_driver = { + .probe = dw_hdmi_cec_probe, + .remove = dw_hdmi_cec_remove, + .driver = { + .name = "dw-hdmi-cec", + .owner = THIS_MODULE, + }, +}; +module_platform_driver(dw_hdmi_cec_driver); + +MODULE_AUTHOR("Russell King "); +MODULE_DESCRIPTION("Synopsis Designware HDMI CEC driver for i.MX"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS(PLATFORM_MODULE_PREFIX "dw-hdmi-cec"); diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index cb6e03efbebf..1ad58e37c0b3 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -108,6 +109,7 @@ struct dw_hdmi { struct drm_bridge *bridge; struct platform_device *audio; + struct platform_device *cec; enum dw_hdmi_devtype dev_type; struct device *dev; struct clk *isfr_clk; @@ -119,6 +121,7 @@ struct dw_hdmi { int vic; u8 edid[HDMI_EDID_LEN]; + u8 mc_clkdis; bool cable_plugin; bool phy_enabled; @@ -1108,8 +1111,6 @@ static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi) /* HDMI Initialization Step B.4 */ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi) { - u8 clkdis; - /* control period minimum duration */ hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR); hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR); @@ -1121,23 +1122,28 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi) hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM); /* Enable pixel clock and tmds data path */ - clkdis = 0x7F; - clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE; - hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); + hdmi->mc_clkdis |= HDMI_MC_CLKDIS_HDCPCLK_DISABLE | + HDMI_MC_CLKDIS_CSCCLK_DISABLE | + HDMI_MC_CLKDIS_AUDCLK_DISABLE | + HDMI_MC_CLKDIS_PREPCLK_DISABLE | + HDMI_MC_CLKDIS_TMDSCLK_DISABLE; + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE; + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); - clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE; - hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE; + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); /* Enable csc path */ if (is_color_space_conversion(hdmi)) { - clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE; - hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE; + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); } } static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi) { - hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS); + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE; + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); } /* Workaround to clear the overflow condition */ @@ -1297,7 +1303,6 @@ static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi) hdmi_writeb(hdmi, 0xff, HDMI_AUD_HBR_MASK); hdmi_writeb(hdmi, 0xff, HDMI_GP_MASK); hdmi_writeb(hdmi, 0xff, HDMI_A_APIINTMSK); - hdmi_writeb(hdmi, 0xff, HDMI_CEC_MASK); hdmi_writeb(hdmi, 0xff, HDMI_I2CM_INT); hdmi_writeb(hdmi, 0xff, HDMI_I2CM_CTLINT); @@ -1666,6 +1671,27 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi) return 0; } +static void dw_hdmi_cec_enable(void *data) +{ + struct dw_hdmi *hdmi = data; + + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CECCLK_DISABLE; + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); +} + +static void dw_hdmi_cec_disable(void *data) +{ + struct dw_hdmi *hdmi = data; + + hdmi->mc_clkdis |= HDMI_MC_CLKDIS_CECCLK_DISABLE; + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); +} + +static const struct dw_hdmi_cec_ops dw_hdmi_cec_ops = { + .enable = dw_hdmi_cec_enable, + .disable = dw_hdmi_cec_disable, +}; + int dw_hdmi_bind(struct device *dev, struct device *master, void *data, struct drm_encoder *encoder, struct resource *iores, int irq, @@ -1676,6 +1702,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master, struct platform_device_info pdevinfo; struct device_node *ddc_node; struct dw_hdmi_audio_data audio; + struct dw_hdmi_cec_data cec; struct dw_hdmi *hdmi; int ret; u32 val = 1; @@ -1694,6 +1721,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master, hdmi->disabled = true; hdmi->rxsense = true; hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE); + hdmi->mc_clkdis = 0x7f; mutex_init(&hdmi->mutex); mutex_init(&hdmi->audio_mutex); @@ -1820,6 +1848,18 @@ int dw_hdmi_bind(struct device *dev, struct device *master, hdmi->audio = platform_device_register_full(&pdevinfo); } + cec.base = hdmi->regs; + cec.irq = irq; + cec.ops = &dw_hdmi_cec_ops; + cec.ops_data = hdmi; + + pdevinfo.name = "dw-hdmi-cec"; + pdevinfo.data = &cec; + pdevinfo.size_data = sizeof(cec); + pdevinfo.dma_mask = 0; + + hdmi->cec = platform_device_register_full(&pdevinfo); + dev_set_drvdata(dev, hdmi); return 0; @@ -1839,6 +1879,8 @@ void dw_hdmi_unbind(struct device *dev, struct device *master, void *data) if (hdmi->audio && !IS_ERR(hdmi->audio)) platform_device_unregister(hdmi->audio); + if (!IS_ERR(hdmi->cec)) + platform_device_unregister(hdmi->cec); /* Disable all interrupts */ hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0); diff --git a/include/linux/platform_data/dw_hdmi-cec.h b/include/linux/platform_data/dw_hdmi-cec.h new file mode 100644 index 000000000000..5ff40cc237a8 --- /dev/null +++ b/include/linux/platform_data/dw_hdmi-cec.h @@ -0,0 +1,16 @@ +#ifndef DW_HDMI_CEC_H +#define DW_HDMI_CEC_H + +struct dw_hdmi_cec_ops { + void (*enable)(void *); + void (*disable)(void *); +}; + +struct dw_hdmi_cec_data { + void __iomem *base; + int irq; + const struct dw_hdmi_cec_ops *ops; + void *ops_data; +}; + +#endif -- 2.1.0 From mboxrd@z Thu Jan 1 00:00:00 1970 From: Russell King Subject: [PATCH RFC 4/5] drm/bridge: add dw-hdmi cec driver using Hans Verkil's CEC code Date: Fri, 12 Aug 2016 15:15:10 +0100 Message-ID: References: <20160812141421.GB1041@n2100.armlinux.org.uk> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: Received: from pandora.armlinux.org.uk (pandora.armlinux.org.uk [IPv6:2001:4d48:ad52:3201:214:fdff:fe10:1be6]) by gabe.freedesktop.org (Postfix) with ESMTPS id E03A66EBBC for ; Fri, 12 Aug 2016 14:15:31 +0000 (UTC) In-Reply-To: <20160812141421.GB1041@n2100.armlinux.org.uk> Content-Disposition: inline List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: David Airlie , Jean-Christophe Plagniol-Villard , Tomi Valkeinen , Hans Verkuil Cc: linux-fbdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org, dri-devel@lists.freedesktop.org List-Id: dri-devel@lists.freedesktop.org QWRkIGEgQ0VDIGRyaXZlciBmb3IgdGhlIGR3LWhkbWkgaGFyZHdhcmUgdXNpbmcgSGFucyBWZXJr aWwncyBDRUMKaW1wbGVtZW50YXRpb24uCgpTaWduZWQtb2ZmLWJ5OiBSdXNzZWxsIEtpbmcgPHJt aytrZXJuZWxAYXJtbGludXgub3JnLnVrPgotLS0KIGRyaXZlcnMvZ3B1L2RybS9icmlkZ2UvS2Nv bmZpZyAgICAgICAgICAgIHwgICA3ICsKIGRyaXZlcnMvZ3B1L2RybS9icmlkZ2UvTWFrZWZpbGUg ICAgICAgICAgIHwgICAxICsKIGRyaXZlcnMvZ3B1L2RybS9icmlkZ2UvZHctaGRtaS1jZWMuYyAg ICAgIHwgMzQ0ICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKwogZHJpdmVycy9ncHUvZHJt L2JyaWRnZS9kdy1oZG1pLmMgICAgICAgICAgfCAgNjQgKysrKystCiBpbmNsdWRlL2xpbnV4L3Bs YXRmb3JtX2RhdGEvZHdfaGRtaS1jZWMuaCB8ICAxNiArKwogNSBmaWxlcyBjaGFuZ2VkLCA0MjEg aW5zZXJ0aW9ucygrKSwgMTEgZGVsZXRpb25zKC0pCiBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVy cy9ncHUvZHJtL2JyaWRnZS9kdy1oZG1pLWNlYy5jCiBjcmVhdGUgbW9kZSAxMDA2NDQgaW5jbHVk ZS9saW51eC9wbGF0Zm9ybV9kYXRhL2R3X2hkbWktY2VjLmgKCmRpZmYgLS1naXQgYS9kcml2ZXJz L2dwdS9kcm0vYnJpZGdlL0tjb25maWcgYi9kcml2ZXJzL2dwdS9kcm0vYnJpZGdlL0tjb25maWcK aW5kZXggNmQ5N2Q5ZjJiMTY0Li4zYWQxOWQxNmY0Y2EgMTAwNjQ0Ci0tLSBhL2RyaXZlcnMvZ3B1 L2RybS9icmlkZ2UvS2NvbmZpZworKysgYi9kcml2ZXJzL2dwdS9kcm0vYnJpZGdlL0tjb25maWcK QEAgLTMzLDYgKzMzLDEzIEBAIGNvbmZpZyBEUk1fRFdfSERNSV9BSEJfQVVESU8KIAkgIERlc2ln bndhcmUgSERNSSBibG9jay4gIFRoaXMgaXMgdXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoCiAJICB0 aGUgaS5NWDYgSERNSSBkcml2ZXIuCiAKK2NvbmZpZyBEUk1fRFdfSERNSV9DRUMKKwl0cmlzdGF0 ZSAiU3lub3BzaXMgRGVzaWdud2FyZSBDRUMgaW50ZXJmYWNlIgorCWRlcGVuZHMgb24gRFJNX0RX X0hETUkgJiYgTUVESUFfQ0VDCisJaGVscAorCSAgU3VwcG9ydCB0aGUgQ0UgaW50ZXJmYWNlIHdo aWNoIGlzIHBhcnQgb2YgdGhlIFN5bm9wc2lzCisJICBEZXNpZ253YXJlIEhETUkgYmxvY2suCisK IGNvbmZpZyBEUk1fTlhQX1BUTjM0NjAKIAl0cmlzdGF0ZSAiTlhQIFBUTjM0NjAgRFAvTFZEUyBi cmlkZ2UiCiAJZGVwZW5kcyBvbiBPRgpkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJtL2JyaWRn ZS9NYWtlZmlsZSBiL2RyaXZlcnMvZ3B1L2RybS9icmlkZ2UvTWFrZWZpbGUKaW5kZXggOTZiMTNi MzBlNmFiLi40ODY5NDQxZDM1ZjQgMTAwNjQ0Ci0tLSBhL2RyaXZlcnMvZ3B1L2RybS9icmlkZ2Uv TWFrZWZpbGUKKysrIGIvZHJpdmVycy9ncHUvZHJtL2JyaWRnZS9NYWtlZmlsZQpAQCAtMyw2ICsz LDcgQEAgY2NmbGFncy15IDo9IC1JaW5jbHVkZS9kcm0KIG9iai0kKENPTkZJR19EUk1fQU5BTE9H SVhfQU5YNzhYWCkgKz0gYW5hbG9naXgtYW54Nzh4eC5vCiBvYmotJChDT05GSUdfRFJNX0RXX0hE TUkpICs9IGR3LWhkbWkubwogb2JqLSQoQ09ORklHX0RSTV9EV19IRE1JX0FIQl9BVURJTykgKz0g ZHctaGRtaS1haGItYXVkaW8ubworb2JqLSQoQ09ORklHX0RSTV9EV19IRE1JX0NFQykgKz0gZHct aGRtaS1jZWMubwogb2JqLSQoQ09ORklHX0RSTV9OWFBfUFROMzQ2MCkgKz0gbnhwLXB0bjM0NjAu bwogb2JqLSQoQ09ORklHX0RSTV9QQVJBREVfUFM4NjIyKSArPSBwYXJhZGUtcHM4NjIyLm8KIG9i ai0kKENPTkZJR19EUk1fQU5BTE9HSVhfRFApICs9IGFuYWxvZ2l4LwpkaWZmIC0tZ2l0IGEvZHJp dmVycy9ncHUvZHJtL2JyaWRnZS9kdy1oZG1pLWNlYy5jIGIvZHJpdmVycy9ncHUvZHJtL2JyaWRn ZS9kdy1oZG1pLWNlYy5jCm5ldyBmaWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAwMDAwMC4u OWQ2YjhkYWE1ODRkCi0tLSAvZGV2L251bGwKKysrIGIvZHJpdmVycy9ncHUvZHJtL2JyaWRnZS9k dy1oZG1pLWNlYy5jCkBAIC0wLDAgKzEsMzQ0IEBACisvKiBodHRwOi8vZ2l0LmZyZWVzY2FsZS5j b20vZ2l0L2NnaXQuY2dpL2lteC9saW51eC0yLjYtaW14LmdpdC8KKyAqIHRyZWUvZHJpdmVycy9t eGMvaGRtaS1jZWMvbXhjX2hkbWktY2VjLmM/aD1pbXhfMy4wLjM1XzQuMS4wICovCisjaW5jbHVk ZSA8bGludXgvaGRtaS1ub3RpZmllci5oPgorI2luY2x1ZGUgPGxpbnV4L2ludGVycnVwdC5oPgor I2luY2x1ZGUgPGxpbnV4L2lvLmg+CisjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+CisjaW5jbHVk ZSA8bGludXgvbm90aWZpZXIuaD4KKyNpbmNsdWRlIDxsaW51eC9wbGF0Zm9ybV9kYXRhL2R3X2hk bWktY2VjLmg+CisjaW5jbHVkZSA8bGludXgvcGxhdGZvcm1fZGV2aWNlLmg+CisjaW5jbHVkZSA8 bGludXgvc2NoZWQuaD4KKyNpbmNsdWRlIDxsaW51eC9zbGFiLmg+CisKKyNpbmNsdWRlIDxkcm0v ZHJtX2VkaWQuaD4KKworI2luY2x1ZGUgPG1lZGlhL2NlYy5oPgorI2luY2x1ZGUgPG1lZGlhL2Nl Yy1lZGlkLmg+CisKKyNkZWZpbmUgREVWX05BTUUgIm14Y19oZG1pX2NlYyIKKworZW51bSB7CisJ SERNSV9JSF9DRUNfU1RBVDAJPSAweDAxMDYsCisJSERNSV9JSF9NVVRFX0NFQ19TVEFUMAk9IDB4 MDE4NiwKKworCUhETUlfQ0VDX0NUUkwJCT0gMHg3ZDAwLAorCUNFQ19DVFJMX1NUQVJUCQk9IEJJ VCgwKSwKKwlDRUNfQ1RSTF9OT1JNQUwJCT0gMSA8PCAxLAorCisJSERNSV9DRUNfU1RBVAkJPSAw eDdkMDEsCisJQ0VDX1NUQVRfRE9ORQkJPSBCSVQoMCksCisJQ0VDX1NUQVRfRU9NCQk9IEJJVCgx KSwKKwlDRUNfU1RBVF9OQUNLCQk9IEJJVCgyKSwKKwlDRUNfU1RBVF9BUkJMT1NUCT0gQklUKDMp LAorCUNFQ19TVEFUX0VSUk9SX0lOSVQJPSBCSVQoNCksCisJQ0VDX1NUQVRfRVJST1JfRk9MTAk9 IEJJVCg1KSwKKwlDRUNfU1RBVF9XQUtFVVAJCT0gQklUKDYpLAorCisJSERNSV9DRUNfTUFTSwkJ PSAweDdkMDIsCisJSERNSV9DRUNfUE9MQVJJVFkJPSAweDdkMDMsCisJSERNSV9DRUNfSU5UCQk9 IDB4N2QwNCwKKwlIRE1JX0NFQ19BRERSX0wJCT0gMHg3ZDA1LAorCUhETUlfQ0VDX0FERFJfSAkJ PSAweDdkMDYsCisJSERNSV9DRUNfVFhfQ05UCQk9IDB4N2QwNywKKwlIRE1JX0NFQ19SWF9DTlQJ CT0gMHg3ZDA4LAorCUhETUlfQ0VDX1RYX0RBVEEwCT0gMHg3ZDEwLAorCUhETUlfQ0VDX1JYX0RB VEEwCT0gMHg3ZDIwLAorCUhETUlfQ0VDX0xPQ0sJCT0gMHg3ZDMwLAorCUhETUlfQ0VDX1dLVVBD VFJMCT0gMHg3ZDMxLAorfTsKKworc3RydWN0IGR3X2hkbWlfY2VjIHsKKwl2b2lkIF9faW9tZW0g KmJhc2U7CisJdTMyIGFkZHJlc3NlczsKKwlzdHJ1Y3QgY2VjX2FkYXB0ZXIgKmFkYXA7CisJc3Ry dWN0IGNlY19tc2cgcnhfbXNnOworCXVuc2lnbmVkIGludCB0eF9zdGF0dXM7CisJYm9vbCB0eF9k b25lOworCWJvb2wgcnhfZG9uZTsKKwljb25zdCBzdHJ1Y3QgZHdfaGRtaV9jZWNfb3BzICpvcHM7 CisJdm9pZCAqb3BzX2RhdGE7CisJaW50IHJldHJpZXM7CisJaW50IGlycTsKKwlzdHJ1Y3Qgbm90 aWZpZXJfYmxvY2sgbmI7Cit9OworCitzdGF0aWMgaW50IGR3X2hkbWlfY2VjX2xvZ19hZGRyKHN0 cnVjdCBjZWNfYWRhcHRlciAqYWRhcCwgdTggbG9naWNhbF9hZGRyKQoreworCXN0cnVjdCBkd19o ZG1pX2NlYyAqY2VjID0gYWRhcC0+cHJpdjsKKwl1MzIgYWRkcmVzc2VzOworCisJaWYgKGxvZ2lj YWxfYWRkciA9PSBDRUNfTE9HX0FERFJfSU5WQUxJRCkKKwkJYWRkcmVzc2VzID0gY2VjLT5hZGRy ZXNzZXMgPSBCSVQoMTUpOworCWVsc2UKKwkJYWRkcmVzc2VzID0gY2VjLT5hZGRyZXNzZXMgfD0g QklUKGxvZ2ljYWxfYWRkcik7CisKKwl3cml0ZWJfcmVsYXhlZChhZGRyZXNzZXMgJiAyNTUsIGNl Yy0+YmFzZSArIEhETUlfQ0VDX0FERFJfTCk7CisJd3JpdGViX3JlbGF4ZWQoYWRkcmVzc2VzID4+ IDgsIGNlYy0+YmFzZSArIEhETUlfQ0VDX0FERFJfSCk7CisKKwlyZXR1cm4gMDsKK30KKworc3Rh dGljIGludCBkd19oZG1pX2NlY190cmFuc21pdChzdHJ1Y3QgY2VjX2FkYXB0ZXIgKmFkYXAsIHU4 IGF0dGVtcHRzLAorCQkJCXUzMiBzaWduYWxfZnJlZV90aW1lLCBzdHJ1Y3QgY2VjX21zZyAqbXNn KQoreworCXN0cnVjdCBkd19oZG1pX2NlYyAqY2VjID0gYWRhcC0+cHJpdjsKKwl1bnNpZ25lZCBp OworCisJY2VjLT5yZXRyaWVzID0gYXR0ZW1wdHM7CisKKwlmb3IgKGkgPSAwOyBpIDwgbXNnLT5s ZW47IGkrKykKKwkJd3JpdGViX3JlbGF4ZWQobXNnLT5tc2dbaV0sIGNlYy0+YmFzZSArIEhETUlf Q0VDX1RYX0RBVEEwICsgaSk7CisKKwl3cml0ZWJfcmVsYXhlZChtc2ctPmxlbiwgY2VjLT5iYXNl ICsgSERNSV9DRUNfVFhfQ05UKTsKKwl3cml0ZWJfcmVsYXhlZChDRUNfQ1RSTF9OT1JNQUwgfCBD RUNfQ1RSTF9TVEFSVCwgY2VjLT5iYXNlICsgSERNSV9DRUNfQ1RSTCk7CisKKwlyZXR1cm4gMDsK K30KKworc3RhdGljIGlycXJldHVybl90IGR3X2hkbWlfY2VjX2hhcmRpcnEoaW50IGlycSwgdm9p ZCAqZGF0YSkKK3sKKwlzdHJ1Y3QgY2VjX2FkYXB0ZXIgKmFkYXAgPSBkYXRhOworCXN0cnVjdCBk d19oZG1pX2NlYyAqY2VjID0gYWRhcC0+cHJpdjsKKwl1bnNpZ25lZCBzdGF0ID0gcmVhZGJfcmVs YXhlZChjZWMtPmJhc2UgKyBIRE1JX0lIX0NFQ19TVEFUMCk7CisJaXJxcmV0dXJuX3QgcmV0ID0g SVJRX0hBTkRMRUQ7CisKKwlpZiAoc3RhdCA9PSAwKQorCQlyZXR1cm4gSVJRX05PTkU7CisKKwl3 cml0ZWJfcmVsYXhlZChzdGF0LCBjZWMtPmJhc2UgKyBIRE1JX0lIX0NFQ19TVEFUMCk7CisKKwlp ZiAoc3RhdCAmIENFQ19TVEFUX0VSUk9SX0lOSVQpIHsKKwkJaWYgKGNlYy0+cmV0cmllcykgewor CQkJdW5zaWduZWQgdiA9IHJlYWRiX3JlbGF4ZWQoY2VjLT5iYXNlICsgSERNSV9DRUNfQ1RSTCk7 CisJCQl3cml0ZWJfcmVsYXhlZCh2IHwgQ0VDX0NUUkxfU1RBUlQsIGNlYy0+YmFzZSArIEhETUlf Q0VDX0NUUkwpOworCQkJY2VjLT5yZXRyaWVzIC09IDE7CisJCX0gZWxzZSB7CisJCQljZWMtPnR4 X3N0YXR1cyA9IENFQ19UWF9TVEFUVVNfTUFYX1JFVFJJRVM7CisJCQljZWMtPnR4X2RvbmUgPSB0 cnVlOworCQkJcmV0ID0gSVJRX1dBS0VfVEhSRUFEOworCQl9CisJfSBlbHNlIGlmIChzdGF0ICYg Q0VDX1NUQVRfRE9ORSkgeworCQljZWMtPnR4X3N0YXR1cyA9IENFQ19UWF9TVEFUVVNfT0s7CisJ CWNlYy0+dHhfZG9uZSA9IHRydWU7CisJCXJldCA9IElSUV9XQUtFX1RIUkVBRDsKKwl9IGVsc2Ug aWYgKHN0YXQgJiBDRUNfU1RBVF9OQUNLKSB7CisJCWNlYy0+dHhfc3RhdHVzID0gQ0VDX1RYX1NU QVRVU19OQUNLOworCQljZWMtPnR4X2RvbmUgPSB0cnVlOworCQlyZXQgPSBJUlFfV0FLRV9USFJF QUQ7CisJfQorCisJaWYgKHN0YXQgJiBDRUNfU1RBVF9FT00pIHsKKwkJdW5zaWduZWQgbGVuLCBp OworCQl2b2lkICpiYXNlID0gY2VjLT5iYXNlOworCisJCWxlbiA9IHJlYWRiX3JlbGF4ZWQoYmFz ZSArIEhETUlfQ0VDX1JYX0NOVCk7CisJCWlmIChsZW4gPiBzaXplb2YoY2VjLT5yeF9tc2cubXNn KSkKKwkJCWxlbiA9IHNpemVvZihjZWMtPnJ4X21zZy5tc2cpOworCisJCWZvciAoaSA9IDA7IGkg PCBsZW47IGkrKykKKwkJCWNlYy0+cnhfbXNnLm1zZ1tpXSA9CisJCQkJcmVhZGJfcmVsYXhlZChi YXNlICsgSERNSV9DRUNfUlhfREFUQTAgKyBpKTsKKworCQl3cml0ZWJfcmVsYXhlZCgwLCBiYXNl ICsgSERNSV9DRUNfTE9DSyk7CisKKwkJY2VjLT5yeF9tc2cubGVuID0gbGVuOworCQlzbXBfd21i KCk7CisJCWNlYy0+cnhfZG9uZSA9IHRydWU7CisKKwkJcmV0ID0gSVJRX1dBS0VfVEhSRUFEOwor CX0KKworCXJldHVybiByZXQ7Cit9CisKK3N0YXRpYyBpcnFyZXR1cm5fdCBkd19oZG1pX2NlY190 aHJlYWQoaW50IGlycSwgdm9pZCAqZGF0YSkKK3sKKwlzdHJ1Y3QgY2VjX2FkYXB0ZXIgKmFkYXAg PSBkYXRhOworCXN0cnVjdCBkd19oZG1pX2NlYyAqY2VjID0gYWRhcC0+cHJpdjsKKworCWlmIChj ZWMtPnR4X2RvbmUpIHsKKwkJY2VjLT50eF9kb25lID0gZmFsc2U7CisJCWNlY190cmFuc21pdF9k b25lKGFkYXAsIGNlYy0+dHhfc3RhdHVzLCAwLCAwLCAwLCAwKTsKKwl9CisJaWYgKGNlYy0+cnhf ZG9uZSkgeworCQljZWMtPnJ4X2RvbmUgPSBmYWxzZTsKKwkJc21wX3JtYigpOworCQljZWNfcmVj ZWl2ZWRfbXNnKGFkYXAsICZjZWMtPnJ4X21zZyk7CisJfQorCXJldHVybiBJUlFfSEFORExFRDsK K30KKworc3RhdGljIGludCBkd19oZG1pX2NlY19lbmFibGUoc3RydWN0IGNlY19hZGFwdGVyICph ZGFwLCBib29sIGVuYWJsZSkKK3sKKwlzdHJ1Y3QgZHdfaGRtaV9jZWMgKmNlYyA9IGFkYXAtPnBy aXY7CisKKwlpZiAoIWVuYWJsZSkgeworCQl3cml0ZWJfcmVsYXhlZCh+MCwgY2VjLT5iYXNlICsg SERNSV9DRUNfTUFTSyk7CisJCXdyaXRlYl9yZWxheGVkKH4wLCBjZWMtPmJhc2UgKyBIRE1JX0lI X01VVEVfQ0VDX1NUQVQwKTsKKwkJd3JpdGViX3JlbGF4ZWQoMCwgY2VjLT5iYXNlICsgSERNSV9D RUNfUE9MQVJJVFkpOworCisJCWNlYy0+b3BzLT5kaXNhYmxlKGNlYy0+b3BzX2RhdGEpOworCX0g ZWxzZSB7CisJCXVuc2lnbmVkIGlycXM7CisKKwkJd3JpdGViX3JlbGF4ZWQoMCwgY2VjLT5iYXNl ICsgSERNSV9DRUNfQ1RSTCk7CisJCXdyaXRlYl9yZWxheGVkKH4wLCBjZWMtPmJhc2UgKyBIRE1J X0lIX0NFQ19TVEFUMCk7CisJCXdyaXRlYl9yZWxheGVkKDAsIGNlYy0+YmFzZSArIEhETUlfQ0VD X0xPQ0spOworCisJCWR3X2hkbWlfY2VjX2xvZ19hZGRyKGNlYy0+YWRhcCwgQ0VDX0xPR19BRERS X0lOVkFMSUQpOworCisJCWNlYy0+b3BzLT5lbmFibGUoY2VjLT5vcHNfZGF0YSk7CisKKwkJaXJx cyA9IENFQ19TVEFUX0VSUk9SX0lOSVQgfCBDRUNfU1RBVF9OQUNLIHwgQ0VDX1NUQVRfRU9NIHwK KwkJICAgICAgIENFQ19TVEFUX0RPTkU7CisJCXdyaXRlYl9yZWxheGVkKGlycXMsIGNlYy0+YmFz ZSArIEhETUlfQ0VDX1BPTEFSSVRZKTsKKwkJd3JpdGViX3JlbGF4ZWQofmlycXMsIGNlYy0+YmFz ZSArIEhETUlfQ0VDX01BU0spOworCQl3cml0ZWJfcmVsYXhlZCh+aXJxcywgY2VjLT5iYXNlICsg SERNSV9JSF9NVVRFX0NFQ19TVEFUMCk7CisJfQorCXJldHVybiAwOworfQorCitzdGF0aWMgY29u c3Qgc3RydWN0IGNlY19hZGFwX29wcyBkd19oZG1pX2NlY19vcHMgPSB7CisJLmFkYXBfZW5hYmxl ID0gZHdfaGRtaV9jZWNfZW5hYmxlLAorCS5hZGFwX2xvZ19hZGRyID0gZHdfaGRtaV9jZWNfbG9n X2FkZHIsCisJLmFkYXBfdHJhbnNtaXQgPSBkd19oZG1pX2NlY190cmFuc21pdCwKK307CisKK3N0 YXRpYyB1bnNpZ25lZCBpbnQgcGFyc2VfaGRtaV9hZGRyKGNvbnN0IHN0cnVjdCBlZGlkICplZGlk KQoreworCWlmICghZWRpZCB8fCBlZGlkLT5leHRlbnNpb25zID09IDApCisJCXJldHVybiAodTE2 KX4wOworCisJcmV0dXJuIGNlY19nZXRfZWRpZF9waHlzX2FkZHIoKHU4ICopZWRpZCwKKwkJCQlF RElEX0xFTkdUSCAqIChlZGlkLT5leHRlbnNpb25zICsgMSksIE5VTEwpOworfQorCitzdGF0aWMg aW50IGR3X2hkbWlfY2VjX25vdGlmeShzdHJ1Y3Qgbm90aWZpZXJfYmxvY2sgKm5iLCB1bnNpZ25l ZCBsb25nIGV2ZW50LAorCQkJICAgICAgdm9pZCAqZGF0YSkKK3sKKwlzdHJ1Y3QgZHdfaGRtaV9j ZWMgKmNlYyA9IGNvbnRhaW5lcl9vZihuYiwgc3RydWN0IGR3X2hkbWlfY2VjLCBuYik7CisJdW5p b24gaGRtaV9ldmVudCAqZXZlbnRfYmxvY2sgPSBkYXRhOworCXVuc2lnbmVkIGludCBwaHlzOwor CisJZGV2X2luZm8oZXZlbnRfYmxvY2stPmJhc2Uuc291cmNlLCAiZXZlbnQgJWx1XG4iLCBldmVu dCk7CisKKwlpZiAoZXZlbnRfYmxvY2stPmJhc2Uuc291cmNlICE9IGNlYy0+YWRhcC0+ZGV2bm9k ZS5wYXJlbnQpCisJCXJldHVybiBOT1RJRllfT0s7CisKKwlzd2l0Y2ggKGV2ZW50KSB7CisJY2Fz ZSBIRE1JX0NPTk5FQ1RFRDoKKwkJYnJlYWs7CisKKwljYXNlIEhETUlfRElTQ09OTkVDVEVEOgor CQljZWNfc19waHlzX2FkZHIoY2VjLT5hZGFwLCBDRUNfUEhZU19BRERSX0lOVkFMSUQsIGZhbHNl KTsKKwkJYnJlYWs7CisKKwljYXNlIEhETUlfTkVXX0VESUQ6CisJCXBoeXMgPSBwYXJzZV9oZG1p X2FkZHIoZXZlbnRfYmxvY2stPmVkaWQuZWRpZCk7CisJCWNlY19zX3BoeXNfYWRkcihjZWMtPmFk YXAsIHBoeXMsIGZhbHNlKTsKKwkJYnJlYWs7CisJfQorCisJcmV0dXJuIE5PVElGWV9PSzsKK30K Kworc3RhdGljIHZvaWQgZHdfaGRtaV9jZWNfZGVsKHZvaWQgKmRhdGEpCit7CisJc3RydWN0IGR3 X2hkbWlfY2VjICpjZWMgPSBkYXRhOworCisJY2VjX2RlbGV0ZV9hZGFwdGVyKGNlYy0+YWRhcCk7 Cit9CisKK3N0YXRpYyBpbnQgZHdfaGRtaV9jZWNfcHJvYmUoc3RydWN0IHBsYXRmb3JtX2Rldmlj ZSAqcGRldikKK3sKKwlzdHJ1Y3QgZHdfaGRtaV9jZWNfZGF0YSAqZGF0YSA9IGRldl9nZXRfcGxh dGRhdGEoJnBkZXYtPmRldik7CisJc3RydWN0IGR3X2hkbWlfY2VjICpjZWM7CisJaW50IHJldDsK KworCWlmICghZGF0YSkKKwkJcmV0dXJuIC1FTlhJTzsKKworCS8qCisJICogT3VyIGRldmljZSBp cyBqdXN0IGEgY29udmVuaWVuY2UgLSB3ZSB3YW50IHRvIGxpbmsgdG8gdGhlIHJlYWwKKwkgKiBo YXJkd2FyZSBkZXZpY2UgaGVyZSwgc28gdGhhdCB1c2Vyc3BhY2UgY2FuIHNlZSB0aGUgYXNzb2Np YXRpb24KKwkgKiBiZXR3ZWVuIHRoZSBIRE1JIGhhcmR3YXJlIGFuZCBpdHMgYXNzb2NpYXRlZCBD RUMgY2hhcmRldi4KKwkgKi8KKwljZWMgPSBkZXZtX2t6YWxsb2MoJnBkZXYtPmRldiwgc2l6ZW9m KCpjZWMpLCBHRlBfS0VSTkVMKTsKKwlpZiAoIWNlYykKKwkJcmV0dXJuIC1FTk9NRU07CisKKwlj ZWMtPmJhc2UgPSBkYXRhLT5iYXNlOworCWNlYy0+aXJxID0gZGF0YS0+aXJxOworCWNlYy0+b3Bz ID0gZGF0YS0+b3BzOworCWNlYy0+b3BzX2RhdGEgPSBkYXRhLT5vcHNfZGF0YTsKKwljZWMtPm5i Lm5vdGlmaWVyX2NhbGwgPSBkd19oZG1pX2NlY19ub3RpZnk7CisKKwlwbGF0Zm9ybV9zZXRfZHJ2 ZGF0YShwZGV2LCBjZWMpOworCisJd3JpdGViX3JlbGF4ZWQoMCwgY2VjLT5iYXNlICsgSERNSV9D RUNfVFhfQ05UKTsKKwl3cml0ZWJfcmVsYXhlZCh+MCwgY2VjLT5iYXNlICsgSERNSV9DRUNfTUFT Syk7CisJd3JpdGViX3JlbGF4ZWQofjAsIGNlYy0+YmFzZSArIEhETUlfSUhfTVVURV9DRUNfU1RB VDApOworCXdyaXRlYl9yZWxheGVkKDAsIGNlYy0+YmFzZSArIEhETUlfQ0VDX1BPTEFSSVRZKTsK KworCWNlYy0+YWRhcCA9IGNlY19hbGxvY2F0ZV9hZGFwdGVyKCZkd19oZG1pX2NlY19vcHMsIGNl YywgImR3X2hkbWkiLAorCQkJCQkgQ0VDX0NBUF9MT0dfQUREUlMgfCBDRUNfQ0FQX1RSQU5TTUlU IHwKKwkJCQkJIENFQ19DQVBfUkMsIENFQ19NQVhfTE9HX0FERFJTLAorCQkJCQkgcGRldi0+ZGV2 LnBhcmVudCk7CisJaWYgKElTX0VSUihjZWMtPmFkYXApKQorCQlyZXR1cm4gUFRSX0VSUihjZWMt PmFkYXApOworCisJLyogb3ZlcnJpZGUgdGhlIG1vZHVsZSBwb2ludGVyICovCisJY2VjLT5hZGFw LT5vd25lciA9IFRISVNfTU9EVUxFOworCisJcmV0ID0gZGV2bV9hZGRfYWN0aW9uKCZwZGV2LT5k ZXYsIGR3X2hkbWlfY2VjX2RlbCwgY2VjKTsKKwlpZiAocmV0KSB7CisJCWNlY19kZWxldGVfYWRh cHRlcihjZWMtPmFkYXApOworCQlyZXR1cm4gcmV0OworCX0KKworCXJldCA9IGRldm1fcmVxdWVz dF90aHJlYWRlZF9pcnEoJnBkZXYtPmRldiwgY2VjLT5pcnEsCisJCQkJCWR3X2hkbWlfY2VjX2hh cmRpcnEsCisJCQkJCWR3X2hkbWlfY2VjX3RocmVhZCwgSVJRRl9TSEFSRUQsCisJCQkJCURFVl9O QU1FLCBjZWMtPmFkYXApOworCWlmIChyZXQgPCAwKQorCQlyZXR1cm4gcmV0OworCisJcmV0ID0g Y2VjX3JlZ2lzdGVyX2FkYXB0ZXIoY2VjLT5hZGFwKTsKKwlpZiAocmV0IDwgMCkKKwkJcmV0dXJu IHJldDsKKworCS8qCisJICogQ0VDIGRvY3VtZW50YXRpb24gc2F5cyB3ZSBtdXN0IG5vdCBjYWxs IGNlY19kZWxldGVfYWRhcHRlcgorCSAqIGFmdGVyIGEgc3VjY2Vzc2Z1bCBjYWxsIHRvIGNlY19y ZWdpc3Rlcl9hZGFwdGVyKCkuCisJICovCisJZGV2bV9yZW1vdmVfYWN0aW9uKCZwZGV2LT5kZXYs IGR3X2hkbWlfY2VjX2RlbCwgY2VjKTsKKworCWhkbWlfcmVnaXN0ZXJfbm90aWZpZXIoJmNlYy0+ bmIpOworCisJcmV0dXJuIDA7Cit9CisKK3N0YXRpYyBpbnQgZHdfaGRtaV9jZWNfcmVtb3ZlKHN0 cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYpCit7CisJc3RydWN0IGR3X2hkbWlfY2VjICpjZWMg PSBwbGF0Zm9ybV9nZXRfZHJ2ZGF0YShwZGV2KTsKKworCWhkbWlfdW5yZWdpc3Rlcl9ub3RpZmll cigmY2VjLT5uYik7CisJY2VjX3VucmVnaXN0ZXJfYWRhcHRlcihjZWMtPmFkYXApOworCisJcmV0 dXJuIDA7Cit9CisKK3N0YXRpYyBzdHJ1Y3QgcGxhdGZvcm1fZHJpdmVyIGR3X2hkbWlfY2VjX2Ry aXZlciA9IHsKKwkucHJvYmUJPSBkd19oZG1pX2NlY19wcm9iZSwKKwkucmVtb3ZlCT0gZHdfaGRt aV9jZWNfcmVtb3ZlLAorCS5kcml2ZXIgPSB7CisJCS5uYW1lID0gImR3LWhkbWktY2VjIiwKKwkJ Lm93bmVyID0gVEhJU19NT0RVTEUsCisJfSwKK307Cittb2R1bGVfcGxhdGZvcm1fZHJpdmVyKGR3 X2hkbWlfY2VjX2RyaXZlcik7CisKK01PRFVMRV9BVVRIT1IoIlJ1c3NlbGwgS2luZyA8cm1rK2tl cm5lbEBhcm0ubGludXgub3JnLnVrPiIpOworTU9EVUxFX0RFU0NSSVBUSU9OKCJTeW5vcHNpcyBE ZXNpZ253YXJlIEhETUkgQ0VDIGRyaXZlciBmb3IgaS5NWCIpOworTU9EVUxFX0xJQ0VOU0UoIkdQ TCIpOworTU9EVUxFX0FMSUFTKFBMQVRGT1JNX01PRFVMRV9QUkVGSVggImR3LWhkbWktY2VjIik7 CmRpZmYgLS1naXQgYS9kcml2ZXJzL2dwdS9kcm0vYnJpZGdlL2R3LWhkbWkuYyBiL2RyaXZlcnMv Z3B1L2RybS9icmlkZ2UvZHctaGRtaS5jCmluZGV4IGNiNmUwM2VmYmViZi4uMWFkNThlMzdjMGIz IDEwMDY0NAotLS0gYS9kcml2ZXJzL2dwdS9kcm0vYnJpZGdlL2R3LWhkbWkuYworKysgYi9kcml2 ZXJzL2dwdS9kcm0vYnJpZGdlL2R3LWhkbWkuYwpAQCAtMTksNiArMTksNyBAQAogI2luY2x1ZGUg PGxpbnV4L2hkbWktbm90aWZpZXIuaD4KICNpbmNsdWRlIDxsaW51eC9tdXRleC5oPgogI2luY2x1 ZGUgPGxpbnV4L29mX2RldmljZS5oPgorI2luY2x1ZGUgPGxpbnV4L3BsYXRmb3JtX2RhdGEvZHdf aGRtaS1jZWMuaD4KICNpbmNsdWRlIDxsaW51eC9zcGlubG9jay5oPgogCiAjaW5jbHVkZSA8ZHJt L2RybV9vZi5oPgpAQCAtMTA4LDYgKzEwOSw3IEBAIHN0cnVjdCBkd19oZG1pIHsKIAlzdHJ1Y3Qg ZHJtX2JyaWRnZSAqYnJpZGdlOwogCiAJc3RydWN0IHBsYXRmb3JtX2RldmljZSAqYXVkaW87CisJ c3RydWN0IHBsYXRmb3JtX2RldmljZSAqY2VjOwogCWVudW0gZHdfaGRtaV9kZXZ0eXBlIGRldl90 eXBlOwogCXN0cnVjdCBkZXZpY2UgKmRldjsKIAlzdHJ1Y3QgY2xrICppc2ZyX2NsazsKQEAgLTEx OSw2ICsxMjEsNyBAQCBzdHJ1Y3QgZHdfaGRtaSB7CiAJaW50IHZpYzsKIAogCXU4IGVkaWRbSERN SV9FRElEX0xFTl07CisJdTggbWNfY2xrZGlzOwogCWJvb2wgY2FibGVfcGx1Z2luOwogCiAJYm9v bCBwaHlfZW5hYmxlZDsKQEAgLTExMDgsOCArMTExMSw2IEBAIHN0YXRpYyB2b2lkIGR3X2hkbWlf cGh5X2Rpc2FibGUoc3RydWN0IGR3X2hkbWkgKmhkbWkpCiAvKiBIRE1JIEluaXRpYWxpemF0aW9u IFN0ZXAgQi40ICovCiBzdGF0aWMgdm9pZCBkd19oZG1pX2VuYWJsZV92aWRlb19wYXRoKHN0cnVj dCBkd19oZG1pICpoZG1pKQogewotCXU4IGNsa2RpczsKLQogCS8qIGNvbnRyb2wgcGVyaW9kIG1p bmltdW0gZHVyYXRpb24gKi8KIAloZG1pX3dyaXRlYihoZG1pLCAxMiwgSERNSV9GQ19DVFJMRFVS KTsKIAloZG1pX3dyaXRlYihoZG1pLCAzMiwgSERNSV9GQ19FWENUUkxEVVIpOwpAQCAtMTEyMSwy MyArMTEyMiwyOCBAQCBzdGF0aWMgdm9pZCBkd19oZG1pX2VuYWJsZV92aWRlb19wYXRoKHN0cnVj dCBkd19oZG1pICpoZG1pKQogCWhkbWlfd3JpdGViKGhkbWksIDB4MjEsIEhETUlfRkNfQ0gyUFJF QU0pOwogCiAJLyogRW5hYmxlIHBpeGVsIGNsb2NrIGFuZCB0bWRzIGRhdGEgcGF0aCAqLwotCWNs a2RpcyA9IDB4N0Y7Ci0JY2xrZGlzICY9IH5IRE1JX01DX0NMS0RJU19QSVhFTENMS19ESVNBQkxF OwotCWhkbWlfd3JpdGViKGhkbWksIGNsa2RpcywgSERNSV9NQ19DTEtESVMpOworCWhkbWktPm1j X2Nsa2RpcyB8PSBIRE1JX01DX0NMS0RJU19IRENQQ0xLX0RJU0FCTEUgfAorCQkJICAgSERNSV9N Q19DTEtESVNfQ1NDQ0xLX0RJU0FCTEUgfAorCQkJICAgSERNSV9NQ19DTEtESVNfQVVEQ0xLX0RJ U0FCTEUgfAorCQkJICAgSERNSV9NQ19DTEtESVNfUFJFUENMS19ESVNBQkxFIHwKKwkJCSAgIEhE TUlfTUNfQ0xLRElTX1RNRFNDTEtfRElTQUJMRTsKKwloZG1pLT5tY19jbGtkaXMgJj0gfkhETUlf TUNfQ0xLRElTX1BJWEVMQ0xLX0RJU0FCTEU7CisJaGRtaV93cml0ZWIoaGRtaSwgaGRtaS0+bWNf Y2xrZGlzLCBIRE1JX01DX0NMS0RJUyk7CiAKLQljbGtkaXMgJj0gfkhETUlfTUNfQ0xLRElTX1RN RFNDTEtfRElTQUJMRTsKLQloZG1pX3dyaXRlYihoZG1pLCBjbGtkaXMsIEhETUlfTUNfQ0xLRElT KTsKKwloZG1pLT5tY19jbGtkaXMgJj0gfkhETUlfTUNfQ0xLRElTX1RNRFNDTEtfRElTQUJMRTsK KwloZG1pX3dyaXRlYihoZG1pLCBoZG1pLT5tY19jbGtkaXMsIEhETUlfTUNfQ0xLRElTKTsKIAog CS8qIEVuYWJsZSBjc2MgcGF0aCAqLwogCWlmIChpc19jb2xvcl9zcGFjZV9jb252ZXJzaW9uKGhk bWkpKSB7Ci0JCWNsa2RpcyAmPSB+SERNSV9NQ19DTEtESVNfQ1NDQ0xLX0RJU0FCTEU7Ci0JCWhk bWlfd3JpdGViKGhkbWksIGNsa2RpcywgSERNSV9NQ19DTEtESVMpOworCQloZG1pLT5tY19jbGtk aXMgJj0gfkhETUlfTUNfQ0xLRElTX0NTQ0NMS19ESVNBQkxFOworCQloZG1pX3dyaXRlYihoZG1p LCBoZG1pLT5tY19jbGtkaXMsIEhETUlfTUNfQ0xLRElTKTsKIAl9CiB9CiAKIHN0YXRpYyB2b2lk IGhkbWlfZW5hYmxlX2F1ZGlvX2NsayhzdHJ1Y3QgZHdfaGRtaSAqaGRtaSkKIHsKLQloZG1pX21v ZGIoaGRtaSwgMCwgSERNSV9NQ19DTEtESVNfQVVEQ0xLX0RJU0FCTEUsIEhETUlfTUNfQ0xLRElT KTsKKwloZG1pLT5tY19jbGtkaXMgJj0gfkhETUlfTUNfQ0xLRElTX0FVRENMS19ESVNBQkxFOwor CWhkbWlfd3JpdGViKGhkbWksIGhkbWktPm1jX2Nsa2RpcywgSERNSV9NQ19DTEtESVMpOwogfQog CiAvKiBXb3JrYXJvdW5kIHRvIGNsZWFyIHRoZSBvdmVyZmxvdyBjb25kaXRpb24gKi8KQEAgLTEy OTcsNyArMTMwMyw2IEBAIHN0YXRpYyB2b2lkIGluaXRpYWxpemVfaGRtaV9paF9tdXRlcyhzdHJ1 Y3QgZHdfaGRtaSAqaGRtaSkKIAloZG1pX3dyaXRlYihoZG1pLCAweGZmLCBIRE1JX0FVRF9IQlJf TUFTSyk7CiAJaGRtaV93cml0ZWIoaGRtaSwgMHhmZiwgSERNSV9HUF9NQVNLKTsKIAloZG1pX3dy aXRlYihoZG1pLCAweGZmLCBIRE1JX0FfQVBJSU5UTVNLKTsKLQloZG1pX3dyaXRlYihoZG1pLCAw eGZmLCBIRE1JX0NFQ19NQVNLKTsKIAloZG1pX3dyaXRlYihoZG1pLCAweGZmLCBIRE1JX0kyQ01f SU5UKTsKIAloZG1pX3dyaXRlYihoZG1pLCAweGZmLCBIRE1JX0kyQ01fQ1RMSU5UKTsKIApAQCAt MTY2Niw2ICsxNjcxLDI3IEBAIHN0YXRpYyBpbnQgZHdfaGRtaV9yZWdpc3RlcihzdHJ1Y3QgZHJt X2RldmljZSAqZHJtLCBzdHJ1Y3QgZHdfaGRtaSAqaGRtaSkKIAlyZXR1cm4gMDsKIH0KIAorc3Rh dGljIHZvaWQgZHdfaGRtaV9jZWNfZW5hYmxlKHZvaWQgKmRhdGEpCit7CisJc3RydWN0IGR3X2hk bWkgKmhkbWkgPSBkYXRhOworCisJaGRtaS0+bWNfY2xrZGlzICY9IH5IRE1JX01DX0NMS0RJU19D RUNDTEtfRElTQUJMRTsKKwloZG1pX3dyaXRlYihoZG1pLCBoZG1pLT5tY19jbGtkaXMsIEhETUlf TUNfQ0xLRElTKTsKK30KKworc3RhdGljIHZvaWQgZHdfaGRtaV9jZWNfZGlzYWJsZSh2b2lkICpk YXRhKQoreworCXN0cnVjdCBkd19oZG1pICpoZG1pID0gZGF0YTsKKworCWhkbWktPm1jX2Nsa2Rp cyB8PSBIRE1JX01DX0NMS0RJU19DRUNDTEtfRElTQUJMRTsKKwloZG1pX3dyaXRlYihoZG1pLCBo ZG1pLT5tY19jbGtkaXMsIEhETUlfTUNfQ0xLRElTKTsKK30KKworc3RhdGljIGNvbnN0IHN0cnVj dCBkd19oZG1pX2NlY19vcHMgZHdfaGRtaV9jZWNfb3BzID0geworCS5lbmFibGUgPSBkd19oZG1p X2NlY19lbmFibGUsCisJLmRpc2FibGUgPSBkd19oZG1pX2NlY19kaXNhYmxlLAorfTsKKwogaW50 IGR3X2hkbWlfYmluZChzdHJ1Y3QgZGV2aWNlICpkZXYsIHN0cnVjdCBkZXZpY2UgKm1hc3RlciwK IAkJIHZvaWQgKmRhdGEsIHN0cnVjdCBkcm1fZW5jb2RlciAqZW5jb2RlciwKIAkJIHN0cnVjdCBy ZXNvdXJjZSAqaW9yZXMsIGludCBpcnEsCkBAIC0xNjc2LDYgKzE3MDIsNyBAQCBpbnQgZHdfaGRt aV9iaW5kKHN0cnVjdCBkZXZpY2UgKmRldiwgc3RydWN0IGRldmljZSAqbWFzdGVyLAogCXN0cnVj dCBwbGF0Zm9ybV9kZXZpY2VfaW5mbyBwZGV2aW5mbzsKIAlzdHJ1Y3QgZGV2aWNlX25vZGUgKmRk Y19ub2RlOwogCXN0cnVjdCBkd19oZG1pX2F1ZGlvX2RhdGEgYXVkaW87CisJc3RydWN0IGR3X2hk bWlfY2VjX2RhdGEgY2VjOwogCXN0cnVjdCBkd19oZG1pICpoZG1pOwogCWludCByZXQ7CiAJdTMy IHZhbCA9IDE7CkBAIC0xNjk0LDYgKzE3MjEsNyBAQCBpbnQgZHdfaGRtaV9iaW5kKHN0cnVjdCBk ZXZpY2UgKmRldiwgc3RydWN0IGRldmljZSAqbWFzdGVyLAogCWhkbWktPmRpc2FibGVkID0gdHJ1 ZTsKIAloZG1pLT5yeHNlbnNlID0gdHJ1ZTsKIAloZG1pLT5waHlfbWFzayA9ICh1OCl+KEhETUlf UEhZX0hQRCB8IEhETUlfUEhZX1JYX1NFTlNFKTsKKwloZG1pLT5tY19jbGtkaXMgPSAweDdmOwog CiAJbXV0ZXhfaW5pdCgmaGRtaS0+bXV0ZXgpOwogCW11dGV4X2luaXQoJmhkbWktPmF1ZGlvX211 dGV4KTsKQEAgLTE4MjAsNiArMTg0OCwxOCBAQCBpbnQgZHdfaGRtaV9iaW5kKHN0cnVjdCBkZXZp Y2UgKmRldiwgc3RydWN0IGRldmljZSAqbWFzdGVyLAogCQloZG1pLT5hdWRpbyA9IHBsYXRmb3Jt X2RldmljZV9yZWdpc3Rlcl9mdWxsKCZwZGV2aW5mbyk7CiAJfQogCisJY2VjLmJhc2UgPSBoZG1p LT5yZWdzOworCWNlYy5pcnEgPSBpcnE7CisJY2VjLm9wcyA9ICZkd19oZG1pX2NlY19vcHM7CisJ Y2VjLm9wc19kYXRhID0gaGRtaTsKKworCXBkZXZpbmZvLm5hbWUgPSAiZHctaGRtaS1jZWMiOwor CXBkZXZpbmZvLmRhdGEgPSAmY2VjOworCXBkZXZpbmZvLnNpemVfZGF0YSA9IHNpemVvZihjZWMp OworCXBkZXZpbmZvLmRtYV9tYXNrID0gMDsKKworCWhkbWktPmNlYyA9IHBsYXRmb3JtX2Rldmlj ZV9yZWdpc3Rlcl9mdWxsKCZwZGV2aW5mbyk7CisKIAlkZXZfc2V0X2RydmRhdGEoZGV2LCBoZG1p KTsKIAogCXJldHVybiAwOwpAQCAtMTgzOSw2ICsxODc5LDggQEAgdm9pZCBkd19oZG1pX3VuYmlu ZChzdHJ1Y3QgZGV2aWNlICpkZXYsIHN0cnVjdCBkZXZpY2UgKm1hc3Rlciwgdm9pZCAqZGF0YSkK IAogCWlmIChoZG1pLT5hdWRpbyAmJiAhSVNfRVJSKGhkbWktPmF1ZGlvKSkKIAkJcGxhdGZvcm1f ZGV2aWNlX3VucmVnaXN0ZXIoaGRtaS0+YXVkaW8pOworCWlmICghSVNfRVJSKGhkbWktPmNlYykp CisJCXBsYXRmb3JtX2RldmljZV91bnJlZ2lzdGVyKGhkbWktPmNlYyk7CiAKIAkvKiBEaXNhYmxl IGFsbCBpbnRlcnJ1cHRzICovCiAJaGRtaV93cml0ZWIoaGRtaSwgfjAsIEhETUlfSUhfTVVURV9Q SFlfU1RBVDApOwpkaWZmIC0tZ2l0IGEvaW5jbHVkZS9saW51eC9wbGF0Zm9ybV9kYXRhL2R3X2hk bWktY2VjLmggYi9pbmNsdWRlL2xpbnV4L3BsYXRmb3JtX2RhdGEvZHdfaGRtaS1jZWMuaApuZXcg ZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAwMDAwMDAuLjVmZjQwY2MyMzdhOAotLS0gL2Rl di9udWxsCisrKyBiL2luY2x1ZGUvbGludXgvcGxhdGZvcm1fZGF0YS9kd19oZG1pLWNlYy5oCkBA IC0wLDAgKzEsMTYgQEAKKyNpZm5kZWYgRFdfSERNSV9DRUNfSAorI2RlZmluZSBEV19IRE1JX0NF Q19ICisKK3N0cnVjdCBkd19oZG1pX2NlY19vcHMgeworCXZvaWQgKCplbmFibGUpKHZvaWQgKik7 CisJdm9pZCAoKmRpc2FibGUpKHZvaWQgKik7Cit9OworCitzdHJ1Y3QgZHdfaGRtaV9jZWNfZGF0 YSB7CisJdm9pZCBfX2lvbWVtICpiYXNlOworCWludCBpcnE7CisJY29uc3Qgc3RydWN0IGR3X2hk bWlfY2VjX29wcyAqb3BzOworCXZvaWQgKm9wc19kYXRhOworfTsKKworI2VuZGlmCi0tIAoyLjEu MAoKX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KZHJpLWRl dmVsIG1haWxpbmcgbGlzdApkcmktZGV2ZWxAbGlzdHMuZnJlZWRlc2t0b3Aub3JnCmh0dHBzOi8v bGlzdHMuZnJlZWRlc2t0b3Aub3JnL21haWxtYW4vbGlzdGluZm8vZHJpLWRldmVsCg==