* [PATCH 0/3] Add initial support for slimport anx78xx
@ 2015-09-06 21:13 Enric Balletbo i Serra
2015-09-06 21:14 ` [PATCH 1/3] of: Add vendor prefix for Analogix Semiconductor, Inc Enric Balletbo i Serra
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Enric Balletbo i Serra @ 2015-09-06 21:13 UTC (permalink / raw)
To: devel, gregkh; +Cc: linux-kernel, sjoerd.simons, javier, span, nathan.chung
Hi all,
The following series add initial support for the Slimport ANX7814 transmitter, a
ultra-low power Full-HD (1080p60) transmitter designed for portable device.
The driver was originally created and based from the work of Junhua Xia from
Analogix. This driver is a refactor of the original driver and fixes different
coding style lines, and different errors/warnings reported by checkpatch. Also
there were thing that I notive that we need to change like:
- Convert the numbered GPIO API to the new descriptor based GPIO API.
- Review the DT binding
- Add missing MODULE_DEVICE_TABLE(of, ...);
- Fix Makefiles and Kconfig to build conditionally.
- Use SIMPLE_DEV_PM_OPS() instead of the deprecated i2c .suspend and
.resume callbacks.
- Move to use managed device resources.
- Remove dead/unused code.
- And others ...
This is the first version so probably will have mistakes so feel free to ping to
incorporate other changes that I need to do in next series.
Best regards,
Enric Balletbo i Serra (3):
of: Add vendor prefix for Analogix Semiconductor, Inc.
devicetree: Add new ANX7814 SlimPort transmitter binding.
staging: slimport: Add anx7814 driver support by analogix.
.../devicetree/bindings/vendor-prefixes.txt | 1 +
.../devicetree/bindings/video/bridge/anx7814.txt | 22 +
drivers/staging/Kconfig | 2 +
drivers/staging/Makefile | 1 +
drivers/staging/slimport/Kconfig | 7 +
drivers/staging/slimport/Makefile | 4 +
drivers/staging/slimport/slimport.c | 301 ++
drivers/staging/slimport/slimport.h | 49 +
drivers/staging/slimport/slimport_tx_drv.c | 3293 ++++++++++++++++++++
drivers/staging/slimport/slimport_tx_drv.h | 254 ++
drivers/staging/slimport/slimport_tx_reg.h | 786 +++++
11 files changed, 4720 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/bridge/anx7814.txt
create mode 100644 drivers/staging/slimport/Kconfig
create mode 100644 drivers/staging/slimport/Makefile
create mode 100644 drivers/staging/slimport/slimport.c
create mode 100644 drivers/staging/slimport/slimport.h
create mode 100644 drivers/staging/slimport/slimport_tx_drv.c
create mode 100644 drivers/staging/slimport/slimport_tx_drv.h
create mode 100644 drivers/staging/slimport/slimport_tx_reg.h
--
2.1.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/3] of: Add vendor prefix for Analogix Semiconductor, Inc.
2015-09-06 21:13 [PATCH 0/3] Add initial support for slimport anx78xx Enric Balletbo i Serra
@ 2015-09-06 21:14 ` Enric Balletbo i Serra
2015-09-06 21:14 ` [PATCH 2/3] devicetree: Add new ANX7814 SlimPort transmitter binding Enric Balletbo i Serra
2015-09-06 21:14 ` [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix Enric Balletbo i Serra
2 siblings, 0 replies; 9+ messages in thread
From: Enric Balletbo i Serra @ 2015-09-06 21:14 UTC (permalink / raw)
To: devel, gregkh; +Cc: linux-kernel, sjoerd.simons, javier, span, nathan.chung
Analogix Semiconductor develops analog and mixed-signal devices for digital
media and communications interconnect applications.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index ac5f0c3..e914a02 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -22,6 +22,7 @@ ampire Ampire Co., Ltd.
ams AMS AG
amstaos AMS-Taos Inc.
apm Applied Micro Circuits Corporation (APM)
+analogix Analogix Semiconductor, Inc.
aptina Aptina Imaging
arasan Arasan Chip Systems
arm ARM Ltd.
--
2.1.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/3] devicetree: Add new ANX7814 SlimPort transmitter binding.
2015-09-06 21:13 [PATCH 0/3] Add initial support for slimport anx78xx Enric Balletbo i Serra
2015-09-06 21:14 ` [PATCH 1/3] of: Add vendor prefix for Analogix Semiconductor, Inc Enric Balletbo i Serra
@ 2015-09-06 21:14 ` Enric Balletbo i Serra
2015-09-06 21:14 ` [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix Enric Balletbo i Serra
2 siblings, 0 replies; 9+ messages in thread
From: Enric Balletbo i Serra @ 2015-09-06 21:14 UTC (permalink / raw)
To: devel, gregkh; +Cc: linux-kernel, sjoerd.simons, javier, span, nathan.chung
The ANX7814 is an ultra-low power Full-HD (1080p60) SlimPort transmitter
designed for portable devices.
You can add support to your board with current binding.
Example:
anx7814: anx7814@38 {
compatible = "analogix,anx7814";
reg = <0x38>;
pd-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
};
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
.../devicetree/bindings/video/bridge/anx7814.txt | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/bridge/anx7814.txt
diff --git a/Documentation/devicetree/bindings/video/bridge/anx7814.txt b/Documentation/devicetree/bindings/video/bridge/anx7814.txt
new file mode 100644
index 0000000..a8cc746
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/bridge/anx7814.txt
@@ -0,0 +1,22 @@
+Analogix ANX7814 SlimPort (Full-HD Transmitter)
+-----------------------------------------------
+
+The ANX7814 is an ultra-low power Full-HD (1080p60) SlimPort transmitter
+designed for portable devices.
+
+Required properties:
+
+ - compatible : "analogix,anx7814"
+ - reg : I2C address of the device
+ - pd-gpios : Which GPIO to use for power down
+ - reset-gpios : Which GPIO to use for reset
+
+Example:
+
+ anx7814: anx7814@38 {
+ compatible = "analogix,anx7814";
+ reg = <0x38>;
+ pd-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
+ };
+
--
2.1.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix.
2015-09-06 21:13 [PATCH 0/3] Add initial support for slimport anx78xx Enric Balletbo i Serra
2015-09-06 21:14 ` [PATCH 1/3] of: Add vendor prefix for Analogix Semiconductor, Inc Enric Balletbo i Serra
2015-09-06 21:14 ` [PATCH 2/3] devicetree: Add new ANX7814 SlimPort transmitter binding Enric Balletbo i Serra
@ 2015-09-06 21:14 ` Enric Balletbo i Serra
2015-09-06 23:27 ` Greg KH
2 siblings, 1 reply; 9+ messages in thread
From: Enric Balletbo i Serra @ 2015-09-06 21:14 UTC (permalink / raw)
To: devel, gregkh; +Cc: linux-kernel, sjoerd.simons, javier, span, nathan.chung
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 <enric.balletbo@collabora.com>
---
drivers/staging/Kconfig | 2 +
drivers/staging/Makefile | 1 +
drivers/staging/slimport/Kconfig | 7 +
drivers/staging/slimport/Makefile | 4 +
drivers/staging/slimport/slimport.c | 301 +++
drivers/staging/slimport/slimport.h | 49 +
drivers/staging/slimport/slimport_tx_drv.c | 3293 ++++++++++++++++++++++++++++
drivers/staging/slimport/slimport_tx_drv.h | 254 +++
drivers/staging/slimport/slimport_tx_reg.h | 786 +++++++
9 files changed, 4697 insertions(+)
create mode 100644 drivers/staging/slimport/Kconfig
create mode 100644 drivers/staging/slimport/Makefile
create mode 100644 drivers/staging/slimport/slimport.c
create mode 100644 drivers/staging/slimport/slimport.h
create mode 100644 drivers/staging/slimport/slimport_tx_drv.c
create mode 100644 drivers/staging/slimport/slimport_tx_drv.h
create mode 100644 drivers/staging/slimport/slimport_tx_reg.h
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index e29293c..24ccd7c 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -110,4 +110,6 @@ source "drivers/staging/wilc1000/Kconfig"
source "drivers/staging/most/Kconfig"
+source "drivers/staging/slimport/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 50824dd..942e886 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -47,3 +47,4 @@ obj-$(CONFIG_FB_TFT) += fbtft/
obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/
obj-$(CONFIG_WILC1000) += wilc1000/
obj-$(CONFIG_MOST) += most/
+obj-$(CONFIG_SLIMPORT_ANX78XX) += slimport/
diff --git a/drivers/staging/slimport/Kconfig b/drivers/staging/slimport/Kconfig
new file mode 100644
index 0000000..f5233ef
--- /dev/null
+++ b/drivers/staging/slimport/Kconfig
@@ -0,0 +1,7 @@
+config SLIMPORT_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/staging/slimport/Makefile b/drivers/staging/slimport/Makefile
new file mode 100644
index 0000000..9bb6ce2
--- /dev/null
+++ b/drivers/staging/slimport/Makefile
@@ -0,0 +1,4 @@
+obj-${CONFIG_SLIMPORT_ANX78XX} := anx78xx.o
+
+anx78xx-y := slimport.o
+anx78xx-y += slimport_tx_drv.o
diff --git a/drivers/staging/slimport/slimport.c b/drivers/staging/slimport/slimport.c
new file mode 100644
index 0000000..95c5114
--- /dev/null
+++ b/drivers/staging/slimport/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 <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/async.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/delay.h>
+
+#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 *anx7814_client;
+
+int sp_read_reg_byte(uint8_t slave_addr, uint8_t offset)
+{
+ int ret = 0;
+ struct device *dev = &anx7814_client->dev;
+
+ anx7814_client->addr = (slave_addr >> 1);
+ ret = i2c_smbus_read_byte_data(anx7814_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 = &anx7814_client->dev;
+
+ anx7814_client->addr = (slave_addr >> 1);
+ ret = i2c_smbus_read_byte_data(anx7814_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 = &anx7814_client->dev;
+
+ anx7814_client->addr = (slave_addr >> 1);
+ ret = i2c_smbus_write_byte_data(anx7814_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 anx7814_data *data)
+{
+ struct device *dev = &data->client->dev;
+ struct anx7814_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: anx7814 power on\n", LOG_TAG);
+}
+
+void sp_tx_hardware_powerdown(struct anx7814_data *data)
+{
+ struct device *dev = &data->client->dev;
+ struct anx7814_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: anx7814 power down\n", LOG_TAG);
+}
+
+static int anx7814_init_gpio(struct anx7814_data *data)
+{
+ struct device *dev = &data->client->dev;
+ struct anx7814_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 anx7814_system_init(struct anx7814_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 anx7814\n");
+ return -ENODEV;
+ }
+
+ sp_tx_variable_init();
+ return 0;
+}
+
+static void anx7814_work_func(struct work_struct *work)
+{
+ struct anx7814_data *data = container_of(work, struct anx7814_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 anx7814_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct anx7814_data *data;
+ struct anx7814_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 anx7814_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ pdata = devm_kzalloc(&client->dev,
+ sizeof(struct anx7814_platform_data),
+ GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ data->pdata = pdata;
+
+ data->client = client;
+ anx7814_client = client;
+
+ mutex_init(&data->lock);
+
+ ret = anx7814_init_gpio(data);
+ if (ret) {
+ dev_err(&client->dev, "failed to initialize gpios\n");
+ return ret;
+ }
+
+ INIT_DELAYED_WORK(&data->work, anx7814_work_func);
+
+ data->workqueue = create_singlethread_workqueue("anx7814_work");
+ if (data->workqueue == NULL) {
+ dev_err(&client->dev, "failed to create work queue\n");
+ return -ENOMEM;
+ }
+
+ ret = anx7814_system_init(data);
+ if (ret) {
+ dev_err(&client->dev, "failed to initialize anx7814\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 anx7814_i2c_remove(struct i2c_client *client)
+{
+ struct anx7814_data *data = i2c_get_clientdata(client);
+
+ destroy_workqueue(data->workqueue);
+
+ return 0;
+}
+
+static int anx7814_i2c_suspend(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct anx7814_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 anx7814_i2c_resume(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct anx7814_data *anx7814 = i2c_get_clientdata(client);
+
+ dev_info(&client->dev, "resume\n");
+ queue_delayed_work(anx7814->workqueue, &anx7814->work, 0);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(anx7814_i2c_pm_ops,
+ anx7814_i2c_suspend, anx7814_i2c_resume);
+
+static const struct i2c_device_id anx7814_id[] = {
+ {"anx7814", 0},
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(i2c, anx7814_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 anx7814_driver = {
+ .driver = {
+ .name = "anx7814",
+ .pm = &anx7814_i2c_pm_ops,
+ .of_match_table = of_match_ptr(anx_match_table),
+ },
+ .probe = anx7814_i2c_probe,
+ .remove = anx7814_i2c_remove,
+ .id_table = anx7814_id,
+};
+
+module_i2c_driver(anx7814_driver);
+
+MODULE_DESCRIPTION("Slimport transmitter ANX7814 driver");
+MODULE_AUTHOR("Junhua Xia <jxia@analogixsemi.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("1.1");
diff --git a/drivers/staging/slimport/slimport.h b/drivers/staging/slimport/slimport.h
new file mode 100644
index 0000000..614d746
--- /dev/null
+++ b/drivers/staging/slimport/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 <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/gpio/consumer.h>
+
+#define AUX_ERR 1
+#define AUX_OK 0
+
+#define LOG_TAG "SlimPort ANX78XX"
+
+struct anx7814_platform_data {
+ struct gpio_desc *gpiod_pd;
+ struct gpio_desc *gpiod_reset;
+ spinlock_t lock;
+};
+
+struct anx7814_data {
+ struct i2c_client *client;
+ struct anx7814_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 anx7814_data *data);
+void sp_tx_hardware_powerdown(struct anx7814_data *data);
+
+#endif
diff --git a/drivers/staging/slimport/slimport_tx_drv.c b/drivers/staging/slimport/slimport_tx_drv.c
new file mode 100644
index 0000000..6fad502
--- /dev/null
+++ b/drivers/staging/slimport/slimport_tx_drv.c
@@ -0,0 +1,3293 @@
+/*
+ * 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 <linux/delay.h>
+#include <linux/types.h>
+
+#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 unsigned char sp_i2c_read_byte(unsigned char dev, unsigned char offset);
+static void hdmi_rx_new_vsi_int(void);
+
+#define reg_bit_ctl(addr, offset, data, enable) \
+ do { \
+ 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); \
+ } \
+ } \
+ } while (0)
+
+#define sp_tx_video_mute(enable) \
+ reg_bit_ctl(TX_P2, VID_CTRL1, VIDEO_MUTE, enable)
+
+#define hdmi_rx_mute_audio(enable) \
+ reg_bit_ctl(RX_P0, RX_MUTE_CTRL, AUD_MUTE, enable)
+
+#define hdmi_rx_mute_video(enable) \
+ reg_bit_ctl(RX_P0, RX_MUTE_CTRL, VID_MUTE, enable)
+
+#define sp_tx_addronly_set(enable) \
+ reg_bit_ctl(TX_P0, AUX_CTRL2, ADDR_ONLY_BIT, enable)
+
+#define sp_tx_set_link_bw(bw) \
+ sp_write_reg(TX_P0, SP_TX_LINK_BW_SET_REG, bw)
+
+#define sp_tx_get_link_bw() \
+ sp_i2c_read_byte(TX_P0, SP_TX_LINK_BW_SET_REG)
+
+#define sp_tx_get_pll_lock_status() \
+ ((sp_i2c_read_byte(TX_P0, TX_DEBUG1) & DEBUG_PLL_LOCK) != 0 ? 1 : 0)
+
+#define gen_m_clk_with_downspeading() \
+ sp_write_reg_or(TX_P0, SP_TX_M_CALCU_CTRL, M_GEN_CLK_SEL)
+
+#define gen_m_clk_without_downspeading \
+ sp_write_reg_and(TX_P0, SP_TX_M_CALCU_CTRL, (~M_GEN_CLK_SEL))
+
+#define hdmi_rx_set_hpd(enable) do { \
+ if ((bool)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); \
+ } while (0)
+
+#define hdmi_rx_set_termination(enable) do { \
+ if ((bool)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); \
+ } while (0)
+
+#define sp_tx_clean_hdcp_status() do { \
+ 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__); \
+ } while (0)
+
+#define reg_hardware_reset() do { \
+ 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); \
+ } while (0)
+
+#define write_dpcd_addr(addrh, addrm, addrl) \
+ do { \
+ u8 temp; \
+ if (sp_i2c_read_byte(TX_P0, AUX_ADDR_7_0) != (u8)addrl) \
+ sp_write_reg(TX_P0, AUX_ADDR_7_0, (u8)addrl); \
+ if (sp_i2c_read_byte(TX_P0, AUX_ADDR_15_8) \
+ != (u8)addrm) \
+ sp_write_reg(TX_P0, \
+ AUX_ADDR_15_8, (u8)addrm); \
+ sp_read_reg(TX_P0, AUX_ADDR_19_16, &temp); \
+ if ((u8)(temp & 0x0F) != ((u8)addrh & 0x0F)) \
+ sp_write_reg(TX_P0, AUX_ADDR_19_16, \
+ (temp & 0xF0) | ((u8)addrh)); \
+ } while (0)
+
+#define sp_tx_set_sys_state(ss) \
+ do { \
+ 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 = (u8)ss; \
+ g_need_clean_status = 1; \
+ print_sys_state(sp_tx_system_state); \
+ } while (0)
+
+#define goto_next_system_state() \
+ do { \
+ 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); \
+ } while (0)
+
+#define redo_cur_system_state() \
+ do { \
+ 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); \
+ } while (0)
+
+#define system_state_change_with_case(status) \
+ do { \
+ 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 = (u8)status; \
+ print_sys_state(sp_tx_system_state); \
+ } \
+ } while (0)
+
+#define sp_write_reg_or(address, offset, mask) \
+ sp_write_reg(address, offset, \
+ ((unsigned char)sp_i2c_read_byte(address, offset) | (mask)))
+
+#define sp_write_reg_and(address, offset, mask) \
+ sp_write_reg(address, offset, \
+ ((unsigned char)sp_i2c_read_byte(address, offset) & (mask)))
+
+#define sp_write_reg_and_or(address, offset, and_mask, or_mask) \
+ sp_write_reg(address, offset, \
+ (((unsigned char)sp_i2c_read_byte(address, offset)) \
+ & and_mask) | (or_mask))
+
+#define sp_write_reg_or_and(address, offset, or_mask, and_mask) \
+ sp_write_reg(address, offset, \
+ (((unsigned char)sp_i2c_read_byte(address, offset)) \
+ | or_mask) & (and_mask))
+
+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 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 anx7814_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, (~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 anx7814_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 anx7814_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,
+ ~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,
+ (~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 anx7814_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 anx7814_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/staging/slimport/slimport_tx_drv.h b/drivers/staging/slimport/slimport_tx_drv.h
new file mode 100644
index 0000000..9aaf47d
--- /dev/null
+++ b/drivers/staging/slimport/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 anx7814_data *data);
+
+void slimport_main_process(struct anx7814_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/staging/slimport/slimport_tx_reg.h b/drivers/staging/slimport/slimport_tx_reg.h
new file mode 100644
index 0000000..ebfa1fc
--- /dev/null
+++ b/drivers/staging/slimport/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
+
--
2.1.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix.
2015-09-06 21:14 ` [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix Enric Balletbo i Serra
@ 2015-09-06 23:27 ` Greg KH
2015-09-07 5:41 ` Enric Balletbo Serra
0 siblings, 1 reply; 9+ messages in thread
From: Greg KH @ 2015-09-06 23:27 UTC (permalink / raw)
To: Enric Balletbo i Serra
Cc: devel, linux-kernel, sjoerd.simons, javier, span, nathan.chung
On Sun, Sep 06, 2015 at 11:14:02PM +0200, Enric Balletbo i Serra wrote:
> 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 <enric.balletbo@collabora.com>
> ---
> drivers/staging/Kconfig | 2 +
> drivers/staging/Makefile | 1 +
> drivers/staging/slimport/Kconfig | 7 +
> drivers/staging/slimport/Makefile | 4 +
> drivers/staging/slimport/slimport.c | 301 +++
> drivers/staging/slimport/slimport.h | 49 +
> drivers/staging/slimport/slimport_tx_drv.c | 3293 ++++++++++++++++++++++++++++
> drivers/staging/slimport/slimport_tx_drv.h | 254 +++
> drivers/staging/slimport/slimport_tx_reg.h | 786 +++++++
Why is this a staging driver?
What prevents it from being merged into the "real" part of the kernel
tree?
All staging drivers need a TODO file, listing what needs to be done and
who is in charge of it. I can't take this without that added.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix.
2015-09-06 23:27 ` Greg KH
@ 2015-09-07 5:41 ` Enric Balletbo Serra
2015-09-07 6:46 ` Greg KH
0 siblings, 1 reply; 9+ messages in thread
From: Enric Balletbo Serra @ 2015-09-07 5:41 UTC (permalink / raw)
To: Greg KH
Cc: devel, linux-kernel, Sjoerd Simons, Javier Martinez Canillas,
span, nathan.chung
2015-09-07 1:27 GMT+02:00 Greg KH <gregkh@linuxfoundation.org>:
> On Sun, Sep 06, 2015 at 11:14:02PM +0200, Enric Balletbo i Serra wrote:
>> 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 <enric.balletbo@collabora.com>
>> ---
>> drivers/staging/Kconfig | 2 +
>> drivers/staging/Makefile | 1 +
>> drivers/staging/slimport/Kconfig | 7 +
>> drivers/staging/slimport/Makefile | 4 +
>> drivers/staging/slimport/slimport.c | 301 +++
>> drivers/staging/slimport/slimport.h | 49 +
>> drivers/staging/slimport/slimport_tx_drv.c | 3293 ++++++++++++++++++++++++++++
>> drivers/staging/slimport/slimport_tx_drv.h | 254 +++
>> drivers/staging/slimport/slimport_tx_reg.h | 786 +++++++
>
> Why is this a staging driver?
> What prevents it from being merged into the "real" part of the kernel
> tree?
>
I'll be glad to move the driver to their subsystem if you think it's a
the better place. Basically there are two reasons why I send the
driver to the staging directory. The first one is because my test
environment is a bit limited, with my environment I can only test the
HDMI to DisplayPort pass-through mode so the driver builds but it's
partially tested. The second one is that I expect I'll need to
refactor some code, specially in slimport_tx_drv.c file to be
accepted, I decided not change too much this file from the original to
not break the functionality, so I thought that will be better send
first to the staging driver to have first reviews.
> All staging drivers need a TODO file, listing what needs to be done and
> who is in charge of it. I can't take this without that added.
>
ok, I'll add in the next series once received some feedback (or move
to the video subsystem)
Thanks,
Enric
> thanks,
>
> greg k-h
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix.
2015-09-07 5:41 ` Enric Balletbo Serra
@ 2015-09-07 6:46 ` Greg KH
2015-09-09 3:38 ` Daniel Kurtz
0 siblings, 1 reply; 9+ messages in thread
From: Greg KH @ 2015-09-07 6:46 UTC (permalink / raw)
To: Enric Balletbo Serra
Cc: devel, linux-kernel, Sjoerd Simons, Javier Martinez Canillas,
span, nathan.chung
On Mon, Sep 07, 2015 at 07:41:08AM +0200, Enric Balletbo Serra wrote:
> 2015-09-07 1:27 GMT+02:00 Greg KH <gregkh@linuxfoundation.org>:
> > On Sun, Sep 06, 2015 at 11:14:02PM +0200, Enric Balletbo i Serra wrote:
> >> 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 <enric.balletbo@collabora.com>
> >> ---
> >> drivers/staging/Kconfig | 2 +
> >> drivers/staging/Makefile | 1 +
> >> drivers/staging/slimport/Kconfig | 7 +
> >> drivers/staging/slimport/Makefile | 4 +
> >> drivers/staging/slimport/slimport.c | 301 +++
> >> drivers/staging/slimport/slimport.h | 49 +
> >> drivers/staging/slimport/slimport_tx_drv.c | 3293 ++++++++++++++++++++++++++++
> >> drivers/staging/slimport/slimport_tx_drv.h | 254 +++
> >> drivers/staging/slimport/slimport_tx_reg.h | 786 +++++++
> >
> > Why is this a staging driver?
> > What prevents it from being merged into the "real" part of the kernel
> > tree?
> >
>
> I'll be glad to move the driver to their subsystem if you think it's a
> the better place. Basically there are two reasons why I send the
> driver to the staging directory. The first one is because my test
> environment is a bit limited, with my environment I can only test the
> HDMI to DisplayPort pass-through mode so the driver builds but it's
> partially tested. The second one is that I expect I'll need to
> refactor some code, specially in slimport_tx_drv.c file to be
> accepted, I decided not change too much this file from the original to
> not break the functionality, so I thought that will be better send
> first to the staging driver to have first reviews.
>
> > All staging drivers need a TODO file, listing what needs to be done and
> > who is in charge of it. I can't take this without that added.
> >
>
> ok, I'll add in the next series once received some feedback (or move
> to the video subsystem)
I suggest trying to get it merged "properly" first before having to
fall-back to the staging subsystem.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix.
2015-09-07 6:46 ` Greg KH
@ 2015-09-09 3:38 ` Daniel Kurtz
2015-09-09 7:10 ` Enric Balletbo Serra
0 siblings, 1 reply; 9+ messages in thread
From: Daniel Kurtz @ 2015-09-09 3:38 UTC (permalink / raw)
To: Enric Balletbo Serra
Cc: devel, Greg KH, linux-kernel@vger.kernel.org, Sjoerd Simons,
Javier Martinez Canillas, span, Nathan Chung, dri-devel
Hi Eric,
Thanks for starting to upstream this Analogix Slimport driver!
As Greg says, please move this driver to its intended directory, I presume:
/drivers/gpu/drm/bridge
And when you submit, use get_maintainer.pl to add the proper reviewers
and lists.
At present, you have no DRM folks, nor dri-devel, so you probably
won't receive any additional feedback on this version, since the
relevant folks have not seen your emails.
Some more very detailed feedback inline...
On Sep 7, 2015 05:15, "Enric Balletbo i Serra" <eballetbo@gmail.com> wrote:
>
> 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 <enric.balletbo@collabora.com>
> ---
> drivers/staging/Kconfig | 2 +
> drivers/staging/Makefile | 1 +
> drivers/staging/slimport/Kconfig | 7 +
> drivers/staging/slimport/Makefile | 4 +
> drivers/staging/slimport/slimport.c | 301 +++
> drivers/staging/slimport/slimport.h | 49 +
> drivers/staging/slimport/slimport_tx_drv.c | 3293 ++++++++++++++++++++++++++++
> drivers/staging/slimport/slimport_tx_drv.h | 254 +++
> drivers/staging/slimport/slimport_tx_reg.h | 786 +++++++
> 9 files changed, 4697 insertions(+)
> create mode 100644 drivers/staging/slimport/Kconfig
> create mode 100644 drivers/staging/slimport/Makefile
> create mode 100644 drivers/staging/slimport/slimport.c
> create mode 100644 drivers/staging/slimport/slimport.h
> create mode 100644 drivers/staging/slimport/slimport_tx_drv.c
> create mode 100644 drivers/staging/slimport/slimport_tx_drv.h
> create mode 100644 drivers/staging/slimport/slimport_tx_reg.h
>
> diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
> index e29293c..24ccd7c 100644
> --- a/drivers/staging/Kconfig
> +++ b/drivers/staging/Kconfig
> @@ -110,4 +110,6 @@ source "drivers/staging/wilc1000/Kconfig"
>
> source "drivers/staging/most/Kconfig"
>
> +source "drivers/staging/slimport/Kconfig"
> +
> endif # STAGING
> diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
> index 50824dd..942e886 100644
> --- a/drivers/staging/Makefile
> +++ b/drivers/staging/Makefile
> @@ -47,3 +47,4 @@ obj-$(CONFIG_FB_TFT) += fbtft/
> obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/
> obj-$(CONFIG_WILC1000) += wilc1000/
> obj-$(CONFIG_MOST) += most/
> +obj-$(CONFIG_SLIMPORT_ANX78XX) += slimport/
> diff --git a/drivers/staging/slimport/Kconfig b/drivers/staging/slimport/Kconfig
> new file mode 100644
> index 0000000..f5233ef
> --- /dev/null
> +++ b/drivers/staging/slimport/Kconfig
> @@ -0,0 +1,7 @@
> +config SLIMPORT_ANX78XX
I think the "SLIMPORT_" here is a bit overkill, and just adds to
confusion over what name to use where. I'd recommend just
CONFIG_ANX78XX.
Likewise, for consistency, the rename the files as "anx78xx*" instead
of "slimport*".
> + 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/staging/slimport/Makefile b/drivers/staging/slimport/Makefile
> new file mode 100644
> index 0000000..9bb6ce2
> --- /dev/null
> +++ b/drivers/staging/slimport/Makefile
> @@ -0,0 +1,4 @@
> +obj-${CONFIG_SLIMPORT_ANX78XX} := anx78xx.o
> +
> +anx78xx-y := slimport.o
> +anx78xx-y += slimport_tx_drv.o
> diff --git a/drivers/staging/slimport/slimport.c b/drivers/staging/slimport/slimport.c
> new file mode 100644
> index 0000000..95c5114
> --- /dev/null
> +++ b/drivers/staging/slimport/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 <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/types.h>
> +#include <linux/err.h>
> +#include <linux/async.h>
> +#include <linux/of_gpio.h>
> +#include <linux/of_platform.h>
> +#include <linux/delay.h>
> +
> +#include "slimport.h"
> +#include "slimport_tx_drv.h"
> +
> +/* HDCP switch for external block */
> +/* external_block_en = 1: enable, 0: disable */
This comment is a bit superfluous.
> +int external_block_en = 1;
> +
> +struct i2c_client *anx7814_client;
A single global client isn't going to work. It is easy to imagine a
machine with more than one anx78xx, requiring multiple instances of
the driver and hence multiple i2c clients.
Also, you'll want to be a bit more consistent with naming; is the
driver for anx78xx? Or anx7814 only?
> +
> +int sp_read_reg_byte(uint8_t slave_addr, uint8_t offset)
> +{
> + int ret = 0;
> + struct device *dev = &anx7814_client->dev;
The use of global anx7814_client has ramifications throughout this
whole driver. direct
Please re-write all of these transaction functions (and their callers)
should to take a context struct pointer as their first parameter.
> +
> + anx7814_client->addr = (slave_addr >> 1);
> + ret = i2c_smbus_read_byte_data(anx7814_client, offset);
> + if (ret < 0) {
> + dev_err(dev, "%s: failed to read i2c addr=%x\n", LOG_TAG,
> + slave_addr);
> + return ret;
> + }
> + return 0;
Don't you need to return the actual byte that was read (ret)?
> +}
> +
> +int sp_read_reg(uint8_t slave_addr, uint8_t offset, uint8_t *buf)
> +{
> + int ret = 0;
> + struct device *dev = &anx7814_client->dev;
> +
> + anx7814_client->addr = (slave_addr >> 1);
> + ret = i2c_smbus_read_byte_data(anx7814_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 = &anx7814_client->dev;
> +
> + anx7814_client->addr = (slave_addr >> 1);
> + ret = i2c_smbus_write_byte_data(anx7814_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 anx7814_data *data)
nit: another personal preference, I prefer to use the specific device
as the local parameter name, rather than the generic "data".
So it would look something like:
void anx7814_tx_hardware_poweron(struct anx7814 *anx7814)
> +{
> + struct device *dev = &data->client->dev;
> + struct anx7814_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: anx7814 power on\n", LOG_TAG);
This kind of verbose logging should be dev_dbg(
> +}
> +
> +void sp_tx_hardware_powerdown(struct anx7814_data *data)
> +{
> + struct device *dev = &data->client->dev;
> + struct anx7814_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: anx7814 power down\n", LOG_TAG);
> +}
> +
> +static int anx7814_init_gpio(struct anx7814_data *data)
> +{
> + struct device *dev = &data->client->dev;
> + struct anx7814_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 anx7814_system_init(struct anx7814_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 anx7814\n");
> + return -ENODEV;
> + }
> +
> + sp_tx_variable_init();
> + return 0;
> +}
> +
> +static void anx7814_work_func(struct work_struct *work)
> +{
> + struct anx7814_data *data = container_of(work, struct anx7814_data,
> + work.work);
> + int workqueu_timer = 0;
spelling: workqueue_timer
> +
> + 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));
The use of a periodic workqueue and a state machine like this seems
like the wrong approach.
The driver should be event driven, and any worker should do whatever
work is required until it completes, rather than arbitrarily chopping
up the tasks into ~100 ms chunks.
> +}
> +
> +static int anx7814_i2c_probe(struct i2c_client *client,
> + const struct i2c_device_id *id)
> +{
> + struct anx7814_data *data;
> + struct anx7814_platform_data *pdata;
> + int ret = 0;
In general, I prefer not to see 'ret' variables initialized up here to
a default value. Rather, only set the ret value as needed.
This let's the compiler catch if there were any 'return' paths that
did not explicitly initialize ret.
> +
> + 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 anx7814_data),
> + GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + pdata = devm_kzalloc(&client->dev,
> + sizeof(struct anx7814_platform_data),
> + GFP_KERNEL);
> + if (!pdata)
> + return -ENOMEM;
If you are always explicitly allocating both anyway, might as well
just embed a "struct anx7814_platform_data" directly in "struct
anx7814_data".
> +
> + data->pdata = pdata;
> +
> + data->client = client;
> + anx7814_client = client;
> +
> + mutex_init(&data->lock);
> +
> + ret = anx7814_init_gpio(data);
> + if (ret) {
> + dev_err(&client->dev, "failed to initialize gpios\n");
> + return ret;
> + }
> +
> + INIT_DELAYED_WORK(&data->work, anx7814_work_func);
> +
> + data->workqueue = create_singlethread_workqueue("anx7814_work");
> + if (data->workqueue == NULL) {
> + dev_err(&client->dev, "failed to create work queue\n");
> + return -ENOMEM;
> + }
> +
> + ret = anx7814_system_init(data);
> + if (ret) {
> + dev_err(&client->dev, "failed to initialize anx7814\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 anx7814_i2c_remove(struct i2c_client *client)
> +{
> + struct anx7814_data *data = i2c_get_clientdata(client);
> +
> + destroy_workqueue(data->workqueue);
> +
> + return 0;
> +}
> +
> +static int anx7814_i2c_suspend(struct device *dev)
> +{
> + struct i2c_client *client = container_of(dev, struct i2c_client, dev);
> + struct anx7814_data *data = i2c_get_clientdata(client);
> +
> + dev_info(&client->dev, "suspend\n");
dev_dbg (or just remove this, since it is a bit redundant with verbose
suspend logging).
> + cancel_delayed_work_sync(&data->work);
> + flush_workqueue(data->workqueue);
> + sp_tx_hardware_powerdown(data);
> + sp_tx_clean_state_machine();
> +
> + return 0;
> +}
> +
> +static int anx7814_i2c_resume(struct device *dev)
> +{
> + struct i2c_client *client = container_of(dev, struct i2c_client, dev);
> + struct anx7814_data *anx7814 = i2c_get_clientdata(client);
> +
> + dev_info(&client->dev, "resume\n");
> + queue_delayed_work(anx7814->workqueue, &anx7814->work, 0);
> +
> + return 0;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(anx7814_i2c_pm_ops,
> + anx7814_i2c_suspend, anx7814_i2c_resume);
> +
> +static const struct i2c_device_id anx7814_id[] = {
> + {"anx7814", 0},
> + { /* sentinel */ }
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, anx7814_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 anx7814_driver = {
> + .driver = {
> + .name = "anx7814",
> + .pm = &anx7814_i2c_pm_ops,
> + .of_match_table = of_match_ptr(anx_match_table),
> + },
> + .probe = anx7814_i2c_probe,
> + .remove = anx7814_i2c_remove,
> + .id_table = anx7814_id,
> +};
> +
> +module_i2c_driver(anx7814_driver);
> +
> +MODULE_DESCRIPTION("Slimport transmitter ANX7814 driver");
> +MODULE_AUTHOR("Junhua Xia <jxia@analogixsemi.com>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_VERSION("1.1");
> diff --git a/drivers/staging/slimport/slimport.h b/drivers/staging/slimport/slimport.h
> new file mode 100644
> index 0000000..614d746
> --- /dev/null
> +++ b/drivers/staging/slimport/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 <linux/i2c.h>
> +#include <linux/mutex.h>
> +#include <linux/slab.h>
> +#include <linux/workqueue.h>
> +#include <linux/gpio/consumer.h>
> +
> +#define AUX_ERR 1
> +#define AUX_OK 0
> +
> +#define LOG_TAG "SlimPort ANX78XX"
> +
> +struct anx7814_platform_data {
> + struct gpio_desc *gpiod_pd;
> + struct gpio_desc *gpiod_reset;
> + spinlock_t lock;
> +};
> +
> +struct anx7814_data {
Nit: my personal preference would be to drop the "_data":
struct anx7814 (or struct anx78xx, to match the driver name).
> + struct i2c_client *client;
> + struct anx7814_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 anx7814_data *data);
> +void sp_tx_hardware_powerdown(struct anx7814_data *data);
> +
> +#endif
> diff --git a/drivers/staging/slimport/slimport_tx_drv.c b/drivers/staging/slimport/slimport_tx_drv.c
> new file mode 100644
> index 0000000..6fad502
> --- /dev/null
> +++ b/drivers/staging/slimport/slimport_tx_drv.c
> @@ -0,0 +1,3293 @@
> +/*
> + * 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 <linux/delay.h>
> +#include <linux/types.h>
> +
> +#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 unsigned char sp_i2c_read_byte(unsigned char dev, unsigned char offset);
> +static void hdmi_rx_new_vsi_int(void);
... yeah, this driver needs a lot of work. All of the above global
state variables need to go away.
> +
> +#define reg_bit_ctl(addr, offset, data, enable) \
> + do { \
> + 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); \
> + } \
> + } \
> + } while (0)
> +
> +#define sp_tx_video_mute(enable) \
> + reg_bit_ctl(TX_P2, VID_CTRL1, VIDEO_MUTE, enable)
> +
> +#define hdmi_rx_mute_audio(enable) \
> + reg_bit_ctl(RX_P0, RX_MUTE_CTRL, AUD_MUTE, enable)
> +
> +#define hdmi_rx_mute_video(enable) \
> + reg_bit_ctl(RX_P0, RX_MUTE_CTRL, VID_MUTE, enable)
> +
> +#define sp_tx_addronly_set(enable) \
> + reg_bit_ctl(TX_P0, AUX_CTRL2, ADDR_ONLY_BIT, enable)
> +
> +#define sp_tx_set_link_bw(bw) \
> + sp_write_reg(TX_P0, SP_TX_LINK_BW_SET_REG, bw)
> +
> +#define sp_tx_get_link_bw() \
> + sp_i2c_read_byte(TX_P0, SP_TX_LINK_BW_SET_REG)
> +
> +#define sp_tx_get_pll_lock_status() \
> + ((sp_i2c_read_byte(TX_P0, TX_DEBUG1) & DEBUG_PLL_LOCK) != 0 ? 1 : 0)
> +
> +#define gen_m_clk_with_downspeading() \
> + sp_write_reg_or(TX_P0, SP_TX_M_CALCU_CTRL, M_GEN_CLK_SEL)
> +
> +#define gen_m_clk_without_downspeading \
> + sp_write_reg_and(TX_P0, SP_TX_M_CALCU_CTRL, (~M_GEN_CLK_SEL))
> +
> +#define hdmi_rx_set_hpd(enable) do { \
> + if ((bool)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); \
> + } while (0)
> +
> +#define hdmi_rx_set_termination(enable) do { \
> + if ((bool)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); \
> + } while (0)
> +
> +#define sp_tx_clean_hdcp_status() do { \
> + 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__); \
> + } while (0)
> +
> +#define reg_hardware_reset() do { \
> + 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); \
> + } while (0)
> +
> +#define write_dpcd_addr(addrh, addrm, addrl) \
> + do { \
> + u8 temp; \
> + if (sp_i2c_read_byte(TX_P0, AUX_ADDR_7_0) != (u8)addrl) \
> + sp_write_reg(TX_P0, AUX_ADDR_7_0, (u8)addrl); \
> + if (sp_i2c_read_byte(TX_P0, AUX_ADDR_15_8) \
> + != (u8)addrm) \
> + sp_write_reg(TX_P0, \
> + AUX_ADDR_15_8, (u8)addrm); \
> + sp_read_reg(TX_P0, AUX_ADDR_19_16, &temp); \
> + if ((u8)(temp & 0x0F) != ((u8)addrh & 0x0F)) \
> + sp_write_reg(TX_P0, AUX_ADDR_19_16, \
> + (temp & 0xF0) | ((u8)addrh)); \
> + } while (0)
> +
> +#define sp_tx_set_sys_state(ss) \
> + do { \
> + 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 = (u8)ss; \
> + g_need_clean_status = 1; \
> + print_sys_state(sp_tx_system_state); \
> + } while (0)
> +
> +#define goto_next_system_state() \
> + do { \
> + 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); \
> + } while (0)
> +
> +#define redo_cur_system_state() \
> + do { \
> + 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); \
> + } while (0)
> +
> +#define system_state_change_with_case(status) \
> + do { \
> + 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 = (u8)status; \
> + print_sys_state(sp_tx_system_state); \
> + } \
> + } while (0)
> +
> +#define sp_write_reg_or(address, offset, mask) \
> + sp_write_reg(address, offset, \
> + ((unsigned char)sp_i2c_read_byte(address, offset) | (mask)))
> +
> +#define sp_write_reg_and(address, offset, mask) \
> + sp_write_reg(address, offset, \
> + ((unsigned char)sp_i2c_read_byte(address, offset) & (mask)))
> +
> +#define sp_write_reg_and_or(address, offset, and_mask, or_mask) \
> + sp_write_reg(address, offset, \
> + (((unsigned char)sp_i2c_read_byte(address, offset)) \
> + & and_mask) | (or_mask))
> +
> +#define sp_write_reg_or_and(address, offset, or_mask, and_mask) \
> + sp_write_reg(address, offset, \
> + (((unsigned char)sp_i2c_read_byte(address, offset)) \
> + | or_mask) & (and_mask))
... and all of the above "function-like macros" should be converted to
type-safe static functions, where applicable.
> +
> +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 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 anx7814_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__);
dev_err() for all of these error prints.
> + *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__);
dev_dbg() for all of these state transitions.
> + 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)
I'd just split this into two functions:
anx78xx_vbus_power_on() & anx78xx_vbus_power_off()
> +{
> + 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] = {
static const struct clock_data pxtal_data[] = {
Also, if this is an anx78xx specific type, it should have a name like
"struct anx78xx_clock_data".
> + {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, (~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 anx7814_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;
bool functions should return "true" and "false".
> +}
> +
> +void slimport_waitting_cable_plug_process(struct anx7814_data *data)
spelling: "_waiting_"
> +{
> + 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};
static const u8
> +
> +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])
memcmp()
> + 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.
"because"
> + */
> + 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))
What are these magic numbers?
> + *bw = LINK_6P75G;
> + else
> + sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x21, 1, bw);
> + /* just for Debug */
> + *bw = LINK_6P75G;
You just set this twice?
> + } else
Use '{}' on both sides of the else:
} 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__);
Why the delay just to print an error message?
dev_err()
> + 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))
In the kernel, the constant is usually on the other side of the !=, like this:
if (sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x18, 1, &c) != AUX_OK)
> + return 0;
> +
> + if ((c & 0x41) == 0x41)
magic number?
> + 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)
> +{
The whole "state machine" in this function seems entirely unnecessary.
Just do all required hotplug actions sequentially in a worker,
triggered from a hotplug event.
> + 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) {
The check here doesn't buy you much.
Just always set/clear the enable bit.
> + 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;
u16 perhaps?
> +
> + 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;
> +}
> +
[snip...]
> +
> diff --git a/drivers/staging/slimport/slimport_tx_drv.h b/drivers/staging/slimport/slimport_tx_drv.h
> new file mode 100644
> index 0000000..9aaf47d
> --- /dev/null
> +++ b/drivers/staging/slimport/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
BIT() already exists.
[snip...]
Ok, enough for now :-).
I'd be happy to review more in detail after you:
(1) clean up the typos, and little nits above
(2) move to the drm/bridge directory
(3) rename the files, variables, types, etc. to anx78xx
(4) plumb through the context struct to all functions that act on the device
(5) use proper messaging (dev_ rather than pr_, _dbg/_err rather than _info)
I think replacing the state machine with an event-driven approach can
wait for a future round of review.
-Dan
On Mon, Sep 7, 2015 at 2:46 PM, Greg KH <gregkh@linuxfoundation.org> wrote:
> On Mon, Sep 07, 2015 at 07:41:08AM +0200, Enric Balletbo Serra wrote:
>> 2015-09-07 1:27 GMT+02:00 Greg KH <gregkh@linuxfoundation.org>:
>> > On Sun, Sep 06, 2015 at 11:14:02PM +0200, Enric Balletbo i Serra wrote:
>> >> 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 <enric.balletbo@collabora.com>
>> >> ---
>> >> drivers/staging/Kconfig | 2 +
>> >> drivers/staging/Makefile | 1 +
>> >> drivers/staging/slimport/Kconfig | 7 +
>> >> drivers/staging/slimport/Makefile | 4 +
>> >> drivers/staging/slimport/slimport.c | 301 +++
>> >> drivers/staging/slimport/slimport.h | 49 +
>> >> drivers/staging/slimport/slimport_tx_drv.c | 3293 ++++++++++++++++++++++++++++
>> >> drivers/staging/slimport/slimport_tx_drv.h | 254 +++
>> >> drivers/staging/slimport/slimport_tx_reg.h | 786 +++++++
>> >
>> > Why is this a staging driver?
>> > What prevents it from being merged into the "real" part of the kernel
>> > tree?
>> >
>>
>> I'll be glad to move the driver to their subsystem if you think it's a
>> the better place. Basically there are two reasons why I send the
>> driver to the staging directory. The first one is because my test
>> environment is a bit limited, with my environment I can only test the
>> HDMI to DisplayPort pass-through mode so the driver builds but it's
>> partially tested. The second one is that I expect I'll need to
>> refactor some code, specially in slimport_tx_drv.c file to be
>> accepted, I decided not change too much this file from the original to
>> not break the functionality, so I thought that will be better send
>> first to the staging driver to have first reviews.
>>
>> > All staging drivers need a TODO file, listing what needs to be done and
>> > who is in charge of it. I can't take this without that added.
>> >
>>
>> ok, I'll add in the next series once received some feedback (or move
>> to the video subsystem)
>
> I suggest trying to get it merged "properly" first before having to
> fall-back to the staging subsystem.
>
> thanks,
>
> greg k-h
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix.
2015-09-09 3:38 ` Daniel Kurtz
@ 2015-09-09 7:10 ` Enric Balletbo Serra
0 siblings, 0 replies; 9+ messages in thread
From: Enric Balletbo Serra @ 2015-09-09 7:10 UTC (permalink / raw)
To: Daniel Kurtz
Cc: devel, Greg KH, linux-kernel@vger.kernel.org, Sjoerd Simons,
Javier Martinez Canillas, span, Nathan Chung, dri-devel
Hi Dan,
Many thanks for this first review.
2015-09-09 5:38 GMT+02:00 Daniel Kurtz <djkurtz@chromium.org>:
> Hi Eric,
>
> Thanks for starting to upstream this Analogix Slimport driver!
> As Greg says, please move this driver to its intended directory, I presume:
> /drivers/gpu/drm/bridge
>
I sent yesterday another version moving the driver. I'm not sure if
you were aware. In the second version I moved the driver to
drivers/gpu/drm/i2c instead of drivers/gpu/drm/bridge. Do you think
bridge is the better place ? If so I'll move to bridge directory. I
had doubts about it.
> And when you submit, use get_maintainer.pl to add the proper reviewers
> and lists.
> At present, you have no DRM folks, nor dri-devel, so you probably
> won't receive any additional feedback on this version, since the
> relevant folks have not seen your emails.
>
> Some more very detailed feedback inline...
>
> On Sep 7, 2015 05:15, "Enric Balletbo i Serra" <eballetbo@gmail.com> wrote:
>>
>> 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 <enric.balletbo@collabora.com>
>> ---
>> drivers/staging/Kconfig | 2 +
>> drivers/staging/Makefile | 1 +
>> drivers/staging/slimport/Kconfig | 7 +
>> drivers/staging/slimport/Makefile | 4 +
>> drivers/staging/slimport/slimport.c | 301 +++
>> drivers/staging/slimport/slimport.h | 49 +
>> drivers/staging/slimport/slimport_tx_drv.c | 3293 ++++++++++++++++++++++++++++
>> drivers/staging/slimport/slimport_tx_drv.h | 254 +++
>> drivers/staging/slimport/slimport_tx_reg.h | 786 +++++++
>> 9 files changed, 4697 insertions(+)
>> create mode 100644 drivers/staging/slimport/Kconfig
>> create mode 100644 drivers/staging/slimport/Makefile
>> create mode 100644 drivers/staging/slimport/slimport.c
>> create mode 100644 drivers/staging/slimport/slimport.h
>> create mode 100644 drivers/staging/slimport/slimport_tx_drv.c
>> create mode 100644 drivers/staging/slimport/slimport_tx_drv.h
>> create mode 100644 drivers/staging/slimport/slimport_tx_reg.h
>>
>> diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
>> index e29293c..24ccd7c 100644
>> --- a/drivers/staging/Kconfig
>> +++ b/drivers/staging/Kconfig
>> @@ -110,4 +110,6 @@ source "drivers/staging/wilc1000/Kconfig"
>>
>> source "drivers/staging/most/Kconfig"
>>
>> +source "drivers/staging/slimport/Kconfig"
>> +
>> endif # STAGING
>> diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
>> index 50824dd..942e886 100644
>> --- a/drivers/staging/Makefile
>> +++ b/drivers/staging/Makefile
>> @@ -47,3 +47,4 @@ obj-$(CONFIG_FB_TFT) += fbtft/
>> obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/
>> obj-$(CONFIG_WILC1000) += wilc1000/
>> obj-$(CONFIG_MOST) += most/
>> +obj-$(CONFIG_SLIMPORT_ANX78XX) += slimport/
>> diff --git a/drivers/staging/slimport/Kconfig b/drivers/staging/slimport/Kconfig
>> new file mode 100644
>> index 0000000..f5233ef
>> --- /dev/null
>> +++ b/drivers/staging/slimport/Kconfig
>> @@ -0,0 +1,7 @@
>> +config SLIMPORT_ANX78XX
>
> I think the "SLIMPORT_" here is a bit overkill, and just adds to
> confusion over what name to use where. I'd recommend just
> CONFIG_ANX78XX.
>
> Likewise, for consistency, the rename the files as "anx78xx*" instead
> of "slimport*".
>
>> + 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/staging/slimport/Makefile b/drivers/staging/slimport/Makefile
>> new file mode 100644
>> index 0000000..9bb6ce2
>> --- /dev/null
>> +++ b/drivers/staging/slimport/Makefile
>> @@ -0,0 +1,4 @@
>> +obj-${CONFIG_SLIMPORT_ANX78XX} := anx78xx.o
>> +
>> +anx78xx-y := slimport.o
>> +anx78xx-y += slimport_tx_drv.o
>> diff --git a/drivers/staging/slimport/slimport.c b/drivers/staging/slimport/slimport.c
>> new file mode 100644
>> index 0000000..95c5114
>> --- /dev/null
>> +++ b/drivers/staging/slimport/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 <linux/delay.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/types.h>
>> +#include <linux/err.h>
>> +#include <linux/async.h>
>> +#include <linux/of_gpio.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/delay.h>
>> +
>> +#include "slimport.h"
>> +#include "slimport_tx_drv.h"
>> +
>> +/* HDCP switch for external block */
>> +/* external_block_en = 1: enable, 0: disable */
>
> This comment is a bit superfluous.
>
>> +int external_block_en = 1;
>> +
>> +struct i2c_client *anx7814_client;
>
> A single global client isn't going to work. It is easy to imagine a
> machine with more than one anx78xx, requiring multiple instances of
> the driver and hence multiple i2c clients.
>
> Also, you'll want to be a bit more consistent with naming; is the
> driver for anx78xx? Or anx7814 only?
>
>> +
>> +int sp_read_reg_byte(uint8_t slave_addr, uint8_t offset)
>> +{
>> + int ret = 0;
>> + struct device *dev = &anx7814_client->dev;
>
> The use of global anx7814_client has ramifications throughout this
> whole driver. direct
> Please re-write all of these transaction functions (and their callers)
> should to take a context struct pointer as their first parameter.
>
>> +
>> + anx7814_client->addr = (slave_addr >> 1);
>> + ret = i2c_smbus_read_byte_data(anx7814_client, offset);
>> + if (ret < 0) {
>> + dev_err(dev, "%s: failed to read i2c addr=%x\n", LOG_TAG,
>> + slave_addr);
>> + return ret;
>> + }
>> + return 0;
>
> Don't you need to return the actual byte that was read (ret)?
>
>> +}
>> +
>> +int sp_read_reg(uint8_t slave_addr, uint8_t offset, uint8_t *buf)
>> +{
>> + int ret = 0;
>> + struct device *dev = &anx7814_client->dev;
>> +
>> + anx7814_client->addr = (slave_addr >> 1);
>> + ret = i2c_smbus_read_byte_data(anx7814_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 = &anx7814_client->dev;
>> +
>> + anx7814_client->addr = (slave_addr >> 1);
>> + ret = i2c_smbus_write_byte_data(anx7814_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 anx7814_data *data)
>
> nit: another personal preference, I prefer to use the specific device
> as the local parameter name, rather than the generic "data".
> So it would look something like:
>
> void anx7814_tx_hardware_poweron(struct anx7814 *anx7814)
>
>> +{
>> + struct device *dev = &data->client->dev;
>> + struct anx7814_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: anx7814 power on\n", LOG_TAG);
>
> This kind of verbose logging should be dev_dbg(
>
>> +}
>> +
>> +void sp_tx_hardware_powerdown(struct anx7814_data *data)
>> +{
>> + struct device *dev = &data->client->dev;
>> + struct anx7814_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: anx7814 power down\n", LOG_TAG);
>> +}
>> +
>> +static int anx7814_init_gpio(struct anx7814_data *data)
>> +{
>> + struct device *dev = &data->client->dev;
>> + struct anx7814_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 anx7814_system_init(struct anx7814_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 anx7814\n");
>> + return -ENODEV;
>> + }
>> +
>> + sp_tx_variable_init();
>> + return 0;
>> +}
>> +
>> +static void anx7814_work_func(struct work_struct *work)
>> +{
>> + struct anx7814_data *data = container_of(work, struct anx7814_data,
>> + work.work);
>> + int workqueu_timer = 0;
>
> spelling: workqueue_timer
>
>> +
>> + 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));
>
> The use of a periodic workqueue and a state machine like this seems
> like the wrong approach.
> The driver should be event driven, and any worker should do whatever
> work is required until it completes, rather than arbitrarily chopping
> up the tasks into ~100 ms chunks.
>
>> +}
>> +
>> +static int anx7814_i2c_probe(struct i2c_client *client,
>> + const struct i2c_device_id *id)
>> +{
>> + struct anx7814_data *data;
>> + struct anx7814_platform_data *pdata;
>> + int ret = 0;
>
> In general, I prefer not to see 'ret' variables initialized up here to
> a default value. Rather, only set the ret value as needed.
> This let's the compiler catch if there were any 'return' paths that
> did not explicitly initialize ret.
>
>> +
>> + 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 anx7814_data),
>> + GFP_KERNEL);
>> + if (!data)
>> + return -ENOMEM;
>> +
>> + pdata = devm_kzalloc(&client->dev,
>> + sizeof(struct anx7814_platform_data),
>> + GFP_KERNEL);
>> + if (!pdata)
>> + return -ENOMEM;
>
> If you are always explicitly allocating both anyway, might as well
> just embed a "struct anx7814_platform_data" directly in "struct
> anx7814_data".
>
>> +
>> + data->pdata = pdata;
>> +
>> + data->client = client;
>> + anx7814_client = client;
>> +
>> + mutex_init(&data->lock);
>> +
>> + ret = anx7814_init_gpio(data);
>> + if (ret) {
>> + dev_err(&client->dev, "failed to initialize gpios\n");
>> + return ret;
>> + }
>> +
>> + INIT_DELAYED_WORK(&data->work, anx7814_work_func);
>> +
>> + data->workqueue = create_singlethread_workqueue("anx7814_work");
>> + if (data->workqueue == NULL) {
>> + dev_err(&client->dev, "failed to create work queue\n");
>> + return -ENOMEM;
>> + }
>> +
>> + ret = anx7814_system_init(data);
>> + if (ret) {
>> + dev_err(&client->dev, "failed to initialize anx7814\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 anx7814_i2c_remove(struct i2c_client *client)
>> +{
>> + struct anx7814_data *data = i2c_get_clientdata(client);
>> +
>> + destroy_workqueue(data->workqueue);
>> +
>> + return 0;
>> +}
>> +
>> +static int anx7814_i2c_suspend(struct device *dev)
>> +{
>> + struct i2c_client *client = container_of(dev, struct i2c_client, dev);
>> + struct anx7814_data *data = i2c_get_clientdata(client);
>> +
>> + dev_info(&client->dev, "suspend\n");
>
> dev_dbg (or just remove this, since it is a bit redundant with verbose
> suspend logging).
>
>> + cancel_delayed_work_sync(&data->work);
>> + flush_workqueue(data->workqueue);
>> + sp_tx_hardware_powerdown(data);
>> + sp_tx_clean_state_machine();
>> +
>> + return 0;
>> +}
>> +
>> +static int anx7814_i2c_resume(struct device *dev)
>> +{
>> + struct i2c_client *client = container_of(dev, struct i2c_client, dev);
>> + struct anx7814_data *anx7814 = i2c_get_clientdata(client);
>> +
>> + dev_info(&client->dev, "resume\n");
>> + queue_delayed_work(anx7814->workqueue, &anx7814->work, 0);
>> +
>> + return 0;
>> +}
>> +
>> +static SIMPLE_DEV_PM_OPS(anx7814_i2c_pm_ops,
>> + anx7814_i2c_suspend, anx7814_i2c_resume);
>> +
>> +static const struct i2c_device_id anx7814_id[] = {
>> + {"anx7814", 0},
>> + { /* sentinel */ }
>> +};
>> +
>> +MODULE_DEVICE_TABLE(i2c, anx7814_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 anx7814_driver = {
>> + .driver = {
>> + .name = "anx7814",
>> + .pm = &anx7814_i2c_pm_ops,
>> + .of_match_table = of_match_ptr(anx_match_table),
>> + },
>> + .probe = anx7814_i2c_probe,
>> + .remove = anx7814_i2c_remove,
>> + .id_table = anx7814_id,
>> +};
>> +
>> +module_i2c_driver(anx7814_driver);
>> +
>> +MODULE_DESCRIPTION("Slimport transmitter ANX7814 driver");
>> +MODULE_AUTHOR("Junhua Xia <jxia@analogixsemi.com>");
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_VERSION("1.1");
>> diff --git a/drivers/staging/slimport/slimport.h b/drivers/staging/slimport/slimport.h
>> new file mode 100644
>> index 0000000..614d746
>> --- /dev/null
>> +++ b/drivers/staging/slimport/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 <linux/i2c.h>
>> +#include <linux/mutex.h>
>> +#include <linux/slab.h>
>> +#include <linux/workqueue.h>
>> +#include <linux/gpio/consumer.h>
>> +
>> +#define AUX_ERR 1
>> +#define AUX_OK 0
>> +
>> +#define LOG_TAG "SlimPort ANX78XX"
>> +
>> +struct anx7814_platform_data {
>> + struct gpio_desc *gpiod_pd;
>> + struct gpio_desc *gpiod_reset;
>> + spinlock_t lock;
>> +};
>> +
>> +struct anx7814_data {
>
> Nit: my personal preference would be to drop the "_data":
>
> struct anx7814 (or struct anx78xx, to match the driver name).
>
>
>> + struct i2c_client *client;
>> + struct anx7814_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 anx7814_data *data);
>> +void sp_tx_hardware_powerdown(struct anx7814_data *data);
>> +
>> +#endif
>> diff --git a/drivers/staging/slimport/slimport_tx_drv.c b/drivers/staging/slimport/slimport_tx_drv.c
>> new file mode 100644
>> index 0000000..6fad502
>> --- /dev/null
>> +++ b/drivers/staging/slimport/slimport_tx_drv.c
>> @@ -0,0 +1,3293 @@
>> +/*
>> + * 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 <linux/delay.h>
>> +#include <linux/types.h>
>> +
>> +#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 unsigned char sp_i2c_read_byte(unsigned char dev, unsigned char offset);
>> +static void hdmi_rx_new_vsi_int(void);
>
> ... yeah, this driver needs a lot of work. All of the above global
> state variables need to go away.
>
>> +
>> +#define reg_bit_ctl(addr, offset, data, enable) \
>> + do { \
>> + 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); \
>> + } \
>> + } \
>> + } while (0)
>> +
>> +#define sp_tx_video_mute(enable) \
>> + reg_bit_ctl(TX_P2, VID_CTRL1, VIDEO_MUTE, enable)
>> +
>> +#define hdmi_rx_mute_audio(enable) \
>> + reg_bit_ctl(RX_P0, RX_MUTE_CTRL, AUD_MUTE, enable)
>> +
>> +#define hdmi_rx_mute_video(enable) \
>> + reg_bit_ctl(RX_P0, RX_MUTE_CTRL, VID_MUTE, enable)
>> +
>> +#define sp_tx_addronly_set(enable) \
>> + reg_bit_ctl(TX_P0, AUX_CTRL2, ADDR_ONLY_BIT, enable)
>> +
>> +#define sp_tx_set_link_bw(bw) \
>> + sp_write_reg(TX_P0, SP_TX_LINK_BW_SET_REG, bw)
>> +
>> +#define sp_tx_get_link_bw() \
>> + sp_i2c_read_byte(TX_P0, SP_TX_LINK_BW_SET_REG)
>> +
>> +#define sp_tx_get_pll_lock_status() \
>> + ((sp_i2c_read_byte(TX_P0, TX_DEBUG1) & DEBUG_PLL_LOCK) != 0 ? 1 : 0)
>> +
>> +#define gen_m_clk_with_downspeading() \
>> + sp_write_reg_or(TX_P0, SP_TX_M_CALCU_CTRL, M_GEN_CLK_SEL)
>> +
>> +#define gen_m_clk_without_downspeading \
>> + sp_write_reg_and(TX_P0, SP_TX_M_CALCU_CTRL, (~M_GEN_CLK_SEL))
>> +
>> +#define hdmi_rx_set_hpd(enable) do { \
>> + if ((bool)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); \
>> + } while (0)
>> +
>> +#define hdmi_rx_set_termination(enable) do { \
>> + if ((bool)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); \
>> + } while (0)
>> +
>> +#define sp_tx_clean_hdcp_status() do { \
>> + 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__); \
>> + } while (0)
>> +
>> +#define reg_hardware_reset() do { \
>> + 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); \
>> + } while (0)
>> +
>> +#define write_dpcd_addr(addrh, addrm, addrl) \
>> + do { \
>> + u8 temp; \
>> + if (sp_i2c_read_byte(TX_P0, AUX_ADDR_7_0) != (u8)addrl) \
>> + sp_write_reg(TX_P0, AUX_ADDR_7_0, (u8)addrl); \
>> + if (sp_i2c_read_byte(TX_P0, AUX_ADDR_15_8) \
>> + != (u8)addrm) \
>> + sp_write_reg(TX_P0, \
>> + AUX_ADDR_15_8, (u8)addrm); \
>> + sp_read_reg(TX_P0, AUX_ADDR_19_16, &temp); \
>> + if ((u8)(temp & 0x0F) != ((u8)addrh & 0x0F)) \
>> + sp_write_reg(TX_P0, AUX_ADDR_19_16, \
>> + (temp & 0xF0) | ((u8)addrh)); \
>> + } while (0)
>> +
>> +#define sp_tx_set_sys_state(ss) \
>> + do { \
>> + 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 = (u8)ss; \
>> + g_need_clean_status = 1; \
>> + print_sys_state(sp_tx_system_state); \
>> + } while (0)
>> +
>> +#define goto_next_system_state() \
>> + do { \
>> + 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); \
>> + } while (0)
>> +
>> +#define redo_cur_system_state() \
>> + do { \
>> + 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); \
>> + } while (0)
>> +
>> +#define system_state_change_with_case(status) \
>> + do { \
>> + 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 = (u8)status; \
>> + print_sys_state(sp_tx_system_state); \
>> + } \
>> + } while (0)
>> +
>> +#define sp_write_reg_or(address, offset, mask) \
>> + sp_write_reg(address, offset, \
>> + ((unsigned char)sp_i2c_read_byte(address, offset) | (mask)))
>> +
>> +#define sp_write_reg_and(address, offset, mask) \
>> + sp_write_reg(address, offset, \
>> + ((unsigned char)sp_i2c_read_byte(address, offset) & (mask)))
>> +
>> +#define sp_write_reg_and_or(address, offset, and_mask, or_mask) \
>> + sp_write_reg(address, offset, \
>> + (((unsigned char)sp_i2c_read_byte(address, offset)) \
>> + & and_mask) | (or_mask))
>> +
>> +#define sp_write_reg_or_and(address, offset, or_mask, and_mask) \
>> + sp_write_reg(address, offset, \
>> + (((unsigned char)sp_i2c_read_byte(address, offset)) \
>> + | or_mask) & (and_mask))
>
> ... and all of the above "function-like macros" should be converted to
> type-safe static functions, where applicable.
>
>
>> +
>> +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 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 anx7814_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__);
>
> dev_err() for all of these error prints.
>
>> + *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__);
>
> dev_dbg() for all of these state transitions.
>
>> + 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)
>
> I'd just split this into two functions:
>
> anx78xx_vbus_power_on() & anx78xx_vbus_power_off()
>
>> +{
>> + 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] = {
>
> static const struct clock_data pxtal_data[] = {
>
> Also, if this is an anx78xx specific type, it should have a name like
> "struct anx78xx_clock_data".
>
>> + {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, (~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 anx7814_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;
>
> bool functions should return "true" and "false".
>
>> +}
>> +
>> +void slimport_waitting_cable_plug_process(struct anx7814_data *data)
>
> spelling: "_waiting_"
>
>> +{
>> + 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};
>
> static const u8
>
>> +
>> +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])
>
> memcmp()
>
>
>> + 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.
>
> "because"
>
>> + */
>> + 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))
>
> What are these magic numbers?
>
>> + *bw = LINK_6P75G;
>> + else
>> + sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x21, 1, bw);
>> + /* just for Debug */
>> + *bw = LINK_6P75G;
>
> You just set this twice?
>
>> + } else
>
> Use '{}' on both sides of the else:
>
> } 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__);
>
> Why the delay just to print an error message?
>
> dev_err()
>
>> + 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))
>
> In the kernel, the constant is usually on the other side of the !=, like this:
>
> if (sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x18, 1, &c) != AUX_OK)
>
>
>
>> + return 0;
>> +
>> + if ((c & 0x41) == 0x41)
>
> magic number?
>
>> + 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)
>> +{
>
> The whole "state machine" in this function seems entirely unnecessary.
> Just do all required hotplug actions sequentially in a worker,
> triggered from a hotplug event.
>
>> + 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) {
>
> The check here doesn't buy you much.
> Just always set/clear the enable bit.
>
>> + 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;
>
> u16 perhaps?
>
>> +
>> + 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;
>> +}
>> +
>
> [snip...]
>
>> +
>> diff --git a/drivers/staging/slimport/slimport_tx_drv.h b/drivers/staging/slimport/slimport_tx_drv.h
>> new file mode 100644
>> index 0000000..9aaf47d
>> --- /dev/null
>> +++ b/drivers/staging/slimport/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
>
> BIT() already exists.
>
> [snip...]
>
> Ok, enough for now :-).
>
> I'd be happy to review more in detail after you:
> (1) clean up the typos, and little nits above
> (2) move to the drm/bridge directory
> (3) rename the files, variables, types, etc. to anx78xx
> (4) plumb through the context struct to all functions that act on the device
> (5) use proper messaging (dev_ rather than pr_, _dbg/_err rather than _info)
>
I'll include all your comments and send for review again.
> I think replacing the state machine with an event-driven approach can
> wait for a future round of review.
>
Looks a good plan for me, first review more trivial problems.
Best regards,
Enric
> -Dan
>
> On Mon, Sep 7, 2015 at 2:46 PM, Greg KH <gregkh@linuxfoundation.org> wrote:
>> On Mon, Sep 07, 2015 at 07:41:08AM +0200, Enric Balletbo Serra wrote:
>>> 2015-09-07 1:27 GMT+02:00 Greg KH <gregkh@linuxfoundation.org>:
>>> > On Sun, Sep 06, 2015 at 11:14:02PM +0200, Enric Balletbo i Serra wrote:
>>> >> 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 <enric.balletbo@collabora.com>
>>> >> ---
>>> >> drivers/staging/Kconfig | 2 +
>>> >> drivers/staging/Makefile | 1 +
>>> >> drivers/staging/slimport/Kconfig | 7 +
>>> >> drivers/staging/slimport/Makefile | 4 +
>>> >> drivers/staging/slimport/slimport.c | 301 +++
>>> >> drivers/staging/slimport/slimport.h | 49 +
>>> >> drivers/staging/slimport/slimport_tx_drv.c | 3293 ++++++++++++++++++++++++++++
>>> >> drivers/staging/slimport/slimport_tx_drv.h | 254 +++
>>> >> drivers/staging/slimport/slimport_tx_reg.h | 786 +++++++
>>> >
>>> > Why is this a staging driver?
>>> > What prevents it from being merged into the "real" part of the kernel
>>> > tree?
>>> >
>>>
>>> I'll be glad to move the driver to their subsystem if you think it's a
>>> the better place. Basically there are two reasons why I send the
>>> driver to the staging directory. The first one is because my test
>>> environment is a bit limited, with my environment I can only test the
>>> HDMI to DisplayPort pass-through mode so the driver builds but it's
>>> partially tested. The second one is that I expect I'll need to
>>> refactor some code, specially in slimport_tx_drv.c file to be
>>> accepted, I decided not change too much this file from the original to
>>> not break the functionality, so I thought that will be better send
>>> first to the staging driver to have first reviews.
>>>
>>> > All staging drivers need a TODO file, listing what needs to be done and
>>> > who is in charge of it. I can't take this without that added.
>>> >
>>>
>>> ok, I'll add in the next series once received some feedback (or move
>>> to the video subsystem)
>>
>> I suggest trying to get it merged "properly" first before having to
>> fall-back to the staging subsystem.
>>
>> thanks,
>>
>> greg k-h
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2015-09-09 7:10 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-09-06 21:13 [PATCH 0/3] Add initial support for slimport anx78xx Enric Balletbo i Serra
2015-09-06 21:14 ` [PATCH 1/3] of: Add vendor prefix for Analogix Semiconductor, Inc Enric Balletbo i Serra
2015-09-06 21:14 ` [PATCH 2/3] devicetree: Add new ANX7814 SlimPort transmitter binding Enric Balletbo i Serra
2015-09-06 21:14 ` [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix Enric Balletbo i Serra
2015-09-06 23:27 ` Greg KH
2015-09-07 5:41 ` Enric Balletbo Serra
2015-09-07 6:46 ` Greg KH
2015-09-09 3:38 ` Daniel Kurtz
2015-09-09 7:10 ` Enric Balletbo Serra
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox