From patchwork Tue Sep 8 07:25:33 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Enric Balletbo Serra X-Patchwork-Id: 7138841 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 0F6DBBEEC1 for ; Tue, 8 Sep 2015 07:26:02 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id B29972065B for ; Tue, 8 Sep 2015 07:25:55 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 2A33820643 for ; Tue, 8 Sep 2015 07:25:49 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 4F1246E885; Tue, 8 Sep 2015 00:25:48 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-wi0-f179.google.com (mail-wi0-f179.google.com [209.85.212.179]) by gabe.freedesktop.org (Postfix) with ESMTPS id A5F7C6E885 for ; Tue, 8 Sep 2015 00:25:46 -0700 (PDT) Received: by wicge5 with SMTP id ge5so104792502wic.0 for ; Tue, 08 Sep 2015 00:25:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=pWyBqt3Z/4agg3KczF1a6NWDfWCvM1A86YFLV/JgYhE=; b=z3Y//xIgpQj/mmC43Krjf0ycIfIyV7PxP6QoLejnOBbHCio4EOV5ixVgHAXL+R0SJP k85xFh4335z50JC0R1TIFmNOtHUAjjIMq4UU964cdO5C7Nb8tLHdK4UsQ6L04mTcPosC xorNj6rIRJdN/mwhRADrj/hl+J34sKuBIhxrPOoaaiQeQGxeT9CbQBj5lEgiQrba+jat FCMZIaHJFUXwJ+t/HUAzxYPb6rQD/Uzbp/z6V9EHH9yCIaLqFtSno26OrxhqOUeDvbLN w21Y0TtG4j0bQmCdLme54a16Jr7a9O++SoFPFYMvMbupXOlYCvS9twR3Rl9VQy05kf5/ +iLA== X-Received: by 10.194.172.33 with SMTP id az1mr43372835wjc.57.1441697145237; Tue, 08 Sep 2015 00:25:45 -0700 (PDT) Received: from localhost.localdomain ([84.236.220.225]) by smtp.gmail.com with ESMTPSA id f7sm3220869wij.17.2015.09.08.00.25.39 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 08 Sep 2015 00:25:44 -0700 (PDT) From: Enric Balletbo i Serra X-Google-Original-From: Enric Balletbo i Serra To: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, devel@driverdev.osuosl.org Subject: [PATCHv2 3/3] drm/i2c: anx78xx: Add anx7814 driver support by analogix. Date: Tue, 8 Sep 2015 09:25:33 +0200 Message-Id: <1441697133-3942-1-git-send-email-enric.balletbo@collabora.com> X-Mailer: git-send-email 2.1.0 Cc: mark.rutland@arm.com, pawel.moll@arm.com, ijc+devicetree@hellion.org.uk, gregkh@linuxfoundation.org, sjoerd.simons@collabora.co.uk, robh+dt@kernel.org, span@analogixsemi.com, galak@codeaurora.org, javier@dowhile0.org, nathan.chung@mediatek.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The ANX7814 is an ultra-low power Full-HD (1080p60) SlimPort transmitter designed for portable devices. This driver adds initial support and supports HDMI to DP pass-through mode. Signed-off-by: Enric Balletbo i Serra --- drivers/gpu/drm/i2c/Kconfig | 2 + drivers/gpu/drm/i2c/Makefile | 2 + drivers/gpu/drm/i2c/anx78xx/Kconfig | 7 + drivers/gpu/drm/i2c/anx78xx/Makefile | 4 + drivers/gpu/drm/i2c/anx78xx/slimport.c | 301 +++ drivers/gpu/drm/i2c/anx78xx/slimport.h | 49 + drivers/gpu/drm/i2c/anx78xx/slimport_tx_drv.c | 3335 +++++++++++++++++++++++++ drivers/gpu/drm/i2c/anx78xx/slimport_tx_drv.h | 254 ++ drivers/gpu/drm/i2c/anx78xx/slimport_tx_reg.h | 786 ++++++ 9 files changed, 4740 insertions(+) create mode 100644 drivers/gpu/drm/i2c/anx78xx/Kconfig create mode 100644 drivers/gpu/drm/i2c/anx78xx/Makefile create mode 100644 drivers/gpu/drm/i2c/anx78xx/slimport.c create mode 100644 drivers/gpu/drm/i2c/anx78xx/slimport.h create mode 100644 drivers/gpu/drm/i2c/anx78xx/slimport_tx_drv.c create mode 100644 drivers/gpu/drm/i2c/anx78xx/slimport_tx_drv.h create mode 100644 drivers/gpu/drm/i2c/anx78xx/slimport_tx_reg.h diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig index 22c7ed6..e666ccd 100644 --- a/drivers/gpu/drm/i2c/Kconfig +++ b/drivers/gpu/drm/i2c/Kconfig @@ -31,4 +31,6 @@ config DRM_I2C_NXP_TDA998X help Support for NXP Semiconductors TDA998X HDMI encoders. +source "drivers/gpu/drm/i2c/anx78xx/Kconfig" + endmenu diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile index 2c72eb5..0ca15d2 100644 --- a/drivers/gpu/drm/i2c/Makefile +++ b/drivers/gpu/drm/i2c/Makefile @@ -10,3 +10,5 @@ obj-$(CONFIG_DRM_I2C_SIL164) += sil164.o tda998x-y := tda998x_drv.o obj-$(CONFIG_DRM_I2C_NXP_TDA998X) += tda998x.o + +obj-$(CONFIG_DRM_I2C_ANX78XX) += anx78xx/ diff --git a/drivers/gpu/drm/i2c/anx78xx/Kconfig b/drivers/gpu/drm/i2c/anx78xx/Kconfig new file mode 100644 index 0000000..4862c06 --- /dev/null +++ b/drivers/gpu/drm/i2c/anx78xx/Kconfig @@ -0,0 +1,7 @@ +config DRM_I2C_ANX78XX + tristate "Analogix Slimport transmitter ANX78XX support" + help + Slimport Transmitter is a HD video transmitter chip + over micro-USB connector for smartphone device. + + diff --git a/drivers/gpu/drm/i2c/anx78xx/Makefile b/drivers/gpu/drm/i2c/anx78xx/Makefile new file mode 100644 index 0000000..e248ee5 --- /dev/null +++ b/drivers/gpu/drm/i2c/anx78xx/Makefile @@ -0,0 +1,4 @@ +obj-${CONFIG_DRM_I2C_ANX78XX} := anx78xx.o + +anx78xx-y := slimport.o +anx78xx-y += slimport_tx_drv.o diff --git a/drivers/gpu/drm/i2c/anx78xx/slimport.c b/drivers/gpu/drm/i2c/anx78xx/slimport.c new file mode 100644 index 0000000..287562e --- /dev/null +++ b/drivers/gpu/drm/i2c/anx78xx/slimport.c @@ -0,0 +1,301 @@ +/* + * Copyright(c) 2015, Analogix Semiconductor. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 "slimport.h" +#include "slimport_tx_drv.h" + +/* HDCP switch for external block */ +/* external_block_en = 1: enable, 0: disable */ +int external_block_en = 1; + +struct i2c_client *anx78xx_client; + +int sp_read_reg_byte(uint8_t slave_addr, uint8_t offset) +{ + int ret = 0; + struct device *dev = &anx78xx_client->dev; + + anx78xx_client->addr = (slave_addr >> 1); + ret = i2c_smbus_read_byte_data(anx78xx_client, offset); + if (ret < 0) { + dev_err(dev, "%s: failed to read i2c addr=%x\n", LOG_TAG, + slave_addr); + return ret; + } + return 0; +} + +int sp_read_reg(uint8_t slave_addr, uint8_t offset, uint8_t *buf) +{ + int ret = 0; + struct device *dev = &anx78xx_client->dev; + + anx78xx_client->addr = (slave_addr >> 1); + ret = i2c_smbus_read_byte_data(anx78xx_client, offset); + if (ret < 0) { + dev_err(dev, "%s: failed to read i2c addr=%x\n", LOG_TAG, + slave_addr); + return ret; + } + *buf = (uint8_t) ret; + + return 0; +} + +int sp_write_reg(uint8_t slave_addr, uint8_t offset, uint8_t value) +{ + int ret = 0; + struct device *dev = &anx78xx_client->dev; + + anx78xx_client->addr = (slave_addr >> 1); + ret = i2c_smbus_write_byte_data(anx78xx_client, offset, value); + if (ret < 0) { + dev_err(dev, "%s: failed to write i2c addr=%x\n", LOG_TAG, + slave_addr); + } + return ret; +} + +void sp_tx_hardware_poweron(struct anx78xx_data *data) +{ + struct device *dev = &data->client->dev; + struct anx78xx_platform_data *pdata = data->pdata; + + gpiod_set_value_cansleep(pdata->gpiod_reset, 0); + usleep_range(1000, 2000); + + gpiod_set_value_cansleep(pdata->gpiod_pd, 0); + usleep_range(1000, 2000); + + gpiod_set_value_cansleep(pdata->gpiod_reset, 1); + + dev_info(dev, "%s: anx78xx power on\n", LOG_TAG); +} + +void sp_tx_hardware_powerdown(struct anx78xx_data *data) +{ + struct device *dev = &data->client->dev; + struct anx78xx_platform_data *pdata = data->pdata; + + gpiod_set_value_cansleep(pdata->gpiod_reset, 0); + usleep_range(1000, 2000); + + gpiod_set_value_cansleep(pdata->gpiod_pd, 1); + usleep_range(1000, 2000); + + dev_info(dev, "%s: anx78xx power down\n", LOG_TAG); +} + +static int anx78xx_init_gpio(struct anx78xx_data *data) +{ + struct device *dev = &data->client->dev; + struct anx78xx_platform_data *pdata = data->pdata; + int ret; + + /* gpio for chip power down */ + pdata->gpiod_pd = devm_gpiod_get(dev, "pd", GPIOD_OUT_HIGH); + if (IS_ERR(pdata->gpiod_pd)) { + dev_err(dev, "unable to claim pd gpio\n"); + ret = PTR_ERR(pdata->gpiod_pd); + return ret; + } + + /* gpio for chip reset */ + pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(pdata->gpiod_reset)) { + dev_err(dev, "unable to claim reset gpio\n"); + ret = PTR_ERR(pdata->gpiod_reset); + return ret; + } + + return 0; +} + +static int anx78xx_system_init(struct anx78xx_data *data) +{ + struct device *dev = &data->client->dev; + + int ret = 0; + + ret = slimport_chip_detect(data); + if (ret == 0) { + sp_tx_hardware_powerdown(data); + dev_err(dev, "failed to detect anx78xx\n"); + return -ENODEV; + } + + sp_tx_variable_init(); + return 0; +} + +static void anx78xx_work_func(struct work_struct *work) +{ + struct anx78xx_data *data = container_of(work, struct anx78xx_data, + work.work); + int workqueu_timer = 0; + + if (sp_tx_cur_states() >= STATE_PLAY_BACK) + workqueu_timer = 500; + else + workqueu_timer = 100; + mutex_lock(&data->lock); + slimport_main_process(data); + mutex_unlock(&data->lock); + queue_delayed_work(data->workqueue, &data->work, + msecs_to_jiffies(workqueu_timer)); +} + +static int anx78xx_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct anx78xx_data *data; + struct anx78xx_platform_data *pdata; + int ret = 0; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_I2C_BLOCK)) { + dev_err(&client->dev, "i2c bus does not support the device\n"); + return -ENODEV; + } + + data = devm_kzalloc(&client->dev, + sizeof(struct anx78xx_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + pdata = devm_kzalloc(&client->dev, + sizeof(struct anx78xx_platform_data), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + data->pdata = pdata; + + data->client = client; + anx78xx_client = client; + + mutex_init(&data->lock); + + ret = anx78xx_init_gpio(data); + if (ret) { + dev_err(&client->dev, "failed to initialize gpios\n"); + return ret; + } + + INIT_DELAYED_WORK(&data->work, anx78xx_work_func); + + data->workqueue = create_singlethread_workqueue("anx78xx_work"); + if (data->workqueue == NULL) { + dev_err(&client->dev, "failed to create work queue\n"); + return -ENOMEM; + } + + ret = anx78xx_system_init(data); + if (ret) { + dev_err(&client->dev, "failed to initialize anx78xx\n"); + goto cleanup; + } + + i2c_set_clientdata(client, data); + + /* enable driver */ + queue_delayed_work(data->workqueue, &data->work, 0); + + return 0; + +cleanup: + destroy_workqueue(data->workqueue); + return ret; +} + +static int anx78xx_i2c_remove(struct i2c_client *client) +{ + struct anx78xx_data *data = i2c_get_clientdata(client); + + destroy_workqueue(data->workqueue); + + return 0; +} + +static int anx78xx_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct anx78xx_data *data = i2c_get_clientdata(client); + + dev_info(&client->dev, "suspend\n"); + cancel_delayed_work_sync(&data->work); + flush_workqueue(data->workqueue); + sp_tx_hardware_powerdown(data); + sp_tx_clean_state_machine(); + + return 0; +} + +static int anx78xx_i2c_resume(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct anx78xx_data *anx78xx = i2c_get_clientdata(client); + + dev_info(&client->dev, "resume\n"); + queue_delayed_work(anx78xx->workqueue, &anx78xx->work, 0); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(anx78xx_i2c_pm_ops, + anx78xx_i2c_suspend, anx78xx_i2c_resume); + +static const struct i2c_device_id anx78xx_id[] = { + {"anx7814", 0}, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(i2c, anx78xx_id); + +static const struct of_device_id anx_match_table[] = { + {.compatible = "analogix,anx7814",}, + { /* sentinel */ }, +}; + +MODULE_DEVICE_TABLE(of, anx_match_table); + +static struct i2c_driver anx78xx_driver = { + .driver = { + .name = "anx7814", + .pm = &anx78xx_i2c_pm_ops, + .of_match_table = of_match_ptr(anx_match_table), + }, + .probe = anx78xx_i2c_probe, + .remove = anx78xx_i2c_remove, + .id_table = anx78xx_id, +}; + +module_i2c_driver(anx78xx_driver); + +MODULE_DESCRIPTION("Slimport transmitter ANX78XX driver"); +MODULE_AUTHOR("Junhua Xia "); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("1.1"); diff --git a/drivers/gpu/drm/i2c/anx78xx/slimport.h b/drivers/gpu/drm/i2c/anx78xx/slimport.h new file mode 100644 index 0000000..c7cb008 --- /dev/null +++ b/drivers/gpu/drm/i2c/anx78xx/slimport.h @@ -0,0 +1,49 @@ +/* + * Copyright(c) 2015, Analogix Semiconductor. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 _SLIMPORT_H +#define _SLIMPORT_H + +#include +#include +#include +#include +#include + +#define AUX_ERR 1 +#define AUX_OK 0 + +#define LOG_TAG "SlimPort ANX78XX" + +struct anx78xx_platform_data { + struct gpio_desc *gpiod_pd; + struct gpio_desc *gpiod_reset; + spinlock_t lock; +}; + +struct anx78xx_data { + struct i2c_client *client; + struct anx78xx_platform_data *pdata; + struct delayed_work work; + struct workqueue_struct *workqueue; + struct mutex lock; +}; + +int sp_read_reg(uint8_t slave_addr, uint8_t offset, uint8_t *buf); +int sp_write_reg(uint8_t slave_addr, uint8_t offset, uint8_t value); + +void sp_tx_hardware_poweron(struct anx78xx_data *data); +void sp_tx_hardware_powerdown(struct anx78xx_data *data); + +#endif diff --git a/drivers/gpu/drm/i2c/anx78xx/slimport_tx_drv.c b/drivers/gpu/drm/i2c/anx78xx/slimport_tx_drv.c new file mode 100644 index 0000000..40d7d4a --- /dev/null +++ b/drivers/gpu/drm/i2c/anx78xx/slimport_tx_drv.c @@ -0,0 +1,3335 @@ +/* + * Copyright(c) 2015, Analogix Semiconductor. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 "slimport.h" +#include "slimport_tx_drv.h" + +#define XTAL_CLK_M10 pxtal_data[XTAL_27M].xtal_clk_m10 +#define XTAL_CLK pxtal_data[XTAL_27M].xtal_clk + +static u8 sp_tx_test_bw; +static bool sp_tx_test_lt; +static bool sp_tx_test_edid; + +static u8 g_changed_bandwidth; +static u8 g_hdmi_dvi_status; + +static u8 g_need_clean_status; + +static u8 ds_vid_stb_cntr; +static u8 hdcp_fail_count; + +u8 g_edid_break; +u8 g_edid_checksum; +u8 edid_blocks[256]; +static u8 g_read_edid_flag; + +static struct packet_avi sp_tx_packet_avi; +static struct packet_spd sp_tx_packet_spd; +static struct packet_mpeg sp_tx_packet_mpeg; +static struct audio_info_frame sp_tx_audioinfoframe; + +enum sp_tx_state sp_tx_system_state; + +enum audio_output_status sp_tx_ao_state; +enum video_output_status sp_tx_vo_state; +enum sink_connection_status sp_tx_sc_state; +enum sp_tx_lt_status sp_tx_lt_state; +enum sp_tx_state sp_tx_system_state_bak; +enum hdcp_status hcdp_state; + +const uint chipid_list[] = { + 0x7818, + 0x7816, + 0x7814, + 0x7812, + 0x7810, + 0x7806, + 0x7802 +}; + +struct common_int common_int_status; +struct hdmi_rx_int hdmi_rx_int_status; + +static u8 down_sample_en; + +static u8 sp_i2c_read_byte(u8 dev, u8 offset); +static void hdmi_rx_new_vsi_int(void); + +static void reg_bit_ctl(u8 addr, u8 offset, u8 data, bool enable) +{ + u8 c; + + sp_read_reg(addr, offset, &c); + if (enable) { + if ((c & data) != data) { + c |= data; + sp_write_reg(addr, offset, c); + } + } else + if ((c & data) == data) { + c &= ~data; + sp_write_reg(addr, offset, c); + } +} + +static inline void sp_write_reg_or(u8 address, u8 offset, u8 mask) +{ + sp_write_reg(address, offset, + sp_i2c_read_byte(address, offset) | mask); +} + +static inline void sp_write_reg_and(u8 address, u8 offset, u8 mask) +{ + sp_write_reg(address, offset, + sp_i2c_read_byte(address, offset) & mask); +} + +static inline void sp_write_reg_and_or(u8 address, u8 offset, + u8 and_mask, u8 or_mask) +{ + sp_write_reg(address, offset, + (sp_i2c_read_byte(address, offset) & and_mask) | or_mask); +} + +static inline void sp_write_reg_or_and(u8 address, u8 offset, + u8 or_mask, u8 and_mask) +{ + sp_write_reg(address, offset, + (sp_i2c_read_byte(address, offset) | or_mask) & and_mask); +} + +static inline void sp_tx_video_mute(bool enable) +{ + reg_bit_ctl(TX_P2, VID_CTRL1, VIDEO_MUTE, enable); +} + +static inline void hdmi_rx_mute_audio(bool enable) +{ + reg_bit_ctl(RX_P0, RX_MUTE_CTRL, AUD_MUTE, enable); +} + +static inline void hdmi_rx_mute_video(bool enable) +{ + reg_bit_ctl(RX_P0, RX_MUTE_CTRL, VID_MUTE, enable); +} + +static inline void sp_tx_addronly_set(bool enable) +{ + reg_bit_ctl(TX_P0, AUX_CTRL2, ADDR_ONLY_BIT, enable); +} + +static inline void sp_tx_set_link_bw(u8 bw) +{ + sp_write_reg(TX_P0, SP_TX_LINK_BW_SET_REG, bw); +} + + +static inline u8 sp_tx_get_link_bw(void) +{ + return sp_i2c_read_byte(TX_P0, SP_TX_LINK_BW_SET_REG); +} + +static inline bool sp_tx_get_pll_lock_status(void) +{ + u8 temp; + + temp = sp_i2c_read_byte(TX_P0, TX_DEBUG1); + + return (temp & DEBUG_PLL_LOCK) != 0 ? 1 : 0; +} + +static inline void gen_m_clk_with_downspeading(void) +{ + sp_write_reg_or(TX_P0, SP_TX_M_CALCU_CTRL, M_GEN_CLK_SEL); +} + +static inline void gen_m_clk_without_downspeading(void) +{ + sp_write_reg_and(TX_P0, SP_TX_M_CALCU_CTRL, (~M_GEN_CLK_SEL)); +} + +static inline void hdmi_rx_set_hpd(bool enable) +{ + if (enable) + sp_write_reg_or(TX_P2, SP_TX_VID_CTRL3_REG, HPD_OUT); + else + sp_write_reg_and(TX_P2, SP_TX_VID_CTRL3_REG, ~HPD_OUT); +} + +static inline void hdmi_rx_set_termination(bool enable) +{ + if (enable) + sp_write_reg_and(RX_P0, HDMI_RX_TMDS_CTRL_REG7, ~TERM_PD); + else + sp_write_reg_or(RX_P0, HDMI_RX_TMDS_CTRL_REG7, TERM_PD); +} + +static inline void sp_tx_clean_hdcp_status(void) +{ + sp_write_reg(TX_P0, TX_HDCP_CTRL0, 0x03); + sp_write_reg_or(TX_P0, TX_HDCP_CTRL0, RE_AUTH); + usleep_range(2000, 4000); + pr_info("%s %s : sp_tx_clean_hdcp_status\n", LOG_TAG, __func__); +} + +static inline void sp_tx_link_phy_initialization(void) +{ + sp_write_reg(TX_P2, SP_TX_ANALOG_CTRL0, 0x02); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG0, 0x01); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG10, 0x00); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG1, 0x03); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG11, 0x00); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG2, 0x07); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG12, 0x00); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG3, 0x7f); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG13, 0x00); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG4, 0x71); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG14, 0x0c); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG5, 0x6b); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG15, 0x42); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG6, 0x7f); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG16, 0x1e); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG7, 0x73); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG17, 0x3e); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG8, 0x7f); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG18, 0x72); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG9, 0x7F); + sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG19, 0x7e); +} + +static inline void sp_tx_set_sys_state(u8 ss) +{ + pr_info("%s %s : set: clean_status: %x,\n ", + LOG_TAG, __func__, (uint)g_need_clean_status); + + if ((sp_tx_system_state >= STATE_LINK_TRAINING) + && (ss < STATE_LINK_TRAINING)) + sp_write_reg_or(TX_P0, SP_TX_ANALOG_PD_REG, CH0_PD); + + sp_tx_system_state_bak = sp_tx_system_state; + sp_tx_system_state = ss; + g_need_clean_status = 1; + print_sys_state(sp_tx_system_state); +} + +static inline void reg_hardware_reset(void) +{ + sp_write_reg_or(TX_P2, SP_TX_RST_CTRL_REG, HW_RST); + sp_tx_clean_state_machine(); + sp_tx_set_sys_state(STATE_SP_INITIALIZED); + msleep(500); +} + +static inline void write_dpcd_addr(u8 addrh, u8 addrm, u8 addrl) +{ + u8 temp; + + if (sp_i2c_read_byte(TX_P0, AUX_ADDR_7_0) != addrl) + sp_write_reg(TX_P0, AUX_ADDR_7_0, addrl); + + if (sp_i2c_read_byte(TX_P0, AUX_ADDR_15_8) != addrm) + sp_write_reg(TX_P0, AUX_ADDR_15_8, addrm); + + sp_read_reg(TX_P0, AUX_ADDR_19_16, &temp); + + if ((temp & 0x0F) != (addrh & 0x0F)) + sp_write_reg(TX_P0, AUX_ADDR_19_16, (temp & 0xF0) | addrh); +} + +static inline void goto_next_system_state(void) +{ + pr_info("%s %s : next: clean_status: %x,\n ", + LOG_TAG, __func__, (uint)g_need_clean_status); + + sp_tx_system_state_bak = sp_tx_system_state; + sp_tx_system_state++; + print_sys_state(sp_tx_system_state); +} + +static inline void redo_cur_system_state(void) +{ + pr_info("%s %s : redo: clean_status: %x,\n ", + LOG_TAG, __func__, (uint)g_need_clean_status); + + g_need_clean_status = 1; + sp_tx_system_state_bak = sp_tx_system_state; + print_sys_state(sp_tx_system_state); +} + +static inline void system_state_change_with_case(u8 status) +{ + if (sp_tx_system_state >= status) { + pr_info("%s %s : change_case: clean_status: %xm,\n ", + LOG_TAG, __func__, (uint)g_need_clean_status); + + if ((sp_tx_system_state >= STATE_LINK_TRAINING) + && (status < STATE_LINK_TRAINING)) + sp_write_reg_or(TX_P0, SP_TX_ANALOG_PD_REG, CH0_PD); + + g_need_clean_status = 1; + sp_tx_system_state_bak = sp_tx_system_state; + sp_tx_system_state = status; + print_sys_state(sp_tx_system_state); + } +} + +static unsigned char sp_i2c_read_byte(unsigned char dev, unsigned char offset) +{ + unsigned char temp; + + sp_read_reg(dev, offset, &temp); + return temp; +} + +static void hardware_power_ctl(struct anx78xx_data *data, u8 enable) +{ + if (enable == 0) + sp_tx_hardware_powerdown(data); + else + sp_tx_hardware_poweron(data); +} + +void wait_aux_op_finish(u8 *err_flag) +{ + u8 cnt; + u8 c; + + *err_flag = 0; + cnt = 150; + while (sp_i2c_read_byte(TX_P0, AUX_CTRL2) & AUX_OP_EN) { + usleep_range(2000, 4000); + if ((cnt--) == 0) { + pr_info("%s %s :aux operate failed!\n", + LOG_TAG, __func__); + *err_flag = 1; + break; + } + } + + sp_read_reg(TX_P0, SP_TX_AUX_STATUS, &c); + if (c & 0x0F) { + pr_info("%s %s : wait aux operation status %.2x\n", + LOG_TAG, __func__, (uint)c); + *err_flag = 1; + } +} + +void print_sys_state(u8 ss) +{ + switch (ss) { + case STATE_WAITTING_CABLE_PLUG: + pr_info("%s %s : -STATE_WAITTING_CABLE_PLUG-\n", + LOG_TAG, __func__); + break; + case STATE_SP_INITIALIZED: + pr_info("%s %s : -STATE_SP_INITIALIZED-\n", LOG_TAG, __func__); + break; + case STATE_SINK_CONNECTION: + pr_info("%s %s : -STATE_SINK_CONNECTION-\n", LOG_TAG, __func__); + break; + case STATE_PARSE_EDID: + pr_info("%s %s : -STATE_PARSE_EDID-\n", LOG_TAG, __func__); + break; + case STATE_LINK_TRAINING: + pr_info("%s %s : -STATE_LINK_TRAINING-\n", LOG_TAG, __func__); + break; + case STATE_VIDEO_OUTPUT: + pr_info("%s %s : -STATE_VIDEO_OUTPUT-\n", LOG_TAG, __func__); + break; + case STATE_HDCP_AUTH: + pr_info("%s %s : -STATE_HDCP_AUTH-\n", LOG_TAG, __func__); + break; + case STATE_AUDIO_OUTPUT: + pr_info("%s %s : -STATE_AUDIO_OUTPUT-\n", LOG_TAG, __func__); + break; + case STATE_PLAY_BACK: + pr_info("%s %s : -STATE_PLAY_BACK-\n", LOG_TAG, __func__); + break; + default: + pr_err("%s %s : system state is error1\n", LOG_TAG, __func__); + break; + } +} + +void sp_tx_rst_aux(void) +{ + sp_write_reg_or(TX_P2, RST_CTRL2, AUX_RST); + sp_write_reg_and(TX_P2, RST_CTRL2, ~AUX_RST); +} + +u8 sp_tx_aux_dpcdread_bytes(u8 addrh, u8 addrm, + u8 addrl, u8 ccount, u8 *pbuf) +{ + u8 c, c1, i; + u8 bok; + + sp_write_reg(TX_P0, BUF_DATA_COUNT, 0x80); + c = ((ccount - 1) << 4) | 0x09; + sp_write_reg(TX_P0, AUX_CTRL, c); + write_dpcd_addr(addrh, addrm, addrl); + sp_write_reg_or(TX_P0, AUX_CTRL2, AUX_OP_EN); + usleep_range(2000, 4000); + + wait_aux_op_finish(&bok); + if (bok == AUX_ERR) { + pr_err("%s %s : aux read failed\n", LOG_TAG, __func__); + sp_read_reg(TX_P2, SP_TX_INT_STATUS1, &c); + sp_read_reg(TX_P0, TX_DEBUG1, &c1); + if (c1 & POLLING_EN) { + if (c & POLLING_ERR) + sp_tx_rst_aux(); + } else + sp_tx_rst_aux(); + return AUX_ERR; + } + + for (i = 0; i < ccount; i++) { + sp_read_reg(TX_P0, BUF_DATA_0 + i, &c); + *(pbuf + i) = c; + if (i >= MAX_BUF_CNT) + break; + } + return AUX_OK; +} + +u8 sp_tx_aux_dpcdwrite_bytes(u8 addrh, u8 addrm, + u8 addrl, u8 ccount, u8 *pbuf) +{ + u8 c, i, ret; + + c = ((ccount - 1) << 4) | 0x08; + sp_write_reg(TX_P0, AUX_CTRL, c); + write_dpcd_addr(addrh, addrm, addrl); + for (i = 0; i < ccount; i++) { + c = *pbuf; + pbuf++; + sp_write_reg(TX_P0, BUF_DATA_0 + i, c); + + if (i >= 15) + break; + } + sp_write_reg_or(TX_P0, AUX_CTRL2, AUX_OP_EN); + wait_aux_op_finish(&ret); + return ret; +} + +u8 sp_tx_aux_dpcdwrite_byte(u8 addrh, u8 addrm, + u8 addrl, u8 data1) +{ + u8 ret; + + sp_write_reg(TX_P0, AUX_CTRL, 0x08); + write_dpcd_addr(addrh, addrm, addrl); + sp_write_reg(TX_P0, BUF_DATA_0, data1); + sp_write_reg_or(TX_P0, AUX_CTRL2, AUX_OP_EN); + wait_aux_op_finish(&ret); + return ret; +} + +void slimport_block_power_ctrl(enum sp_tx_power_block sp_tx_pd_block, + u8 power) +{ + if (power == SP_POWER_ON) + sp_write_reg_and(TX_P2, SP_POWERD_CTRL_REG, (~sp_tx_pd_block)); + else + sp_write_reg_or(TX_P2, SP_POWERD_CTRL_REG, (sp_tx_pd_block)); + pr_info("%s %s : sp_tx_power_on: %.2x\n", + LOG_TAG, __func__, (uint)sp_tx_pd_block); +} + +void vbus_power_ctrl(unsigned char on) +{ + u8 i; + + if (on == 0) { + sp_write_reg_and(TX_P2, TX_PLL_FILTER, ~V33_SWITCH_ON); + sp_write_reg_or(TX_P2, TX_PLL_FILTER5, + P5V_PROTECT_PD | SHORT_PROTECT_PD); + pr_info("%s %s : 3.3V output disabled\n", LOG_TAG, __func__); + } else { + for (i = 0; i < 5; i++) { + sp_write_reg_and(TX_P2, TX_PLL_FILTER5, + (~P5V_PROTECT_PD & ~SHORT_PROTECT_PD)); + sp_write_reg_or(TX_P2, TX_PLL_FILTER, V33_SWITCH_ON); + if (!((u8)sp_i2c_read_byte(TX_P2, TX_PLL_FILTER5) + & 0xc0)) { + pr_info("%s %s : 3.3V output enabled\n", + LOG_TAG, __func__); + break; + } + + pr_info("%s %s : VBUS power can not be supplied\n", + LOG_TAG, __func__); + } + } +} + +void sp_tx_clean_state_machine(void) +{ + sp_tx_system_state = STATE_WAITTING_CABLE_PLUG; + sp_tx_system_state_bak = STATE_WAITTING_CABLE_PLUG; + sp_tx_sc_state = SC_INIT; + sp_tx_lt_state = LT_INIT; + hcdp_state = HDCP_CAPABLE_CHECK; + sp_tx_vo_state = VO_WAIT_VIDEO_STABLE; + sp_tx_ao_state = AO_INIT; +} + +u8 sp_tx_cur_states(void) +{ + return sp_tx_system_state; +} + +u8 sp_tx_cur_bw(void) +{ + return g_changed_bandwidth; +} + +void sp_tx_set_bw(u8 bw) +{ + g_changed_bandwidth = bw; +} + +void sp_tx_variable_init(void) +{ + uint i; + + sp_tx_system_state = STATE_WAITTING_CABLE_PLUG; + sp_tx_system_state_bak = STATE_WAITTING_CABLE_PLUG; + + g_edid_break = 0; + g_read_edid_flag = 0; + g_edid_checksum = 0; + for (i = 0; i < 256; i++) + edid_blocks[i] = 0; + + sp_tx_lt_state = LT_INIT; + hcdp_state = HDCP_CAPABLE_CHECK; + g_need_clean_status = 0; + sp_tx_sc_state = SC_INIT; + sp_tx_vo_state = VO_WAIT_VIDEO_STABLE; + sp_tx_ao_state = AO_INIT; + g_changed_bandwidth = LINK_5P4G; + g_hdmi_dvi_status = HDMI_MODE; + + sp_tx_test_lt = 0; + sp_tx_test_bw = 0; + sp_tx_test_edid = 0; + + ds_vid_stb_cntr = 0; + hdcp_fail_count = 0; + +} + +static void hdmi_rx_tmds_phy_initialization(void) +{ + sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG2, 0xa9); + sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG7, 0x80); + + sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG1, 0x90); + sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG6, 0x92); + sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG20, 0xf2); +} + +void hdmi_rx_initialization(void) +{ + sp_write_reg(RX_P0, RX_MUTE_CTRL, AUD_MUTE | VID_MUTE); + sp_write_reg_or(RX_P0, RX_CHIP_CTRL, + MAN_HDMI5V_DET | PLLLOCK_CKDT_EN | DIGITAL_CKDT_EN); + + sp_write_reg_or(RX_P0, RX_SRST, HDCP_MAN_RST | SW_MAN_RST | + TMDS_RST | VIDEO_RST); + sp_write_reg_and(RX_P0, RX_SRST, (~HDCP_MAN_RST) & (~SW_MAN_RST) & + (~TMDS_RST) & (~VIDEO_RST)); + + sp_write_reg_or(RX_P0, RX_AEC_EN0, AEC_EN06 | AEC_EN05); + sp_write_reg_or(RX_P0, RX_AEC_EN2, AEC_EN21); + sp_write_reg_or(RX_P0, RX_AEC_CTRL, AVC_EN | AAC_OE | AAC_EN); + + sp_write_reg_and(RX_P0, RX_SYS_PWDN1, ~PWDN_CTRL); + + sp_write_reg_or(RX_P0, RX_VID_DATA_RNG, R2Y_INPUT_LIMIT); + sp_write_reg(RX_P0, 0x65, 0xc4); + sp_write_reg(RX_P0, 0x66, 0x18); + + sp_write_reg(TX_P0, TX_EXTRA_ADDR, 0x50); /* enable DDC stretch */ + + hdmi_rx_tmds_phy_initialization(); + hdmi_rx_set_hpd(0); + hdmi_rx_set_termination(0); + pr_info("%s %s : HDMI Rx is initialized...\n", LOG_TAG, __func__); +} + +struct clock_data const pxtal_data[XTAL_CLK_NUM] = { + {19, 192}, + {24, 240}, + {25, 250}, + {26, 260}, + {27, 270}, + {38, 384}, + {52, 520}, + {27, 270}, +}; + +void xtal_clk_sel(void) +{ + pr_info("%s %s : define XTAL_CLK: %x\n ", + LOG_TAG, __func__, (uint)XTAL_27M); + sp_write_reg_and_or(TX_P2, + TX_ANALOG_DEBUG2, (~0x3c), 0x3c & (XTAL_27M << 2)); + sp_write_reg(TX_P0, 0xEC, (u8)(((uint)XTAL_CLK_M10))); + sp_write_reg(TX_P0, 0xED, + (u8)(((uint)XTAL_CLK_M10 & 0xFF00) >> 2) | XTAL_CLK); + + sp_write_reg(TX_P0, + I2C_GEN_10US_TIMER0, (u8)(((uint)XTAL_CLK_M10))); + sp_write_reg(TX_P0, I2C_GEN_10US_TIMER1, + (u8)(((uint)XTAL_CLK_M10 & 0xFF00) >> 8)); + sp_write_reg(TX_P0, 0xBF, (u8)(((uint)XTAL_CLK - 1))); + + sp_write_reg_and_or(RX_P0, 0x49, 0x07, + (u8)(((((uint)XTAL_CLK) >> 1) - 2) << 3)); + +} + +void sp_tx_initialization(void) +{ + sp_write_reg(TX_P0, AUX_CTRL2, 0x30); + sp_write_reg_or(TX_P0, AUX_CTRL2, 0x08); + + sp_write_reg_and(TX_P0, TX_HDCP_CTRL, + (u8)(~AUTO_EN) & (~AUTO_START)); + sp_write_reg(TX_P0, OTP_KEY_PROTECT1, OTP_PSW1); + sp_write_reg(TX_P0, OTP_KEY_PROTECT2, OTP_PSW2); + sp_write_reg(TX_P0, OTP_KEY_PROTECT3, OTP_PSW3); + sp_write_reg_or(TX_P0, HDCP_KEY_CMD, DISABLE_SYNC_HDCP); + sp_write_reg(TX_P2, SP_TX_VID_CTRL8_REG, VID_VRES_TH); + + sp_write_reg(TX_P0, HDCP_AUTO_TIMER, HDCP_AUTO_TIMER_VAL); + sp_write_reg_or(TX_P0, TX_HDCP_CTRL, LINK_POLLING); + + sp_write_reg_or(TX_P0, TX_LINK_DEBUG, M_VID_DEBUG); + sp_write_reg_or(TX_P2, TX_ANALOG_DEBUG2, POWERON_TIME_1P5MS); + + xtal_clk_sel(); + sp_write_reg(TX_P0, AUX_DEFER_CTRL, 0x8C); + + sp_write_reg_or(TX_P0, TX_DP_POLLING, AUTO_POLLING_DISABLE); + /* + * Short the link intergrity check timer to speed up bstatus + * polling for HDCP CTS item 1A-07 + */ + sp_write_reg(TX_P0, SP_TX_LINK_CHK_TIMER, 0x1d); + sp_write_reg_or(TX_P0, TX_MISC, EQ_TRAINING_LOOP); + + sp_write_reg_or(TX_P0, SP_TX_ANALOG_PD_REG, CH0_PD); + + sp_write_reg(TX_P2, SP_TX_INT_CTRL_REG, 0X01); + /* disable HDCP mismatch function for VGA dongle */ + sp_tx_link_phy_initialization(); + gen_m_clk_with_downspeading(); + + down_sample_en = 0; +} + +bool slimport_chip_detect(struct anx78xx_data *data) +{ + uint16_t id; + uint8_t idh = 0, idl = 0; + int i; + + hardware_power_ctl(data, 1); + + /* check chip id */ + sp_read_reg(TX_P2, SP_TX_DEV_IDL_REG, &idl); + sp_read_reg(TX_P2, SP_TX_DEV_IDH_REG, &idh); + id = idl | (idh << 8); + + pr_info("%s %s : CHIPID: ANX%x\n", LOG_TAG, __func__, id & 0xffff); + for (i = 0; i < sizeof(chipid_list) / sizeof(uint16_t); i++) { + if (id == chipid_list[i]) + return 1; + } + return 0; +} + +void slimport_waitting_cable_plug_process(struct anx78xx_data *data) +{ + sp_tx_variable_init(); + hardware_power_ctl(data, 1); + goto_next_system_state(); +} + +/* + * Check if it is ANALOGIX dongle. + */ +unsigned char ANX_OUI[3] = {0x00, 0x22, 0xB9}; + +unsigned char is_anx_dongle(void) +{ + unsigned char buf[3]; + + /* 0x0500~0x0502: BRANCH_IEEE_OUI */ + sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x00, 3, buf); + if (buf[0] == ANX_OUI[0] && buf[1] == ANX_OUI[1] + && buf[2] == ANX_OUI[2]) + return 1; + + return 0; +} + +void sp_tx_get_rx_bw(unsigned char *bw) +{ + u8 data_buf[4]; + /* + * When ANX dongle connected, if CHIP_ID = 0x7750, bandwidth is 6.75G, + * ecause ANX7750 DPCD 0x052x was not available. + */ + if (is_anx_dongle()) { + sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x03, 0x04, data_buf); + if ((data_buf[0] == 0x37) && (data_buf[1] == 0x37) + && (data_buf[2] == 0x35) && (data_buf[3] == 0x30)) + *bw = LINK_6P75G; + else + sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x21, 1, bw); + /* just for Debug */ + *bw = LINK_6P75G; + } else + sp_tx_aux_dpcdread_bytes(0x00, 0x00, DPCD_MAX_LINK_RATE, 1, bw); +} + +static u8 sp_tx_get_cable_type(enum cable_type_status det_cable_type_state) +{ + u8 ds_port_preset; + u8 aux_status; + u8 data_buf[16]; + u8 cur_cable_type; + + ds_port_preset = 0; + cur_cable_type = DWN_STRM_IS_NULL; + + aux_status = + sp_tx_aux_dpcdread_bytes(0x00, 0x00, 0x05, 1, &ds_port_preset); + pr_info("%s %s : DPCD 0x005: %x\n", + LOG_TAG, __func__, (int)ds_port_preset); + + switch (det_cable_type_state) { + case CHECK_AUXCH: + if (AUX_OK == aux_status) { + sp_tx_aux_dpcdread_bytes(0x00, 0x00, 0, 0x0c, data_buf); + det_cable_type_state = GETTED_CABLE_TYPE; + } else { + msleep(50); + pr_err("%s %s : AUX access error\n", + LOG_TAG, __func__); + break; + } + case GETTED_CABLE_TYPE: + switch ((ds_port_preset & (_BIT1 | _BIT2)) >> 1) { + case 0x00: + cur_cable_type = DWN_STRM_IS_DIGITAL; + pr_info("%s %s : Downstream is DP dongle.\n", + LOG_TAG, __func__); + break; + case 0x01: + case 0x03: + cur_cable_type = DWN_STRM_IS_ANALOG; + pr_info("%s %s : Downstream is VGA dongle.\n", + LOG_TAG, __func__); + break; + case 0x02: + cur_cable_type = DWN_STRM_IS_HDMI; + pr_info("%s %s : Downstream is HDMI dongle.\n", + LOG_TAG, __func__); + break; + default: + cur_cable_type = DWN_STRM_IS_NULL; + pr_err("%s %s : Downstream can not recognized.\n", + LOG_TAG, __func__); + break; + } + default: + break; + } + return cur_cable_type; +} + +u8 sp_tx_get_hdmi_connection(void) +{ + u8 c; + + if (AUX_OK != sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x18, 1, &c)) + return 0; + + if ((c & 0x41) == 0x41) + return 1; + else + return 0; + +} + +u8 sp_tx_get_vga_connection(void) +{ + u8 c; + + if (AUX_OK != + sp_tx_aux_dpcdread_bytes(0x00, 0x02, DPCD_SINK_COUNT, 1, &c)) { + pr_err("%s %s : aux error.\n", LOG_TAG, __func__); + return 0; + } + + if (c & 0x01) + return 1; + else + return 0; +} + +u8 sp_tx_get_dp_connection(void) +{ + u8 c; + + if (AUX_OK != + sp_tx_aux_dpcdread_bytes(0x00, 0x02, DPCD_SINK_COUNT, 1, &c)) + return 0; + + if (c & 0x1f) { + sp_tx_aux_dpcdread_bytes(0x00, 0x00, 0x04, 1, &c); + if (c & 0x20) { + sp_tx_aux_dpcdread_bytes(0x00, 0x06, 0x00, 1, &c); + /* + * Bit 5 = SET_DN_DEVICE_DP_PWR_5V + * Bit 6 = SET_DN_DEVICE_DP_PWR_12V + * Bit 7 = SET_DN_DEVICE_DP_PWR_18V + */ + c = c & 0x1F; + sp_tx_aux_dpcdwrite_byte(0x00, 0x06, 0x00, c | 0x20); + } + return 1; + } else + return 0; +} + +u8 sp_tx_get_downstream_connection(void) +{ + return sp_tx_get_dp_connection(); +} + +void slimport_sink_connection(void) +{ + switch (sp_tx_sc_state) { + case SC_INIT: + sp_tx_sc_state++; + case SC_CHECK_CABLE_TYPE: + case SC_WAITTING_CABLE_TYPE: + default: + if (sp_tx_get_cable_type(CHECK_AUXCH) == DWN_STRM_IS_NULL) { + sp_tx_sc_state++; + if (sp_tx_sc_state >= SC_WAITTING_CABLE_TYPE) { + sp_tx_sc_state = SC_NOT_CABLE; + pr_info("%s %s : Can not get cable type!\n", + LOG_TAG, __func__); + } + break; + } + + sp_tx_sc_state = SC_SINK_CONNECTED; + case SC_SINK_CONNECTED: + if (sp_tx_get_downstream_connection()) + goto_next_system_state(); + break; + case SC_NOT_CABLE: + vbus_power_ctrl(0); + reg_hardware_reset(); + break; + } +} + +/******************start EDID process********************/ +void sp_tx_enable_video_input(u8 enable) +{ + u8 c; + + sp_read_reg(TX_P2, VID_CTRL1, &c); + if (enable) { + if ((c & VIDEO_EN) != VIDEO_EN) { + c = (c & 0xf7) | VIDEO_EN; + sp_write_reg(TX_P2, VID_CTRL1, c); + pr_info("%s %s : Slimport Video is enabled!\n", + LOG_TAG, __func__); + } + } else { + if ((c & VIDEO_EN) == VIDEO_EN) { + c &= ~VIDEO_EN; + sp_write_reg(TX_P2, VID_CTRL1, c); + pr_info("%s %s : Slimport Video is disabled!\n", + LOG_TAG, __func__); + } + } +} + +static u8 read_dvi_hdmi_mode(void) +{ + return 1; +} + +static u8 get_edid_detail(u8 *data_buf) +{ + uint pixclock_edid; + + pixclock_edid = ((((uint)data_buf[1] << 8)) + | ((uint)data_buf[0] & 0xFF)); + if (pixclock_edid <= 5300) + return LINK_1P62G; + else if ((5300 < pixclock_edid) && (pixclock_edid <= 8900)) + return LINK_2P7G; + else if ((8900 < pixclock_edid) && (pixclock_edid <= 18000)) + return LINK_5P4G; + else + return LINK_6P75G; +} + +static u8 parse_edid_to_get_bandwidth(void) +{ + u8 desc_offset = 0; + u8 i, bandwidth, temp; + + bandwidth = LINK_1P62G; + temp = LINK_1P62G; + i = 0; + while (4 > i && 0 != edid_blocks[0x36 + desc_offset]) { + temp = get_edid_detail(edid_blocks + 0x36 + desc_offset); + pr_info("%s %s : bandwidth via EDID : %x\n", + LOG_TAG, __func__, (uint)temp); + if (bandwidth < temp) + bandwidth = temp; + if (bandwidth > LINK_5P4G) + break; + desc_offset += 0x12; + ++i; + } + return bandwidth; + +} + +static void sp_tx_aux_wr(u8 offset) +{ + sp_write_reg(TX_P0, BUF_DATA_0, offset); + sp_write_reg(TX_P0, AUX_CTRL, 0x04); + sp_write_reg_or(TX_P0, AUX_CTRL2, AUX_OP_EN); + wait_aux_op_finish(&g_edid_break); +} + +static void sp_tx_aux_rd(u8 len_cmd) +{ + sp_write_reg(TX_P0, AUX_CTRL, len_cmd); + sp_write_reg_or(TX_P0, AUX_CTRL2, AUX_OP_EN); + wait_aux_op_finish(&g_edid_break); +} + +u8 sp_tx_get_edid_block(void) +{ + u8 c; + + sp_tx_aux_wr(0x7e); + sp_tx_aux_rd(0x01); + sp_read_reg(TX_P0, BUF_DATA_0, &c); + pr_info("%s %s : EDID Block = %d\n", LOG_TAG, __func__, (int)(c + 1)); + + if (c > 3) + c = 1; + return c; +} + +void edid_read(u8 offset, u8 *pblock_buf) +{ + u8 data_cnt, cnt; + u8 c; + + sp_tx_aux_wr(offset); + sp_tx_aux_rd(0xf5); + data_cnt = 0; + cnt = 0; + + while ((data_cnt) < 16) { + sp_read_reg(TX_P0, BUF_DATA_COUNT, &c); + + if ((c & 0x1f) != 0) { + data_cnt = data_cnt + c; + do { + sp_read_reg(TX_P0, BUF_DATA_0 + c - 1, + &(pblock_buf[c - 1])); + if (c == 1) + break; + } while (c--); + } else { + if (cnt++ <= 2) { + sp_tx_rst_aux(); + c = 0x05 | ((0x0f - data_cnt) << 4); + sp_tx_aux_rd(c); + } else { + g_edid_break = 1; + break; + } + } + } + sp_write_reg(TX_P0, AUX_CTRL, 0x01); + sp_write_reg_or(TX_P0, AUX_CTRL2, ADDR_ONLY_BIT | AUX_OP_EN); + wait_aux_op_finish(&g_edid_break); + sp_tx_addronly_set(0); +} + +void sp_tx_edid_read_initial(void) +{ + sp_write_reg(TX_P0, AUX_ADDR_7_0, 0x50); + sp_write_reg(TX_P0, AUX_ADDR_15_8, 0); + sp_write_reg_and(TX_P0, AUX_ADDR_19_16, 0xf0); +} + +static void segments_edid_read(u8 segment, u8 offset) +{ + u8 c, cnt; + int i; + + sp_write_reg(TX_P0, AUX_CTRL, 0x04); + + sp_write_reg(TX_P0, AUX_ADDR_7_0, 0x30); + + sp_write_reg_or(TX_P0, AUX_CTRL2, ADDR_ONLY_BIT | AUX_OP_EN); + + sp_read_reg(TX_P0, AUX_CTRL2, &c); + + wait_aux_op_finish(&g_edid_break); + sp_read_reg(TX_P0, AUX_CTRL, &c); + + sp_write_reg(TX_P0, BUF_DATA_0, segment); + + sp_write_reg(TX_P0, AUX_CTRL, 0x04); + + sp_write_reg_and_or(TX_P0, AUX_CTRL2, ~ADDR_ONLY_BIT, AUX_OP_EN); + cnt = 0; + sp_read_reg(TX_P0, AUX_CTRL2, &c); + while (c & AUX_OP_EN) { + usleep_range(1000, 2000); + cnt++; + if (cnt == 10) { + pr_info("%s %s : write break", LOG_TAG, __func__); + sp_tx_rst_aux(); + cnt = 0; + g_edid_break = 1; + return; + } + sp_read_reg(TX_P0, AUX_CTRL2, &c); + + } + + sp_write_reg(TX_P0, AUX_ADDR_7_0, 0x50); + + sp_tx_aux_wr(offset); + + sp_tx_aux_rd(0xf5); + cnt = 0; + for (i = 0; i < 16; i++) { + sp_read_reg(TX_P0, BUF_DATA_COUNT, &c); + while ((c & 0x1f) == 0) { + usleep_range(2000, 4000); + cnt++; + sp_read_reg(TX_P0, BUF_DATA_COUNT, &c); + if (cnt == 10) { + pr_info("%s %s : read break", + LOG_TAG, __func__); + sp_tx_rst_aux(); + g_edid_break = 1; + return; + } + } + + + sp_read_reg(TX_P0, BUF_DATA_0+i, &c); + } + + sp_write_reg(TX_P0, AUX_CTRL, 0x01); + sp_write_reg_or(TX_P0, AUX_CTRL2, ADDR_ONLY_BIT | AUX_OP_EN); + sp_write_reg_and(TX_P0, AUX_CTRL2, ~ADDR_ONLY_BIT); + sp_read_reg(TX_P0, AUX_CTRL2, &c); + while (c & AUX_OP_EN) + sp_read_reg(TX_P0, AUX_CTRL2, &c); +} + +static bool edid_checksum_result(u8 *pbuf) +{ + u8 cnt, checksum; + + checksum = 0; + + for (cnt = 0; cnt < 0x80; cnt++) + checksum = checksum + pbuf[cnt]; + + g_edid_checksum = checksum - pbuf[0x7f]; + g_edid_checksum = ~g_edid_checksum + 1; + + return checksum == 0 ? 1 : 0; +} + +static void edid_header_result(u8 *pbuf) +{ + if ((pbuf[0] == 0) && (pbuf[7] == 0) && (pbuf[1] == 0xff) + && (pbuf[2] == 0xff) && (pbuf[3] == 0xff) + && (pbuf[4] == 0xff) && (pbuf[5] == 0xff) && (pbuf[6] == 0xff)) + pr_info("%s %s : Good EDID header!\n", LOG_TAG, __func__); + else + pr_err("%s %s : Bad EDID header!\n", LOG_TAG, __func__); + +} + +void check_edid_data(u8 *pblock_buf) +{ + u8 i; + + edid_header_result(pblock_buf); + for (i = 0; i <= ((pblock_buf[0x7e] > 1) ? 1 : pblock_buf[0x7e]); i++) { + if (!edid_checksum_result(pblock_buf + i * 128)) + pr_err("%s %s : Block %x edid checksum error\n", + LOG_TAG, __func__, (uint)i); + else + pr_info("%s %s : Block %x edid checksum OK\n", + LOG_TAG, __func__, (uint)i); + } +} + +bool sp_tx_edid_read(u8 *pedid_blocks_buf) +{ + u8 offset = 0; + u8 count, blocks_num; + u8 pblock_buf[16]; + u8 i, j, c; + + g_edid_break = 0; + sp_tx_edid_read_initial(); + sp_write_reg(TX_P0, AUX_CTRL, 0x04); + sp_write_reg_or(TX_P0, AUX_CTRL2, 0x03); + wait_aux_op_finish(&g_edid_break); + sp_tx_addronly_set(0); + + blocks_num = sp_tx_get_edid_block(); + + count = 0; + do { + switch (count) { + case 0: + case 1: + for (i = 0; i < 8; i++) { + offset = (i + count * 8) * 16; + edid_read(offset, pblock_buf); + if (g_edid_break == 1) + break; + for (j = 0; j < 16; j++) { + pedid_blocks_buf[offset + j] + = pblock_buf[j]; + } + } + break; + case 2: + offset = 0x00; + for (j = 0; j < 8; j++) { + if (g_edid_break == 1) + break; + segments_edid_read(count / 2, offset); + offset = offset + 0x10; + } + break; + case 3: + offset = 0x80; + for (j = 0; j < 8; j++) { + if (g_edid_break == 1) + break; + segments_edid_read(count / 2, offset); + offset = offset + 0x10; + } + break; + default: + break; + } + count++; + if (g_edid_break == 1) + break; + } while (blocks_num >= count); + + sp_tx_rst_aux(); + if (g_read_edid_flag == 0) { + check_edid_data(pedid_blocks_buf); + g_read_edid_flag = 1; + } + sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x18, 1, &c); + if (c & 0x04) { + pr_info("%s %s : check sum = %.2x\n", + LOG_TAG, __func__, (uint)g_edid_checksum); + c = g_edid_checksum; + sp_tx_aux_dpcdwrite_bytes(0x00, 0x02, 0x61, 1, &c); + sp_tx_test_edid = 1; + c = 0x04; + sp_tx_aux_dpcdwrite_bytes(0x00, 0x02, 0x60, 1, &c); + pr_info("%s %s : Test EDID done\n", LOG_TAG, __func__); + + } + + return 0; +} + +static bool check_with_pre_edid(u8 *org_buf) +{ + u8 i; + u8 temp_buf[16]; + bool return_flag; + + return_flag = 0; + g_edid_break = 0; + sp_tx_edid_read_initial(); + sp_write_reg(TX_P0, AUX_CTRL, 0x04); + sp_write_reg_or(TX_P0, AUX_CTRL2, 0x03); + wait_aux_op_finish(&g_edid_break); + sp_tx_addronly_set(0); + + edid_read(0x70, temp_buf); + + if (g_edid_break == 0) { + + for (i = 0; i < 16; i++) { + if (org_buf[0x70 + i] != temp_buf[i]) { + pr_info("%s %s : %s\n", LOG_TAG, __func__, + "different checksum and blocks num\n"); + return_flag = 1; + break; + } + } + } else + return_flag = 1; + + if (return_flag) + goto return_point; + + edid_read(0x08, temp_buf); + if (g_edid_break == 0) { + for (i = 0; i < 16; i++) { + if (org_buf[i + 8] != temp_buf[i]) { + pr_info("%s %s : different edid information\n", + LOG_TAG, __func__); + return_flag = 1; + break; + } + } + } else + return_flag = 1; + +return_point: + sp_tx_rst_aux(); + return return_flag; +} + +void slimport_edid_process(void) +{ + u8 temp_value, temp_value1; + u8 i; + + pr_info("%s %s : edid_process\n", LOG_TAG, __func__); + + if (g_read_edid_flag == 1) { + if (check_with_pre_edid(edid_blocks)) + g_read_edid_flag = 0; + else + pr_info("%s %s : Don`t need to read edid!\n", + LOG_TAG, __func__); + } + + if (g_read_edid_flag == 0) { + sp_tx_edid_read(edid_blocks); + if (g_edid_break) + pr_err("%s %s : ERR:EDID corruption!\n", + LOG_TAG, __func__); + } + + + /* Release the HPD after the OTP loaddown */ + i = 10; + do { + if ((sp_i2c_read_byte(TX_P0, HDCP_KEY_STATUS) & 0x01)) + break; + + pr_info("%s %s : waiting HDCP KEY loaddown\n", + LOG_TAG, __func__); + usleep_range(1000, 2000); + } while (--i); + sp_write_reg(RX_P0, HDMI_RX_INT_MASK1_REG, 0xe2); + hdmi_rx_set_hpd(1); + pr_info("%s %s : hdmi_rx_set_hpd 1 !\n", LOG_TAG, __func__); + hdmi_rx_set_termination(1); + + sp_tx_get_rx_bw(&temp_value); + pr_info("%s %s : RX BW %x\n", LOG_TAG, __func__, (uint)temp_value); + temp_value1 = parse_edid_to_get_bandwidth(); + if (temp_value <= temp_value1) + temp_value1 = temp_value; + pr_info("%s %s : set link bw in edid %x\n", + LOG_TAG, __func__, (uint)temp_value1); + g_changed_bandwidth = temp_value1; + goto_next_system_state(); +} +/******************End EDID process********************/ + +/******************start Link training process********************/ +static void sp_tx_lvttl_bit_mapping(void) +{ + u8 c, colorspace; + u8 vid_bit; + + vid_bit = 0; + sp_read_reg(RX_P1, HDMI_RX_AVI_DATA00_REG, &colorspace); + colorspace &= 0x60; + + switch (((sp_i2c_read_byte(RX_P0, HDMI_RX_VIDEO_STATUS_REG1) + & COLOR_DEPTH) >> 4)) { + default: + case HDMI_LEGACY: + c = IN_BPC_8BIT; + vid_bit = 0; + break; + case HDMI_24BIT: + c = IN_BPC_8BIT; + if (colorspace == 0x20) + vid_bit = 5; + else + vid_bit = 1; + break; + case HDMI_30BIT: + c = IN_BPC_10BIT; + if (colorspace == 0x20) + vid_bit = 6; + else + vid_bit = 2; + break; + case HDMI_36BIT: + c = IN_BPC_12BIT; + if (colorspace == 0x20) + vid_bit = 6; + else + vid_bit = 3; + break; + + } + /* + * For down sample video (12bit, 10bit ---> 8bit), + * this register don`t change + */ + if (down_sample_en == 0) + sp_write_reg_and_or(TX_P2, + SP_TX_VID_CTRL2_REG, 0x8c, colorspace >> 5 | c); + + /* Patch: for 10bit video must be set this value to 12bit by someone */ + if (down_sample_en == 1 && c == IN_BPC_10BIT) + vid_bit = 3; + + sp_write_reg_and_or(TX_P2, + BIT_CTRL_SPECIFIC, 0x00, ENABLE_BIT_CTRL | vid_bit << 1); + + if (sp_tx_test_edid) { + sp_write_reg_and(TX_P2, SP_TX_VID_CTRL2_REG, 0x8f); + pr_info("%s %s : ***color space is set to 18bit***\n", + LOG_TAG, __func__); + } + + if (colorspace) { + sp_write_reg(TX_P0, SP_TX_VID_BLANK_SET1, 0x80); + sp_write_reg(TX_P0, SP_TX_VID_BLANK_SET2, 0x00); + sp_write_reg(TX_P0, SP_TX_VID_BLANK_SET3, 0x80); + } else { + sp_write_reg(TX_P0, SP_TX_VID_BLANK_SET1, 0x0); + sp_write_reg(TX_P0, SP_TX_VID_BLANK_SET2, 0x0); + sp_write_reg(TX_P0, SP_TX_VID_BLANK_SET3, 0x0); + } +} + +ulong sp_tx_pclk_calc(void) +{ + ulong str_plck; + uint vid_counter; + u8 c; + + sp_read_reg(RX_P0, 0x8d, &c); + vid_counter = c; + vid_counter = vid_counter << 8; + sp_read_reg(RX_P0, 0x8c, &c); + vid_counter |= c; + str_plck = ((ulong)vid_counter * XTAL_CLK_M10) >> 12; + pr_info("%s %s : PCLK = %d.%d\n", + LOG_TAG, __func__, (((uint)(str_plck))/10), + ((uint)str_plck - (((uint)str_plck/10)*10))); + return str_plck; +} + +static u8 sp_tx_bw_lc_sel(ulong pclk) +{ + ulong pixel_clk; + u8 c1; + + switch (((sp_i2c_read_byte(RX_P0, HDMI_RX_VIDEO_STATUS_REG1) + & COLOR_DEPTH) >> 4)) { + case HDMI_LEGACY: + case HDMI_24BIT: + default: + pixel_clk = pclk; + break; + case HDMI_30BIT: + pixel_clk = (pclk * 5) >> 2; + break; + case HDMI_36BIT: + pixel_clk = (pclk * 3) >> 1; + break; + } + pr_info("%s %s : pixel_clk = %d.%d\n", + LOG_TAG, __func__, (((uint)(pixel_clk))/10), + ((uint)pixel_clk - (((uint)pixel_clk/10)*10))); + + down_sample_en = 0; + if (pixel_clk <= 530) + c1 = LINK_1P62G; + else if ((530 < pixel_clk) && (pixel_clk <= 890)) + c1 = LINK_2P7G; + else if ((890 < pixel_clk) && (pixel_clk <= 1800)) + c1 = LINK_5P4G; + else { + c1 = LINK_6P75G; + if (pixel_clk > 2240) + down_sample_en = 1; + } + + if (sp_tx_get_link_bw() != c1) { + g_changed_bandwidth = c1; + pr_info("%s %s : %s! %.2x\n", LOG_TAG, __func__, + "different bandwidth between sink support and cur video", + (uint)c1); + return 1; + } + return 0; +} + +void sp_tx_spread_enable(u8 benable) +{ + u8 c; + + sp_read_reg(TX_P0, SP_TX_DOWN_SPREADING_CTRL1, &c); + + if (benable) { + c |= SP_TX_SSC_DWSPREAD; + sp_write_reg(TX_P0, SP_TX_DOWN_SPREADING_CTRL1, c); + + sp_tx_aux_dpcdread_bytes(0x00, 0x01, + DPCD_DOWNSPREAD_CTRL, 1, &c); + c |= SPREAD_AMPLITUDE; + sp_tx_aux_dpcdwrite_byte(0x00, 0x01, DPCD_DOWNSPREAD_CTRL, c); + + } else { + c &= ~SP_TX_SSC_DISABLE; + sp_write_reg(TX_P0, SP_TX_DOWN_SPREADING_CTRL1, c); + + sp_tx_aux_dpcdread_bytes(0x00, 0x01, + DPCD_DOWNSPREAD_CTRL, 1, &c); + c &= ~SPREAD_AMPLITUDE; + sp_tx_aux_dpcdwrite_byte(0x00, 0x01, DPCD_DOWNSPREAD_CTRL, c); + } + +} + +void sp_tx_config_ssc(enum sp_ssc_dep sscdep) +{ + sp_write_reg(TX_P0, SP_TX_DOWN_SPREADING_CTRL1, 0x0); + sp_write_reg(TX_P0, SP_TX_DOWN_SPREADING_CTRL1, sscdep); + sp_tx_spread_enable(1); +} + +void sp_tx_enhancemode_set(void) +{ + u8 c; + + sp_tx_aux_dpcdread_bytes(0x00, 0x00, DPCD_MAX_LANE_COUNT, 1, &c); + if (c & ENHANCED_FRAME_CAP) { + sp_write_reg_or(TX_P0, SP_TX_SYS_CTRL4_REG, ENHANCED_MODE); + + sp_tx_aux_dpcdread_bytes(0x00, 0x01, + DPCD_LANE_COUNT_SET, 1, &c); + c |= ENHANCED_FRAME_EN; + sp_tx_aux_dpcdwrite_byte(0x00, 0x01, + DPCD_LANE_COUNT_SET, c); + + pr_info("%s %s : Enhance mode enabled\n", LOG_TAG, __func__); + } else { + + sp_write_reg_and(TX_P0, SP_TX_SYS_CTRL4_REG, ~ENHANCED_MODE); + + sp_tx_aux_dpcdread_bytes(0x00, 0x01, + DPCD_LANE_COUNT_SET, 1, &c); + c &= ~ENHANCED_FRAME_EN; + sp_tx_aux_dpcdwrite_byte(0x00, 0x01, + DPCD_LANE_COUNT_SET, c); + + pr_info("%s %s : Enhance mode disabled\n", LOG_TAG, __func__); + } +} + +uint sp_tx_link_err_check(void) +{ + uint errl = 0, errh = 0; + u8 bytebuf[2]; + + sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x10, 2, bytebuf); + usleep_range(5000, 10000); + sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x10, 2, bytebuf); + errh = bytebuf[1]; + + if (errh & 0x80) { + errl = bytebuf[0]; + errh = (errh & 0x7f) << 8; + errl = errh + errl; + } + + pr_err("%s %s : Err of Lane = %d\n", LOG_TAG, __func__, errl); + return errl; +} + +static inline void sp_lt_finish(u8 temp_value) +{ + sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x02, 1, &temp_value); + if ((temp_value & 0x07) == 0x07) { + /* + * if there is link error, + * adjust pre-emphsis to check error again. + * If there is no error,keep the setting, + * otherwise use 400mv0db + */ + if (!sp_tx_test_lt) { + if (sp_tx_link_err_check()) { + sp_read_reg(TX_P0, + SP_TX_LT_SET_REG, &temp_value); + if (!(temp_value & MAX_PRE_REACH)) { + sp_write_reg(TX_P0, + SP_TX_LT_SET_REG, + (temp_value + 0x08)); + if (sp_tx_link_err_check()) + sp_write_reg(TX_P0, + SP_TX_LT_SET_REG, + temp_value); + } + } + + sp_read_reg(TX_P0, + SP_TX_LINK_BW_SET_REG, &temp_value); + if (temp_value == g_changed_bandwidth) { + pr_info("%s %s : LT succeed, bw: %.2x", + LOG_TAG, __func__, + (uint) temp_value); + pr_info("Lane0 Set: %.2x\n", + (uint) sp_i2c_read_byte(TX_P0, + SP_TX_LT_SET_REG)); + sp_tx_lt_state = LT_INIT; + goto_next_system_state(); + } else { + pr_info("%s %s : cur:%.2x, per:%.2x\n", + LOG_TAG, __func__, + (uint)temp_value, + (uint)g_changed_bandwidth); + sp_tx_lt_state = LT_ERROR; + } + } else { + sp_tx_test_lt = 0; + sp_tx_lt_state = LT_INIT; + goto_next_system_state(); + } + } else { + pr_info("%s %s : LANE0 Status error: %.2x\n", + LOG_TAG, __func__, (uint)(temp_value & 0x07)); + sp_tx_lt_state = LT_ERROR; + } +} + +void slimport_link_training(void) +{ + u8 temp_value, return_value, c; + + return_value = 1; + pr_info("%s %s : sp_tx_lt_state : %x\n", + LOG_TAG, __func__, (int)sp_tx_lt_state); + switch (sp_tx_lt_state) { + case LT_INIT: + slimport_block_power_ctrl(SP_TX_PWR_VIDEO, SP_POWER_ON); + sp_tx_video_mute(1); + sp_tx_enable_video_input(0); + sp_tx_lt_state++; + /* fallthrough */ + case LT_WAIT_PLL_LOCK: + if (!sp_tx_get_pll_lock_status()) { + sp_read_reg(TX_P0, SP_TX_PLL_CTRL_REG, &temp_value); + temp_value |= PLL_RST; + sp_write_reg(TX_P0, SP_TX_PLL_CTRL_REG, temp_value); + temp_value &= ~PLL_RST; + sp_write_reg(TX_P0, SP_TX_PLL_CTRL_REG, temp_value); + pr_info("%s %s : PLL not lock!\n", LOG_TAG, __func__); + } else + sp_tx_lt_state = LT_CHECK_LINK_BW; + SP_BREAK(LT_WAIT_PLL_LOCK, sp_tx_lt_state); + /* fallthrough */ + case LT_CHECK_LINK_BW: + sp_tx_get_rx_bw(&temp_value); + if (temp_value < g_changed_bandwidth) { + pr_info("%s %s : ****Over bandwidth****\n", + LOG_TAG, __func__); + g_changed_bandwidth = temp_value; + } else + sp_tx_lt_state++; + /* fallthrough */ + case LT_START: + if (sp_tx_test_lt) { + g_changed_bandwidth = sp_tx_test_bw; + sp_write_reg_and(TX_P2, SP_TX_VID_CTRL2_REG, 0x8f); + } else + sp_write_reg(TX_P0, SP_TX_LT_SET_REG, 0x00); + + sp_write_reg_and(TX_P0, SP_TX_ANALOG_PD_REG, ~CH0_PD); + + sp_tx_config_ssc(SSC_DEP_4000PPM); + sp_tx_set_link_bw(g_changed_bandwidth); + sp_tx_enhancemode_set(); + + sp_tx_aux_dpcdread_bytes(0x00, 0x00, 0x00, 0x01, &c); + sp_tx_aux_dpcdread_bytes(0x00, 0x06, 0x00, 0x01, &temp_value); + if (c >= 0x12) + temp_value &= 0xf8; + else + temp_value &= 0xfc; + temp_value |= 0x01; + sp_tx_aux_dpcdwrite_byte(0x00, 0x06, 0x00, temp_value); + + + sp_write_reg(TX_P0, LT_CTRL, SP_TX_LT_EN); + sp_tx_lt_state = LT_WAITTING_FINISH; + /* fallthrough */ + case LT_WAITTING_FINISH: + /* here : waiting interrupt to change training state. */ + break; + + case LT_ERROR: + sp_write_reg_or(TX_P2, RST_CTRL2, SERDES_FIFO_RST); + msleep(20); + sp_write_reg_and(TX_P2, RST_CTRL2, (~SERDES_FIFO_RST)); + pr_err("LT ERROR Status: SERDES FIFO reset."); + redo_cur_system_state(); + sp_tx_lt_state = LT_INIT; + break; + + case LT_FINISH: + sp_lt_finish(temp_value); + break; + default: + break; + } + +} +/******************End Link training process********************/ + +/******************Start Output video process********************/ +void sp_tx_set_colorspace(void) +{ + u8 color_space; + + if (down_sample_en) { + sp_read_reg(RX_P1, HDMI_RX_AVI_DATA00_REG, &color_space); + color_space &= 0x60; + if (color_space == 0x20) { + pr_info("%s %s : YCbCr4:2:2 ---> PASS THROUGH.\n", + LOG_TAG, __func__); + sp_write_reg(TX_P2, SP_TX_VID_CTRL6_REG, 0x00); + sp_write_reg(TX_P2, SP_TX_VID_CTRL5_REG, 0x00); + sp_write_reg(TX_P2, SP_TX_VID_CTRL2_REG, 0x11); + } else if (color_space == 0x40) { + pr_info("%s %s : YCbCr4:4:4 ---> YCbCr4:2:2\n", + LOG_TAG, __func__); + sp_write_reg(TX_P2, SP_TX_VID_CTRL6_REG, 0x41); + sp_write_reg(TX_P2, SP_TX_VID_CTRL5_REG, 0x00); + sp_write_reg(TX_P2, SP_TX_VID_CTRL2_REG, 0x12); + } else if (color_space == 0x00) { + pr_info("%s %s : RGB4:4:4 ---> YCbCr4:2:2\n", + LOG_TAG, __func__); + sp_write_reg(TX_P2, SP_TX_VID_CTRL6_REG, 0x41); + sp_write_reg(TX_P2, SP_TX_VID_CTRL5_REG, 0x83); + sp_write_reg(TX_P2, SP_TX_VID_CTRL2_REG, 0x10); + } + } else { + sp_write_reg(TX_P2, SP_TX_VID_CTRL6_REG, 0x00); + sp_write_reg(TX_P2, SP_TX_VID_CTRL5_REG, 0x00); + } +} + +void sp_tx_avi_setup(void) +{ + u8 c; + int i; + + for (i = 0; i < 13; i++) { + sp_read_reg(RX_P1, (HDMI_RX_AVI_DATA00_REG + i), &c); + sp_tx_packet_avi.avi_data[i] = c; + } +} + +static void sp_tx_load_packet(enum packets_type type) +{ + int i; + u8 c; + + switch (type) { + case AVI_PACKETS: + sp_write_reg(TX_P2, SP_TX_AVI_TYPE, 0x82); + sp_write_reg(TX_P2, SP_TX_AVI_VER, 0x02); + sp_write_reg(TX_P2, SP_TX_AVI_LEN, 0x0d); + + for (i = 0; i < 13; i++) { + sp_write_reg(TX_P2, SP_TX_AVI_DB0 + i, + sp_tx_packet_avi.avi_data[i]); + } + + break; + + case SPD_PACKETS: + sp_write_reg(TX_P2, SP_TX_SPD_TYPE, 0x83); + sp_write_reg(TX_P2, SP_TX_SPD_VER, 0x01); + sp_write_reg(TX_P2, SP_TX_SPD_LEN, 0x19); + + for (i = 0; i < 25; i++) { + sp_write_reg(TX_P2, SP_TX_SPD_DB0 + i, + sp_tx_packet_spd.spd_data[i]); + } + + break; + + case VSI_PACKETS: + sp_write_reg(TX_P2, SP_TX_MPEG_TYPE, 0x81); + sp_write_reg(TX_P2, SP_TX_MPEG_VER, 0x01); + sp_read_reg(RX_P1, HDMI_RX_MPEG_LEN_REG, &c); + sp_write_reg(TX_P2, SP_TX_MPEG_LEN, c); + + for (i = 0; i < 10; i++) { + sp_write_reg(TX_P2, SP_TX_MPEG_DB0 + i, + sp_tx_packet_mpeg.mpeg_data[i]); + } + + break; + case MPEG_PACKETS: + sp_write_reg(TX_P2, SP_TX_MPEG_TYPE, 0x85); + sp_write_reg(TX_P2, SP_TX_MPEG_VER, 0x01); + sp_write_reg(TX_P2, SP_TX_MPEG_LEN, 0x0d); + + for (i = 0; i < 10; i++) { + sp_write_reg(TX_P2, SP_TX_MPEG_DB0 + i, + sp_tx_packet_mpeg.mpeg_data[i]); + } + + break; + case AUDIF_PACKETS: + sp_write_reg(TX_P2, SP_TX_AUD_TYPE, 0x84); + sp_write_reg(TX_P2, SP_TX_AUD_VER, 0x01); + sp_write_reg(TX_P2, SP_TX_AUD_LEN, 0x0a); + for (i = 0; i < 10; i++) { + sp_write_reg(TX_P2, SP_TX_AUD_DB0 + i, + sp_tx_audioinfoframe.pb_byte[i]); + } + + break; + + default: + break; + } +} + +void sp_tx_config_packets(enum packets_type type) +{ + u8 c; + + switch (type) { + case AVI_PACKETS: + + sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c); + c &= ~AVI_IF_EN; + sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c); + sp_tx_load_packet(AVI_PACKETS); + + sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c); + c |= AVI_IF_UD; + sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c); + + sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c); + c |= AVI_IF_EN; + sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c); + + break; + + case SPD_PACKETS: + sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c); + c &= ~SPD_IF_EN; + sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c); + sp_tx_load_packet(SPD_PACKETS); + + sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c); + c |= SPD_IF_UD; + sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c); + + sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c); + c |= SPD_IF_EN; + sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c); + + break; + + case VSI_PACKETS: + sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c); + c &= ~MPEG_IF_EN; + sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c); + + sp_tx_load_packet(VSI_PACKETS); + + sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c); + c |= MPEG_IF_UD; + sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c); + + sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c); + c |= MPEG_IF_EN; + sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c); + + break; + case MPEG_PACKETS: + sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c); + c &= ~MPEG_IF_EN; + sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c); + + + sp_tx_load_packet(MPEG_PACKETS); + + sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c); + c |= MPEG_IF_UD; + sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c); + + sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c); + c |= MPEG_IF_EN; + sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c); + + break; + case AUDIF_PACKETS: + sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c); + c &= ~AUD_IF_EN; + sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c); + + + sp_tx_load_packet(AUDIF_PACKETS); + + sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c); + c |= AUD_IF_UP; + sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c); + + sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c); + c |= AUD_IF_EN; + sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c); + + break; + + default: + break; + } + +} + +void slimport_config_video_output(void) +{ + u8 temp_value; + + switch (sp_tx_vo_state) { + default: + case VO_WAIT_VIDEO_STABLE: + sp_read_reg(RX_P0, HDMI_RX_SYS_STATUS_REG, &temp_value); + if ((temp_value & (TMDS_DE_DET | TMDS_CLOCK_DET)) == 0x03) { + sp_tx_bw_lc_sel(sp_tx_pclk_calc()); + sp_tx_enable_video_input(0); + sp_tx_avi_setup(); + sp_tx_config_packets(AVI_PACKETS); + sp_tx_set_colorspace(); + sp_tx_lvttl_bit_mapping(); + if (sp_i2c_read_byte(RX_P0, RX_PACKET_REV_STA) + & VSI_RCVD) + hdmi_rx_new_vsi_int(); + sp_tx_enable_video_input(1); + sp_tx_vo_state = VO_WAIT_TX_VIDEO_STABLE; + } else + pr_info("%s %s :HDMI input video not stable!\n", + LOG_TAG, __func__); + SP_BREAK(VO_WAIT_VIDEO_STABLE, sp_tx_vo_state); + /* fallthrough */ + case VO_WAIT_TX_VIDEO_STABLE: + sp_read_reg(TX_P0, SP_TX_SYS_CTRL2_REG, &temp_value); + sp_write_reg(TX_P0, SP_TX_SYS_CTRL2_REG, temp_value); + sp_read_reg(TX_P0, SP_TX_SYS_CTRL2_REG, &temp_value); + if (temp_value & CHA_STA) + pr_info("%s %s : Stream clock not stable!\n", + LOG_TAG, __func__); + else { + sp_read_reg(TX_P0, SP_TX_SYS_CTRL3_REG, &temp_value); + sp_write_reg(TX_P0, SP_TX_SYS_CTRL3_REG, temp_value); + sp_read_reg(TX_P0, SP_TX_SYS_CTRL3_REG, &temp_value); + if (!(temp_value & STRM_VALID)) + pr_err("%s %s : video stream not valid!\n", + LOG_TAG, __func__); + else + sp_tx_vo_state = VO_CHECK_VIDEO_INFO; + } + SP_BREAK(VO_WAIT_TX_VIDEO_STABLE, sp_tx_vo_state); + /* fallthrough */ + case VO_CHECK_VIDEO_INFO: + if (!sp_tx_bw_lc_sel(sp_tx_pclk_calc())) + sp_tx_vo_state++; + else + sp_tx_set_sys_state(STATE_LINK_TRAINING); + SP_BREAK(VO_CHECK_VIDEO_INFO, sp_tx_vo_state); + /* fallthrough */ + case VO_FINISH: + slimport_block_power_ctrl(SP_TX_PWR_AUDIO, SP_POWER_DOWN); + hdmi_rx_mute_video(0); + sp_tx_video_mute(0); + sp_tx_show_information(); + goto_next_system_state(); + break; + } +} +/******************End Output video process********************/ + +/******************Start HDCP process********************/ +static void sp_tx_hdcp_encryption_disable(void) +{ + sp_write_reg_and(TX_P0, TX_HDCP_CTRL0, ~ENC_EN); +} + +static void sp_tx_hdcp_encryption_enable(void) +{ + sp_write_reg_or(TX_P0, TX_HDCP_CTRL0, ENC_EN); +} + +static void sp_tx_hw_hdcp_enable(void) +{ + u8 c; + + sp_write_reg_and(TX_P0, TX_HDCP_CTRL0, (~ENC_EN) & (~HARD_AUTH_EN)); + sp_write_reg_or(TX_P0, TX_HDCP_CTRL0, + HARD_AUTH_EN | BKSV_SRM_PASS | KSVLIST_VLD | ENC_EN); + + sp_read_reg(TX_P0, TX_HDCP_CTRL0, &c); + pr_info("%s %s : TX_HDCP_CTRL0 = %.2x\n", LOG_TAG, __func__, (uint)c); + sp_write_reg(TX_P0, SP_TX_WAIT_R0_TIME, 0xb0); + sp_write_reg(TX_P0, SP_TX_WAIT_KSVR_TIME, 0xc8); + + pr_info("%s %s : Hardware HDCP is enabled.\n", LOG_TAG, __func__); + +} + +void slimport_hdcp_process(void) +{ + switch (hcdp_state) { + case HDCP_CAPABLE_CHECK: + ds_vid_stb_cntr = 0; + hdcp_fail_count = 0; + if (is_anx_dongle()) + hcdp_state = HDCP_WAITTING_VID_STB; + else + hcdp_state = HDCP_HW_ENABLE; + if (external_block_en == 0) { + if (slimport_hdcp_cap_check() == 0) + hcdp_state = HDCP_NOT_SUPPORT; + } + /* + * Just for debug, pin: P2-2 + * There is a switch to disable/enable HDCP. + */ + hcdp_state = HDCP_NOT_SUPPORT; + /*****************************************/ + SP_BREAK(HDCP_CAPABLE_CHECK, hcdp_state); + /* fallthrough */ + case HDCP_WAITTING_VID_STB: + msleep(100); + hcdp_state = HDCP_HW_ENABLE; + SP_BREAK(HDCP_WAITTING_VID_STB, hcdp_state); + /* fallthrough */ + case HDCP_HW_ENABLE: + sp_tx_video_mute(1); + sp_tx_clean_hdcp_status(); + slimport_block_power_ctrl(SP_TX_PWR_HDCP, SP_POWER_DOWN); + msleep(20); + slimport_block_power_ctrl(SP_TX_PWR_HDCP, SP_POWER_ON); + sp_write_reg(TX_P2, SP_COMMON_INT_MASK2, 0x01); + msleep(50); + sp_tx_hw_hdcp_enable(); + hcdp_state = HDCP_WAITTING_FINISH; + /* fallthrough */ + case HDCP_WAITTING_FINISH: + break; + case HDCP_FINISH: + sp_tx_hdcp_encryption_enable(); + hdmi_rx_mute_video(0); + sp_tx_video_mute(0); + goto_next_system_state(); + hcdp_state = HDCP_CAPABLE_CHECK; + pr_info("%s %s : @@@@@@@hdcp_auth_pass@@@@@@\n", + LOG_TAG, __func__); + break; + case HDCP_FAILE: + if (hdcp_fail_count > 5) { + vbus_power_ctrl(0); + reg_hardware_reset(); + hcdp_state = HDCP_CAPABLE_CHECK; + hdcp_fail_count = 0; + pr_info("%s %s : *********hdcp_auth_failed*********\n", + LOG_TAG, __func__); + } else { + hdcp_fail_count++; + hcdp_state = HDCP_WAITTING_VID_STB; + } + break; + default: + case HDCP_NOT_SUPPORT: + pr_info("%s %s : Sink is not capable HDCP\n", + LOG_TAG, __func__); + slimport_block_power_ctrl(SP_TX_PWR_HDCP, SP_POWER_DOWN); + sp_tx_video_mute(0); + goto_next_system_state(); + hcdp_state = HDCP_CAPABLE_CHECK; + break; + } +} +/******************End HDCP process********************/ + +/******************Start Audio process********************/ +static void sp_tx_audioinfoframe_setup(void) +{ + int i; + u8 c; + + sp_read_reg(RX_P1, HDMI_RX_AUDIO_TYPE_REG, &c); + sp_tx_audioinfoframe.type = c; + sp_read_reg(RX_P1, HDMI_RX_AUDIO_VER_REG, &c); + sp_tx_audioinfoframe.version = c; + sp_read_reg(RX_P1, HDMI_RX_AUDIO_LEN_REG, &c); + sp_tx_audioinfoframe.length = c; + for (i = 0; i < 11; i++) { + sp_read_reg(RX_P1, (HDMI_RX_AUDIO_DATA00_REG + i), &c); + sp_tx_audioinfoframe.pb_byte[i] = c; + } + +} + +static void sp_tx_enable_audio_output(u8 benable) +{ + u8 c; + + sp_read_reg(TX_P0, SP_TX_AUD_CTRL, &c); + if (benable) { + if (c & AUD_EN) { + c &= ~AUD_EN; + sp_write_reg(TX_P0, SP_TX_AUD_CTRL, c); + } + sp_tx_audioinfoframe_setup(); + sp_tx_config_packets(AUDIF_PACKETS); + + c |= AUD_EN; + sp_write_reg(TX_P0, SP_TX_AUD_CTRL, c); + + } else { + c &= ~AUD_EN; + sp_write_reg(TX_P0, SP_TX_AUD_CTRL, c); + sp_write_reg_and(TX_P0, SP_TX_PKT_EN_REG, ~AUD_IF_EN); + } + +} + +static void sp_tx_config_audio(void) +{ + u8 c; + int i; + ulong M_AUD, LS_Clk = 0; + ulong AUD_Freq = 0; + + pr_info("%s %s : **Config audio **\n", LOG_TAG, __func__); + slimport_block_power_ctrl(SP_TX_PWR_AUDIO, SP_POWER_ON); + sp_read_reg(RX_P0, 0xCA, &c); + + switch (c & 0x0f) { + case 0x00: + AUD_Freq = 44.1; + break; + case 0x02: + AUD_Freq = 48; + break; + case 0x03: + AUD_Freq = 32; + break; + case 0x08: + AUD_Freq = 88.2; + break; + case 0x0a: + AUD_Freq = 96; + break; + case 0x0c: + AUD_Freq = 176.4; + break; + case 0x0e: + AUD_Freq = 192; + break; + default: + break; + } + + + switch (sp_tx_get_link_bw()) { + case LINK_1P62G: + LS_Clk = 162000; + break; + case LINK_2P7G: + LS_Clk = 270000; + break; + case LINK_5P4G: + LS_Clk = 540000; + break; + case LINK_6P75G: + LS_Clk = 675000; + break; + default: + break; + } + + pr_info("%s %s : AUD_Freq = %ld , LS_CLK = %ld\n", + LOG_TAG, __func__, AUD_Freq, LS_Clk); + + M_AUD = ((512 * AUD_Freq) / LS_Clk) * 32768; + M_AUD = M_AUD + 0x05; + sp_write_reg(TX_P1, SP_TX_AUD_INTERFACE_CTRL4, (M_AUD & 0xff)); + M_AUD = M_AUD >> 8; + sp_write_reg(TX_P1, SP_TX_AUD_INTERFACE_CTRL5, (M_AUD & 0xff)); + sp_write_reg(TX_P1, SP_TX_AUD_INTERFACE_CTRL6, 0x00); + + sp_write_reg_and(TX_P1, SP_TX_AUD_INTERFACE_CTRL0, + (u8)~AUD_INTERFACE_DISABLE); + + sp_write_reg_or(TX_P1, SP_TX_AUD_INTERFACE_CTRL2, M_AUD_ADJUST_ST); + + sp_read_reg(RX_P0, HDMI_STATUS, &c); + if (c & HDMI_AUD_LAYOUT) + sp_write_reg_or(TX_P2, SP_TX_AUD_CH_NUM_REG5, + CH_NUM_8 | AUD_LAYOUT); + else + sp_write_reg_and(TX_P2, SP_TX_AUD_CH_NUM_REG5, + (u8)(~CH_NUM_8) & (~AUD_LAYOUT)); + + /* transfer audio chaneel status from HDMI Rx to Slinmport Tx */ + for (i = 0; i < 5; i++) { + sp_read_reg(RX_P0, (HDMI_RX_AUD_IN_CH_STATUS1_REG + i), &c); + sp_write_reg(TX_P2, (SP_TX_AUD_CH_STATUS_REG1 + i), c); + } + + /* enable audio */ + sp_tx_enable_audio_output(1); +} + +void slimport_config_audio_output(void) +{ + static u8 count; + + switch (sp_tx_ao_state) { + default: + case AO_INIT: + case AO_CTS_RCV_INT: + case AO_AUDIO_RCV_INT: + if (!(sp_i2c_read_byte(RX_P0, HDMI_STATUS) & HDMI_MODE)) { + sp_tx_ao_state = AO_INIT; + goto_next_system_state(); + } + break; + case AO_RCV_INT_FINISH: + if (count++ > 2) + sp_tx_ao_state = AO_OUTPUT; + else + sp_tx_ao_state = AO_INIT; + SP_BREAK(AO_INIT, sp_tx_ao_state); + /* fallthrough */ + case AO_OUTPUT: + count = 0; + sp_tx_ao_state = AO_INIT; + hdmi_rx_mute_audio(0); + sp_tx_config_audio(); + goto_next_system_state(); + break; + } + +} +/******************End Audio process********************/ + +void slimport_initialization(void) +{ + /* Waitting Hot plug event! */ + if (!(common_int_status.common_int[3] & PLUG)) + return; + + g_read_edid_flag = 0; + + /* Power on all modules */ + sp_write_reg(TX_P2, SP_POWERD_CTRL_REG, 0x00); + /* Driver Version */ + sp_write_reg(TX_P1, FW_VER_REG, FW_VERSION); + hdmi_rx_initialization(); + sp_tx_initialization(); + msleep(200); + goto_next_system_state(); +} + +void hdcp_external_ctrl_flag_monitor(void) +{ + static u8 cur_flag; + + if (external_block_en != cur_flag) { + cur_flag = external_block_en; + system_state_change_with_case(STATE_HDCP_AUTH); + } + +} + +void slimport_state_process(struct anx78xx_data *data) +{ + switch (sp_tx_system_state) { + case STATE_WAITTING_CABLE_PLUG: + slimport_waitting_cable_plug_process(data); + SP_BREAK(STATE_WAITTING_CABLE_PLUG, sp_tx_system_state); + /* fallthrough */ + case STATE_SP_INITIALIZED: + slimport_initialization(); + SP_BREAK(STATE_SP_INITIALIZED, sp_tx_system_state); + /* fallthrough */ + case STATE_SINK_CONNECTION: + slimport_sink_connection(); + SP_BREAK(STATE_SINK_CONNECTION, sp_tx_system_state); + /* fallthrough */ + case STATE_PARSE_EDID: + slimport_edid_process(); + SP_BREAK(STATE_PARSE_EDID, sp_tx_system_state); + /* fallthrough */ + case STATE_LINK_TRAINING: + slimport_link_training(); + SP_BREAK(STATE_LINK_TRAINING, sp_tx_system_state); + /* fallthrough */ + case STATE_VIDEO_OUTPUT: + slimport_config_video_output(); + SP_BREAK(STATE_VIDEO_OUTPUT, sp_tx_system_state); + /* fallthrough */ + case STATE_HDCP_AUTH: + slimport_hdcp_process(); + SP_BREAK(STATE_HDCP_AUTH, sp_tx_system_state); + /* fallthrough */ + case STATE_AUDIO_OUTPUT: + slimport_config_audio_output(); + SP_BREAK(STATE_AUDIO_OUTPUT, sp_tx_system_state); + /* fallthrough */ + case STATE_PLAY_BACK: + SP_BREAK(STATE_PLAY_BACK, sp_tx_system_state); + /* fallthrough */ + default: + break; + } +} + +/******************Start INT process********************/ +void sp_tx_int_rec(void) +{ + sp_read_reg(TX_P2, SP_COMMON_INT_STATUS1, + &common_int_status.common_int[0]); + sp_write_reg(TX_P2, SP_COMMON_INT_STATUS1, + common_int_status.common_int[0]); + + sp_read_reg(TX_P2, SP_COMMON_INT_STATUS1 + 1, + &common_int_status.common_int[1]); + sp_write_reg(TX_P2, SP_COMMON_INT_STATUS1 + 1, + common_int_status.common_int[1]); + + sp_read_reg(TX_P2, SP_COMMON_INT_STATUS1 + 2, + &common_int_status.common_int[2]); + sp_write_reg(TX_P2, SP_COMMON_INT_STATUS1 + 2, + common_int_status.common_int[2]); + + sp_read_reg(TX_P2, SP_COMMON_INT_STATUS1 + 3, + &common_int_status.common_int[3]); + sp_write_reg(TX_P2, SP_COMMON_INT_STATUS1 + 3, + common_int_status.common_int[3]); + + sp_read_reg(TX_P2, SP_COMMON_INT_STATUS1 + 6, + &common_int_status.common_int[4]); + sp_write_reg(TX_P2, SP_COMMON_INT_STATUS1 + 6, + common_int_status.common_int[4]); +} + +void hdmi_rx_int_rec(void) +{ + sp_read_reg(RX_P0, HDMI_RX_INT_STATUS1_REG, + &hdmi_rx_int_status.hdmi_rx_int[0]); + sp_write_reg(RX_P0, HDMI_RX_INT_STATUS1_REG, + hdmi_rx_int_status.hdmi_rx_int[0]); + sp_read_reg(RX_P0, HDMI_RX_INT_STATUS2_REG, + &hdmi_rx_int_status.hdmi_rx_int[1]); + sp_write_reg(RX_P0, HDMI_RX_INT_STATUS2_REG, + hdmi_rx_int_status.hdmi_rx_int[1]); + sp_read_reg(RX_P0, HDMI_RX_INT_STATUS3_REG, + &hdmi_rx_int_status.hdmi_rx_int[2]); + sp_write_reg(RX_P0, HDMI_RX_INT_STATUS3_REG, + hdmi_rx_int_status.hdmi_rx_int[2]); + sp_read_reg(RX_P0, HDMI_RX_INT_STATUS4_REG, + &hdmi_rx_int_status.hdmi_rx_int[3]); + sp_write_reg(RX_P0, HDMI_RX_INT_STATUS4_REG, + hdmi_rx_int_status.hdmi_rx_int[3]); + sp_read_reg(RX_P0, HDMI_RX_INT_STATUS5_REG, + &hdmi_rx_int_status.hdmi_rx_int[4]); + sp_write_reg(RX_P0, HDMI_RX_INT_STATUS5_REG, + hdmi_rx_int_status.hdmi_rx_int[4]); + sp_read_reg(RX_P0, HDMI_RX_INT_STATUS6_REG, + &hdmi_rx_int_status.hdmi_rx_int[5]); + sp_write_reg(RX_P0, HDMI_RX_INT_STATUS6_REG, + hdmi_rx_int_status.hdmi_rx_int[5]); + sp_read_reg(RX_P0, HDMI_RX_INT_STATUS7_REG, + &hdmi_rx_int_status.hdmi_rx_int[6]); + sp_write_reg(RX_P0, HDMI_RX_INT_STATUS7_REG, + hdmi_rx_int_status.hdmi_rx_int[6]); +} + +void slimport_int_rec(void) +{ + sp_tx_int_rec(); + hdmi_rx_int_rec(); +} +/******************End INT process********************/ + +/******************Start task process********************/ +static void sp_tx_pll_changed_int_handler(void) +{ + if (sp_tx_system_state >= STATE_LINK_TRAINING) { + if (!sp_tx_get_pll_lock_status()) { + pr_info("%s %s : PLL:PLL not lock!\n", + LOG_TAG, __func__); + sp_tx_set_sys_state(STATE_LINK_TRAINING); + } + } +} + +static void sp_tx_hdcp_link_chk_fail_handler(void) +{ + system_state_change_with_case(STATE_HDCP_AUTH); + + pr_info("%s %s : hdcp_link_chk_fail:HDCP Sync lost!\n", + LOG_TAG, __func__); +} + +void link_down_check(void) +{ + u8 data_buf[6]; + + pr_info("%s %s : link_down_check\n", LOG_TAG, __func__); + sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x00, 6, data_buf); + if (sp_tx_system_state > STATE_LINK_TRAINING) { + if (!(data_buf[4] & 0x01) + || ((data_buf[2] & (0x01 | 0x04)) != 0x05)) { + sp_tx_set_sys_state(STATE_LINK_TRAINING); + pr_info("%s %s : INT:re-LT request!\n", + LOG_TAG, __func__); + } else { + pr_info("%s %s : Lane align %x\n", + LOG_TAG, __func__, (uint)data_buf[4]); + pr_info("%s %s : Lane clock recovery %x\n", + LOG_TAG, __func__, (uint)data_buf[2]); + } + } +} + +static void sp_tx_phy_auto_test(void) +{ + u8 b_sw; + u8 c1; + u8 bytebuf[16]; + u8 link_bw; + + /* DPCD 0x219 TEST_LINK_RATE */ + sp_tx_aux_dpcdread_bytes(0x0, 0x02, 0x19, 1, bytebuf); + pr_info("%s %s : DPCD:0x00219 = %.2x\n", + LOG_TAG, __func__, (uint)bytebuf[0]); + switch (bytebuf[0]) { + case 0x06: + case 0x0A: + case 0x14: + case 0x19: + sp_tx_set_link_bw(bytebuf[0]); + sp_tx_test_bw = bytebuf[0]; + break; + default: + sp_tx_set_link_bw(0x19); + sp_tx_test_bw = 0x19; + break; + } + + + /* DPCD 0x248 PHY_TEST_PATTERN */ + sp_tx_aux_dpcdread_bytes(0x0, 0x02, 0x48, 1, bytebuf); + pr_info("%s %s : DPCD:0x00248 = %.2x\n", + LOG_TAG, __func__, (uint)bytebuf[0]); + switch (bytebuf[0]) { + case 0: + break; + case 1: + sp_write_reg(TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x04); + break; + case 2: + sp_write_reg(TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x08); + break; + case 3: + sp_write_reg(TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x0c); + break; + case 4: + sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x50, 0xa, bytebuf); + sp_write_reg(TX_P1, 0x80, bytebuf[0]); + sp_write_reg(TX_P1, 0x81, bytebuf[1]); + sp_write_reg(TX_P1, 0x82, bytebuf[2]); + sp_write_reg(TX_P1, 0x83, bytebuf[3]); + sp_write_reg(TX_P1, 0x84, bytebuf[4]); + sp_write_reg(TX_P1, 0x85, bytebuf[5]); + sp_write_reg(TX_P1, 0x86, bytebuf[6]); + sp_write_reg(TX_P1, 0x87, bytebuf[7]); + sp_write_reg(TX_P1, 0x88, bytebuf[8]); + sp_write_reg(TX_P1, 0x89, bytebuf[9]); + sp_write_reg(TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x30); + break; + case 5: + sp_write_reg(TX_P0, 0xA9, 0x00); + sp_write_reg(TX_P0, 0xAA, 0x01); + sp_write_reg(TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x14); + break; + } + + sp_tx_aux_dpcdread_bytes(0x00, 0x00, 0x03, 1, bytebuf); + pr_info("%s %s : DPCD:0x00003 = %.2x\n", + LOG_TAG, __func__, (uint)bytebuf[0]); + switch (bytebuf[0] & 0x01) { + case 0: + sp_tx_spread_enable(0); + break; + case 1: + sp_read_reg(TX_P0, SP_TX_LINK_BW_SET_REG, &c1); + switch (c1) { + case 0x06: + link_bw = 0x06; + break; + case 0x0a: + link_bw = 0x0a; + break; + case 0x14: + link_bw = 0x14; + break; + case 0x19: + link_bw = 0x19; + break; + default: + link_bw = 0x00; + break; + } + sp_tx_config_ssc(SSC_DEP_4000PPM); + break; + } + + /* get swing and emphasis adjust request */ + sp_read_reg(TX_P0, 0xA3, &b_sw); + + sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x06, 1, bytebuf); + pr_info("%s %s : DPCD:0x00206 = %.2x\n", + LOG_TAG, __func__, (uint)bytebuf[0]); + c1 = bytebuf[0] & 0x0f; + switch (c1) { + case 0x00: + sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x00); + break; + case 0x01: + sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x01); + break; + case 0x02: + sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x02); + break; + case 0x03: + sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x03); + break; + case 0x04: + sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x08); + break; + case 0x05: + sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x09); + break; + case 0x06: + sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x0a); + break; + case 0x08: + sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x10); + break; + case 0x09: + sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x11); + break; + case 0x0c: + sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x18); + break; + default: + break; + } +} + +static void hpd_irq_process(void) +{ + u8 c, c1; + u8 test_vector; + u8 data_buf[6]; + + sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x00, 6, data_buf); + pr_info("+++++++++++++Get HPD IRQ %x\n", (int)data_buf[1]); + + if (data_buf[1] != 0) + sp_tx_aux_dpcdwrite_bytes(0x00, 0x02, DPCD_SERVICE_IRQ_VECTOR, + 1, &(data_buf[1])); + + /* HDCP IRQ */ + if (data_buf[1] & CP_IRQ) { + if (hcdp_state > HDCP_WAITTING_FINISH + || sp_tx_system_state > STATE_HDCP_AUTH) { + sp_tx_aux_dpcdread_bytes(0x06, 0x80, 0x29, 1, &c1); + if (c1 & 0x04) { + system_state_change_with_case(STATE_HDCP_AUTH); + pr_info("%s %s : IRQ:_______HDCP Sync lost!\n", + LOG_TAG, __func__); + } + } + } + + /* AUTOMATED TEST IRQ */ + if (data_buf[1] & TEST_IRQ) { + sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x18, 1, &test_vector); + + if (test_vector & 0x01) { + sp_tx_test_lt = 1; + + sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x19, 1, &c); + switch (c) { + case 0x06: + case 0x0A: + case 0x14: + case 0x19: + sp_tx_set_link_bw(c); + sp_tx_test_bw = c; + break; + default: + sp_tx_set_link_bw(0x19); + sp_tx_test_bw = 0x19; + break; + } + + pr_info("%s %s : test_bw = %.2x\n", + LOG_TAG, __func__, (uint)sp_tx_test_bw); + + sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x60, 1, &c); + c = c | TEST_ACK; + sp_tx_aux_dpcdwrite_bytes(0x00, 0x02, 0x60, 1, &c); + + pr_info("%s %s : Set TEST_ACK!\n", LOG_TAG, __func__); + if (sp_tx_system_state >= STATE_LINK_TRAINING) { + sp_tx_lt_state = LT_INIT; + sp_tx_set_sys_state(STATE_LINK_TRAINING); + } + pr_info("%s %s : IRQ:test-LT request!\n", + LOG_TAG, __func__); + } + + if (test_vector & 0x02) { + sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x60, 1, &c); + c = c | TEST_ACK; + sp_tx_aux_dpcdwrite_bytes(0x00, 0x02, 0x60, 1, &c); + } + if (test_vector & 0x04) { + if (sp_tx_system_state > STATE_PARSE_EDID) + sp_tx_set_sys_state(STATE_PARSE_EDID); + sp_tx_test_edid = 1; + pr_info("%s %s : Test EDID Requested!\n", + LOG_TAG, __func__); + } + + if (test_vector & 0x08) { + sp_tx_test_lt = 1; + + sp_tx_phy_auto_test(); + + sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x60, 1, &c); + c = c | 0x01; + sp_tx_aux_dpcdwrite_bytes(0x00, 0x02, 0x60, 1, &c); + } + } + + if (sp_tx_system_state > STATE_LINK_TRAINING) { + if (!(data_buf[4] & 0x01) + || ((data_buf[2] & (0x01 | 0x04)) != 0x05)) { + sp_tx_set_sys_state(STATE_LINK_TRAINING); + pr_info("%s %s : INT:re-LT request!\n", + LOG_TAG, __func__); + return; + } + + pr_info("%s %s : Lane align %x\n", + LOG_TAG, __func__, (uint)data_buf[4]); + pr_info("%s %s : Lane clock recovery %x\n", + LOG_TAG, __func__, (uint)data_buf[2]); + } +} + +static void sp_tx_vsi_setup(void) +{ + u8 c; + int i; + + for (i = 0; i < 10; i++) { + sp_read_reg(RX_P1, (HDMI_RX_MPEG_DATA00_REG + i), &c); + sp_tx_packet_mpeg.mpeg_data[i] = c; + } +} + +static void sp_tx_mpeg_setup(void) +{ + u8 c; + int i; + + for (i = 0; i < 10; i++) { + sp_read_reg(RX_P1, (HDMI_RX_MPEG_DATA00_REG + i), &c); + sp_tx_packet_mpeg.mpeg_data[i] = c; + } +} + +static void sp_tx_auth_done_int_handler(void) +{ + u8 bytebuf[2]; + + if (hcdp_state > HDCP_HW_ENABLE + && sp_tx_system_state == STATE_HDCP_AUTH) { + sp_read_reg(TX_P0, SP_TX_HDCP_STATUS, bytebuf); + if (bytebuf[0] & SP_TX_HDCP_AUTH_PASS) { + sp_tx_aux_dpcdread_bytes(0x06, 0x80, 0x2A, 2, bytebuf); + if ((bytebuf[1] & 0x08) || (bytebuf[0] & 0x80)) { + pr_info("%s %s : max cascade/devs exceeded!\n", + LOG_TAG, __func__); + sp_tx_hdcp_encryption_disable(); + } else + pr_info("%s %s : %s\n", LOG_TAG, __func__, + "Authentication pass in Auth_Done"); + + hcdp_state = HDCP_FINISH; + } else { + pr_err("%s %s : Authentication failed in AUTH_done\n", + LOG_TAG, __func__); + sp_tx_video_mute(1); + sp_tx_clean_hdcp_status(); + hcdp_state = HDCP_FAILE; + } + } + + pr_info("%s %s : sp_tx_auth_done_int_handler\n", LOG_TAG, __func__); + +} + +static void sp_tx_lt_done_int_handler(void) +{ + u8 c; + + if (sp_tx_lt_state == LT_WAITTING_FINISH + && sp_tx_system_state == STATE_LINK_TRAINING) { + sp_read_reg(TX_P0, LT_CTRL, &c); + if (c & 0x70) { + c = (c & 0x70) >> 4; + pr_info("%s %s : LT failed in interrupt, ERR = %.2x\n", + LOG_TAG, __func__, (uint) c); + sp_tx_lt_state = LT_ERROR; + } else { + pr_info("%s %s : lt_done: LT Finish\n", + LOG_TAG, __func__); + sp_tx_lt_state = LT_FINISH; + } + } + +} + +static void hdmi_rx_clk_det_int(void) +{ + pr_info("%s %s : *HDMI_RX Interrupt: Pixel Clock Change.\n", + LOG_TAG, __func__); + if (sp_tx_system_state > STATE_VIDEO_OUTPUT) { + sp_tx_video_mute(1); + sp_tx_enable_audio_output(0); + sp_tx_set_sys_state(STATE_VIDEO_OUTPUT); + } +} + +static void hdmi_rx_sync_det_int(void) +{ + pr_info("%s %s : *HDMI_RX Interrupt: Sync Detect.\n", + LOG_TAG, __func__); +} + +static void hdmi_rx_hdmi_dvi_int(void) +{ + u8 c; + + pr_info("%s %s : hdmi_rx_hdmi_dvi_int.\n", LOG_TAG, __func__); + sp_read_reg(RX_P0, HDMI_STATUS, &c); + g_hdmi_dvi_status = read_dvi_hdmi_mode(); + if ((c & _BIT0) != (g_hdmi_dvi_status & _BIT0)) { + pr_info("%s %s : hdmi_dvi_int: Is HDMI MODE: %x.\n", + LOG_TAG, __func__, (uint)(c & HDMI_MODE)); + g_hdmi_dvi_status = (c & _BIT0); + hdmi_rx_mute_audio(1); + system_state_change_with_case(STATE_LINK_TRAINING); + } +} + +static void hdmi_rx_new_avi_int(void) +{ + pr_info("%s %s : *HDMI_RX Interrupt: New AVI Packet.\n", + LOG_TAG, __func__); + sp_tx_lvttl_bit_mapping(); + sp_tx_set_colorspace(); + sp_tx_avi_setup(); + sp_tx_config_packets(AVI_PACKETS); +} + +static void hdmi_rx_new_vsi_int(void) +{ + u8 hdmi_video_format, v3d_structure; + + pr_info("%s %s : *HDMI_RX Interrupt: NEW VSI packet.\n", + LOG_TAG, __func__); + + sp_write_reg_and(TX_P0, SP_TX_3D_VSC_CTRL, ~INFO_FRAME_VSC_EN); + /* VSI package header */ + if ((sp_i2c_read_byte(RX_P1, HDMI_RX_MPEG_TYPE_REG) != 0x81) + || (sp_i2c_read_byte(RX_P1, HDMI_RX_MPEG_VER_REG) != 0x01)) + return; + pr_info("%s %s : Setup VSI package!\n", LOG_TAG, __func__); + + sp_tx_vsi_setup(); + sp_tx_config_packets(VSI_PACKETS); + + sp_read_reg(RX_P1, HDMI_RX_MPEG_DATA03_REG, &hdmi_video_format); + if ((hdmi_video_format & 0xe0) == 0x40) { + pr_info("%s %s : 3D VSI packet detected. Config VSC packet\n", + LOG_TAG, __func__); + sp_read_reg(RX_P1, HDMI_RX_MPEG_DATA05_REG, &v3d_structure); + switch (v3d_structure&0xf0) { + case 0x00: + v3d_structure = 0x02; + break; + case 0x20: + v3d_structure = 0x03; + break; + case 0x30: + v3d_structure = 0x04; + break; + default: + v3d_structure = 0x00; + pr_info("%s %s : 3D structure is not supported\n", + LOG_TAG, __func__); + break; + } + sp_write_reg(TX_P0, SP_TX_VSC_DB1, v3d_structure); + } + sp_write_reg_or(TX_P0, SP_TX_3D_VSC_CTRL, INFO_FRAME_VSC_EN); + sp_write_reg_and(TX_P0, SP_TX_PKT_EN_REG, ~SPD_IF_EN); + sp_write_reg_or(TX_P0, SP_TX_PKT_EN_REG, SPD_IF_UD); + sp_write_reg_or(TX_P0, SP_TX_PKT_EN_REG, SPD_IF_EN); +} + +static void hdmi_rx_no_vsi_int(void) +{ + + u8 c; + + sp_read_reg(TX_P0, SP_TX_3D_VSC_CTRL, &c); + if (c & INFO_FRAME_VSC_EN) { + pr_info("%s %s : No new VSI is received, disable VSC packet\n", + LOG_TAG, __func__); + c &= ~INFO_FRAME_VSC_EN; + sp_write_reg(TX_P0, SP_TX_3D_VSC_CTRL, c); + sp_tx_mpeg_setup(); + sp_tx_config_packets(MPEG_PACKETS); + } + +} + +static void hdmi_rx_restart_audio_chk(void) +{ + pr_info("%s %s : WAIT_AUDIO: hdmi_rx_restart_audio_chk.\n", + LOG_TAG, __func__); + system_state_change_with_case(STATE_AUDIO_OUTPUT); +} + +static void hdmi_rx_cts_rcv_int(void) +{ + if (sp_tx_ao_state == AO_INIT) + sp_tx_ao_state = AO_CTS_RCV_INT; + else if (sp_tx_ao_state == AO_AUDIO_RCV_INT) + sp_tx_ao_state = AO_RCV_INT_FINISH; +} + +static void hdmi_rx_audio_rcv_int(void) +{ + if (sp_tx_ao_state == AO_INIT) + sp_tx_ao_state = AO_AUDIO_RCV_INT; + else if (sp_tx_ao_state == AO_CTS_RCV_INT) + sp_tx_ao_state = AO_RCV_INT_FINISH; +} + +static void hdmi_rx_audio_samplechg_int(void) +{ + uint i; + u8 c; + /* transfer audio chaneel status from HDMI Rx to Slinmport Tx */ + for (i = 0; i < 5; i++) { + sp_read_reg(RX_P0, (HDMI_RX_AUD_IN_CH_STATUS1_REG + i), &c); + sp_write_reg(TX_P2, (SP_TX_AUD_CH_STATUS_REG1 + i), c); + } +} + +static void hdmi_rx_hdcp_error_int(void) +{ + static u8 count; + + pr_info("%s %s : *HDMI_RX Interrupt: hdcp error.\n", LOG_TAG, __func__); + if (count >= 40) { + count = 0; + pr_info("%s %s : Lots of hdcp error occurred ...\n", + LOG_TAG, __func__); + hdmi_rx_mute_audio(1); + hdmi_rx_mute_video(1); + hdmi_rx_set_hpd(0); + usleep_range(10000, 11000); + hdmi_rx_set_hpd(1); + } else + count++; +} + +static void hdmi_rx_new_gcp_int(void) +{ + u8 c; + + sp_read_reg(RX_P1, HDMI_RX_GENERAL_CTRL, &c); + if (c&SET_AVMUTE) { + hdmi_rx_mute_video(1); + hdmi_rx_mute_audio(1); + + } else if (c&CLEAR_AVMUTE) { + hdmi_rx_mute_video(0); + hdmi_rx_mute_audio(0); + } +} + +static void sp_tx_hpd_int_handler(u8 hpd_source) +{ + pr_info("%s %s : sp_tx_hpd_int_handler\n", LOG_TAG, __func__); + + switch (hpd_source) { + case HPD_LOST: + hdmi_rx_set_hpd(0); + sp_tx_set_sys_state(STATE_WAITTING_CABLE_PLUG); + break; + case HPD_CHANGE: + pr_info("HPD:____________HPD changed!\n"); + usleep_range(2000, 4000); + if (common_int_status.common_int[3] & HPD_IRQ) + hpd_irq_process(); + + if (sp_i2c_read_byte(TX_P0, SP_TX_SYS_CTRL3_REG) & HPD_STATUS) { + if (common_int_status.common_int[3] & HPD_IRQ) + hpd_irq_process(); + } else { + if (sp_i2c_read_byte(TX_P0, SP_TX_SYS_CTRL3_REG) + & HPD_STATUS) { + hdmi_rx_set_hpd(0); + sp_tx_set_sys_state(STATE_WAITTING_CABLE_PLUG); + } + } + break; + case PLUG: + pr_info("HPD:____________HPD changed!\n"); + if (sp_tx_system_state < STATE_SP_INITIALIZED) + sp_tx_set_sys_state(STATE_SP_INITIALIZED); + break; + default: + break; + } +} + +void system_isr_handler(void) +{ + if (common_int_status.common_int[3] & HPD_CHANGE) + sp_tx_hpd_int_handler(HPD_CHANGE); + if (common_int_status.common_int[3] & HPD_LOST) + sp_tx_hpd_int_handler(HPD_LOST); + if (common_int_status.common_int[3] & HPD_IRQ) + pr_info("++++++++++++++++========HDCP_IRQ interrupt\n"); + if (common_int_status.common_int[0] & PLL_LOCK_CHG) + sp_tx_pll_changed_int_handler(); + + if (common_int_status.common_int[1] & HDCP_AUTH_DONE) + sp_tx_auth_done_int_handler(); + + if (common_int_status.common_int[2] & HDCP_LINK_CHECK_FAIL) + sp_tx_hdcp_link_chk_fail_handler(); + + if (common_int_status.common_int[4] & TRAINING_Finish) + sp_tx_lt_done_int_handler(); + + if (sp_tx_system_state > STATE_SINK_CONNECTION) { + if (hdmi_rx_int_status.hdmi_rx_int[5] & NEW_AVI) + hdmi_rx_new_avi_int(); + } + + if (sp_tx_system_state > STATE_VIDEO_OUTPUT) { + if (hdmi_rx_int_status.hdmi_rx_int[6] & NEW_VS) { + hdmi_rx_int_status.hdmi_rx_int[6] &= ~NO_VSI; + hdmi_rx_new_vsi_int(); + } + if (hdmi_rx_int_status.hdmi_rx_int[6] & NO_VSI) + hdmi_rx_no_vsi_int(); + } + + if (sp_tx_system_state >= STATE_VIDEO_OUTPUT) { + if (hdmi_rx_int_status.hdmi_rx_int[0] & CKDT_CHANGE) + hdmi_rx_clk_det_int(); + + if (hdmi_rx_int_status.hdmi_rx_int[0] & SCDT_CHANGE) + hdmi_rx_sync_det_int(); + + if (hdmi_rx_int_status.hdmi_rx_int[0] & HDMI_DVI) + hdmi_rx_hdmi_dvi_int(); + + if ((hdmi_rx_int_status.hdmi_rx_int[5] & NEW_AUD) + || (hdmi_rx_int_status.hdmi_rx_int[2] & AUD_MODE_CHANGE)) + hdmi_rx_restart_audio_chk(); + + + if (hdmi_rx_int_status.hdmi_rx_int[5] & CTS_RCV) + hdmi_rx_cts_rcv_int(); + + if (hdmi_rx_int_status.hdmi_rx_int[4] & AUDIO_RCV) + hdmi_rx_audio_rcv_int(); + + + if (hdmi_rx_int_status.hdmi_rx_int[1] & HDCP_ERR) + hdmi_rx_hdcp_error_int(); + + if (hdmi_rx_int_status.hdmi_rx_int[5] & NEW_CP) + hdmi_rx_new_gcp_int(); + + if (hdmi_rx_int_status.hdmi_rx_int[1] & AUDIO_SAMPLE_CHANGE) + hdmi_rx_audio_samplechg_int(); + } + +} + +void sp_tx_show_information(void) +{ + u8 c, c1; + uint h_res, h_act, v_res, v_act; + uint h_fp, h_sw, h_bp, v_fp, v_sw, v_bp; + ulong fresh_rate; + ulong pclk; + + pr_info("\n******************SP Video Information*******************\n"); + + sp_read_reg(TX_P0, SP_TX_LINK_BW_SET_REG, &c); + switch (c) { + case 0x06: + pr_info("%s %s : BW = 1.62G\n", LOG_TAG, __func__); + break; + case 0x0a: + pr_info("%s %s : BW = 2.7G\n", LOG_TAG, __func__); + break; + case 0x14: + pr_info("%s %s : BW = 5.4G\n", LOG_TAG, __func__); + break; + case 0x19: + pr_info("%s %s : BW = 6.75G\n", LOG_TAG, __func__); + break; + default: + break; + } + + pclk = sp_tx_pclk_calc(); + pclk = pclk / 10; + + sp_read_reg(TX_P2, SP_TX_TOTAL_LINE_STA_L, &c); + sp_read_reg(TX_P2, SP_TX_TOTAL_LINE_STA_H, &c1); + + v_res = c1; + v_res = v_res << 8; + v_res = v_res + c; + + + sp_read_reg(TX_P2, SP_TX_ACT_LINE_STA_L, &c); + sp_read_reg(TX_P2, SP_TX_ACT_LINE_STA_H, &c1); + + v_act = c1; + v_act = v_act << 8; + v_act = v_act + c; + + + sp_read_reg(TX_P2, SP_TX_TOTAL_PIXEL_STA_L, &c); + sp_read_reg(TX_P2, SP_TX_TOTAL_PIXEL_STA_H, &c1); + + h_res = c1; + h_res = h_res << 8; + h_res = h_res + c; + + + sp_read_reg(TX_P2, SP_TX_ACT_PIXEL_STA_L, &c); + sp_read_reg(TX_P2, SP_TX_ACT_PIXEL_STA_H, &c1); + + h_act = c1; + h_act = h_act << 8; + h_act = h_act + c; + + sp_read_reg(TX_P2, SP_TX_H_F_PORCH_STA_L, &c); + sp_read_reg(TX_P2, SP_TX_H_F_PORCH_STA_H, &c1); + + h_fp = c1; + h_fp = h_fp << 8; + h_fp = h_fp + c; + + sp_read_reg(TX_P2, SP_TX_H_SYNC_STA_L, &c); + sp_read_reg(TX_P2, SP_TX_H_SYNC_STA_H, &c1); + + h_sw = c1; + h_sw = h_sw << 8; + h_sw = h_sw + c; + + sp_read_reg(TX_P2, SP_TX_H_B_PORCH_STA_L, &c); + sp_read_reg(TX_P2, SP_TX_H_B_PORCH_STA_H, &c1); + + h_bp = c1; + h_bp = h_bp << 8; + h_bp = h_bp + c; + + sp_read_reg(TX_P2, SP_TX_V_F_PORCH_STA, &c); + v_fp = c; + + sp_read_reg(TX_P2, SP_TX_V_SYNC_STA, &c); + v_sw = c; + + sp_read_reg(TX_P2, SP_TX_V_B_PORCH_STA, &c); + v_bp = c; + + pr_info("%s %s : Total resolution is %d * %d\n", + LOG_TAG, __func__, h_res, v_res); + + pr_info("%s %s : HF=%d, HSW=%d, HBP=%d\n", + LOG_TAG, __func__, h_fp, h_sw, h_bp); + pr_info("%s %s : VF=%d, VSW=%d, VBP=%d\n", + LOG_TAG, __func__, v_fp, v_sw, v_bp); + pr_info("%s %s : Active resolution is %d * %d", + LOG_TAG, __func__, h_act, v_act); + + if (h_res == 0 || v_res == 0) + fresh_rate = 0; + else { + fresh_rate = pclk * 1000; + fresh_rate = fresh_rate / h_res; + fresh_rate = fresh_rate * 1000; + fresh_rate = fresh_rate / v_res; + } + pr_info(" @ %ldHz\n", fresh_rate); + + sp_read_reg(TX_P0, SP_TX_VID_CTRL, &c); + + if ((c & 0x06) == 0x00) + pr_info("%s %s : ColorSpace: RGB,", LOG_TAG, __func__); + else if ((c & 0x06) == 0x02) + pr_info("%s %s : ColorSpace: YCbCr422,", LOG_TAG, __func__); + else if ((c & 0x06) == 0x04) + pr_info("%s %s : ColorSpace: YCbCr444,", LOG_TAG, __func__); + + sp_read_reg(TX_P0, SP_TX_VID_CTRL, &c); + + if ((c & 0xe0) == 0x00) + pr_info("6 BPC\n"); + else if ((c & 0xe0) == 0x20) + pr_info("8 BPC\n"); + else if ((c & 0xe0) == 0x40) + pr_info("10 BPC\n"); + else if ((c & 0xe0) == 0x60) + pr_info("12 BPC\n"); + + + if (is_anx_dongle()) { + sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x23, 1, &c); + pr_info("%s %s : Analogix Dongle FW Ver %.2x\n", + LOG_TAG, __func__, (uint)(c & 0x7f)); + } + + pr_info("\n**************************************************\n"); + +} + +void hdmi_rx_show_video_info(void) +{ + u8 c, c1; + u8 cl, ch; + uint n; + uint h_res, v_res; + + sp_read_reg(RX_P0, HDMI_RX_HACT_LOW, &cl); + sp_read_reg(RX_P0, HDMI_RX_HACT_HIGH, &ch); + n = ch; + n = (n << 8) + cl; + h_res = n; + + sp_read_reg(RX_P0, HDMI_RX_VACT_LOW, &cl); + sp_read_reg(RX_P0, HDMI_RX_VACT_HIGH, &ch); + n = ch; + n = (n << 8) + cl; + v_res = n; + + pr_info("%s %s : >HDMI_RX Info<\n", LOG_TAG, __func__); + sp_read_reg(RX_P0, HDMI_STATUS, &c); + if (c & HDMI_MODE) + pr_info("%s %s : HDMI_RX Mode = HDMI Mode.\n", + LOG_TAG, __func__); + else + pr_info("%s %s : HDMI_RX Mode = DVI Mode.\n", + LOG_TAG, __func__); + + sp_read_reg(RX_P0, HDMI_RX_VIDEO_STATUS_REG1, &c); + if (c & VIDEO_TYPE) + v_res += v_res; + pr_info("%s %s : HDMI_RX Video Resolution = %d * %d ", + LOG_TAG, __func__, h_res, v_res); + sp_read_reg(RX_P0, HDMI_RX_VIDEO_STATUS_REG1, &c); + if (c & VIDEO_TYPE) + pr_info("Interlace Video.\n"); + else + pr_info("Progressive Video.\n"); + + sp_read_reg(RX_P0, HDMI_RX_SYS_CTRL1_REG, &c); + if ((c & 0x30) == 0x00) + pr_info("%s %s : Input Pixel Clock = Not Repeated.\n", + LOG_TAG, __func__); + else if ((c & 0x30) == 0x10) + pr_info("%s %s : Input pclk = 2x Video Clock. Repeated.\n", + LOG_TAG, __func__); + else if ((c & 0x30) == 0x30) + pr_info("%s %s : Input pclk = 4x Vvideo Clock. Repeated.\n", + LOG_TAG, __func__); + + if ((c & 0xc0) == 0x00) + pr_info("%s %s : Output Video Clock = Not Divided.\n", + LOG_TAG, __func__); + else if ((c & 0xc0) == 0x40) + pr_info("%s %s : Output Video Clock = Divided By 2.\n", + LOG_TAG, __func__); + else if ((c & 0xc0) == 0xc0) + pr_info("%s %s : Output Video Clock = Divided By 4.\n", + LOG_TAG, __func__); + + if (c & 0x02) + pr_info("%s %s : %s\n", LOG_TAG, __func__, + "Output Video Using Rising Edge To Latch Data.\n"); + else + pr_info("%s %s : %s\n", LOG_TAG, __func__, + "Output Video Using Falling Edge To Latch Data.\n"); + + + pr_info("Input Video Color Depth = "); + sp_read_reg(RX_P0, 0x70, &c1); + c1 &= 0xf0; + if (c1 == 0x00) + pr_info("%s %s : Legacy Mode.\n", LOG_TAG, __func__); + else if (c1 == 0x40) + pr_info("%s %s : 24 Bit Mode.\n", LOG_TAG, __func__); + else if (c1 == 0x50) + pr_info("%s %s : 30 Bit Mode.\n", LOG_TAG, __func__); + else if (c1 == 0x60) + pr_info("%s %s : 36 Bit Mode.\n", LOG_TAG, __func__); + else if (c1 == 0x70) + pr_info("%s %s : 48 Bit Mode.\n", LOG_TAG, __func__); + + pr_info("%s %s : Input Video Color Space = ", LOG_TAG, __func__); + sp_read_reg(RX_P1, HDMI_RX_AVI_DATA00_REG, &c); + c &= 0x60; + if (c == 0x20) + pr_info("YCbCr4:2:2 .\n"); + else if (c == 0x40) + pr_info("YCbCr4:4:4 .\n"); + else if (c == 0x00) + pr_info("RGB.\n"); + else + pr_err("Unknown 0x44 = 0x%.2x\n", (int)c); + + sp_read_reg(RX_P1, HDMI_RX_HDCP_STATUS_REG, &c); + if (c & AUTH_EN) + pr_info("%s %s : Authentication is attempted.\n", + LOG_TAG, __func__); + else + pr_info("%s %s : Authentication is not attempted.\n", + LOG_TAG, __func__); + + for (cl = 0; cl < 20; cl++) { + sp_read_reg(RX_P1, HDMI_RX_HDCP_STATUS_REG, &c); + if (c & DECRYPT_EN) + break; + + usleep_range(10000, 11000); + } + + if (cl < 20) + pr_info("%s %s : Decryption is active.\n", LOG_TAG, __func__); + else + pr_info("%s %s : Decryption is not active.\n", + LOG_TAG, __func__); +} + +void clean_system_status(void) +{ + if (g_need_clean_status) { + pr_info("%s %s : clean_system_status. A -> B;\n", + LOG_TAG, __func__); + pr_info("A:"); + print_sys_state(sp_tx_system_state_bak); + pr_info("B:"); + print_sys_state(sp_tx_system_state); + + g_need_clean_status = 0; + if (sp_tx_system_state_bak >= STATE_LINK_TRAINING) { + if (sp_tx_system_state >= STATE_AUDIO_OUTPUT) + hdmi_rx_mute_audio(1); + else { + hdmi_rx_mute_video(1); + sp_tx_video_mute(1); + } + } + if (sp_tx_system_state_bak >= STATE_HDCP_AUTH + && sp_tx_system_state <= STATE_HDCP_AUTH) { + if (sp_i2c_read_byte(TX_P0, TX_HDCP_CTRL0) & 0xFC) + sp_tx_clean_hdcp_status(); + } + + if (hcdp_state != HDCP_CAPABLE_CHECK) + hcdp_state = HDCP_CAPABLE_CHECK; + + if (sp_tx_sc_state != SC_INIT) + sp_tx_sc_state = SC_INIT; + if (sp_tx_lt_state != LT_INIT) + sp_tx_lt_state = LT_INIT; + if (sp_tx_vo_state != VO_WAIT_VIDEO_STABLE) + sp_tx_vo_state = VO_WAIT_VIDEO_STABLE; + } +} + +/******************add for HDCP cap check********************/ +void sp_tx_get_ddc_hdcp_BCAP(u8 *bcap) +{ + u8 c; + + sp_write_reg(TX_P0, AUX_ADDR_7_0, 0X3A); + sp_write_reg(TX_P0, AUX_ADDR_15_8, 0); + sp_read_reg(TX_P0, AUX_ADDR_19_16, &c); + c &= 0xf0; + sp_write_reg(TX_P0, AUX_ADDR_19_16, c); + + sp_tx_aux_wr(0x00); + sp_tx_aux_rd(0x01); + sp_read_reg(TX_P0, BUF_DATA_0, &c); + + + sp_tx_aux_wr(0x40); + sp_tx_aux_rd(0x01); + sp_read_reg(TX_P0, BUF_DATA_0, bcap); + +} + +void sp_tx_get_ddc_hdcp_BKSV(u8 *bksv) +{ + u8 c; + + sp_write_reg(TX_P0, AUX_ADDR_7_0, 0X3A); + sp_write_reg(TX_P0, AUX_ADDR_15_8, 0); + sp_read_reg(TX_P0, AUX_ADDR_19_16, &c); + c &= 0xf0; + sp_write_reg(TX_P0, AUX_ADDR_19_16, c); + + sp_tx_aux_wr(0x00); + sp_tx_aux_rd(0x01); + sp_read_reg(TX_P0, BUF_DATA_0, &c); + + + sp_tx_aux_wr(0x00); + sp_tx_aux_rd(0x01); + sp_read_reg(TX_P0, BUF_DATA_0, bksv); + +} + +u8 slimport_hdcp_cap_check(void) +{ + u8 g_hdcp_cap = 0; + u8 temp; + + if (AUX_OK == sp_tx_aux_dpcdread_bytes(0x06, 0x80, 0x28, 1, &temp)) + g_hdcp_cap = (temp & 0x01) ? 1 : 0; + else + pr_info("HDCP CAPABLE: read AUX err!\n"); + + pr_info("%s %s :hdcp cap check: %s Supported\n", + LOG_TAG, __func__, g_hdcp_cap ? "" : "No"); + return g_hdcp_cap; +} +/******************End HDCP cap check********************/ + +void slimport_tasks_handler(void) +{ + system_isr_handler(); + hdcp_external_ctrl_flag_monitor(); + clean_system_status(); + /*clear up backup system state*/ + if (sp_tx_system_state_bak != sp_tx_system_state) + sp_tx_system_state_bak = sp_tx_system_state; +} +/******************End task process********************/ + +void slimport_main_process(struct anx78xx_data *data) +{ + slimport_state_process(data); + if (sp_tx_system_state > STATE_WAITTING_CABLE_PLUG) { + slimport_int_rec(); + slimport_tasks_handler(); + } +} + diff --git a/drivers/gpu/drm/i2c/anx78xx/slimport_tx_drv.h b/drivers/gpu/drm/i2c/anx78xx/slimport_tx_drv.h new file mode 100644 index 0000000..4928b0a --- /dev/null +++ b/drivers/gpu/drm/i2c/anx78xx/slimport_tx_drv.h @@ -0,0 +1,254 @@ +/* + * Copyright(c) 2015, Analogix Semiconductor. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 _SP_TX_DRV_H +#define _SP_TX_DRV_H + +#include "slimport.h" +#include "slimport_tx_reg.h" + +#define FW_VERSION 0x22 + +#define _BIT0 0x01 +#define _BIT1 0x02 +#define _BIT2 0x04 +#define _BIT3 0x08 +#define _BIT4 0x10 +#define _BIT5 0x20 +#define _BIT6 0x40 +#define _BIT7 0x80 + +#define DVI_MODE 0x00 +#define HDMI_MODE 0x01 + +#define SP_POWER_ON 1 +#define SP_POWER_DOWN 0 + +#define MAX_BUF_CNT 16 + +#define SP_BREAK(current_status, next_status) \ + { if (next_status != (current_status) + 1) break; } + +extern u8 edid_blocks[256]; + +/* HDCP control enable/ disable from AP */ +/* external_block_en = 1: enable, 0: disable*/ +extern int external_block_en; + +enum rx_cbl_type { + DWN_STRM_IS_NULL, + DWN_STRM_IS_HDMI, + DWN_STRM_IS_DIGITAL, + DWN_STRM_IS_ANALOG, + DWN_STRM_NUM +}; + +enum sp_tx_state { + STATE_WAITTING_CABLE_PLUG, + STATE_SP_INITIALIZED, + STATE_SINK_CONNECTION, + STATE_PARSE_EDID, + STATE_LINK_TRAINING, + STATE_VIDEO_OUTPUT, + STATE_HDCP_AUTH, + STATE_AUDIO_OUTPUT, + STATE_PLAY_BACK +}; + +enum sp_tx_power_block { + SP_TX_PWR_REG = REGISTER_PD, + SP_TX_PWR_HDCP = HDCP_PD, + SP_TX_PWR_AUDIO = AUDIO_PD, + SP_TX_PWR_VIDEO = VIDEO_PD, + SP_TX_PWR_LINK = LINK_PD, + SP_TX_PWR_TOTAL = TOTAL_PD, + SP_TX_PWR_NUMS +}; + +enum hdmi_color_depth { + HDMI_LEGACY = 0x00, + HDMI_24BIT = 0x04, + HDMI_30BIT = 0x05, + HDMI_36BIT = 0x06, + HDMI_48BIT = 0x07, +}; + +enum sp_tx_send_msg { + MSG_OCM_EN, + MSG_INPUT_HDMI, + MSG_INPUT_DVI, + MSG_CLEAR_IRQ, +}; + +enum sink_connection_status { + SC_INIT, + SC_CHECK_CABLE_TYPE, + SC_WAITTING_CABLE_TYPE = SC_CHECK_CABLE_TYPE+5, + SC_SINK_CONNECTED, + SC_NOT_CABLE, + SC_STATE_NUM +}; + +enum cable_type_status { + CHECK_AUXCH, + GETTED_CABLE_TYPE, + CABLE_TYPE_STATE_NUM +}; + +enum sp_tx_lt_status { + LT_INIT, + LT_WAIT_PLL_LOCK, + LT_CHECK_LINK_BW, + LT_START, + LT_WAITTING_FINISH, + LT_ERROR, + LT_FINISH, + LT_END, + LT_STATES_NUM +}; + +enum hdcp_status { + HDCP_CAPABLE_CHECK, + HDCP_WAITTING_VID_STB, + HDCP_HW_ENABLE, + HDCP_WAITTING_FINISH, + HDCP_FINISH, + HDCP_FAILE, + HDCP_NOT_SUPPORT, + HDCP_PROCESS_STATE_NUM +}; + +enum video_output_status { + VO_WAIT_VIDEO_STABLE, + VO_WAIT_TX_VIDEO_STABLE, + VO_CHECK_VIDEO_INFO, + VO_FINISH, + VO_STATE_NUM +}; + +enum audio_output_status { + AO_INIT, + AO_CTS_RCV_INT, + AO_AUDIO_RCV_INT, + AO_RCV_INT_FINISH, + AO_OUTPUT, + AO_STATE_NUM +}; + +struct packet_avi { + u8 avi_data[13]; +}; + + +struct packet_spd { + u8 spd_data[25]; +}; + +struct packet_mpeg { + u8 mpeg_data[13]; +}; + +struct audio_info_frame { + u8 type; + u8 version; + u8 length; + u8 pb_byte[11]; +}; + +enum packets_type { + AVI_PACKETS, + SPD_PACKETS, + MPEG_PACKETS, + VSI_PACKETS, + AUDIF_PACKETS +}; + +struct common_int { + u8 common_int[5]; + u8 change_flag; +}; + +struct hdmi_rx_int { + u8 hdmi_rx_int[7]; + u8 change_flag; +}; + +enum xtal_enum { + XTAL_19D2M, + XTAL_24M, + XTAL_25M, + XTAL_26M, + XTAL_27M, + XTAL_38D4M, + XTAL_52M, + XTAL_NOT_SUPPORT, + XTAL_CLK_NUM +}; + +enum sp_ssc_dep { + SSC_DEP_DISABLE = 0x0, + SSC_DEP_500PPM, + SSC_DEP_1000PPM, + SSC_DEP_1500PPM, + SSC_DEP_2000PPM, + SSC_DEP_2500PPM, + SSC_DEP_3000PPM, + SSC_DEP_3500PPM, + SSC_DEP_4000PPM, + SSC_DEP_4500PPM, + SSC_DEP_5000PPM, + SSC_DEP_5500PPM, + SSC_DEP_6000PPM +}; + +struct clock_data { + unsigned char xtal_clk; + unsigned int xtal_clk_m10; +}; + +void sp_tx_edid_read_initial(void); +u8 sp_tx_get_edid_block(void); +void sp_tx_rst_aux(void); +void edid_read(u8 offset, u8 *pblock_buf); +bool sp_tx_edid_read(u8 *pbuf); +void check_edid_data(u8 *pblock_buf); + +bool slimport_chip_detect(struct anx78xx_data *data); + +void slimport_main_process(struct anx78xx_data *data); + +void sp_tx_variable_init(void); + +u8 sp_tx_aux_dpcdread_bytes(u8 addrh, u8 addrm, + u8 addrl, u8 cCount, u8 *pBuf); +u8 sp_tx_aux_dpcdwrite_bytes(u8 addrh, u8 addrm, + u8 addrl, u8 cCount, u8 *pBuf); +u8 sp_tx_aux_dpcdwrite_byte(u8 addrh, u8 addrm, + u8 addrl, u8 data1); +void sp_tx_show_information(void); +void hdmi_rx_show_video_info(void); +void slimport_block_power_ctrl(enum sp_tx_power_block sp_tx_pd_block, + u8 power); +void vbus_power_ctrl(unsigned char on); +void slimport_initialization(void); +void sp_tx_clean_state_machine(void); +u8 sp_tx_cur_states(void); +void print_sys_state(u8 ss); +u8 slimport_hdcp_cap_check(void); + +void sp_tx_initialization(void); +u8 sp_tx_cur_bw(void); +void sp_tx_set_bw(u8 bw); + +#endif diff --git a/drivers/gpu/drm/i2c/anx78xx/slimport_tx_reg.h b/drivers/gpu/drm/i2c/anx78xx/slimport_tx_reg.h new file mode 100644 index 0000000..db00e7d --- /dev/null +++ b/drivers/gpu/drm/i2c/anx78xx/slimport_tx_reg.h @@ -0,0 +1,786 @@ +/* + * Copyright(c) 2015, Analogix Semiconductor. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 _SP_TX_REG_DEF_H +#define _SP_TX_REG_DEF_H + +#define TX_P0 0x70 +#define TX_P1 0x7A +#define TX_P2 0x72 + +#define RX_P0 0x7e +#define RX_P1 0x80 + +/***************************************************************/ +/*Register definition of device address 0x7e*/ +#define HDMI_RX_PORT_SEL_REG 0x10 +#define DDC_EN 0x10 +#define TMDS_EN 0x01 + +#define RX_SRST 0x11 +#define VIDEO_RST 0x10 +#define HDCP_MAN_RST 0X04 +#define TMDS_RST 0X02 +#define SW_MAN_RST 0X01 + +#define RX_SW_RST2 0x12 +#define DDC_RST 0x04 + +#define HDMI_RX_SYS_STATUS_REG 0X14 +#define PWR5V 0X08 +#define TMDS_VSYNC_DET 0X04 +#define TMDS_CLOCK_DET 0X02 +#define TMDS_DE_DET 0X01 + +#define HDMI_STATUS 0X15 +#define DEEP_COLOR_MODE 0X40 +#define HDMI_AUD_LAYOUT 0X08 +#define MUTE_STAT 0X04 + +#define RX_MUTE_CTRL 0X16 +#define MUTE_POL 0X04 +#define AUD_MUTE 0X02 +#define VID_MUTE 0X01 + +#define HDMI_RX_SYS_CTRL1_REG 0X17 + +#define RX_SYS_PWDN1 0X18 +#define PWDN_CTRL 0X01 + +#define RX_AEC_CTRL 0X20 +#define AVC_OE 0x80 +#define AAC_OE 0X40 +#define AVC_EN 0X02 +#define AAC_EN 0X01 + +#define RX_AEC_EN0 0X24 +#define AEC_EN07 0X80 +#define AEC_EN06 0X40 +#define AEC_EN05 0X20 +#define AEC_EN04 0X10 +#define AEC_EN03 0X08 +#define AEC_EN02 0X04 +#define AEC_EN01 0X02 +#define AEC_EN00 0X01 + +#define RX_AEC_EN1 0X25 +#define AEC_EN15 0X80 +#define AEC_EN14 0X40 +#define AEC_EN13 0X20 +#define AEC_EN12 0X10 +#define AEC_EN11 0X08 +#define AEC_EN10 0X04 +#define AEC_EN09 0X02 +#define AEC_EN08 0X01 + +#define RX_AEC_EN2 0X26 +#define AEC_EN23 0X80 +#define AEC_EN22 0X40 +#define AEC_EN21 0X20 +#define AEC_EN20 0X10 +#define AEC_EN19 0X08 +#define AEC_EN18 0X04 +#define AEC_EN17 0X02 +#define AEC_EN16 0X01 + + +#define HDMI_RX_INT_STATUS1_REG 0X31 +#define HDMI_DVI 0X80 +#define CKDT_CHANGE 0X40 +#define SCDT_CHANGE 0X20 +#define PCLK_CHANGE 0X10 +#define PLL_UNLOCK 0X08 +#define CABLE_UNPLUG 0X04 +#define SET_MUTE 0X02 +#define SW_INTR 0X01 + +#define HDMI_RX_INT_STATUS2_REG 0X32 +#define AUTH_START 0X80 +#define AUTH_DONE 0X40 +#define HDCP_ERR 0X20 +#define ECC_ERR 0X10 +#define AUDIO_SAMPLE_CHANGE 0X01 + +#define HDMI_RX_INT_STATUS3_REG 0X33 +#define AUD_MODE_CHANGE 0X01 + +#define HDMI_RX_INT_STATUS4_REG 0X34 +#define VSYNC_DET 0X80 +#define SYNC_POL_CHANGE 0X40 +#define V_RES_CHANGE 0X20 +#define H_RES_CHANGE 0X10 +#define I_P_CHANGE 0X08 +#define DP_CHANGE 0X04 +#define COLOR_DEPTH_CHANGE 0X02 +#define COLOR_MODE_CHANGE 0X01 + +#define HDMI_RX_INT_STATUS5_REG 0X35 +#define VFIFO_OVERFLOW 0X80 +#define VFIFO_UNDERFLOW 0X40 +#define CTS_N_ERR 0X08 +#define NO_AVI 0X02 +#define AUDIO_RCV 0X01 + +#define HDMI_RX_INT_STATUS6_REG 0X36 +#define CTS_RCV 0X80 +#define NEW_UNR_PKT 0X40 +#define NEW_MPEG 0X20 +#define NEW_AUD 0X10 +#define NEW_SPD 0X08 +#define NEW_ACP 0X04 +#define NEW_AVI 0X02 +#define NEW_CP 0X01 + +#define HDMI_RX_INT_STATUS7_REG 0X37 +#define NO_VSI 0X80 +#define HSYNC_DET 0X20 +#define NEW_VS 0X10 +#define NO_ACP 0X08 +#define REF_CLK_CHG 0X04 +#define CEC_RX_READY 0X02 +#define CEC_TX_DONE 0X01 + +#define HDMI_RX_PKT_RX_INDU_INT_CTRL 0X3F +#define NEW_VS_CTRL 0X80 +#define NEW_UNR 0X40 +#define NEW_MPEG 0X20 +#define NEW_AUD 0X10 +#define NEW_SPD 0X08 +#define NEW_ACP 0X04 +#define NEW_AVI 0X02 + + +#define HDMI_RX_INT_MASK1_REG 0X41 +#define HDMI_RX_INT_MASK2_REG 0X42 +#define HDMI_RX_INT_MASK3_REG 0X43 +#define HDMI_RX_INT_MASK4_REG 0X44 +#define HDMI_RX_INT_MASK5_REG 0X45 +#define HDMI_RX_INT_MASK6_REG 0X46 +#define HDMI_RX_INT_MASK7_REG 0X47 + +#define HDMI_RX_TMDS_CTRL_REG1 0X50 +#define HDMI_RX_TMDS_CTRL_REG2 0X51 +#define HDMI_RX_TMDS_CTRL_REG4 0X53 +#define HDMI_RX_TMDS_CTRL_REG5 0X54 +#define HDMI_RX_TMDS_CTRL_REG6 0X55 +#define HDMI_RX_TMDS_CTRL_REG7 0X56 +#define TERM_PD 0x01 + +#define HDMI_RX_TMDS_CTRL_REG18 0X61 +#define PLL_RESET 0x10 + +#define HDMI_RX_TMDS_CTRL_REG19 0X62 +#define HDMI_RX_TMDS_CTRL_REG20 0X63 +#define HDMI_RX_TMDS_CTRL_REG21 0X64 +#define HDMI_RX_TMDS_CTRL_REG22 0X65 + + +#define HDMI_RX_VIDEO_STATUS_REG1 0x70 +#define COLOR_DEPTH 0xF0 +#define DEFAULT_PHASE 0X08 +#define VIDEO_TYPE 0X04 + + +#define HDMI_RX_HTOTAL_LOW 0X71 +#define HDMI_RX_HTOTAL_HIGH 0X72 +#define HDMI_RX_VTOTAL_LOW 0X73 +#define HDMI_RX_VTOTAL_HIGH 0X74 + +#define HDMI_RX_HACT_LOW 0X75 +#define HDMI_RX_HACT_HIGH 0X76 +#define HDMI_RX_VACT_LOW 0X77 +#define HDMI_RX_VACT_HIGH 0X78 + +#define HDMI_RX_V_SYNC_WIDTH 0X79 +#define HDMI_RX_V_BACK_PORCH 0X7A +#define HDMI_RX_H_FRONT_PORCH_LOW 0X7B +#define HDMI_RX_H_FRONT_PORCH_HIGH 0X7C + +#define HDMI_RX_H_SYNC_WIDTH_LOW 0X7D +#define HDMI_RX_H_SYNC_WIDTH_HIGH 0X7E + +#define RX_VID_DATA_RNG 0X83 +#define YC_LIMT 0X10 +#define OUTPUT_LIMIT_EN 0X08 +#define OUTPUT_LIMIT_RANGE 0X04 +#define R2Y_INPUT_LIMIT 0X02 +#define XVYCC_LIMIT 0X01 + +#define HDMI_RX_VID_OUTPUT_CTRL3_REG 0X86 + +#define HDMI_RX_VID_PCLK_CNTR_REG 0X8B + +#define HDMI_RX_AUD_IN_CH_STATUS1_REG 0xC7 +#define HDMI_RX_AUD_IN_CH_STATUS4_REG 0XCA + +#define RX_CEC_CTRL 0XD0 +#define CEC_RX_EN 0X08 +#define CEC_TX_ST 0X04 +#define CEC_PIN_SEL 0X02 +#define CEC_RST 0X01 + +#define HDMI_RX_CEC_RX_STATUS_REG 0XD1 +#define HDMI_RX_CEC_RX_BUSY 0X80 +#define HDMI_RX_CEC_RX_FULL 0X20 +#define HDMI_RX_CEC_RX_EMP 0X10 + +#define HDMI_RX_CEC_TX_STATUS_REG 0XD2 +#define HDMI_RX_CEC_TX_BUSY 0X80 +#define HDMI_RX_CEC_TX_FAIL 0X40 +#define HDMI_RX_CEC_TX_FULL 0X20 +#define HDMI_RX_CEC_TX_EMP 0X10 + + +#define HDMI_RX_CEC_FIFO_REG 0XD3 + +#define RX_CEC_SPEED 0XD4 +#define CEC_SPEED_27M 0x40 + +#define HDMI_RX_HDMI_CRITERIA_REG 0XE1 + +#define HDMI_RX_HDCP_EN_CRITERIA_REG 0XE2 +#define ENC_EN_MODE 0X20 + +#define RX_CHIP_CTRL 0XE3 +#define MAN_HDMI5V_DET 0X08 +#define PLLLOCK_CKDT_EN 0X04 +#define ANALOG_CKDT_EN 0X02 +#define DIGITAL_CKDT_EN 0X01 + +#define RX_PACKET_REV_STA 0XF3 +#define AVI_RCVD 0X40 +#define VSI_RCVD 0X20 +/***************************************************************/ +/*Register definition of device address 0x80*/ + + +#define HDMI_RX_HDCP_STATUS_REG 0X3F +#define ADV_CIPHER 0X80 +#define LOAD_KEY_DONE 0X40 +#define DECRYPT_EN 0X20 +#define AUTH_EN 0X10 +#define BKSV_DISABLE 0X02 +#define CLEAR_RI 0X01 + +#define HDMI_RX_SPD_TYPE_REG 0X40 +#define HDMI_RX_SPD_VER_REG 0X41 +#define HDMI_RX_SPD_LEN_REG 0X42 +#define HDMI_RX_SPD_CHKSUM_REG 0X43 +#define HDMI_RX_SPD_DATA00_REG 0X44 + +#define HDMI_RX_ACP_HB0_REG 0X60 +#define HDMI_RX_ACP_HB1_REG 0X61 +#define HDMI_RX_ACP_HB2_REG 0X62 +#define HDMI_RX_ACP_DATA00_REG 0X63 + +#define HDMI_RX_AVI_TYPE_REG 0XA0 +#define HDMI_RX_AVI_VER_REG 0XA1 +#define HDMI_RX_AVI_LEN_REG 0XA2 +#define HDMI_RX_AVI_CHKSUM_REG 0XA3 +#define HDMI_RX_AVI_DATA00_REG 0XA4 + +#define HDMI_RX_AUDIO_TYPE_REG 0XC0 +#define HDMI_RX_AUDIO_VER_REG 0XC1 +#define HDMI_RX_AUDIO_LEN_REG 0XC2 +#define HDMI_RX_AUDIO_CHKSUM_REG 0XC3 +#define HDMI_RX_AUDIO_DATA00_REG 0XC4 + +#define HDMI_RX_MPEG_TYPE_REG 0XE0 +#define HDMI_RX_MPEG_VER_REG 0XE1 +#define HDMI_RX_MPEG_LEN_REG 0XE2 +#define HDMI_RX_MPEG_CHKSUM_REG 0XE3 +#define HDMI_RX_MPEG_DATA00_REG 0XE4 +#define HDMI_RX_MPEG_DATA03_REG 0XE7 +#define HDMI_RX_MPEG_DATA05_REG 0XE9 + +#define HDMI_RX_SPD_INFO_CTRL 0X5F +#define HDMI_RX_ACP_INFO_CTRL 0X7F + +#define HDMI_RX_GENERAL_CTRL 0X9F +#define CLEAR_AVMUTE 0x10 +#define SET_AVMUTE 0x01 + +#define HDMI_RX_MPEG_VS_CTRL 0XDF +#define HDMI_RX_MPEG_VS_INFO_CTRL 0XFF + + +/***************************************************************/ +/*Register definition of device address 0x70*/ +#define SP_TX_HDCP_STATUS 0x00 +#define SP_TX_HDCP_AUTH_PASS 0x02 + +#define TX_HDCP_CTRL0 0x01 +#define STORE_AN 0x80 +#define RX_REPEATER 0x40 +#define RE_AUTH 0x20 +#define SW_AUTH_OK 0x10 +#define HARD_AUTH_EN 0x08 +#define ENC_EN 0x04 +#define BKSV_SRM_PASS 0x02 +#define KSVLIST_VLD 0x01 + +#define SP_TX_HDCP_CTRL1_REG 0x02 +#define AINFO_EN 0x04 +#define RCV_11_EN 0x02 +#define HDCP_11_EN 0x01 + +#define SP_TX_HDCP_LINK_CHK_FRAME_NUM 0x03 +#define SP_TX_HDCP_CTRL2_REG 0x04 + + +#define SP_TX_VID_BLANK_SET1 0X2C +#define SP_TX_VID_BLANK_SET2 0X2D +#define SP_TX_VID_BLANK_SET3 0X2E + +#define SP_TX_WAIT_R0_TIME 0x40 +#define SP_TX_LINK_CHK_TIMER 0x41 +#define SP_TX_WAIT_KSVR_TIME 0X42 + +#define HDCP_KEY_STATUS 0x5E + + +#define M_VID_0 0xC0 +#define M_VID_1 0xC1 +#define M_VID_2 0xC2 +#define N_VID_0 0xC3 +#define N_VID_1 0xC4 +#define N_VID_2 0xC5 +#define HDCP_AUTO_TIMER 0x51 +#define HDCP_AUTO_TIMER_VAL 0x00 + +#define HDCP_KEY_CMD 0x5F +#define DISABLE_SYNC_HDCP 0x04 + +#define OTP_KEY_PROTECT1 0x60 +#define OTP_KEY_PROTECT2 0x61 +#define OTP_KEY_PROTECT3 0x62 +#define OTP_PSW1 0xa2 +#define OTP_PSW2 0x7e +#define OTP_PSW3 0xc6 + + +#define SP_TX_SYS_CTRL1_REG 0x80 +#define CHIP_AUTH_RESET 0x80 +#define PD_BYPASS_CHIP_AUTH 0x40 +#define DET_STA 0x04 +#define FORCE_DET 0x02 +#define DET_CTRL 0x01 + +#define SP_TX_SYS_CTRL2_REG 0x81 +#define CHA_STA 0x04 +#define FORCE_CHA 0x02 +#define CHA_CTRL 0x01 + +#define SP_TX_SYS_CTRL3_REG 0x82 +#define HPD_STATUS 0x40 +#define F_HPD 0x20 +#define HPD_CTRL 0x10 +#define STRM_VALID 0x04 +#define F_VALID 0x02 +#define VALID_CTRL 0x01 + +#define SP_TX_SYS_CTRL4_REG 0x83 +#define ENHANCED_MODE 0x08 + +#define SP_TX_VID_CTRL 0x84 + +#define SP_TX_AUD_CTRL 0x87 +#define AUD_EN 0x01 + +#define I2C_GEN_10US_TIMER0 0x88 +#define I2C_GEN_10US_TIMER1 0x89 + +#define SP_TX_PKT_EN_REG 0x90 +#define AUD_IF_UP 0x80 +#define AVI_IF_UD 0x40 +#define MPEG_IF_UD 0x20 +#define SPD_IF_UD 0x10 +#define AUD_IF_EN 0x08 +#define AVI_IF_EN 0x04 +#define MPEG_IF_EN 0x02 +#define SPD_IF_EN 0x01 + +#define TX_HDCP_CTRL 0x92 +#define AUTO_EN 0x80 +#define AUTO_START 0x20 +#define LINK_POLLING 0x02 + +#define SP_TX_LINK_BW_SET_REG 0xA0 +#define LINK_6P75G 0x19 +#define LINK_5P4G 0x14 +#define LINK_2P7G 0x0A +#define LINK_1P62G 0x06 + +#define SP_TX_TRAINING_PTN_SET_REG 0xA2 +#define SCRAMBLE_DISABLE 0x20 + +#define SP_TX_LT_SET_REG 0xA3 +#define MAX_PRE_REACH 0x20 +#define MAX_DRIVE_REACH 0x04 +#define DRVIE_CURRENT_LEVEL1 0x01 +#define PRE_EMP_LEVEL1 0x08 + + +#define LT_CTRL 0xA8 +#define SP_TX_LT_EN 0x01 + +#define TX_DEBUG1 0xB0 +#define FORCE_HPD 0X80 +#define HPD_POLLING_DET 0x40 +#define HPD_POLLING_EN 0x20 +#define DEBUG_PLL_LOCK 0x10 +#define FORCE_PLL_LOCK 0X08 +#define POLLING_EN 0x02 + +#define SP_TX_DP_POLLING_PERIOD 0xB3 + +#define TX_DP_POLLING 0xB4 +#define AUTO_POLLING_DISABLE 0x01 + +#define TX_LINK_DEBUG 0xB8 +#define M_VID_DEBUG 0x20 +#define NEW_PRBS7 0x10 +#define INSERT_ER 0x02 +#define PRBS31_EN 0x01 + +#define DPCD_200 0xB9 +#define DPCD_201 0xBA +#define DPCD_202 0xBB +#define DPCD_203 0xBC +#define DPCD_204 0xBD +#define DPCD_205 0xBE + +#define SP_TX_PLL_CTRL_REG 0xC7 +#define PLL_RST 0x40 + +#define SP_TX_ANALOG_PD_REG 0xC8 +#define MACRO_PD 0x20 +#define AUX_PD 0x10 +#define CH0_PD 0x01 + +#define TX_MISC 0xCD +#define EQ_TRAINING_LOOP 0x40 + + +#define SP_TX_DOWN_SPREADING_CTRL1 0xD0 +#define SP_TX_SSC_DISABLE 0xC0 +#define SP_TX_SSC_DWSPREAD 0x40 + + +#define SP_TX_M_CALCU_CTRL 0xD9 +#define M_GEN_CLK_SEL 0x01 + +#define TX_EXTRA_ADDR 0xCE +#define I2C_STRETCH_DISABLE 0X80 +#define I2C_EXTRA_ADDR 0X50 + +#define SP_TX_AUX_STATUS 0xE0 +#define AUX_BUSY 0x10 + +#define AUX_DEFER_CTRL 0xE2 +#define BUF_DATA_COUNT 0xE4 + +#define AUX_CTRL 0xE5 +#define AUX_ADDR_7_0 0xE6 +#define AUX_ADDR_15_8 0xE7 +#define AUX_ADDR_19_16 0xE8 + +#define AUX_CTRL2 0xE9 +#define ADDR_ONLY_BIT 0x02 +#define AUX_OP_EN 0x01 + +#define SP_TX_3D_VSC_CTRL 0xEA +#define INFO_FRAME_VSC_EN 0x01 + +#define SP_TX_VSC_DB1 0xEB + +#define BUF_DATA_0 0xF0 + + +/***************************************************************/ +/*Register definition of device address 0x72*/ +#define SP_TX_VND_IDL_REG 0x00 +#define SP_TX_VND_IDH_REG 0x01 +#define SP_TX_DEV_IDL_REG 0x02 +#define SP_TX_DEV_IDH_REG 0x03 +#define SP_TX_DEV_REV_REG 0x04 + +#define SP_POWERD_CTRL_REG 0x05 +#define REGISTER_PD 0x80 +#define HDCP_PD 0x20 +#define AUDIO_PD 0x10 +#define VIDEO_PD 0x08 +#define LINK_PD 0x04 +#define TOTAL_PD 0x02 + +#define SP_TX_RST_CTRL_REG 0x06 +#define MISC_RST 0x80 +#define VIDCAP_RST 0x40 +#define VIDFIF_RST 0x20 +#define AUDFIF_RST 0x10 +#define AUDCAP_RST 0x08 +#define HDCP_RST 0x04 +#define SW_RST 0x02 +#define HW_RST 0x01 + +#define RST_CTRL2 0x07 +#define AUX_RST 0x04 +#define SERDES_FIFO_RST 0x02 +#define I2C_REG_RST 0x01 + +#define VID_CTRL1 0x08 +#define VIDEO_EN 0x80 +#define VIDEO_MUTE 0x40 +#define IN_BIT_SEl 0x04 +#define DDR_CTRL 0x02 +#define EDGE_CTRL 0x01 + +#define SP_TX_VID_CTRL2_REG 0x09 +#define IN_BPC_12BIT 0x30 +#define IN_BPC_10BIT 0x20 +#define IN_BPC_8BIT 0x10 + +#define SP_TX_VID_CTRL3_REG 0x0A +#define HPD_OUT 0x40 + +#define SP_TX_VID_CTRL5_REG 0x0C +#define CSC_STD_SEL 0x80 +#define RANGE_Y2R 0x20 +#define CSPACE_Y2R 0x10 + +#define SP_TX_VID_CTRL6_REG 0x0D +#define VIDEO_PROCESS_EN 0x40 +#define UP_SAMPLE 0x02 +#define DOWN_SAMPLE 0x01 + +#define SP_TX_VID_CTRL8_REG 0x0F +#define VID_VRES_TH 0x01 + +#define SP_TX_TOTAL_LINE_STA_L 0x24 +#define SP_TX_TOTAL_LINE_STA_H 0x25 +#define SP_TX_ACT_LINE_STA_L 0x26 +#define SP_TX_ACT_LINE_STA_H 0x27 +#define SP_TX_V_F_PORCH_STA 0x28 +#define SP_TX_V_SYNC_STA 0x29 +#define SP_TX_V_B_PORCH_STA 0x2A +#define SP_TX_TOTAL_PIXEL_STA_L 0x2B +#define SP_TX_TOTAL_PIXEL_STA_H 0x2C +#define SP_TX_ACT_PIXEL_STA_L 0x2D +#define SP_TX_ACT_PIXEL_STA_H 0x2E +#define SP_TX_H_F_PORCH_STA_L 0x2F +#define SP_TX_H_F_PORCH_STA_H 0x30 +#define SP_TX_H_SYNC_STA_L 0x31 +#define SP_TX_H_SYNC_STA_H 0x32 +#define SP_TX_H_B_PORCH_STA_L 0x33 +#define SP_TX_H_B_PORCH_STA_H 0x34 + +#define SP_TX_DP_ADDR_REG1 0x3E + +#define SP_TX_VID_BIT_CTRL0_REG 0x40 +#define SP_TX_VID_BIT_CTRL10_REG 0x4a +#define SP_TX_VID_BIT_CTRL20_REG 0x54 + +#define SP_TX_AVI_TYPE 0x70 +#define SP_TX_AVI_VER 0x71 +#define SP_TX_AVI_LEN 0x72 +#define SP_TX_AVI_DB0 0x73 + +#define BIT_CTRL_SPECIFIC 0x80 +#define ENABLE_BIT_CTRL 0x01 + +#define SP_TX_AUD_TYPE 0x83 +#define SP_TX_AUD_VER 0x84 +#define SP_TX_AUD_LEN 0x85 +#define SP_TX_AUD_DB0 0x86 + +#define SP_TX_SPD_TYPE 0x91 +#define SP_TX_SPD_VER 0x92 +#define SP_TX_SPD_LEN 0x93 +#define SP_TX_SPD_DB0 0x94 + +#define SP_TX_MPEG_TYPE 0xB0 +#define SP_TX_MPEG_VER 0xB1 +#define SP_TX_MPEG_LEN 0xB2 +#define SP_TX_MPEG_DB0 0xB3 + +#define SP_TX_AUD_CH_STATUS_REG1 0xD0 + +#define SP_TX_AUD_CH_NUM_REG5 0xD5 +#define CH_NUM_8 0xE0 +#define AUD_LAYOUT 0x01 + +#define GPIO_1_CONTROL 0xD6 +#define GPIO_1_PULL_UP 0x04 +#define GPIO_1_OEN 0x02 +#define GPIO_1_DATA 0x01 + +#define TX_ANALOG_DEBUG2 0xDD +#define POWERON_TIME_1P5MS 0X03 + +#define TX_PLL_FILTER 0xDF +#define PD_RING_OSC 0x40 +#define V33_SWITCH_ON 0x08 + +#define TX_PLL_FILTER5 0xE0 +#define SP_TX_ANALOG_CTRL0 0xE1 +#define P5V_PROTECT 0X80 +#define SHORT_PROTECT 0X40 +#define P5V_PROTECT_PD 0X20 +#define SHORT_PROTECT_PD 0X10 + +#define TX_ANALOG_CTRL 0xE5 +#define SHORT_DPDM 0X4 + +#define SP_COMMON_INT_STATUS1 0xF1 +#define PLL_LOCK_CHG 0x40 +#define VIDEO_FORMAT_CHG 0x08 +#define AUDIO_CLK_CHG 0x04 +#define VIDEO_CLOCK_CHG 0x02 + +#define SP_COMMON_INT_STATUS2 0xF2 +#define HDCP_AUTH_CHG 0x02 +#define HDCP_AUTH_DONE 0x01 + +#define SP_COMMON_INT_STATUS3 0xF3 +#define HDCP_LINK_CHECK_FAIL 0x01 + +#define SP_COMMON_INT_STATUS4 0xF4 +#define PLUG 0x01 +#define ESYNC_ERR 0x10 +#define HPD_LOST 0x02 +#define HPD_CHANGE 0x04 +#define HPD_IRQ 0x40 + +#define SP_TX_INT_STATUS1 0xF7 +#define DPCD_IRQ_REQUEST 0x80 +#define HPD 0x40 +#define TRAINING_Finish 0x20 +#define POLLING_ERR 0x10 +#define LINK_CHANGE 0x04 +#define SINK_CHG 0x08 + +#define SP_COMMON_INT_MASK1 0xF8 +#define SP_COMMON_INT_MASK2 0xF9 +#define SP_COMMON_INT_MASK3 0xFA +#define SP_COMMON_INT_MASK4 0xFB +#define SP_INT_MASK 0xFE +#define SP_TX_INT_CTRL_REG 0xFF + + +/***************************************************************/ +/*Register definition of device address 0x7a*/ + +#define SP_TX_LT_CTRL_REG0 0x30 +#define SP_TX_LT_CTRL_REG1 0x31 +#define SP_TX_LT_CTRL_REG2 0x34 +#define SP_TX_LT_CTRL_REG3 0x35 +#define SP_TX_LT_CTRL_REG4 0x36 +#define SP_TX_LT_CTRL_REG5 0x37 +#define SP_TX_LT_CTRL_REG6 0x38 +#define SP_TX_LT_CTRL_REG7 0x39 +#define SP_TX_LT_CTRL_REG8 0x3A +#define SP_TX_LT_CTRL_REG9 0x3B +#define SP_TX_LT_CTRL_REG10 0x40 +#define SP_TX_LT_CTRL_REG11 0x41 +#define SP_TX_LT_CTRL_REG12 0x44 +#define SP_TX_LT_CTRL_REG13 0x45 +#define SP_TX_LT_CTRL_REG14 0x46 +#define SP_TX_LT_CTRL_REG15 0x47 +#define SP_TX_LT_CTRL_REG16 0x48 +#define SP_TX_LT_CTRL_REG17 0x49 +#define SP_TX_LT_CTRL_REG18 0x4A +#define SP_TX_LT_CTRL_REG19 0x4B + +#define SP_TX_AUD_INTERFACE_CTRL0 0x5f +#define AUD_INTERFACE_DISABLE 0x80 + +#define SP_TX_AUD_INTERFACE_CTRL2 0x60 +#define M_AUD_ADJUST_ST 0x04 + +#define SP_TX_AUD_INTERFACE_CTRL3 0x62 +#define SP_TX_AUD_INTERFACE_CTRL4 0x67 +#define SP_TX_AUD_INTERFACE_CTRL5 0x68 +#define SP_TX_AUD_INTERFACE_CTRL6 0x69 + +#define OCM_REG3 0x96 +#define OCM_RST 0x80 + +#define FW_VER_REG 0xB7 + + +/***************************************************************/ +/*Definition of DPCD*/ + + +#define DOWN_R_TERM_DET _BIT6 +#define SRAM_EEPROM_LOAD_DONE _BIT5 +#define SRAM_CRC_CHK_DONE _BIT4 +#define SRAM_CRC_CHK_PASS _BIT3 +#define DOWN_STRM_ENC _BIT2 +#define DOWN_STRM_AUTH _BIT1 +#define DOWN_STRM_HPD _BIT0 + + +#define DPCD_DPCD_REV 0x00 +#define DPCD_MAX_LINK_RATE 0x01 + +#define DPCD_MAX_LANE_COUNT 0x02 +#define ENHANCED_FRAME_CAP 0x80 + +#define DPCD_MAX_DOWNSPREAD 0x03 +#define DPCD_NORP 0x04 +#define DPCD_DSPORT_PRESENT 0x05 + +#define DPCD_LINK_BW_SET 0x00 +#define DPCD_LANE_COUNT_SET 0x01 +#define ENHANCED_FRAME_EN 0x80 + +#define DPCD_TRAINING_PATTERN_SET 0x02 +#define DPCD_TRAINNIG_LANE0_SET 0x03 + +#define DPCD_DOWNSPREAD_CTRL 0x07 +#define SPREAD_AMPLITUDE 0X10 + +#define DPCD_SINK_COUNT 0x00 +#define DPCD_SERVICE_IRQ_VECTOR 0x01 +#define TEST_IRQ 0x02 +#define CP_IRQ 0x04 +#define SINK_SPECIFIC_IRQ 0x40 + +#define DPCD_LANE0_1_STATUS 0x02 + +#define DPCD_LANE_ALIGN_UD 0x04 +#define DPCD_SINK_STATUS 0x05 + +#define DPCD_TEST_RESPONSE 0x60 +#define TEST_ACK 0x01 +#define DPCD_TEST_EDID_CHECKSUM_WRITE 0x04 + +#define DPCD_TEST_EDID_CHECKSUM 0x61 + + +#define DPCD_SPECIFIC_INTERRUPT1 0x10 +#define DPCD_USER_COMM1 0x22 + +#define DPCD_SPECIFIC_INTERRUPT2 0x11 + +#define DPCD_TEST_REQUEST 0x18 +#define DPCD_TEST_LINK_RATE 0x19 + +#define DPCD_TEST_LANE_COUNT 0x20 + +#define DPCD_PHY_TEST_PATTERN 0x48 + +#endif +