Hi all,
This is the fouth version with fixes suggested by Nicolas Boichat and Dan Carpenter.
See the changelog below for details.
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 things that I noticed 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 ...
Changes since v3:
Nicolas Boichat: - Integrate sp_edid_header_result with sp_check_edid_data - Fix loop forever. - Use meaningful messages and variable names - Replace some 'while' loops and use a for loop. - Might be clearer to say >= LINK_6P75G - Convert a function to void function because always return 0 - Remove some magic numbers and refactor sp_tx_pclk_calc - Replace sp_read_reg(SP_TX_LINK_BW_SET_REG) for sp_tx_get_link_bw. - Mask bits 4:0. Bit 5 has another purpose, and 7:6 are reserved. - Use ARRAY_SIZE. - Use memset for initialization. - Simply condition if (!(c1 & POLLING_EN) || (c & POLLING_ERR)) - Don not use a temporal variable write the value directly. - Fix various typos - Return directly PTR_ERR.
Dan Carpenter: - Refactor while loop removing the earlier condition and do while (--c) instead - Simplify double negative and fix alignment - Remove the superflous casts to u16 and parens - Remove debug printks and use ftrace instead. - Flip this condition around and pull the code in one indent level. - Fix return value 'ret' that should be an int. It causes a signedness bug later. - Use better style for devm_kzalloc - Get rid of AUX_*. They aren't used much and we could easily use normal error codes instead.
Enric Balletbo - Fix errors reported by scripts/checkpatch.pl --strict --subjective - Remove XTAL_CLK_M10 XTAL_CLK definitions - replace ulong for unsigned long - remove some magic numbers and refactor sp_tx_enable_audio_output - remove some magic numbers and refactor sp_tx_phy_auto_test
Changes since v2 (requested by Daniel Kurtz): - clean up the typos, and little nits requested by Dan. - move to the drm/bridge directory - rename the files, variables, types, etc. to anx78xx - plumb through the context struct to all functions that act on the device - use proper messaging (dev_ rather than pr_, _dbg/_err rather than _info)
Changes since v1: - As requested by Greg, move from staging to a subsystem.
Best regards,
Enric Balletbo i Serra (3): of: Add vendor prefix for Analogix Semiconductor, Inc. devicetree: Add new ANX7814 SlimPort transmitter binding. drm: bridge: anx78xx: Add anx78xx driver support by analogix.
.../devicetree/bindings/vendor-prefixes.txt | 1 + .../devicetree/bindings/video/bridge/anx7814.txt | 22 + drivers/gpu/drm/bridge/Kconfig | 2 + drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/anx78xx/Kconfig | 7 + drivers/gpu/drm/bridge/anx78xx/Makefile | 4 + drivers/gpu/drm/bridge/anx78xx/anx78xx.h | 41 + drivers/gpu/drm/bridge/anx78xx/anx78xx_main.c | 228 ++ drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c | 3148 ++++++++++++++++++++ drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.h | 214 ++ drivers/gpu/drm/bridge/anx78xx/slimport_tx_reg.h | 807 +++++ 11 files changed, 4475 insertions(+) create mode 100644 Documentation/devicetree/bindings/video/bridge/anx7814.txt create mode 100644 drivers/gpu/drm/bridge/anx78xx/Kconfig create mode 100644 drivers/gpu/drm/bridge/anx78xx/Makefile create mode 100644 drivers/gpu/drm/bridge/anx78xx/anx78xx.h create mode 100644 drivers/gpu/drm/bridge/anx78xx/anx78xx_main.c create mode 100644 drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c create mode 100644 drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.h create mode 100644 drivers/gpu/drm/bridge/anx78xx/slimport_tx_reg.h
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 Acked-by: Rob Herring robh@kernel.org --- 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.
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>; + }; +
At the moment it only supports ANX7814.
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/gpu/drm/bridge/Kconfig | 2 + drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/anx78xx/Kconfig | 7 + drivers/gpu/drm/bridge/anx78xx/Makefile | 4 + drivers/gpu/drm/bridge/anx78xx/anx78xx.h | 41 + drivers/gpu/drm/bridge/anx78xx/anx78xx_main.c | 228 ++ drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c | 3148 ++++++++++++++++++++++ drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.h | 214 ++ drivers/gpu/drm/bridge/anx78xx/slimport_tx_reg.h | 807 ++++++ 9 files changed, 4452 insertions(+) create mode 100644 drivers/gpu/drm/bridge/anx78xx/Kconfig create mode 100644 drivers/gpu/drm/bridge/anx78xx/Makefile create mode 100644 drivers/gpu/drm/bridge/anx78xx/anx78xx.h create mode 100644 drivers/gpu/drm/bridge/anx78xx/anx78xx_main.c create mode 100644 drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c create mode 100644 drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.h create mode 100644 drivers/gpu/drm/bridge/anx78xx/slimport_tx_reg.h
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 2de52a5..aa6fe12 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -29,4 +29,6 @@ config DRM_PARADE_PS8622 ---help--- Parade eDP-LVDS bridge chip driver.
+source "drivers/gpu/drm/bridge/anx78xx/Kconfig" + endmenu diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index e2eef1c..e5bd38b 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -3,3 +3,4 @@ ccflags-y := -Iinclude/drm obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o +obj-$(CONFIG_DRM_ANX78XX) += anx78xx/ diff --git a/drivers/gpu/drm/bridge/anx78xx/Kconfig b/drivers/gpu/drm/bridge/anx78xx/Kconfig new file mode 100644 index 0000000..08f9c08 --- /dev/null +++ b/drivers/gpu/drm/bridge/anx78xx/Kconfig @@ -0,0 +1,7 @@ +config DRM_ANX78XX + tristate "Analogix ANX78XX bridge" + help + ANX78XX is a HD video transmitter chip over micro-USB + connector for smartphone device. + + diff --git a/drivers/gpu/drm/bridge/anx78xx/Makefile b/drivers/gpu/drm/bridge/anx78xx/Makefile new file mode 100644 index 0000000..a843733 --- /dev/null +++ b/drivers/gpu/drm/bridge/anx78xx/Makefile @@ -0,0 +1,4 @@ +obj-${CONFIG_DRM_ANX78XX} := anx78xx.o + +anx78xx-y += anx78xx_main.o +anx78xx-y += slimport_tx_drv.o diff --git a/drivers/gpu/drm/bridge/anx78xx/anx78xx.h b/drivers/gpu/drm/bridge/anx78xx/anx78xx.h new file mode 100644 index 0000000..f62c8e7 --- /dev/null +++ b/drivers/gpu/drm/bridge/anx78xx/anx78xx.h @@ -0,0 +1,41 @@ +/* + * 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 __ANX78xx_H +#define __ANX78xx_H + +#include <linux/i2c.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <linux/gpio/consumer.h> + +struct anx78xx_platform_data { + struct gpio_desc *gpiod_pd; + struct gpio_desc *gpiod_reset; + spinlock_t lock; +}; + +struct anx78xx { + struct i2c_client *client; + struct anx78xx_platform_data *pdata; + struct delayed_work work; + struct workqueue_struct *workqueue; + struct mutex lock; +}; + +void anx78xx_poweron(struct anx78xx *data); +void anx78xx_poweroff(struct anx78xx *data); + +#endif diff --git a/drivers/gpu/drm/bridge/anx78xx/anx78xx_main.c b/drivers/gpu/drm/bridge/anx78xx/anx78xx_main.c new file mode 100644 index 0000000..1e4a87e --- /dev/null +++ b/drivers/gpu/drm/bridge/anx78xx/anx78xx_main.c @@ -0,0 +1,228 @@ +/* + * 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 "anx78xx.h" +#include "slimport_tx_drv.h" + +void anx78xx_poweron(struct anx78xx *anx78xx) +{ + struct anx78xx_platform_data *pdata = anx78xx->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); +} + +void anx78xx_poweroff(struct anx78xx *anx78xx) +{ + struct anx78xx_platform_data *pdata = anx78xx->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); +} + +static int anx78xx_init_gpio(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + struct anx78xx_platform_data *pdata = anx78xx->pdata; + + /* 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"); + return PTR_ERR(pdata->gpiod_pd); + } + + /* 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"); + return PTR_ERR(pdata->gpiod_reset); + } + + return 0; +} + +static int anx78xx_system_init(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + + if (!sp_chip_detect(anx78xx)) { + anx78xx_poweroff(anx78xx); + dev_err(dev, "failed to detect anx78xx\n"); + return -ENODEV; + } + + sp_tx_variable_init(); + return 0; +} + +static void anx78xx_work_func(struct work_struct *work) +{ + struct anx78xx *anx78xx = container_of(work, struct anx78xx, + work.work); + int workqueue_timer = 0; + + if (sp_tx_current_state() >= STATE_PLAY_BACK) + workqueue_timer = 500; + else + workqueue_timer = 100; + mutex_lock(&anx78xx->lock); + sp_main_process(anx78xx); + mutex_unlock(&anx78xx->lock); + queue_delayed_work(anx78xx->workqueue, &anx78xx->work, + msecs_to_jiffies(workqueue_timer)); +} + +static int anx78xx_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct anx78xx *anx78xx; + int 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; + } + + anx78xx = devm_kzalloc(&client->dev, sizeof(*anx78xx), GFP_KERNEL); + if (!anx78xx) + return -ENOMEM; + + anx78xx->pdata = devm_kzalloc(&client->dev, + sizeof(struct anx78xx_platform_data), + GFP_KERNEL); + if (!anx78xx->pdata) + return -ENOMEM; + + anx78xx->client = client; + + i2c_set_clientdata(client, anx78xx); + + mutex_init(&anx78xx->lock); + + ret = anx78xx_init_gpio(anx78xx); + if (ret) { + dev_err(&client->dev, "failed to initialize gpios\n"); + return ret; + } + + INIT_DELAYED_WORK(&anx78xx->work, anx78xx_work_func); + + anx78xx->workqueue = create_singlethread_workqueue("anx78xx_work"); + if (!anx78xx->workqueue) { + dev_err(&client->dev, "failed to create work queue\n"); + return -ENOMEM; + } + + ret = anx78xx_system_init(anx78xx); + if (ret) { + dev_err(&client->dev, "failed to initialize anx78xx\n"); + goto cleanup; + } + + /* enable driver */ + queue_delayed_work(anx78xx->workqueue, &anx78xx->work, 0); + + return 0; + +cleanup: + destroy_workqueue(anx78xx->workqueue); + return ret; +} + +static int anx78xx_i2c_remove(struct i2c_client *client) +{ + struct anx78xx *anx78xx = i2c_get_clientdata(client); + + destroy_workqueue(anx78xx->workqueue); + + return 0; +} + +static int anx78xx_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct anx78xx *anx78xx = i2c_get_clientdata(client); + + cancel_delayed_work_sync(&anx78xx->work); + flush_workqueue(anx78xx->workqueue); + anx78xx_poweroff(anx78xx); + sp_tx_clean_state_machine(); + + return 0; +} + +static int anx78xx_i2c_resume(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct anx78xx *anx78xx = i2c_get_clientdata(client); + + queue_delayed_work(anx78xx->workqueue, &anx78xx->work, 0); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(anx78xx_i2c_pm_ops, + anx78xx_i2c_suspend, anx78xx_i2c_resume); + +static const struct i2c_device_id anx78xx_id[] = { + {"anx7814", 0}, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(i2c, anx78xx_id); + +static const struct of_device_id anx78xx_match_table[] = { + {.compatible = "analogix,anx7814",}, + { /* sentinel */ }, +}; + +MODULE_DEVICE_TABLE(of, anx78xx_match_table); + +static struct i2c_driver anx78xx_driver = { + .driver = { + .name = "anx7814", + .pm = &anx78xx_i2c_pm_ops, + .of_match_table = of_match_ptr(anx78xx_match_table), + }, + .probe = anx78xx_i2c_probe, + .remove = anx78xx_i2c_remove, + .id_table = anx78xx_id, +}; + +module_i2c_driver(anx78xx_driver); + +MODULE_DESCRIPTION("Slimport transmitter ANX78XX driver"); +MODULE_AUTHOR("Junhua Xia jxia@analogixsemi.com"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("1.1"); diff --git a/drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c b/drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c new file mode 100644 index 0000000..7721326 --- /dev/null +++ b/drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c @@ -0,0 +1,3148 @@ +/* + * 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 "anx78xx.h" +#include "slimport_tx_drv.h" + +struct slimport { + int block_en; /* HDCP control enable/ disable from AP */ + + u8 tx_test_bw; + bool tx_test_lt; + bool tx_test_edid; + + u8 changed_bandwidth; + + u8 hdmi_dvi_status; + u8 need_clean_status; + + u8 ds_vid_stb_cntr; + u8 hdcp_fail_count; + + u8 edid_break; + u8 edid_checksum; + u8 edid_blocks[256]; + + u8 read_edid_flag; + + u8 down_sample_en; + + struct packet_avi tx_packet_avi; + struct packet_spd tx_packet_spd; + struct packet_mpeg tx_packet_mpeg; + struct audio_info_frame tx_audioinfoframe; + + struct common_int common_int_status; + struct hdmi_rx_int hdmi_rx_int_status; + + enum sp_tx_state tx_system_state; + enum sp_tx_state tx_system_state_bak; + enum audio_output_status tx_ao_state; + enum video_output_status tx_vo_state; + enum sink_connection_status tx_sc_state; + enum sp_tx_lt_status tx_lt_state; + enum hdcp_status hcdp_state; +}; + +static struct slimport sp; + +static const u16 chipid_list[] = { + 0x7818, + 0x7816, + 0x7814, + 0x7812, + 0x7810, + 0x7806, + 0x7802 +}; + +static void sp_hdmi_rx_new_vsi_int(struct anx78xx *anx78xx); +static u8 sp_hdcp_cap_check(struct anx78xx *anx78xx); +static void sp_tx_show_information(struct anx78xx *anx78xx); +static void sp_print_system_state(struct anx78xx *anx78xx, u8 ss); + +static int sp_read_reg(struct anx78xx *anx78xx, u8 slave_addr, + u8 offset, u8 *buf) +{ + int ret; + struct i2c_client *client = anx78xx->client; + + client->addr = slave_addr >> 1; + + ret = i2c_smbus_read_byte_data(client, offset); + if (ret < 0) { + dev_err(&client->dev, "failed to read i2c addr=%x\n", + slave_addr); + return ret; + } + + *buf = ret; + + return 0; +} + +static int sp_write_reg(struct anx78xx *anx78xx, u8 slave_addr, + u8 offset, u8 value) +{ + int ret; + struct i2c_client *client = anx78xx->client; + + client->addr = slave_addr >> 1; + + ret = i2c_smbus_write_byte_data(client, offset, value); + if (ret < 0) + dev_err(&client->dev, "failed to write i2c addr=%x\n", + slave_addr); + + return ret; +} + +static u8 sp_i2c_read_byte(struct anx78xx *anx78xx, + u8 dev, u8 offset) +{ + u8 ret; + + sp_read_reg(anx78xx, dev, offset, &ret); + return ret; +} + +static void sp_reg_bit_ctl(struct anx78xx *anx78xx, u8 addr, u8 offset, + u8 data, bool enable) +{ + u8 regval; + + sp_read_reg(anx78xx, addr, offset, ®val); + if (enable) { + if ((regval & data) != data) { + regval |= data; + sp_write_reg(anx78xx, addr, offset, regval); + } + } else { + if ((regval & data) == data) { + regval &= ~data; + sp_write_reg(anx78xx, addr, offset, regval); + } + } +} + +static inline void sp_write_reg_or(struct anx78xx *anx78xx, u8 address, + u8 offset, u8 mask) +{ + sp_write_reg(anx78xx, address, offset, + sp_i2c_read_byte(anx78xx, address, offset) | mask); +} + +static inline void sp_write_reg_and(struct anx78xx *anx78xx, u8 address, + u8 offset, u8 mask) +{ + sp_write_reg(anx78xx, address, offset, + sp_i2c_read_byte(anx78xx, address, offset) & mask); +} + +static inline void sp_write_reg_and_or(struct anx78xx *anx78xx, u8 address, + u8 offset, u8 and_mask, u8 or_mask) +{ + sp_write_reg(anx78xx, address, offset, + (sp_i2c_read_byte(anx78xx, address, offset) & and_mask) + | or_mask); +} + +static inline void sp_write_reg_or_and(struct anx78xx *anx78xx, u8 address, + u8 offset, u8 or_mask, u8 and_mask) +{ + sp_write_reg(anx78xx, address, offset, + (sp_i2c_read_byte(anx78xx, address, offset) | or_mask) + & and_mask); +} + +static inline void sp_tx_video_mute(struct anx78xx *anx78xx, bool enable) +{ + sp_reg_bit_ctl(anx78xx, TX_P2, VID_CTRL1, VIDEO_MUTE, enable); +} + +static inline void hdmi_rx_mute_audio(struct anx78xx *anx78xx, bool enable) +{ + sp_reg_bit_ctl(anx78xx, RX_P0, RX_MUTE_CTRL, AUD_MUTE, enable); +} + +static inline void hdmi_rx_mute_video(struct anx78xx *anx78xx, bool enable) +{ + sp_reg_bit_ctl(anx78xx, RX_P0, RX_MUTE_CTRL, VID_MUTE, enable); +} + +static inline void sp_tx_addronly_set(struct anx78xx *anx78xx, bool enable) +{ + sp_reg_bit_ctl(anx78xx, TX_P0, AUX_CTRL2, ADDR_ONLY_BIT, enable); +} + +static inline void sp_tx_set_link_bw(struct anx78xx *anx78xx, u8 bw) +{ + sp_write_reg(anx78xx, TX_P0, SP_TX_LINK_BW_SET_REG, bw); +} + +static inline u8 sp_tx_get_link_bw(struct anx78xx *anx78xx) +{ + return (sp_i2c_read_byte(anx78xx, TX_P0, SP_TX_LINK_BW_SET_REG) & + LINK_BW_SET_MASK); +} + +static inline bool sp_tx_get_pll_lock_status(struct anx78xx *anx78xx) +{ + u8 byte; + + byte = sp_i2c_read_byte(anx78xx, TX_P0, TX_DEBUG1); + + return (byte & DEBUG_PLL_LOCK) != 0; +} + +static inline void gen_m_clk_with_downspeading(struct anx78xx *anx78xx) +{ + sp_write_reg_or(anx78xx, TX_P0, SP_TX_M_CALCU_CTRL, M_GEN_CLK_SEL); +} + +static inline void gen_m_clk_without_downspeading(struct anx78xx *anx78xx) +{ + sp_write_reg_and(anx78xx, TX_P0, SP_TX_M_CALCU_CTRL, (~M_GEN_CLK_SEL)); +} + +static inline void hdmi_rx_set_hpd(struct anx78xx *anx78xx, bool enable) +{ + if (enable) + sp_write_reg_or(anx78xx, TX_P2, SP_TX_VID_CTRL3_REG, HPD_OUT); + else + sp_write_reg_and(anx78xx, TX_P2, SP_TX_VID_CTRL3_REG, + ~HPD_OUT); +} + +static inline void hdmi_rx_set_termination(struct anx78xx *anx78xx, + bool enable) +{ + if (enable) + sp_write_reg_and(anx78xx, RX_P0, HDMI_RX_TMDS_CTRL_REG7, + ~TERM_PD); + else + sp_write_reg_or(anx78xx, RX_P0, HDMI_RX_TMDS_CTRL_REG7, + TERM_PD); +} + +static inline void sp_tx_clean_hdcp_status(struct anx78xx *anx78xx) +{ + sp_write_reg(anx78xx, TX_P0, TX_HDCP_CTRL0, 0x03); + sp_write_reg_or(anx78xx, TX_P0, TX_HDCP_CTRL0, RE_AUTH); + usleep_range(2000, 4000); +} + +static inline void sp_tx_link_phy_initialization(struct anx78xx *anx78xx) +{ + sp_write_reg(anx78xx, TX_P2, SP_TX_ANALOG_CTRL0, 0x02); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG0, 0x01); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG10, 0x00); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG1, 0x03); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG11, 0x00); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG2, 0x07); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG12, 0x00); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG3, 0x7f); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG13, 0x00); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG4, 0x71); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG14, 0x0c); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG5, 0x6b); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG15, 0x42); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG6, 0x7f); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG16, 0x1e); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG7, 0x73); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG17, 0x3e); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG8, 0x7f); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG18, 0x72); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG9, 0x7f); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG19, 0x7e); +} + +static inline void sp_tx_set_sys_state(struct anx78xx *anx78xx, u8 ss) +{ + struct device *dev = &anx78xx->client->dev; + + dev_dbg(dev, "set: clean_status: %x,\n", sp.need_clean_status); + + if ((sp.tx_system_state >= STATE_LINK_TRAINING) && + (ss < STATE_LINK_TRAINING)) + sp_write_reg_or(anx78xx, TX_P0, SP_TX_ANALOG_PD_REG, CH0_PD); + + sp.tx_system_state_bak = sp.tx_system_state; + sp.tx_system_state = ss; + sp.need_clean_status = 1; + sp_print_system_state(anx78xx, sp.tx_system_state); +} + +static inline void reg_hardware_reset(struct anx78xx *anx78xx) +{ + sp_write_reg_or(anx78xx, TX_P2, SP_TX_RST_CTRL_REG, HW_RST); + sp_tx_clean_state_machine(); + sp_tx_set_sys_state(anx78xx, STATE_SP_INITIALIZED); + msleep(500); +} + +static inline void write_dpcd_addr(struct anx78xx *anx78xx, u8 addrh, + u8 addrm, u8 addrl) +{ + u8 regval; + + if (sp_i2c_read_byte(anx78xx, TX_P0, AUX_ADDR_7_0) != addrl) + sp_write_reg(anx78xx, TX_P0, AUX_ADDR_7_0, addrl); + + if (sp_i2c_read_byte(anx78xx, TX_P0, AUX_ADDR_15_8) != addrm) + sp_write_reg(anx78xx, TX_P0, AUX_ADDR_15_8, addrm); + + sp_read_reg(anx78xx, TX_P0, AUX_ADDR_19_16, ®val); + + if ((regval & 0x0f) != (addrh & 0x0f)) + sp_write_reg(anx78xx, TX_P0, AUX_ADDR_19_16, + (regval & 0xf0) | addrh); +} + +static inline void goto_next_system_state(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + + dev_dbg(dev, "next: clean_status: %x,\n", sp.need_clean_status); + + sp.tx_system_state_bak = sp.tx_system_state; + sp.tx_system_state++; + sp_print_system_state(anx78xx, sp.tx_system_state); +} + +static inline void redo_cur_system_state(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + + dev_dbg(dev, "redo: clean_status: %x,\n", sp.need_clean_status); + + sp.need_clean_status = 1; + sp.tx_system_state_bak = sp.tx_system_state; + sp_print_system_state(anx78xx, sp.tx_system_state); +} + +static inline void system_state_change_with_case(struct anx78xx *anx78xx, + u8 status) +{ + struct device *dev = &anx78xx->client->dev; + + if (sp.tx_system_state < status) + return; + + dev_dbg(dev, "change_case: clean_status: %xm,\n", + sp.need_clean_status); + + if (sp.tx_system_state >= STATE_LINK_TRAINING && + status < STATE_LINK_TRAINING) + sp_write_reg_or(anx78xx, TX_P0, SP_TX_ANALOG_PD_REG, + CH0_PD); + + sp.need_clean_status = 1; + sp.tx_system_state_bak = sp.tx_system_state; + sp.tx_system_state = status; + sp_print_system_state(anx78xx, sp.tx_system_state); +} + +static void sp_wait_aux_op_finish(struct anx78xx *anx78xx, u8 *err_flag) +{ + u8 cnt; + u8 regval; + struct device *dev = &anx78xx->client->dev; + + *err_flag = 0; + cnt = 150; + while (sp_i2c_read_byte(anx78xx, TX_P0, AUX_CTRL2) & AUX_OP_EN) { + usleep_range(2000, 4000); + if (cnt-- == 0) { + dev_err(dev, "aux operate failed!\n"); + *err_flag = 1; + break; + } + } + + sp_read_reg(anx78xx, TX_P0, SP_TX_AUX_STATUS, ®val); + if (regval & 0x0f) { + dev_err(dev, "wait aux operation status %.2x\n", regval); + *err_flag = 1; + } +} + +static void sp_print_system_state(struct anx78xx *anx78xx, u8 ss) +{ + struct device *dev = &anx78xx->client->dev; + + switch (ss) { + case STATE_WAITTING_CABLE_PLUG: + dev_dbg(dev, "-STATE_WAITTING_CABLE_PLUG-\n"); + break; + case STATE_SP_INITIALIZED: + dev_dbg(dev, "-STATE_SP_INITIALIZED-\n"); + break; + case STATE_SINK_CONNECTION: + dev_dbg(dev, "-STATE_SINK_CONNECTION-\n"); + break; + case STATE_PARSE_EDID: + dev_dbg(dev, "-STATE_PARSE_EDID-\n"); + break; + case STATE_LINK_TRAINING: + dev_dbg(dev, "-STATE_LINK_TRAINING-\n"); + break; + case STATE_VIDEO_OUTPUT: + dev_dbg(dev, "-STATE_VIDEO_OUTPUT-\n"); + break; + case STATE_HDCP_AUTH: + dev_dbg(dev, "-STATE_HDCP_AUTH-\n"); + break; + case STATE_AUDIO_OUTPUT: + dev_dbg(dev, "-STATE_AUDIO_OUTPUT-\n"); + break; + case STATE_PLAY_BACK: + dev_dbg(dev, "-STATE_PLAY_BACK-\n"); + break; + default: + dev_err(dev, "unknown system state\n"); + break; + } +} + +static void sp_tx_rst_aux(struct anx78xx *anx78xx) +{ + sp_write_reg_or(anx78xx, TX_P2, RST_CTRL2, AUX_RST); + sp_write_reg_and(anx78xx, TX_P2, RST_CTRL2, ~AUX_RST); +} + +static u8 sp_tx_aux_dpcdread_bytes(struct anx78xx *anx78xx, u8 addrh, + u8 addrm, u8 addrl, u8 ccount, u8 *pbuf) +{ + u8 regval, regval1, i; + u8 bok; + struct device *dev = &anx78xx->client->dev; + + sp_write_reg(anx78xx, TX_P0, BUF_DATA_COUNT, 0x80); + sp_write_reg(anx78xx, TX_P0, AUX_CTRL, ((ccount - 1) << 4) | 0x09); + write_dpcd_addr(anx78xx, addrh, addrm, addrl); + sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, AUX_OP_EN); + usleep_range(2000, 4000); + + sp_wait_aux_op_finish(anx78xx, &bok); + if (bok) { + dev_err(dev, "aux read failed\n"); + sp_read_reg(anx78xx, TX_P2, SP_TX_INT_STATUS1, ®val); + sp_read_reg(anx78xx, TX_P0, TX_DEBUG1, ®val1); + if (!(regval1 & POLLING_EN) || (regval & POLLING_ERR)) + sp_tx_rst_aux(anx78xx); + return 1; + } + + for (i = 0; i < ccount; i++) { + sp_read_reg(anx78xx, TX_P0, BUF_DATA_0 + i, ®val); + *(pbuf + i) = regval; + if (i >= MAX_BUF_CNT) + break; + } + return 0; +} + +static u8 sp_tx_aux_dpcdwrite_bytes(struct anx78xx *anx78xx, u8 addrh, + u8 addrm, u8 addrl, u8 ccount, u8 *pbuf) +{ + u8 regval, i, ret; + + sp_write_reg(anx78xx, TX_P0, AUX_CTRL, ((ccount - 1) << 4) | 0x08); + write_dpcd_addr(anx78xx, addrh, addrm, addrl); + for (i = 0; i < ccount; i++) { + regval = *pbuf; + pbuf++; + sp_write_reg(anx78xx, TX_P0, BUF_DATA_0 + i, regval); + + if (i >= 15) + break; + } + sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, AUX_OP_EN); + sp_wait_aux_op_finish(anx78xx, &ret); + return ret; +} + +static u8 sp_tx_aux_dpcdwrite_byte(struct anx78xx *anx78xx, u8 addrh, + u8 addrm, u8 addrl, u8 data1) +{ + u8 ret; + + sp_write_reg(anx78xx, TX_P0, AUX_CTRL, 0x08); + write_dpcd_addr(anx78xx, addrh, addrm, addrl); + sp_write_reg(anx78xx, TX_P0, BUF_DATA_0, data1); + sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, AUX_OP_EN); + sp_wait_aux_op_finish(anx78xx, &ret); + return ret; +} + +static void sp_block_power_ctrl(struct anx78xx *anx78xx, + enum sp_tx_power_block sp_tx_pd_block, + u8 power) +{ + struct device *dev = &anx78xx->client->dev; + + if (power == SP_POWER_ON) + sp_write_reg_and(anx78xx, TX_P2, SP_POWERD_CTRL_REG, + ~sp_tx_pd_block); + else + sp_write_reg_or(anx78xx, TX_P2, SP_POWERD_CTRL_REG, + sp_tx_pd_block); + + dev_dbg(dev, "sp_tx_power_on: %.2x\n", sp_tx_pd_block); +} + +static void sp_vbus_power_off(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + int i; + + for (i = 0; i < 5; i++) { + sp_write_reg_and(anx78xx, TX_P2, TX_PLL_FILTER5, + ~P5V_PROTECT_PD & ~SHORT_PROTECT_PD); + sp_write_reg_or(anx78xx, TX_P2, TX_PLL_FILTER, V33_SWITCH_ON); + if (!(sp_i2c_read_byte(anx78xx, TX_P2, TX_PLL_FILTER5) + & 0xc0)) { + dev_dbg(dev, "3.3V output enabled\n"); + break; + } + } +} + +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; + sp.hcdp_state = HDCP_CAPABLE_CHECK; + sp.tx_vo_state = VO_WAIT_VIDEO_STABLE; + sp.tx_ao_state = AO_INIT; +} + +enum sp_tx_state sp_tx_current_state(void) +{ + return sp.tx_system_state; +} + +void sp_tx_variable_init(void) +{ + sp.block_en = 1; + + sp.tx_system_state = STATE_WAITTING_CABLE_PLUG; + sp.tx_system_state_bak = STATE_WAITTING_CABLE_PLUG; + + sp.edid_break = 0; + sp.read_edid_flag = 0; + sp.edid_checksum = 0; + + memset(sp.edid_blocks, 0, 256); + + sp.tx_lt_state = LT_INIT; + sp.hcdp_state = HDCP_CAPABLE_CHECK; + sp.need_clean_status = 0; + sp.tx_sc_state = SC_INIT; + sp.tx_vo_state = VO_WAIT_VIDEO_STABLE; + sp.tx_ao_state = AO_INIT; + sp.changed_bandwidth = LINK_5P4G; + sp.hdmi_dvi_status = HDMI_MODE; + + sp.tx_test_lt = 0; + sp.tx_test_bw = 0; + sp.tx_test_edid = 0; + + sp.ds_vid_stb_cntr = 0; + sp.hdcp_fail_count = 0; +} + +static void hdmi_rx_tmds_phy_initialization(struct anx78xx *anx78xx) +{ + sp_write_reg(anx78xx, RX_P0, HDMI_RX_TMDS_CTRL_REG2, 0xa9); + sp_write_reg(anx78xx, RX_P0, HDMI_RX_TMDS_CTRL_REG7, 0x80); + + sp_write_reg(anx78xx, RX_P0, HDMI_RX_TMDS_CTRL_REG1, 0x90); + sp_write_reg(anx78xx, RX_P0, HDMI_RX_TMDS_CTRL_REG6, 0x92); + sp_write_reg(anx78xx, RX_P0, HDMI_RX_TMDS_CTRL_REG20, 0xf2); +} + +static void hdmi_rx_initialization(struct anx78xx *anx78xx) +{ + sp_write_reg(anx78xx, RX_P0, RX_MUTE_CTRL, AUD_MUTE | VID_MUTE); + sp_write_reg_or(anx78xx, RX_P0, RX_CHIP_CTRL, + MAN_HDMI5V_DET | PLLLOCK_CKDT_EN | DIGITAL_CKDT_EN); + + sp_write_reg_or(anx78xx, RX_P0, RX_SRST, HDCP_MAN_RST | SW_MAN_RST | + TMDS_RST | VIDEO_RST); + sp_write_reg_and(anx78xx, RX_P0, RX_SRST, ~HDCP_MAN_RST & + ~SW_MAN_RST & ~TMDS_RST & ~VIDEO_RST); + + sp_write_reg_or(anx78xx, RX_P0, RX_AEC_EN0, AEC_EN06 | AEC_EN05); + sp_write_reg_or(anx78xx, RX_P0, RX_AEC_EN2, AEC_EN21); + sp_write_reg_or(anx78xx, RX_P0, RX_AEC_CTRL, AVC_EN | AAC_OE | AAC_EN); + + sp_write_reg_and(anx78xx, RX_P0, RX_SYS_PWDN1, ~PWDN_CTRL); + + sp_write_reg_or(anx78xx, RX_P0, RX_VID_DATA_RNG, R2Y_INPUT_LIMIT); + sp_write_reg(anx78xx, RX_P0, 0x65, 0xc4); + sp_write_reg(anx78xx, RX_P0, 0x66, 0x18); + + /* enable DDC stretch */ + sp_write_reg(anx78xx, TX_P0, TX_EXTRA_ADDR, 0x50); + + hdmi_rx_tmds_phy_initialization(anx78xx); + hdmi_rx_set_hpd(anx78xx, 0); + hdmi_rx_set_termination(anx78xx, 0); +} + +struct anx78xx_clock_data const pxtal_data[XTAL_CLK_NUM] = { + {19, 192}, + {24, 240}, + {25, 250}, + {26, 260}, + {27, 270}, + {38, 384}, + {52, 520}, + {27, 270}, +}; + +static void xtal_clk_sel(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + + dev_dbg(dev, "define XTAL_CLK: %x\n", XTAL_27M); + sp_write_reg_and_or(anx78xx, TX_P2, + TX_ANALOG_DEBUG2, ~0x3c, 0x3c & (XTAL_27M << 2)); + sp_write_reg(anx78xx, TX_P0, 0xec, pxtal_data[XTAL_27M].xtal_clk_m10); + sp_write_reg(anx78xx, TX_P0, 0xed, + ((pxtal_data[XTAL_27M].xtal_clk_m10 & 0xff00) >> 2) + | pxtal_data[XTAL_27M].xtal_clk); + + sp_write_reg(anx78xx, TX_P0, I2C_GEN_10US_TIMER0, + pxtal_data[XTAL_27M].xtal_clk_m10); + sp_write_reg(anx78xx, TX_P0, I2C_GEN_10US_TIMER1, + (pxtal_data[XTAL_27M].xtal_clk_m10 & 0xff00) >> 8); + sp_write_reg(anx78xx, TX_P0, 0xbf, pxtal_data[XTAL_27M].xtal_clk - 1); + + sp_write_reg_and_or(anx78xx, RX_P0, 0x49, 0x07, + ((pxtal_data[XTAL_27M].xtal_clk >> 1) - 2) << 3); +} + +void sp_tx_initialization(struct anx78xx *anx78xx) +{ + sp_write_reg(anx78xx, TX_P0, AUX_CTRL2, 0x30); + sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, 0x08); + + sp_write_reg_and(anx78xx, TX_P0, TX_HDCP_CTRL, + (u8)~AUTO_EN & ~AUTO_START); + sp_write_reg(anx78xx, TX_P0, OTP_KEY_PROTECT1, OTP_PSW1); + sp_write_reg(anx78xx, TX_P0, OTP_KEY_PROTECT2, OTP_PSW2); + sp_write_reg(anx78xx, TX_P0, OTP_KEY_PROTECT3, OTP_PSW3); + sp_write_reg_or(anx78xx, TX_P0, HDCP_KEY_CMD, DISABLE_SYNC_HDCP); + sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL8_REG, VID_VRES_TH); + + sp_write_reg(anx78xx, TX_P0, HDCP_AUTO_TIMER, HDCP_AUTO_TIMER_VAL); + sp_write_reg_or(anx78xx, TX_P0, TX_HDCP_CTRL, LINK_POLLING); + + sp_write_reg_or(anx78xx, TX_P0, TX_LINK_DEBUG, M_VID_DEBUG); + sp_write_reg_or(anx78xx, TX_P2, TX_ANALOG_DEBUG2, POWERON_TIME_1P5MS); + + xtal_clk_sel(anx78xx); + sp_write_reg(anx78xx, TX_P0, AUX_DEFER_CTRL, 0x8c); + + sp_write_reg_or(anx78xx, 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(anx78xx, TX_P0, SP_TX_LINK_CHK_TIMER, 0x1d); + sp_write_reg_or(anx78xx, TX_P0, TX_MISC, EQ_TRAINING_LOOP); + + sp_write_reg_or(anx78xx, TX_P0, SP_TX_ANALOG_PD_REG, CH0_PD); + + sp_write_reg(anx78xx, TX_P2, SP_TX_INT_CTRL_REG, 0x01); + /* disable HDCP mismatch function for VGA dongle */ + sp_tx_link_phy_initialization(anx78xx); + gen_m_clk_with_downspeading(anx78xx); + + sp.down_sample_en = 0; +} + +bool sp_chip_detect(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u16 id; + u8 idh = 0, idl = 0; + int i; + + anx78xx_poweron(anx78xx); + + /* check chip id */ + sp_read_reg(anx78xx, TX_P2, SP_TX_DEV_IDL_REG, &idl); + sp_read_reg(anx78xx, TX_P2, SP_TX_DEV_IDH_REG, &idh); + id = idl | (idh << 8); + + dev_dbg(dev, "CHIPID: ANX%x\n", id & 0xffff); + + for (i = 0; i < ARRAY_SIZE(chipid_list); i++) { + if (id == chipid_list[i]) + return true; + } + + return false; +} + +static void sp_waiting_cable_plug_process(struct anx78xx *anx78xx) +{ + sp_tx_variable_init(); + anx78xx_poweron(anx78xx); + goto_next_system_state(anx78xx); +} + +/* + * Check if it is ANALOGIX dongle. + */ +static const u8 ANX_OUI[3] = {0x00, 0x22, 0xb9}; + +static u8 is_anx_dongle(struct anx78xx *anx78xx) +{ + u8 buf[3]; + + /* 0x0500~0x0502: BRANCH_IEEE_OUI */ + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x05, 0x00, 3, buf); + + if (!memcmp(buf, ANX_OUI, 3)) + return 1; + + return 0; +} + +static void sp_tx_get_rx_bw(struct anx78xx *anx78xx, u8 *bw) +{ + if (is_anx_dongle(anx78xx)) + *bw = LINK_6P75G; /* just for debug */ + else + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x00, + DPCD_MAX_LINK_RATE, 1, bw); +} + +static u8 sp_tx_get_cable_type(struct anx78xx *anx78xx, + enum cable_type_status det_cable_type_state) +{ + struct device *dev = &anx78xx->client->dev; + + 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(anx78xx, 0x00, 0x00, 0x05, 1, + &ds_port_preset); + + dev_dbg(dev, "DPCD 0x005: %x\n", (int)ds_port_preset); + + switch (det_cable_type_state) { + case CHECK_AUXCH: + if (aux_status == 0) { + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x00, 0, 0x0c, + data_buf); + det_cable_type_state = GETTED_CABLE_TYPE; + } else { + dev_err(dev, "AUX access error\n"); + break; + } + case GETTED_CABLE_TYPE: + switch ((ds_port_preset & (BIT(1) | BIT(2))) >> 1) { + case 0x00: + cur_cable_type = DWN_STRM_IS_DIGITAL; + dev_dbg(dev, "Downstream is DP dongle.\n"); + break; + case 0x01: + case 0x03: + cur_cable_type = DWN_STRM_IS_ANALOG; + dev_dbg(dev, "Downstream is VGA dongle.\n"); + break; + case 0x02: + cur_cable_type = DWN_STRM_IS_HDMI; + dev_dbg(dev, "Downstream is HDMI dongle.\n"); + break; + default: + cur_cable_type = DWN_STRM_IS_NULL; + dev_err(dev, "Downstream can not recognized.\n"); + break; + } + default: + break; + } + return cur_cable_type; +} + +static u8 sp_tx_get_dp_connection(struct anx78xx *anx78xx) +{ + u8 regval; + + if (sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, + DPCD_SINK_COUNT, 1, ®val)) + return 0; + + if (regval & 0x1f) { + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x00, 0x04, 1, ®val); + if (regval & 0x20) { + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x06, 0x00, 1, + ®val); + /* + * Bit 5 = SET_DN_DEVICE_DP_PWR_5V + * Bit 6 = SET_DN_DEVICE_DP_PWR_12V + * Bit 7 = SET_DN_DEVICE_DP_PWR_18V + */ + regval = regval & 0x1f; + sp_tx_aux_dpcdwrite_byte(anx78xx, 0x00, 0x06, 0x00, + regval | 0x20); + } + return 1; + } else { + return 0; + } +} + +static void sp_sink_connection(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + + 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(anx78xx, 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; + dev_dbg(dev, "Can not get cable type!\n"); + } + break; + } + + sp.tx_sc_state = SC_SINK_CONNECTED; + case SC_SINK_CONNECTED: + if (sp_tx_get_dp_connection(anx78xx)) + goto_next_system_state(anx78xx); + break; + case SC_NOT_CABLE: + sp_vbus_power_off(anx78xx); + reg_hardware_reset(anx78xx); + break; + } +} + +/******************start EDID process********************/ +static void sp_tx_enable_video_input(struct anx78xx *anx78xx, u8 enable) +{ + struct device *dev = &anx78xx->client->dev; + u8 regval; + + sp_read_reg(anx78xx, TX_P2, VID_CTRL1, ®val); + if (enable) { + sp_write_reg(anx78xx, TX_P2, VID_CTRL1, + (regval & 0xf7) | VIDEO_EN); + dev_dbg(dev, "Slimport Video is enabled!\n"); + + } else { + sp_write_reg(anx78xx, TX_P2, VID_CTRL1, regval & ~VIDEO_EN); + dev_dbg(dev, "Slimport Video is disabled!\n"); + } +} + +static u8 sp_get_edid_detail(u8 *data_buf) +{ + u16 pixclock_edid; + + pixclock_edid = (((u16)data_buf[1] << 8) | ((u16)data_buf[0] & 0xff)); + if (pixclock_edid <= 5300) + return LINK_1P62G; + else if ((pixclock_edid > 5300) && (pixclock_edid <= 8900)) + return LINK_2P7G; + else if ((pixclock_edid > 8900) && (pixclock_edid <= 18000)) + return LINK_5P4G; + else + return LINK_6P75G; +} + +static u8 sp_parse_edid_to_get_bandwidth(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 i, bandwidth, temp; + + bandwidth = LINK_1P62G; + for (i = 0; i < 4; i++) { + if (sp.edid_blocks[0x36 + 0x12 * i] == 0) + break; + temp = sp_get_edid_detail(sp.edid_blocks + 0x36 + 0x12 * i); + dev_dbg(dev, "bandwidth via EDID : %x\n", temp); + if (bandwidth < temp) + bandwidth = temp; + if (bandwidth >= LINK_6P75G) + break; + } + + return bandwidth; +} + +static void sp_tx_aux_wr(struct anx78xx *anx78xx, u8 offset) +{ + sp_write_reg(anx78xx, TX_P0, BUF_DATA_0, offset); + sp_write_reg(anx78xx, TX_P0, AUX_CTRL, 0x04); + sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, AUX_OP_EN); + sp_wait_aux_op_finish(anx78xx, &sp.edid_break); +} + +static void sp_tx_aux_rd(struct anx78xx *anx78xx, u8 len_cmd) +{ + sp_write_reg(anx78xx, TX_P0, AUX_CTRL, len_cmd); + sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, AUX_OP_EN); + sp_wait_aux_op_finish(anx78xx, &sp.edid_break); +} + +static u8 sp_tx_get_edid_block(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 regval; + + sp_tx_aux_wr(anx78xx, 0x7e); + sp_tx_aux_rd(anx78xx, 0x01); + sp_read_reg(anx78xx, TX_P0, BUF_DATA_0, ®val); + dev_dbg(dev, "EDID Block = %d\n", regval + 1); + + if (regval > 3) + regval = 1; + return regval; +} + +static void sp_edid_read(struct anx78xx *anx78xx, u8 offset, + u8 *pblock_buf) +{ + u8 data_cnt, error_cnt; + u8 regval; + + sp_tx_aux_wr(anx78xx, offset); + sp_tx_aux_rd(anx78xx, 0xf5); + data_cnt = 0; + error_cnt = 0; + + while ((data_cnt) < 16) { + sp_read_reg(anx78xx, TX_P0, BUF_DATA_COUNT, ®val); + + if (regval & 0x1f) { + data_cnt = data_cnt + (regval & 0x1f); + do { + sp_read_reg(anx78xx, TX_P0, + BUF_DATA_0 + regval - 1, + &pblock_buf[regval - 1]); + } while (--regval); + } else { + if (error_cnt++ <= 2) { + sp_tx_rst_aux(anx78xx); + regval = 0x05 | ((0x0f - data_cnt) << 4); + sp_tx_aux_rd(anx78xx, regval); + } else { + sp.edid_break = 1; + break; + } + } + } + sp_write_reg(anx78xx, TX_P0, AUX_CTRL, 0x01); + sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, ADDR_ONLY_BIT | AUX_OP_EN); + sp_wait_aux_op_finish(anx78xx, &sp.edid_break); + sp_tx_addronly_set(anx78xx, 0); +} + +static void sp_tx_edid_read_initial(struct anx78xx *anx78xx) +{ + sp_write_reg(anx78xx, TX_P0, AUX_ADDR_7_0, 0x50); + sp_write_reg(anx78xx, TX_P0, AUX_ADDR_15_8, 0); + sp_write_reg_and(anx78xx, TX_P0, AUX_ADDR_19_16, 0xf0); +} + +static void sp_seg_edid_read(struct anx78xx *anx78xx, + u8 segment, u8 offset) +{ + struct device *dev = &anx78xx->client->dev; + u8 regval, cnt; + int i; + + sp_write_reg(anx78xx, TX_P0, AUX_CTRL, 0x04); + + sp_write_reg(anx78xx, TX_P0, AUX_ADDR_7_0, 0x30); + + sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, ADDR_ONLY_BIT | AUX_OP_EN); + + sp_read_reg(anx78xx, TX_P0, AUX_CTRL2, ®val); + + sp_wait_aux_op_finish(anx78xx, &sp.edid_break); + sp_read_reg(anx78xx, TX_P0, AUX_CTRL, ®val); + + sp_write_reg(anx78xx, TX_P0, BUF_DATA_0, segment); + + sp_write_reg(anx78xx, TX_P0, AUX_CTRL, 0x04); + + sp_write_reg_and_or(anx78xx, TX_P0, AUX_CTRL2, ~ADDR_ONLY_BIT, + AUX_OP_EN); + cnt = 0; + sp_read_reg(anx78xx, TX_P0, AUX_CTRL2, ®val); + while (regval & AUX_OP_EN) { + usleep_range(1000, 2000); + cnt++; + if (cnt == 10) { + dev_err(dev, "read AUX_CTRL2 failed.\n"); + sp_tx_rst_aux(anx78xx); + cnt = 0; + sp.edid_break = 1; + return; + } + sp_read_reg(anx78xx, TX_P0, AUX_CTRL2, ®val); + } + + sp_write_reg(anx78xx, TX_P0, AUX_ADDR_7_0, 0x50); + + sp_tx_aux_wr(anx78xx, offset); + + sp_tx_aux_rd(anx78xx, 0xf5); + cnt = 0; + for (i = 0; i < 16; i++) { + sp_read_reg(anx78xx, TX_P0, BUF_DATA_COUNT, ®val); + while ((regval & 0x1f) == 0) { + usleep_range(2000, 4000); + cnt++; + sp_read_reg(anx78xx, TX_P0, BUF_DATA_COUNT, ®val); + if (cnt == 10) { + dev_err(dev, + "read BUF_DATA_COUNT failed.\n"); + dev_dbg(dev, "read break"); + sp_tx_rst_aux(anx78xx); + sp.edid_break = 1; + return; + } + } + + sp_read_reg(anx78xx, TX_P0, BUF_DATA_0 + i, ®val); + } + + sp_write_reg(anx78xx, TX_P0, AUX_CTRL, 0x01); + sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, ADDR_ONLY_BIT | AUX_OP_EN); + sp_write_reg_and(anx78xx, TX_P0, AUX_CTRL2, ~ADDR_ONLY_BIT); + sp_read_reg(anx78xx, TX_P0, AUX_CTRL2, ®val); + + cnt = 0; + while (regval & AUX_OP_EN) { + usleep_range(1000, 2000); + cnt++; + if (cnt == 10) { + dev_err(dev, "read AUX_CTRL2 failed.\n"); + sp_tx_rst_aux(anx78xx); + cnt = 0; + sp.edid_break = 1; + return; + } + sp_read_reg(anx78xx, TX_P0, AUX_CTRL2, ®val); + } +} + +static bool sp_edid_checksum_result(u8 *pbuf) +{ + u8 cnt, checksum; + + checksum = 0; + + for (cnt = 0; cnt < 0x80; cnt++) + checksum = checksum + pbuf[cnt]; + + sp.edid_checksum = checksum - pbuf[0x7f]; + sp.edid_checksum = ~sp.edid_checksum + 1; + + return checksum == 0 ? 1 : 0; +} + +static void sp_check_edid_data(struct anx78xx *anx78xx, u8 *pbuf) +{ + struct device *dev = &anx78xx->client->dev; + u8 i; + + if ((pbuf[0] == 0x00) && (pbuf[1] == 0xff) && + (pbuf[2] == 0xff) && (pbuf[3] == 0xff) && + (pbuf[4] == 0xff) && (pbuf[5] == 0xff) && + (pbuf[6] == 0xff) && (pbuf[7] == 0x00)) + dev_dbg(dev, "Good EDID header!\n"); + else + dev_err(dev, "Bad EDID header!\n"); + + for (i = 0; i <= (pbuf[0x7e] > 1 ? 1 : pbuf[0x7e]); i++) { + if (!sp_edid_checksum_result(pbuf + i * 128)) + dev_err(dev, "Block %x edid checksum error\n", i); + else + dev_dbg(dev, "Block %x edid checksum OK\n", i); + } +} + +static void sp_tx_edid_read(struct anx78xx *anx78xx, u8 *pedid_blocks_buf) +{ + struct device *dev = &anx78xx->client->dev; + u8 offset = 0; + u8 count, blocks_num; + u8 pblock_buf[16]; + u8 i, j, regval; + + sp.edid_break = 0; + sp_tx_edid_read_initial(anx78xx); + sp_write_reg(anx78xx, TX_P0, AUX_CTRL, 0x04); + sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, 0x03); + sp_wait_aux_op_finish(anx78xx, &sp.edid_break); + sp_tx_addronly_set(anx78xx, 0); + + blocks_num = sp_tx_get_edid_block(anx78xx); + + count = 0; + do { + switch (count) { + case 0: + case 1: + for (i = 0; i < 8; i++) { + offset = (i + count * 8) * 16; + sp_edid_read(anx78xx, offset, pblock_buf); + if (sp.edid_break == 1) + break; + for (j = 0; j < 16; j++) { + pedid_blocks_buf[offset + j] + = pblock_buf[j]; + } + } + break; + case 2: + case 3: + if (count == 2) + offset = 0x00; + else /* count == 3 */ + offset = 0x80; + for (j = 0; j < 8; j++) { + if (sp.edid_break == 1) + break; + sp_seg_edid_read(anx78xx, count / 2, offset); + offset = offset + 0x10; + } + break; + default: + break; + } + count++; + if (sp.edid_break == 1) + break; + } while (blocks_num >= count); + + sp_tx_rst_aux(anx78xx); + if (sp.read_edid_flag == 0) { + sp_check_edid_data(anx78xx, pedid_blocks_buf); + sp.read_edid_flag = 1; + } + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x18, 1, ®val); + if (regval & 0x04) { + dev_dbg(dev, "check sum = %.2x\n", sp.edid_checksum); + regval = sp.edid_checksum; + sp_tx_aux_dpcdwrite_bytes(anx78xx, 0x00, 0x02, 0x61, 1, + ®val); + sp.tx_test_edid = 1; + regval = 0x04; + sp_tx_aux_dpcdwrite_bytes(anx78xx, 0x00, 0x02, 0x60, 1, + ®val); + dev_dbg(dev, "Test EDID done\n"); + } +} + +static bool sp_check_with_pre_edid(struct anx78xx *anx78xx, u8 *org_buf) +{ + struct device *dev = &anx78xx->client->dev; + u8 i; + u8 buf[16]; + bool ret = false; + + sp.edid_break = 0; + sp_tx_edid_read_initial(anx78xx); + sp_write_reg(anx78xx, TX_P0, AUX_CTRL, 0x04); + sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, 0x03); + sp_wait_aux_op_finish(anx78xx, &sp.edid_break); + sp_tx_addronly_set(anx78xx, 0); + + sp_edid_read(anx78xx, 0x70, buf); + + if (sp.edid_break == 0) { + for (i = 0; i < 16; i++) { + if (org_buf[0x70 + i] != buf[i]) { + dev_dbg(dev, "%s\n", + "different checksum and blocks num\n"); + goto return_point; + } + } + } else { + goto return_point; + } + + sp_edid_read(anx78xx, 0x08, buf); + if (sp.edid_break == 0) { + for (i = 0; i < 16; i++) { + if (org_buf[i + 8] != buf[i]) { + dev_dbg(dev, "different edid information\n"); + goto return_point; + } + } + } else { + goto return_point; + } + + ret = true; +return_point: + sp_tx_rst_aux(anx78xx); + + return ret; +} + +static void sp_edid_process(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 temp_value, temp_value1; + u8 i; + + dev_dbg(dev, "edid_process\n"); + + if (sp.read_edid_flag == 1) + if (!sp_check_with_pre_edid(anx78xx, sp.edid_blocks)) + sp.read_edid_flag = 0; + + if (sp.read_edid_flag == 0) { + sp_tx_edid_read(anx78xx, sp.edid_blocks); + if (sp.edid_break) + dev_err(dev, "ERR:EDID corruption!\n"); + } + + /* Release the HPD after the OTP loaddown */ + for (i = 0; i < 10; i++) { + if (sp_i2c_read_byte(anx78xx, TX_P0, HDCP_KEY_STATUS) & 0x01) + break; + + dev_dbg(dev, "waiting HDCP KEY loaddown\n"); + usleep_range(1000, 2000); + } + + sp_write_reg(anx78xx, RX_P0, HDMI_RX_INT_MASK1_REG, 0xe2); + hdmi_rx_set_hpd(anx78xx, 1); + dev_dbg(dev, "hdmi_rx_set_hpd 1 !\n"); + + hdmi_rx_set_termination(anx78xx, 1); + + sp_tx_get_rx_bw(anx78xx, &temp_value); + dev_dbg(dev, "RX BW %x\n", temp_value); + + temp_value1 = sp_parse_edid_to_get_bandwidth(anx78xx); + if (temp_value <= temp_value1) + temp_value1 = temp_value; + + dev_dbg(dev, "set link bw in edid %x\n", temp_value1); + sp.changed_bandwidth = temp_value1; + goto_next_system_state(anx78xx); +} + +/******************End EDID process********************/ + +/******************start Link training process********************/ +static void sp_tx_lvttl_bit_mapping(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 regval, colorspace; + u8 vid_bit; + + vid_bit = 0; + sp_read_reg(anx78xx, RX_P1, HDMI_RX_AVI_DATA00_REG, &colorspace); + colorspace &= 0x60; + + switch (((sp_i2c_read_byte(anx78xx, RX_P0, HDMI_RX_VIDEO_STATUS_REG1) + & COLOR_DEPTH) >> 4)) { + default: + case HDMI_LEGACY: + regval = IN_BPC_8BIT; + vid_bit = 0; + break; + case HDMI_24BIT: + regval = IN_BPC_8BIT; + if (colorspace == 0x20) + vid_bit = 5; + else + vid_bit = 1; + break; + case HDMI_30BIT: + regval = IN_BPC_10BIT; + if (colorspace == 0x20) + vid_bit = 6; + else + vid_bit = 2; + break; + case HDMI_36BIT: + regval = IN_BPC_12BIT; + if (colorspace == 0x20) + vid_bit = 6; + else + vid_bit = 3; + break; + } + + /* + * For down sample video (12bit, 10bit ---> 8bit), + * this register doesn't change + */ + if (sp.down_sample_en == 0) + sp_write_reg_and_or(anx78xx, TX_P2, + SP_TX_VID_CTRL2_REG, 0x8c, + colorspace >> 5 | regval); + + /* Patch: for 10bit video must be set this value to 12bit by someone */ + if (sp.down_sample_en == 1 && regval == IN_BPC_10BIT) + vid_bit = 3; + + sp_write_reg_and_or(anx78xx, TX_P2, + BIT_CTRL_SPECIFIC, 0x00, + ENABLE_BIT_CTRL | vid_bit << 1); + + if (sp.tx_test_edid) { + sp_write_reg_and(anx78xx, TX_P2, SP_TX_VID_CTRL2_REG, 0x8f); + dev_dbg(dev, "***color space is set to 18bit***\n"); + } + + if (colorspace) { + sp_write_reg(anx78xx, TX_P0, SP_TX_VID_BLANK_SET1, 0x80); + sp_write_reg(anx78xx, TX_P0, SP_TX_VID_BLANK_SET2, 0x00); + sp_write_reg(anx78xx, TX_P0, SP_TX_VID_BLANK_SET3, 0x80); + } else { + sp_write_reg(anx78xx, TX_P0, SP_TX_VID_BLANK_SET1, 0x0); + sp_write_reg(anx78xx, TX_P0, SP_TX_VID_BLANK_SET2, 0x0); + sp_write_reg(anx78xx, TX_P0, SP_TX_VID_BLANK_SET3, 0x0); + } +} + +static unsigned long sp_tx_pclk_calc(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + unsigned long str_plck; + u16 vid_counter; + u8 regval; + + sp_read_reg(anx78xx, RX_P0, PCLK_HR_CNT2, ®val); + vid_counter = regval << 8; + sp_read_reg(anx78xx, RX_P0, PCLK_HR_CNT1, ®val); + vid_counter |= regval; + str_plck = (vid_counter * pxtal_data[XTAL_27M].xtal_clk_m10) >> 12; + dev_dbg(dev, "PCLK = %d.%d\n", (u16)str_plck / 10, + (u16)(str_plck - ((str_plck / 10) * 10))); + return str_plck; +} + +static u8 sp_tx_bw_lc_sel(struct anx78xx *anx78xx, unsigned long pclk) +{ + struct device *dev = &anx78xx->client->dev; + unsigned long pixel_clk; + u8 link; + + switch (((sp_i2c_read_byte(anx78xx, 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; + } + + dev_dbg(dev, "pixel_clk = %d.%d\n", (u16)pixel_clk / 10, + (u16)(pixel_clk - ((pixel_clk / 10) * 10))); + + sp.down_sample_en = 0; + if (pixel_clk <= 530) { + link = LINK_1P62G; + } else if ((530 < pixel_clk) && (pixel_clk <= 890)) { + link = LINK_2P7G; + } else if ((890 < pixel_clk) && (pixel_clk <= 1800)) { + link = LINK_5P4G; + } else { + link = LINK_6P75G; + if (pixel_clk > 2240) + sp.down_sample_en = 1; + } + + if (sp_tx_get_link_bw(anx78xx) != link) { + sp.changed_bandwidth = link; + dev_dbg(dev, + "different bandwidth between sink and video %.2x", + link); + return 1; + } + return 0; +} + +static void sp_tx_spread_enable(struct anx78xx *anx78xx, u8 benable) +{ + u8 regval; + + sp_read_reg(anx78xx, TX_P0, SP_TX_DOWN_SPREADING_CTRL1, ®val); + + if (benable) { + regval |= SP_TX_SSC_DWSPREAD; + sp_write_reg(anx78xx, TX_P0, SP_TX_DOWN_SPREADING_CTRL1, + regval); + + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x01, + DPCD_DOWNSPREAD_CTRL, 1, ®val); + regval |= SPREAD_AMPLITUDE; + sp_tx_aux_dpcdwrite_byte(anx78xx, 0x00, 0x01, + DPCD_DOWNSPREAD_CTRL, regval); + } else { + regval &= ~SP_TX_SSC_DISABLE; + sp_write_reg(anx78xx, TX_P0, SP_TX_DOWN_SPREADING_CTRL1, + regval); + + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x01, + DPCD_DOWNSPREAD_CTRL, 1, ®val); + regval &= ~SPREAD_AMPLITUDE; + sp_tx_aux_dpcdwrite_byte(anx78xx, 0x00, 0x01, + DPCD_DOWNSPREAD_CTRL, regval); + } +} + +static void sp_tx_config_ssc(struct anx78xx *anx78xx, + enum sp_ssc_dep sscdep) +{ + sp_write_reg(anx78xx, TX_P0, SP_TX_DOWN_SPREADING_CTRL1, 0x0); + sp_write_reg(anx78xx, TX_P0, SP_TX_DOWN_SPREADING_CTRL1, sscdep); + sp_tx_spread_enable(anx78xx, 1); +} + +static void sp_tx_enhancemode_set(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 regval; + + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x00, DPCD_MAX_LANE_COUNT, + 1, ®val); + if (regval & ENHANCED_FRAME_CAP) { + sp_write_reg_or(anx78xx, TX_P0, SP_TX_SYS_CTRL4_REG, + ENHANCED_MODE); + + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x01, + DPCD_LANE_COUNT_SET, 1, ®val); + regval |= ENHANCED_FRAME_EN; + sp_tx_aux_dpcdwrite_byte(anx78xx, 0x00, 0x01, + DPCD_LANE_COUNT_SET, regval); + + dev_dbg(dev, "Enhance mode enabled\n"); + } else { + sp_write_reg_and(anx78xx, TX_P0, SP_TX_SYS_CTRL4_REG, + ~ENHANCED_MODE); + + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x01, + DPCD_LANE_COUNT_SET, 1, ®val); + + regval &= ~ENHANCED_FRAME_EN; + sp_tx_aux_dpcdwrite_byte(anx78xx, 0x00, 0x01, + DPCD_LANE_COUNT_SET, regval); + + dev_dbg(dev, "Enhance mode disabled\n"); + } +} + +static u16 sp_tx_link_err_check(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u16 errl = 0, errh = 0; + u8 bytebuf[2]; + + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x10, 2, bytebuf); + usleep_range(5000, 10000); + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x10, 2, bytebuf); + errh = bytebuf[1]; + + if (errh & 0x80) { + errl = bytebuf[0]; + errh = (errh & 0x7f) << 8; + errl = errh + errl; + } + + dev_err(dev, " Err of Lane = %d\n", errl); + return errl; +} + +static void sp_lt_finish(struct anx78xx *anx78xx, u8 temp_value) +{ + struct device *dev = &anx78xx->client->dev; + + sp_tx_aux_dpcdread_bytes(anx78xx, 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(anx78xx)) { + sp_read_reg(anx78xx, TX_P0, + SP_TX_LT_SET_REG, &temp_value); + if (!(temp_value & MAX_PRE_REACH)) { + sp_write_reg(anx78xx, TX_P0, + SP_TX_LT_SET_REG, + temp_value + 0x08); + if (sp_tx_link_err_check(anx78xx)) + sp_write_reg(anx78xx, TX_P0, + SP_TX_LT_SET_REG, + temp_value); + } + } + + temp_value = sp_tx_get_link_bw(anx78xx); + if (temp_value == sp.changed_bandwidth) { + dev_dbg(dev, "LT succeed, bw: %.2x", + temp_value); + dev_dbg(dev, "Lane0 Set: %.2x\n", + sp_i2c_read_byte(anx78xx, TX_P0, + SP_TX_LT_SET_REG)); + sp.tx_lt_state = LT_INIT; + goto_next_system_state(anx78xx); + } else { + dev_dbg(dev, "cur:%.2x, per:%.2x\n", + temp_value, + sp.changed_bandwidth); + sp.tx_lt_state = LT_ERROR; + } + } else { + sp.tx_test_lt = 0; + sp.tx_lt_state = LT_INIT; + goto_next_system_state(anx78xx); + } + } else { + dev_dbg(dev, "LANE0 Status error: %.2x\n", + temp_value & 0x07); + sp.tx_lt_state = LT_ERROR; + } +} + +static void sp_link_training(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 value, regval; + + dev_dbg(dev, "sp.tx_lt_state : %x\n", (int)sp.tx_lt_state); + + switch (sp.tx_lt_state) { + case LT_INIT: + sp_block_power_ctrl(anx78xx, SP_TX_PWR_VIDEO, SP_POWER_ON); + sp_tx_video_mute(anx78xx, 1); + sp_tx_enable_video_input(anx78xx, 0); + sp.tx_lt_state++; + /* fallthrough */ + case LT_WAIT_PLL_LOCK: + if (!sp_tx_get_pll_lock_status(anx78xx)) { + sp_read_reg(anx78xx, TX_P0, SP_TX_PLL_CTRL_REG, + &value); + + value |= PLL_RST; + sp_write_reg(anx78xx, TX_P0, SP_TX_PLL_CTRL_REG, + value); + + value &= ~PLL_RST; + sp_write_reg(anx78xx, TX_P0, SP_TX_PLL_CTRL_REG, + value); + + dev_dbg(dev, "PLL not lock!\n"); + } 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(anx78xx, &value); + if (value < sp.changed_bandwidth) { + dev_dbg(dev, "****Over bandwidth****\n"); + sp.changed_bandwidth = value; + } else { + sp.tx_lt_state++; + } + /* fallthrough */ + case LT_START: + if (sp.tx_test_lt) { + sp.changed_bandwidth = sp.tx_test_bw; + sp_write_reg_and(anx78xx, TX_P2, SP_TX_VID_CTRL2_REG, + 0x8f); + } else { + sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG, 0x00); + } + + sp_write_reg_and(anx78xx, TX_P0, SP_TX_ANALOG_PD_REG, + ~CH0_PD); + + sp_tx_config_ssc(anx78xx, SSC_DEP_4000PPM); + sp_tx_set_link_bw(anx78xx, sp.changed_bandwidth); + sp_tx_enhancemode_set(anx78xx); + + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x00, 0x00, 0x01, + ®val); + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x06, 0x00, 0x01, + &value); + if (regval >= 0x12) + value &= 0xf8; + else + value &= 0xfc; + value |= 0x01; + sp_tx_aux_dpcdwrite_byte(anx78xx, 0x00, 0x06, 0x00, value); + + sp_write_reg(anx78xx, 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(anx78xx, TX_P2, RST_CTRL2, SERDES_FIFO_RST); + msleep(20); + sp_write_reg_and(anx78xx, TX_P2, RST_CTRL2, ~SERDES_FIFO_RST); + dev_err(dev, "LT ERROR Status: SERDES FIFO reset."); + redo_cur_system_state(anx78xx); + sp.tx_lt_state = LT_INIT; + break; + case LT_FINISH: + sp_lt_finish(anx78xx, value); + break; + default: + break; + } +} + +/******************End Link training process********************/ + +/******************Start Output video process********************/ +static void sp_tx_set_colorspace(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 color_space; + + if (sp.down_sample_en) { + sp_read_reg(anx78xx, RX_P1, HDMI_RX_AVI_DATA00_REG, + &color_space); + color_space &= 0x60; + if (color_space == 0x20) { + dev_dbg(dev, "YCbCr4:2:2 ---> PASS THROUGH.\n"); + sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL6_REG, + 0x00); + sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL5_REG, + 0x00); + sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL2_REG, + 0x11); + } else if (color_space == 0x40) { + dev_dbg(dev, "YCbCr4:4:4 ---> YCbCr4:2:2\n"); + sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL6_REG, + 0x41); + sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL5_REG, + 0x00); + sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL2_REG, + 0x12); + } else if (color_space == 0x00) { + dev_dbg(dev, "RGB4:4:4 ---> YCbCr4:2:2\n"); + sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL6_REG, + 0x41); + sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL5_REG, + 0x83); + sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL2_REG, + 0x10); + } + } else { + sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL6_REG, 0x00); + sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL5_REG, 0x00); + } +} + +static void sp_tx_avi_setup(struct anx78xx *anx78xx) +{ + u8 regval; + int i; + + for (i = 0; i < 13; i++) { + sp_read_reg(anx78xx, RX_P1, (HDMI_RX_AVI_DATA00_REG + i), + ®val); + sp.tx_packet_avi.avi_data[i] = regval; + } +} + +static void sp_tx_load_packet(struct anx78xx *anx78xx, + enum packets_type type) +{ + int i; + u8 regval; + + switch (type) { + case AVI_PACKETS: + sp_write_reg(anx78xx, TX_P2, SP_TX_AVI_TYPE, 0x82); + sp_write_reg(anx78xx, TX_P2, SP_TX_AVI_VER, 0x02); + sp_write_reg(anx78xx, TX_P2, SP_TX_AVI_LEN, 0x0d); + + for (i = 0; i < 13; i++) { + sp_write_reg(anx78xx, TX_P2, SP_TX_AVI_DB0 + i, + sp.tx_packet_avi.avi_data[i]); + } + + break; + + case SPD_PACKETS: + sp_write_reg(anx78xx, TX_P2, SP_TX_SPD_TYPE, 0x83); + sp_write_reg(anx78xx, TX_P2, SP_TX_SPD_VER, 0x01); + sp_write_reg(anx78xx, TX_P2, SP_TX_SPD_LEN, 0x19); + + for (i = 0; i < 25; i++) { + sp_write_reg(anx78xx, TX_P2, SP_TX_SPD_DB0 + i, + sp.tx_packet_spd.spd_data[i]); + } + + break; + + case VSI_PACKETS: + sp_write_reg(anx78xx, TX_P2, SP_TX_MPEG_TYPE, 0x81); + sp_write_reg(anx78xx, TX_P2, SP_TX_MPEG_VER, 0x01); + sp_read_reg(anx78xx, RX_P1, HDMI_RX_MPEG_LEN_REG, ®val); + sp_write_reg(anx78xx, TX_P2, SP_TX_MPEG_LEN, regval); + + for (i = 0; i < 10; i++) { + sp_write_reg(anx78xx, TX_P2, SP_TX_MPEG_DB0 + i, + sp.tx_packet_mpeg.mpeg_data[i]); + } + + break; + case MPEG_PACKETS: + sp_write_reg(anx78xx, TX_P2, SP_TX_MPEG_TYPE, 0x85); + sp_write_reg(anx78xx, TX_P2, SP_TX_MPEG_VER, 0x01); + sp_write_reg(anx78xx, TX_P2, SP_TX_MPEG_LEN, 0x0d); + + for (i = 0; i < 10; i++) { + sp_write_reg(anx78xx, TX_P2, SP_TX_MPEG_DB0 + i, + sp.tx_packet_mpeg.mpeg_data[i]); + } + + break; + case AUDIF_PACKETS: + sp_write_reg(anx78xx, TX_P2, SP_TX_AUD_TYPE, 0x84); + sp_write_reg(anx78xx, TX_P2, SP_TX_AUD_VER, 0x01); + sp_write_reg(anx78xx, TX_P2, SP_TX_AUD_LEN, 0x0a); + for (i = 0; i < 10; i++) { + sp_write_reg(anx78xx, TX_P2, SP_TX_AUD_DB0 + i, + sp.tx_audioinfoframe.pb_byte[i]); + } + + break; + + default: + break; + } +} + +static void sp_tx_config_packets(struct anx78xx *anx78xx, + enum packets_type type) +{ + u8 regval; + + switch (type) { + case AVI_PACKETS: + sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val); + regval &= ~AVI_IF_EN; + sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval); + sp_tx_load_packet(anx78xx, AVI_PACKETS); + + sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val); + regval |= AVI_IF_UD; + sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval); + + sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val); + regval |= AVI_IF_EN; + sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval); + break; + case SPD_PACKETS: + sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val); + regval &= ~SPD_IF_EN; + sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval); + sp_tx_load_packet(anx78xx, SPD_PACKETS); + + sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val); + regval |= SPD_IF_UD; + sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval); + + sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val); + regval |= SPD_IF_EN; + sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval); + break; + case VSI_PACKETS: + sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val); + regval &= ~MPEG_IF_EN; + sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval); + + sp_tx_load_packet(anx78xx, VSI_PACKETS); + + sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val); + regval |= MPEG_IF_UD; + sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval); + + sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val); + regval |= MPEG_IF_EN; + sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval); + break; + case MPEG_PACKETS: + sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val); + regval &= ~MPEG_IF_EN; + sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval); + + sp_tx_load_packet(anx78xx, MPEG_PACKETS); + + sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val); + regval |= MPEG_IF_UD; + sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval); + + sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val); + regval |= MPEG_IF_EN; + sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval); + break; + case AUDIF_PACKETS: + sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val); + regval &= ~AUD_IF_EN; + sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval); + + sp_tx_load_packet(anx78xx, AUDIF_PACKETS); + + sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val); + regval |= AUD_IF_UP; + sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval); + + sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val); + regval |= AUD_IF_EN; + sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval); + break; + default: + break; + } +} + +static void sp_config_video_output(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 regval; + + switch (sp.tx_vo_state) { + default: + case VO_WAIT_VIDEO_STABLE: + sp_read_reg(anx78xx, RX_P0, HDMI_RX_SYS_STATUS_REG, ®val); + if ((regval & (TMDS_DE_DET | TMDS_CLOCK_DET)) == 0x03) { + sp_tx_bw_lc_sel(anx78xx, sp_tx_pclk_calc(anx78xx)); + sp_tx_enable_video_input(anx78xx, 0); + sp_tx_avi_setup(anx78xx); + sp_tx_config_packets(anx78xx, AVI_PACKETS); + sp_tx_set_colorspace(anx78xx); + sp_tx_lvttl_bit_mapping(anx78xx); + if (sp_i2c_read_byte(anx78xx, RX_P0, RX_PACKET_REV_STA) + & VSI_RCVD) + sp_hdmi_rx_new_vsi_int(anx78xx); + sp_tx_enable_video_input(anx78xx, 1); + sp.tx_vo_state = VO_WAIT_TX_VIDEO_STABLE; + } else { + dev_dbg(dev, "HDMI input video not stable!\n"); + } + SP_BREAK(VO_WAIT_VIDEO_STABLE, sp.tx_vo_state); + /* fallthrough */ + case VO_WAIT_TX_VIDEO_STABLE: + sp_read_reg(anx78xx, TX_P0, SP_TX_SYS_CTRL2_REG, ®val); + sp_write_reg(anx78xx, TX_P0, SP_TX_SYS_CTRL2_REG, regval); + sp_read_reg(anx78xx, TX_P0, SP_TX_SYS_CTRL2_REG, ®val); + if (regval & CHA_STA) { + dev_dbg(dev, "Stream clock not stable!\n"); + } else { + sp_read_reg(anx78xx, TX_P0, SP_TX_SYS_CTRL3_REG, + ®val); + sp_write_reg(anx78xx, TX_P0, SP_TX_SYS_CTRL3_REG, + regval); + sp_read_reg(anx78xx, TX_P0, SP_TX_SYS_CTRL3_REG, + ®val); + if (!(regval & STRM_VALID)) + dev_err(dev, "video stream not valid!\n"); + 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(anx78xx, sp_tx_pclk_calc(anx78xx))) + sp.tx_vo_state++; + else + sp_tx_set_sys_state(anx78xx, STATE_LINK_TRAINING); + SP_BREAK(VO_CHECK_VIDEO_INFO, sp.tx_vo_state); + /* fallthrough */ + case VO_FINISH: + sp_block_power_ctrl(anx78xx, SP_TX_PWR_AUDIO, SP_POWER_DOWN); + hdmi_rx_mute_video(anx78xx, 0); + sp_tx_video_mute(anx78xx, 0); + sp_tx_show_information(anx78xx); + goto_next_system_state(anx78xx); + break; + } +} + +/******************End Output video process********************/ + +/******************Start HDCP process********************/ +static inline void sp_tx_hdcp_encryption_disable(struct anx78xx *anx78xx) +{ + sp_write_reg_and(anx78xx, TX_P0, TX_HDCP_CTRL0, ~ENC_EN); +} + +static inline void sp_tx_hdcp_encryption_enable(struct anx78xx *anx78xx) +{ + sp_write_reg_or(anx78xx, TX_P0, TX_HDCP_CTRL0, ENC_EN); +} + +static void sp_tx_hw_hdcp_enable(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 regval; + + sp_write_reg_and(anx78xx, TX_P0, TX_HDCP_CTRL0, + ~ENC_EN & ~HARD_AUTH_EN); + sp_write_reg_or(anx78xx, TX_P0, TX_HDCP_CTRL0, + HARD_AUTH_EN | BKSV_SRM_PASS | KSVLIST_VLD | ENC_EN); + + sp_read_reg(anx78xx, TX_P0, TX_HDCP_CTRL0, ®val); + dev_dbg(dev, "TX_HDCP_CTRL0 = %.2x\n", regval); + sp_write_reg(anx78xx, TX_P0, SP_TX_WAIT_R0_TIME, 0xb0); + sp_write_reg(anx78xx, TX_P0, SP_TX_WAIT_KSVR_TIME, 0xc8); + + dev_dbg(dev, "Hardware HDCP is enabled.\n"); +} + +static void sp_hdcp_process(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + + switch (sp.hcdp_state) { + case HDCP_CAPABLE_CHECK: + sp.ds_vid_stb_cntr = 0; + sp.hdcp_fail_count = 0; + if (is_anx_dongle(anx78xx)) + sp.hcdp_state = HDCP_WAITTING_VID_STB; + else + sp.hcdp_state = HDCP_HW_ENABLE; + if (sp.block_en == 0) { + if (sp_hdcp_cap_check(anx78xx) == 0) + sp.hcdp_state = HDCP_NOT_SUPPORT; + } + /* + * Just for debug, pin: P2-2 + * There is a switch to disable/enable HDCP. + */ + sp.hcdp_state = HDCP_NOT_SUPPORT; + /*****************************************/ + SP_BREAK(HDCP_CAPABLE_CHECK, sp.hcdp_state); + /* fallthrough */ + case HDCP_WAITTING_VID_STB: + msleep(100); + sp.hcdp_state = HDCP_HW_ENABLE; + SP_BREAK(HDCP_WAITTING_VID_STB, sp.hcdp_state); + /* fallthrough */ + case HDCP_HW_ENABLE: + sp_tx_video_mute(anx78xx, 1); + sp_tx_clean_hdcp_status(anx78xx); + sp_block_power_ctrl(anx78xx, SP_TX_PWR_HDCP, SP_POWER_DOWN); + msleep(20); + sp_block_power_ctrl(anx78xx, SP_TX_PWR_HDCP, SP_POWER_ON); + sp_write_reg(anx78xx, TX_P2, SP_COMMON_INT_MASK2, 0x01); + msleep(50); + sp_tx_hw_hdcp_enable(anx78xx); + sp.hcdp_state = HDCP_WAITTING_FINISH; + /* fallthrough */ + case HDCP_WAITTING_FINISH: + break; + case HDCP_FINISH: + sp_tx_hdcp_encryption_enable(anx78xx); + hdmi_rx_mute_video(anx78xx, 0); + sp_tx_video_mute(anx78xx, 0); + goto_next_system_state(anx78xx); + sp.hcdp_state = HDCP_CAPABLE_CHECK; + dev_dbg(dev, "@@@@@@@hdcp_auth_pass@@@@@@\n"); + break; + case HDCP_FAILED: + if (sp.hdcp_fail_count > 5) { + sp_vbus_power_off(anx78xx); + reg_hardware_reset(anx78xx); + sp.hcdp_state = HDCP_CAPABLE_CHECK; + sp.hdcp_fail_count = 0; + dev_dbg(dev, "*********hdcp_auth_failed*********\n"); + } else { + sp.hdcp_fail_count++; + sp.hcdp_state = HDCP_WAITTING_VID_STB; + } + break; + default: + case HDCP_NOT_SUPPORT: + dev_dbg(dev, "Sink is not capable HDCP\n"); + sp_block_power_ctrl(anx78xx, SP_TX_PWR_HDCP, + SP_POWER_DOWN); + sp_tx_video_mute(anx78xx, 0); + goto_next_system_state(anx78xx); + sp.hcdp_state = HDCP_CAPABLE_CHECK; + break; + } +} + +/******************End HDCP process********************/ + +/******************Start Audio process********************/ +static void sp_tx_audioinfoframe_setup(struct anx78xx *anx78xx) +{ + int i; + u8 regval; + + sp_read_reg(anx78xx, RX_P1, HDMI_RX_AUDIO_TYPE_REG, ®val); + sp.tx_audioinfoframe.type = regval; + sp_read_reg(anx78xx, RX_P1, HDMI_RX_AUDIO_VER_REG, ®val); + sp.tx_audioinfoframe.version = regval; + sp_read_reg(anx78xx, RX_P1, HDMI_RX_AUDIO_LEN_REG, ®val); + sp.tx_audioinfoframe.length = regval; + + for (i = 0; i < 11; i++) { + sp_read_reg(anx78xx, RX_P1, HDMI_RX_AUDIO_DATA00_REG + i, + ®val); + sp.tx_audioinfoframe.pb_byte[i] = regval; + } +} + +static void sp_tx_enable_audio_output(struct anx78xx *anx78xx, u8 enable) +{ + u8 regval; + + sp_read_reg(anx78xx, TX_P0, SP_TX_AUD_CTRL, ®val); + if (enable) { + if (regval & AUD_EN) { + regval &= ~AUD_EN; + sp_write_reg(anx78xx, TX_P0, SP_TX_AUD_CTRL, regval); + } + sp_tx_audioinfoframe_setup(anx78xx); + sp_tx_config_packets(anx78xx, AUDIF_PACKETS); + + regval |= AUD_EN; + sp_write_reg(anx78xx, TX_P0, SP_TX_AUD_CTRL, regval); + } else { + regval &= ~AUD_EN; + sp_write_reg(anx78xx, TX_P0, SP_TX_AUD_CTRL, regval); + sp_write_reg_and(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ~AUD_IF_EN); + } +} + +static void sp_tx_config_audio(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 regval; + int i; + unsigned long m_aud, ls_clk = 0; + unsigned long aud_freq = 0; + + sp_block_power_ctrl(anx78xx, SP_TX_PWR_AUDIO, SP_POWER_ON); + sp_read_reg(anx78xx, RX_P0, AUD_SPDIF_CHST4, ®val); + + switch (regval & 0x0f) { + case FS_FREQ_44100HZ: + aud_freq = 44100; + break; + case FS_FREQ_48000HZ: + aud_freq = 48000; + break; + case FS_FREQ_32000HZ: + aud_freq = 32000; + break; + case FS_FREQ_88200HZ: + aud_freq = 88200; + break; + case FS_FREQ_96000HZ: + aud_freq = 96000; + break; + case FS_FREQ_176400HZ: + aud_freq = 176400; + break; + case FS_FREQ_192000HZ: + aud_freq = 192000; + break; + default: + break; + } + + switch (sp_tx_get_link_bw(anx78xx)) { + 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; + } + + dev_dbg(dev, "aud_freq = %ld , LS_CLK = %ld\n", aud_freq, ls_clk); + + m_aud = ((512 * aud_freq) / ls_clk) * 32768; + m_aud = m_aud + 0x05; + sp_write_reg(anx78xx, TX_P1, SP_TX_AUD_INTERFACE_CTRL4, m_aud & 0xff); + m_aud = m_aud >> 8; + sp_write_reg(anx78xx, TX_P1, SP_TX_AUD_INTERFACE_CTRL5, m_aud & 0xff); + sp_write_reg(anx78xx, TX_P1, SP_TX_AUD_INTERFACE_CTRL6, 0x00); + + sp_write_reg_and(anx78xx, TX_P1, SP_TX_AUD_INTERFACE_CTRL0, + (u8)~AUD_INTERFACE_DISABLE); + + sp_write_reg_or(anx78xx, TX_P1, SP_TX_AUD_INTERFACE_CTRL2, + M_AUD_ADJUST_ST); + + sp_read_reg(anx78xx, RX_P0, HDMI_STATUS, ®val); + if (regval & HDMI_AUD_LAYOUT) + sp_write_reg_or(anx78xx, TX_P2, SP_TX_AUD_CH_NUM_REG5, + CH_NUM_8 | AUD_LAYOUT); + else + sp_write_reg_and(anx78xx, TX_P2, SP_TX_AUD_CH_NUM_REG5, + (u8)~CH_NUM_8 & ~AUD_LAYOUT); + + /* transfer audio chaneel status from HDMI Rx to Slinmport Tx */ + for (i = 0; i < 5; i++) { + sp_read_reg(anx78xx, RX_P0, HDMI_RX_AUD_IN_CH_STATUS1_REG + i, + ®val); + sp_write_reg(anx78xx, TX_P2, SP_TX_AUD_CH_STATUS_REG1 + i, + regval); + } + + /* enable audio */ + sp_tx_enable_audio_output(anx78xx, 1); +} + +static void sp_config_audio_output(struct anx78xx *anx78xx) +{ + 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(anx78xx, RX_P0, HDMI_STATUS) + & HDMI_MODE)) { + sp.tx_ao_state = AO_INIT; + goto_next_system_state(anx78xx); + } + 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(anx78xx, 0); + sp_tx_config_audio(anx78xx); + goto_next_system_state(anx78xx); + break; + } +} + +/******************End Audio process********************/ + +void sp_initialization(struct anx78xx *anx78xx) +{ + /* Waitting Hot plug event! */ + if (!(sp.common_int_status.common_int[3] & PLUG)) + return; + + sp.read_edid_flag = 0; + + /* Power on all modules */ + sp_write_reg(anx78xx, TX_P2, SP_POWERD_CTRL_REG, 0x00); + /* Driver Version */ + sp_write_reg(anx78xx, TX_P1, FW_VER_REG, FW_VERSION); + hdmi_rx_initialization(anx78xx); + sp_tx_initialization(anx78xx); + msleep(200); + goto_next_system_state(anx78xx); +} + +static void sp_hdcp_external_ctrl_flag_monitor(struct anx78xx *anx78xx) +{ + static u8 cur_flag; + + if (sp.block_en != cur_flag) { + cur_flag = sp.block_en; + system_state_change_with_case(anx78xx, STATE_HDCP_AUTH); + } +} + +static void sp_state_process(struct anx78xx *anx78xx) +{ + switch (sp.tx_system_state) { + case STATE_WAITTING_CABLE_PLUG: + sp_waiting_cable_plug_process(anx78xx); + SP_BREAK(STATE_WAITTING_CABLE_PLUG, sp.tx_system_state); + /* fallthrough */ + case STATE_SP_INITIALIZED: + sp_initialization(anx78xx); + SP_BREAK(STATE_SP_INITIALIZED, sp.tx_system_state); + /* fallthrough */ + case STATE_SINK_CONNECTION: + sp_sink_connection(anx78xx); + SP_BREAK(STATE_SINK_CONNECTION, sp.tx_system_state); + /* fallthrough */ + case STATE_PARSE_EDID: + sp_edid_process(anx78xx); + SP_BREAK(STATE_PARSE_EDID, sp.tx_system_state); + /* fallthrough */ + case STATE_LINK_TRAINING: + sp_link_training(anx78xx); + SP_BREAK(STATE_LINK_TRAINING, sp.tx_system_state); + /* fallthrough */ + case STATE_VIDEO_OUTPUT: + sp_config_video_output(anx78xx); + SP_BREAK(STATE_VIDEO_OUTPUT, sp.tx_system_state); + /* fallthrough */ + case STATE_HDCP_AUTH: + sp_hdcp_process(anx78xx); + SP_BREAK(STATE_HDCP_AUTH, sp.tx_system_state); + /* fallthrough */ + case STATE_AUDIO_OUTPUT: + sp_config_audio_output(anx78xx); + 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********************/ +static void sp_tx_int_rec(struct anx78xx *anx78xx) +{ + sp_read_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1, + &sp.common_int_status.common_int[0]); + sp_write_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1, + sp.common_int_status.common_int[0]); + + sp_read_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1 + 1, + &sp.common_int_status.common_int[1]); + sp_write_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1 + 1, + sp.common_int_status.common_int[1]); + + sp_read_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1 + 2, + &sp.common_int_status.common_int[2]); + sp_write_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1 + 2, + sp.common_int_status.common_int[2]); + + sp_read_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1 + 3, + &sp.common_int_status.common_int[3]); + sp_write_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1 + 3, + sp.common_int_status.common_int[3]); + + sp_read_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1 + 6, + &sp.common_int_status.common_int[4]); + sp_write_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1 + 6, + sp.common_int_status.common_int[4]); +} + +static void sp_hdmi_rx_int_rec(struct anx78xx *anx78xx) +{ + sp_read_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS1_REG, + &sp.hdmi_rx_int_status.hdmi_rx_int[0]); + sp_write_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS1_REG, + sp.hdmi_rx_int_status.hdmi_rx_int[0]); + sp_read_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS2_REG, + &sp.hdmi_rx_int_status.hdmi_rx_int[1]); + sp_write_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS2_REG, + sp.hdmi_rx_int_status.hdmi_rx_int[1]); + sp_read_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS3_REG, + &sp.hdmi_rx_int_status.hdmi_rx_int[2]); + sp_write_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS3_REG, + sp.hdmi_rx_int_status.hdmi_rx_int[2]); + sp_read_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS4_REG, + &sp.hdmi_rx_int_status.hdmi_rx_int[3]); + sp_write_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS4_REG, + sp.hdmi_rx_int_status.hdmi_rx_int[3]); + sp_read_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS5_REG, + &sp.hdmi_rx_int_status.hdmi_rx_int[4]); + sp_write_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS5_REG, + sp.hdmi_rx_int_status.hdmi_rx_int[4]); + sp_read_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS6_REG, + &sp.hdmi_rx_int_status.hdmi_rx_int[5]); + sp_write_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS6_REG, + sp.hdmi_rx_int_status.hdmi_rx_int[5]); + sp_read_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS7_REG, + &sp.hdmi_rx_int_status.hdmi_rx_int[6]); + sp_write_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS7_REG, + sp.hdmi_rx_int_status.hdmi_rx_int[6]); +} + +static void sp_int_rec(struct anx78xx *anx78xx) +{ + sp_tx_int_rec(anx78xx); + sp_hdmi_rx_int_rec(anx78xx); +} + +/******************End INT process********************/ + +/******************Start task process********************/ +static void sp_tx_pll_changed_int_handler(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + + if (sp.tx_system_state >= STATE_LINK_TRAINING) { + if (!sp_tx_get_pll_lock_status(anx78xx)) { + dev_dbg(dev, "PLL:PLL not lock!\n"); + sp_tx_set_sys_state(anx78xx, STATE_LINK_TRAINING); + } + } +} + +static void sp_tx_hdcp_link_chk_fail_handler(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + + system_state_change_with_case(anx78xx, STATE_HDCP_AUTH); + + dev_dbg(dev, "hdcp_link_chk_fail:HDCP Sync lost!\n"); +} + +static void sp_tx_phy_auto_test(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 b_sw; + u8 bytebuf[16]; + + /* DPCD 0x219 TEST_LINK_RATE */ + sp_tx_aux_dpcdread_bytes(anx78xx, 0x0, 0x02, 0x19, 1, bytebuf); + dev_dbg(dev, "DPCD:0x00219 = %.2x\n", bytebuf[0]); + switch (bytebuf[0]) { + case LINK_1P62G: + case LINK_2P7G: + case LINK_5P4G: + case LINK_6P75G: + sp_tx_set_link_bw(anx78xx, bytebuf[0]); + sp.tx_test_bw = bytebuf[0]; + break; + default: + sp_tx_set_link_bw(anx78xx, LINK_6P75G); + sp.tx_test_bw = LINK_6P75G; + break; + } + + /* DPCD 0x248 PHY_TEST_PATTERN */ + sp_tx_aux_dpcdread_bytes(anx78xx, 0x0, 0x02, 0x48, 1, bytebuf); + dev_dbg(dev, "DPCD:0x00248 = %.2x\n", bytebuf[0]); + switch (bytebuf[0]) { + case 0: + break; + case 1: + sp_write_reg(anx78xx, TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x04); + break; + case 2: + sp_write_reg(anx78xx, TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x08); + break; + case 3: + sp_write_reg(anx78xx, TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x0c); + break; + case 4: + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x50, 0xa, + bytebuf); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG0, + bytebuf[0]); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG1, + bytebuf[1]); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG2, + bytebuf[2]); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG3, + bytebuf[3]); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG4, + bytebuf[4]); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG5, + bytebuf[5]); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG6, + bytebuf[6]); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG7, + bytebuf[7]); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG8, + bytebuf[8]); + sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG9, + bytebuf[9]); + sp_write_reg(anx78xx, TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x30); + break; + case 5: + sp_write_reg(anx78xx, TX_P0, ADDR_DP_CEP_TRAINING_CTRL0, 0x00); + sp_write_reg(anx78xx, TX_P0, ADDR_DP_CEP_TRAINING_CTRL1, 0x01); + sp_write_reg(anx78xx, TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x14); + break; + } + + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x00, 0x03, 1, bytebuf); + dev_dbg(dev, "DPCD:0x00003 = %.2x\n", bytebuf[0]); + if (bytebuf[0] & 0x01) + sp_tx_config_ssc(anx78xx, SSC_DEP_4000PPM); + else + sp_tx_spread_enable(anx78xx, 0); + + /* get swing and emphasis adjust request */ + sp_read_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG, &b_sw); + + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x06, 1, bytebuf); + dev_dbg(dev, "DPCD:0x00206 = %.2x\n", bytebuf[0]); + switch (bytebuf[0] & 0x0f) { + case 0x00: + sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG, + (b_sw & ~TX_SW_SET_MASK) | 0x00); + break; + case 0x01: + sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG, + (b_sw & ~TX_SW_SET_MASK) | 0x01); + break; + case 0x02: + sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG, + (b_sw & ~TX_SW_SET_MASK) | 0x02); + break; + case 0x03: + sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG, + (b_sw & ~TX_SW_SET_MASK) | 0x03); + break; + case 0x04: + sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG, + (b_sw & ~TX_SW_SET_MASK) | 0x08); + break; + case 0x05: + sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG, + (b_sw & ~TX_SW_SET_MASK) | 0x09); + break; + case 0x06: + sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG, + (b_sw & ~TX_SW_SET_MASK) | 0x0a); + break; + case 0x08: + sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG, + (b_sw & ~TX_SW_SET_MASK) | 0x10); + break; + case 0x09: + sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG, + (b_sw & ~TX_SW_SET_MASK) | 0x11); + break; + case 0x0c: + sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG, + (b_sw & ~TX_SW_SET_MASK) | 0x18); + break; + default: + break; + } +} + +static void sp_hpd_irq_process(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 regval; + u8 test_vector; + u8 data_buf[6]; + + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x00, 6, data_buf); + dev_dbg(dev, "+++++++++++++Get HPD IRQ %x\n", (int)data_buf[1]); + + if (data_buf[1] != 0) + sp_tx_aux_dpcdwrite_bytes(anx78xx, 0x00, 0x02, + DPCD_SERVICE_IRQ_VECTOR, 1, + &data_buf[1]); + + /* HDCP IRQ */ + if (data_buf[1] & CP_IRQ) { + if (sp.hcdp_state > HDCP_WAITTING_FINISH || + sp.tx_system_state > STATE_HDCP_AUTH) { + sp_tx_aux_dpcdread_bytes(anx78xx, 0x06, 0x80, 0x29, 1, + ®val); + if (regval & 0x04) { + system_state_change_with_case(anx78xx, + STATE_HDCP_AUTH); + dev_dbg(dev, "IRQ:_______HDCP Sync lost!\n"); + } + } + } + + /* AUTOMATED TEST IRQ */ + if (data_buf[1] & TEST_IRQ) { + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x18, 1, + &test_vector); + + if (test_vector & 0x01) { + sp.tx_test_lt = 1; + + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x19, 1, + ®val); + switch (regval) { + case LINK_1P62G: + case LINK_2P7G: + case LINK_5P4G: + case LINK_6P75G: + sp_tx_set_link_bw(anx78xx, regval); + sp.tx_test_bw = regval; + break; + default: + sp_tx_set_link_bw(anx78xx, LINK_6P75G); + sp.tx_test_bw = LINK_6P75G; + break; + } + + dev_dbg(dev, " test_bw = %.2x\n", sp.tx_test_bw); + + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x60, 1, + ®val); + regval = regval | TEST_ACK; + sp_tx_aux_dpcdwrite_bytes(anx78xx, 0x00, 0x02, 0x60, 1, + ®val); + + dev_dbg(dev, "Set TEST_ACK!\n"); + if (sp.tx_system_state >= STATE_LINK_TRAINING) { + sp.tx_lt_state = LT_INIT; + sp_tx_set_sys_state(anx78xx, + STATE_LINK_TRAINING); + } + dev_dbg(dev, "IRQ:test-LT request!\n"); + } + + if (test_vector & 0x02) { + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x60, 1, + ®val); + regval = regval | TEST_ACK; + sp_tx_aux_dpcdwrite_bytes(anx78xx, 0x00, 0x02, 0x60, 1, + ®val); + } + if (test_vector & 0x04) { + if (sp.tx_system_state > STATE_PARSE_EDID) + sp_tx_set_sys_state(anx78xx, STATE_PARSE_EDID); + sp.tx_test_edid = 1; + dev_dbg(dev, "Test EDID Requested!\n"); + } + + if (test_vector & 0x08) { + sp.tx_test_lt = 1; + + sp_tx_phy_auto_test(anx78xx); + + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x60, 1, + ®val); + regval = regval | 0x01; + sp_tx_aux_dpcdwrite_bytes(anx78xx, 0x00, 0x02, 0x60, 1, + ®val); + } + } + + if (sp.tx_system_state > STATE_LINK_TRAINING) { + if (!(data_buf[4] & 0x01) || + ((data_buf[2] & (0x01 | 0x04)) != 0x05)) { + sp_tx_set_sys_state(anx78xx, STATE_LINK_TRAINING); + dev_dbg(dev, "INT:re-LT request!\n"); + return; + } + + dev_dbg(dev, "Lane align %x\n", data_buf[4]); + dev_dbg(dev, "Lane clock recovery %x\n", data_buf[2]); + } +} + +static void sp_tx_vsi_setup(struct anx78xx *anx78xx) +{ + u8 regval; + int i; + + for (i = 0; i < 10; i++) { + sp_read_reg(anx78xx, RX_P1, (HDMI_RX_MPEG_DATA00_REG + i), + ®val); + sp.tx_packet_mpeg.mpeg_data[i] = regval; + } +} + +static void sp_tx_mpeg_setup(struct anx78xx *anx78xx) +{ + u8 regval; + int i; + + for (i = 0; i < 10; i++) { + sp_read_reg(anx78xx, RX_P1, (HDMI_RX_MPEG_DATA00_REG + i), + ®val); + sp.tx_packet_mpeg.mpeg_data[i] = regval; + } +} + +static void sp_tx_auth_done_int_handler(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 bytebuf[2]; + + if (sp.hcdp_state > HDCP_HW_ENABLE && + sp.tx_system_state == STATE_HDCP_AUTH) { + sp_read_reg(anx78xx, TX_P0, SP_TX_HDCP_STATUS, bytebuf); + if (bytebuf[0] & SP_TX_HDCP_AUTH_PASS) { + sp_tx_aux_dpcdread_bytes(anx78xx, 0x06, 0x80, 0x2a, 2, + bytebuf); + if ((bytebuf[1] & 0x08) || (bytebuf[0] & 0x80)) { + dev_dbg(dev, "max cascade/devs exceeded!\n"); + sp_tx_hdcp_encryption_disable(anx78xx); + } else + dev_dbg(dev, "%s\n", + "Authentication pass in Auth_Done"); + + sp.hcdp_state = HDCP_FINISH; + } else { + dev_err(dev, "Authentication failed in AUTH_done\n"); + sp_tx_video_mute(anx78xx, 1); + sp_tx_clean_hdcp_status(anx78xx); + sp.hcdp_state = HDCP_FAILED; + } + } +} + +static void sp_tx_lt_done_int_handler(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 regval; + + if (sp.tx_lt_state == LT_WAITTING_FINISH && + sp.tx_system_state == STATE_LINK_TRAINING) { + sp_read_reg(anx78xx, TX_P0, LT_CTRL, ®val); + if (regval & 0x70) { + regval = (regval & 0x70) >> 4; + dev_dbg(dev, "LT failed in interrupt, ERR = %.2x\n", + regval); + sp.tx_lt_state = LT_ERROR; + } else { + dev_dbg(dev, "lt_done: LT Finish\n"); + sp.tx_lt_state = LT_FINISH; + } + } +} + +static void sp_hdmi_rx_clk_det_int(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + + dev_dbg(dev, "*HDMI_RX Interrupt: Pixel Clock Change.\n"); + if (sp.tx_system_state > STATE_VIDEO_OUTPUT) { + sp_tx_video_mute(anx78xx, 1); + sp_tx_enable_audio_output(anx78xx, 0); + sp_tx_set_sys_state(anx78xx, STATE_VIDEO_OUTPUT); + } +} + +static void sp_hdmi_rx_hdmi_dvi_int(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 regval; + + dev_dbg(dev, "sp_hdmi_rx_hdmi_dvi_int.\n"); + sp_read_reg(anx78xx, RX_P0, HDMI_STATUS, ®val); + sp.hdmi_dvi_status = 1; + if ((regval & BIT(0)) != (sp.hdmi_dvi_status & BIT(0))) { + dev_dbg(dev, "hdmi_dvi_int: Is HDMI MODE: %x.\n", + regval & HDMI_MODE); + sp.hdmi_dvi_status = regval & BIT(0); + hdmi_rx_mute_audio(anx78xx, 1); + system_state_change_with_case(anx78xx, STATE_LINK_TRAINING); + } +} + +static void sp_hdmi_rx_new_avi_int(struct anx78xx *anx78xx) +{ + sp_tx_lvttl_bit_mapping(anx78xx); + sp_tx_set_colorspace(anx78xx); + sp_tx_avi_setup(anx78xx); + sp_tx_config_packets(anx78xx, AVI_PACKETS); +} + +static void sp_hdmi_rx_new_vsi_int(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 hdmi_video_format, v3d_structure; + + sp_write_reg_and(anx78xx, TX_P0, SP_TX_3D_VSC_CTRL, + ~INFO_FRAME_VSC_EN); + + /* VSI package header */ + if ((sp_i2c_read_byte(anx78xx, RX_P1, + HDMI_RX_MPEG_TYPE_REG) != 0x81) || + (sp_i2c_read_byte(anx78xx, RX_P1, HDMI_RX_MPEG_VER_REG) != 0x01)) + return; + + dev_dbg(dev, "Setup VSI package!\n"); + + sp_tx_vsi_setup(anx78xx); + sp_tx_config_packets(anx78xx, VSI_PACKETS); + + sp_read_reg(anx78xx, RX_P1, HDMI_RX_MPEG_DATA03_REG, + &hdmi_video_format); + + if ((hdmi_video_format & 0xe0) == 0x40) { + dev_dbg(dev, "3D VSI packet detected. Config VSC packet\n"); + + sp_read_reg(anx78xx, 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; + dev_dbg(dev, "3D structure is not supported\n"); + break; + } + sp_write_reg(anx78xx, TX_P0, SP_TX_VSC_DB1, v3d_structure); + } + sp_write_reg_or(anx78xx, TX_P0, SP_TX_3D_VSC_CTRL, INFO_FRAME_VSC_EN); + sp_write_reg_and(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ~SPD_IF_EN); + sp_write_reg_or(anx78xx, TX_P0, SP_TX_PKT_EN_REG, SPD_IF_UD); + sp_write_reg_or(anx78xx, TX_P0, SP_TX_PKT_EN_REG, SPD_IF_EN); +} + +static void sp_hdmi_rx_no_vsi_int(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 regval; + + sp_read_reg(anx78xx, TX_P0, SP_TX_3D_VSC_CTRL, ®val); + if (regval & INFO_FRAME_VSC_EN) { + dev_dbg(dev, "No new VSI is received, disable VSC packet\n"); + regval &= ~INFO_FRAME_VSC_EN; + sp_write_reg(anx78xx, TX_P0, SP_TX_3D_VSC_CTRL, regval); + sp_tx_mpeg_setup(anx78xx); + sp_tx_config_packets(anx78xx, MPEG_PACKETS); + } +} + +static inline void sp_hdmi_rx_restart_audio_chk(struct anx78xx *anx78xx) +{ + system_state_change_with_case(anx78xx, STATE_AUDIO_OUTPUT); +} + +static void sp_hdmi_rx_cts_rcv_int(struct anx78xx *anx78xx) +{ + 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 sp_hdmi_rx_audio_rcv_int(struct anx78xx *anx78xx) +{ + 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 sp_hdmi_rx_audio_samplechg_int(struct anx78xx *anx78xx) +{ + u16 i; + u8 regval; + + /* transfer audio chaneel status from HDMI Rx to Slinmport Tx */ + for (i = 0; i < 5; i++) { + sp_read_reg(anx78xx, RX_P0, HDMI_RX_AUD_IN_CH_STATUS1_REG + i, + ®val); + sp_write_reg(anx78xx, TX_P2, SP_TX_AUD_CH_STATUS_REG1 + i, + regval); + } +} + +static void sp_hdmi_rx_hdcp_error_int(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + static u8 count; + + dev_dbg(dev, "*HDMI_RX Interrupt: hdcp error.\n"); + if (count >= 40) { + count = 0; + dev_dbg(dev, "Lots of hdcp error occurred ...\n"); + hdmi_rx_mute_audio(anx78xx, 1); + hdmi_rx_mute_video(anx78xx, 1); + hdmi_rx_set_hpd(anx78xx, 0); + usleep_range(10000, 11000); + hdmi_rx_set_hpd(anx78xx, 1); + } else { + count++; + } +} + +static void sp_hdmi_rx_new_gcp_int(struct anx78xx *anx78xx) +{ + u8 regval; + + sp_read_reg(anx78xx, RX_P1, HDMI_RX_GENERAL_CTRL, ®val); + if (regval & SET_AVMUTE) { + hdmi_rx_mute_video(anx78xx, 1); + hdmi_rx_mute_audio(anx78xx, 1); + } else if (regval & CLEAR_AVMUTE) { + hdmi_rx_mute_video(anx78xx, 0); + hdmi_rx_mute_audio(anx78xx, 0); + } +} + +static void sp_tx_hpd_int_handler(struct anx78xx *anx78xx, u8 hpd_source) +{ + struct device *dev = &anx78xx->client->dev; + + switch (hpd_source) { + case HPD_LOST: + hdmi_rx_set_hpd(anx78xx, 0); + sp_tx_set_sys_state(anx78xx, STATE_WAITTING_CABLE_PLUG); + break; + case HPD_CHANGE: + dev_dbg(dev, "HPD:____________HPD changed!\n"); + usleep_range(2000, 4000); + if (sp.common_int_status.common_int[3] & HPD_IRQ) + sp_hpd_irq_process(anx78xx); + + if (sp_i2c_read_byte(anx78xx, TX_P0, + SP_TX_SYS_CTRL3_REG) & HPD_STATUS) { + if (sp.common_int_status.common_int[3] & HPD_IRQ) + sp_hpd_irq_process(anx78xx); + } else { + if (sp_i2c_read_byte(anx78xx, TX_P0, + SP_TX_SYS_CTRL3_REG) & + HPD_STATUS) { + hdmi_rx_set_hpd(anx78xx, 0); + sp_tx_set_sys_state(anx78xx, + STATE_WAITTING_CABLE_PLUG); + } + } + break; + case PLUG: + dev_dbg(dev, "HPD:____________HPD changed!\n"); + if (sp.tx_system_state < STATE_SP_INITIALIZED) + sp_tx_set_sys_state(anx78xx, STATE_SP_INITIALIZED); + break; + default: + break; + } +} + +static void sp_system_isr_handler(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + + if (sp.common_int_status.common_int[3] & HPD_CHANGE) + sp_tx_hpd_int_handler(anx78xx, HPD_CHANGE); + if (sp.common_int_status.common_int[3] & HPD_LOST) + sp_tx_hpd_int_handler(anx78xx, HPD_LOST); + if (sp.common_int_status.common_int[3] & HPD_IRQ) + dev_dbg(dev, "++++++++++++++++========HDCP_IRQ interrupt\n"); + if (sp.common_int_status.common_int[0] & PLL_LOCK_CHG) + sp_tx_pll_changed_int_handler(anx78xx); + + if (sp.common_int_status.common_int[1] & HDCP_AUTH_DONE) + sp_tx_auth_done_int_handler(anx78xx); + + if (sp.common_int_status.common_int[2] & HDCP_LINK_CHECK_FAIL) + sp_tx_hdcp_link_chk_fail_handler(anx78xx); + + if (sp.common_int_status.common_int[4] & TRAINING_FINISH) + sp_tx_lt_done_int_handler(anx78xx); + + if (sp.tx_system_state > STATE_SINK_CONNECTION) { + if (sp.hdmi_rx_int_status.hdmi_rx_int[5] & NEW_AVI) + sp_hdmi_rx_new_avi_int(anx78xx); + } + + if (sp.tx_system_state > STATE_VIDEO_OUTPUT) { + if (sp.hdmi_rx_int_status.hdmi_rx_int[6] & NEW_VS) { + sp.hdmi_rx_int_status.hdmi_rx_int[6] &= ~NO_VSI; + sp_hdmi_rx_new_vsi_int(anx78xx); + } + if (sp.hdmi_rx_int_status.hdmi_rx_int[6] & NO_VSI) + sp_hdmi_rx_no_vsi_int(anx78xx); + } + + if (sp.tx_system_state >= STATE_VIDEO_OUTPUT) { + if (sp.hdmi_rx_int_status.hdmi_rx_int[0] & CKDT_CHANGE) + sp_hdmi_rx_clk_det_int(anx78xx); + + if (sp.hdmi_rx_int_status.hdmi_rx_int[0] & SCDT_CHANGE) + dev_dbg(dev, "*HDMI_RX Interrupt: Sync Detect.\n"); + + if (sp.hdmi_rx_int_status.hdmi_rx_int[0] & HDMI_DVI) + sp_hdmi_rx_hdmi_dvi_int(anx78xx); + + if ((sp.hdmi_rx_int_status.hdmi_rx_int[5] & NEW_AUD) || + (sp.hdmi_rx_int_status.hdmi_rx_int[2] & AUD_MODE_CHANGE)) + sp_hdmi_rx_restart_audio_chk(anx78xx); + + if (sp.hdmi_rx_int_status.hdmi_rx_int[5] & CTS_RCV) + sp_hdmi_rx_cts_rcv_int(anx78xx); + + if (sp.hdmi_rx_int_status.hdmi_rx_int[4] & AUDIO_RCV) + sp_hdmi_rx_audio_rcv_int(anx78xx); + + if (sp.hdmi_rx_int_status.hdmi_rx_int[1] & HDCP_ERR) + sp_hdmi_rx_hdcp_error_int(anx78xx); + + if (sp.hdmi_rx_int_status.hdmi_rx_int[5] & NEW_CP) + sp_hdmi_rx_new_gcp_int(anx78xx); + + if (sp.hdmi_rx_int_status.hdmi_rx_int[1] & AUDIO_SAMPLE_CHANGE) + sp_hdmi_rx_audio_samplechg_int(anx78xx); + } +} + +static void sp_tx_show_information(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 regval, regval1; + u16 h_res, h_act, v_res, v_act; + u16 h_fp, h_sw, h_bp, v_fp, v_sw, v_bp; + unsigned long fresh_rate; + unsigned long pclk; + + dev_dbg(dev, "\n************* SP Video Information **************\n"); + + switch (sp_tx_get_link_bw(anx78xx)) { + case LINK_1P62G: + dev_dbg(dev, "BW = 1.62G\n"); + break; + case LINK_2P7G: + dev_dbg(dev, "BW = 2.7G\n"); + break; + case LINK_5P4G: + dev_dbg(dev, "BW = 5.4G\n"); + break; + case LINK_6P75G: + dev_dbg(dev, "BW = 6.75G\n"); + break; + default: + break; + } + + pclk = sp_tx_pclk_calc(anx78xx); + pclk = pclk / 10; + + sp_read_reg(anx78xx, TX_P2, SP_TX_TOTAL_LINE_STA_L, ®val); + sp_read_reg(anx78xx, TX_P2, SP_TX_TOTAL_LINE_STA_H, ®val1); + + v_res = regval1; + v_res = v_res << 8; + v_res = v_res + regval; + + sp_read_reg(anx78xx, TX_P2, SP_TX_ACT_LINE_STA_L, ®val); + sp_read_reg(anx78xx, TX_P2, SP_TX_ACT_LINE_STA_H, ®val1); + + v_act = regval1; + v_act = v_act << 8; + v_act = v_act + regval; + + sp_read_reg(anx78xx, TX_P2, SP_TX_TOTAL_PIXEL_STA_L, ®val); + sp_read_reg(anx78xx, TX_P2, SP_TX_TOTAL_PIXEL_STA_H, ®val1); + + h_res = regval1; + h_res = h_res << 8; + h_res = h_res + regval; + + sp_read_reg(anx78xx, TX_P2, SP_TX_ACT_PIXEL_STA_L, ®val); + sp_read_reg(anx78xx, TX_P2, SP_TX_ACT_PIXEL_STA_H, ®val1); + + h_act = regval1; + h_act = h_act << 8; + h_act = h_act + regval; + + sp_read_reg(anx78xx, TX_P2, SP_TX_H_F_PORCH_STA_L, ®val); + sp_read_reg(anx78xx, TX_P2, SP_TX_H_F_PORCH_STA_H, ®val1); + + h_fp = regval1; + h_fp = h_fp << 8; + h_fp = h_fp + regval; + + sp_read_reg(anx78xx, TX_P2, SP_TX_H_SYNC_STA_L, ®val); + sp_read_reg(anx78xx, TX_P2, SP_TX_H_SYNC_STA_H, ®val1); + + h_sw = regval1; + h_sw = h_sw << 8; + h_sw = h_sw + regval; + + sp_read_reg(anx78xx, TX_P2, SP_TX_H_B_PORCH_STA_L, ®val); + sp_read_reg(anx78xx, TX_P2, SP_TX_H_B_PORCH_STA_H, ®val1); + + h_bp = regval1; + h_bp = h_bp << 8; + h_bp = h_bp + regval; + + sp_read_reg(anx78xx, TX_P2, SP_TX_V_F_PORCH_STA, ®val); + v_fp = regval; + + sp_read_reg(anx78xx, TX_P2, SP_TX_V_SYNC_STA, ®val); + v_sw = regval; + + sp_read_reg(anx78xx, TX_P2, SP_TX_V_B_PORCH_STA, ®val); + v_bp = regval; + + dev_dbg(dev, "Total resolution is %d * %d\n", h_res, v_res); + + dev_dbg(dev, "HF=%d, HSW=%d, HBP=%d\n", h_fp, h_sw, h_bp); + dev_dbg(dev, "VF=%d, VSW=%d, VBP=%d\n", v_fp, v_sw, v_bp); + dev_dbg(dev, "Active resolution is %d * %d", 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; + } + dev_dbg(dev, " @ %ldHz\n", fresh_rate); + + sp_read_reg(anx78xx, TX_P0, SP_TX_VID_CTRL, ®val); + + if ((regval & 0x06) == 0x00) + dev_dbg(dev, "ColorSpace: RGB,"); + else if ((regval & 0x06) == 0x02) + dev_dbg(dev, "ColorSpace: YCbCr422,"); + else if ((regval & 0x06) == 0x04) + dev_dbg(dev, "ColorSpace: YCbCr444,"); + + sp_read_reg(anx78xx, TX_P0, SP_TX_VID_CTRL, ®val); + + if ((regval & 0xe0) == 0x00) + dev_dbg(dev, "6 BPC\n"); + else if ((regval & 0xe0) == 0x20) + dev_dbg(dev, "8 BPC\n"); + else if ((regval & 0xe0) == 0x40) + dev_dbg(dev, "10 BPC\n"); + else if ((regval & 0xe0) == 0x60) + dev_dbg(dev, "12 BPC\n"); + + if (is_anx_dongle(anx78xx)) { + sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x05, 0x23, 1, ®val); + dev_dbg(dev, "Analogix Dongle FW Ver %.2x\n", regval & 0x7f); + } + + dev_dbg(dev, "\n**************************************************\n"); +} + +static void sp_clean_system_status(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + + if (sp.need_clean_status) { + dev_dbg(dev, "sp_clean_system_status. A -> B;\n"); + dev_dbg(dev, "A:"); + sp_print_system_state(anx78xx, sp.tx_system_state_bak); + dev_dbg(dev, "B:"); + sp_print_system_state(anx78xx, sp.tx_system_state); + + sp.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(anx78xx, 1); + } else { + hdmi_rx_mute_video(anx78xx, 1); + sp_tx_video_mute(anx78xx, 1); + } + } + if (sp.tx_system_state_bak >= STATE_HDCP_AUTH && + sp.tx_system_state <= STATE_HDCP_AUTH) { + if (sp_i2c_read_byte(anx78xx, TX_P0, TX_HDCP_CTRL0) + & 0xfc) + sp_tx_clean_hdcp_status(anx78xx); + } + + if (sp.hcdp_state != HDCP_CAPABLE_CHECK) + sp.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********************/ +static u8 sp_hdcp_cap_check(struct anx78xx *anx78xx) +{ + struct device *dev = &anx78xx->client->dev; + u8 g_hdcp_cap = 0; + u8 value; + + if (sp_tx_aux_dpcdread_bytes(anx78xx, 0x06, 0x80, 0x28, 1, &value) == 0) + g_hdcp_cap = value & 0x01; + else + dev_dbg(dev, "HDCP CAPABLE: read AUX err!\n"); + + dev_dbg(dev, "hdcp cap check: %s Supported\n", + g_hdcp_cap ? "" : "No"); + + return g_hdcp_cap; +} + +/******************End HDCP cap check********************/ + +static void sp_tasks_handler(struct anx78xx *anx78xx) +{ + sp_system_isr_handler(anx78xx); + sp_hdcp_external_ctrl_flag_monitor(anx78xx); + sp_clean_system_status(anx78xx); + /*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 sp_main_process(struct anx78xx *anx78xx) +{ + sp_state_process(anx78xx); + if (sp.tx_system_state > STATE_WAITTING_CABLE_PLUG) { + sp_int_rec(anx78xx); + sp_tasks_handler(anx78xx); + } +} diff --git a/drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.h b/drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.h new file mode 100644 index 0000000..04dbe06 --- /dev/null +++ b/drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.h @@ -0,0 +1,214 @@ +/* + * 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_TX_DRV_H +#define __SLIMPORT_TX_DRV_H + +#include "anx78xx.h" +#include "slimport_tx_reg.h" + +#define FW_VERSION 0x22 + +#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; } + +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_FAILED, + 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 anx78xx_clock_data { + unsigned char xtal_clk; + unsigned int xtal_clk_m10; +}; + +bool sp_chip_detect(struct anx78xx *anx78xx); + +void sp_main_process(struct anx78xx *anx78xx); + +void sp_tx_variable_init(void); + +enum sp_tx_state sp_tx_current_state(void); + +void sp_tx_clean_state_machine(void); + +#endif diff --git a/drivers/gpu/drm/bridge/anx78xx/slimport_tx_reg.h b/drivers/gpu/drm/bridge/anx78xx/slimport_tx_reg.h new file mode 100644 index 0000000..56b575c --- /dev/null +++ b/drivers/gpu/drm/bridge/anx78xx/slimport_tx_reg.h @@ -0,0 +1,807 @@ +/* + * 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_TX_REG_DEF_H +#define __SLIMPORT_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 + +/* Pixel Clock High Resolution Counter Register 1 */ +#define PCLK_HR_CNT1 0x8c +/* Pixel Clock High Resolution Counter Register 2 */ +#define PCLK_HR_CNT2 0x8d + +#define HDMI_RX_AUD_IN_CH_STATUS1_REG 0xc7 + +/* Audio in S/PDIF Channel Status Register 4 */ +#define AUD_SPDIF_CHST4 0xca +#define FS_FREQ_44100HZ 0x00 +#define FS_FREQ_48000HZ 0x02 +#define FS_FREQ_32000HZ 0x03 +#define FS_FREQ_88200HZ 0x08 +#define FS_FREQ_96000HZ 0x0a +#define FS_FREQ_176400HZ 0x0c +#define FS_FREQ_192000HZ 0x0e + +#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_BW_SET_MASK 0x0f +#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 TX_SW_SET_MASK 0x1b +#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 ADDR_DP_CEP_TRAINING_CTRL0 0xa9 +#define ADDR_DP_CEP_TRAINING_CTRL1 0xaa +#define ADDR_DP_CEP_TRAINING_CTRL2 0xab + +#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_LT_TEST_PATTERN_REG0 0x80 +#define SP_TX_LT_TEST_PATTERN_REG1 0x81 +#define SP_TX_LT_TEST_PATTERN_REG2 0x82 +#define SP_TX_LT_TEST_PATTERN_REG3 0x83 +#define SP_TX_LT_TEST_PATTERN_REG4 0x84 +#define SP_TX_LT_TEST_PATTERN_REG5 0x85 +#define SP_TX_LT_TEST_PATTERN_REG6 0x86 +#define SP_TX_LT_TEST_PATTERN_REG7 0x87 +#define SP_TX_LT_TEST_PATTERN_REG8 0x88 +#define SP_TX_LT_TEST_PATTERN_REG9 0x89 + +#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 +
Signed-off-by: Fengguang Wu fengguang.wu@intel.com --- slimport_tx_drv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c b/drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c index 7721326..9afebab 100644 --- a/drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c +++ b/drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c @@ -607,7 +607,7 @@ static void hdmi_rx_initialization(struct anx78xx *anx78xx) hdmi_rx_set_termination(anx78xx, 0); }
-struct anx78xx_clock_data const pxtal_data[XTAL_CLK_NUM] = { +static struct anx78xx_clock_data const pxtal_data[XTAL_CLK_NUM] = { {19, 192}, {24, 240}, {25, 250}, @@ -640,7 +640,7 @@ static void xtal_clk_sel(struct anx78xx *anx78xx) ((pxtal_data[XTAL_27M].xtal_clk >> 1) - 2) << 3); }
-void sp_tx_initialization(struct anx78xx *anx78xx) +static void sp_tx_initialization(struct anx78xx *anx78xx) { sp_write_reg(anx78xx, TX_P0, AUX_CTRL2, 0x30); sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, 0x08); @@ -2185,7 +2185,7 @@ static void sp_config_audio_output(struct anx78xx *anx78xx)
/******************End Audio process********************/
-void sp_initialization(struct anx78xx *anx78xx) +static void sp_initialization(struct anx78xx *anx78xx) { /* Waitting Hot plug event! */ if (!(sp.common_int_status.common_int[3] & PLUG))
Hi Enric,
FYI, build test results on v4.3-rc2 (pls ignore if it's inappropriate base for your patch).
reproduce: # apt-get install sparse make ARCH=x86_64 allmodconfig make C=1 CF=-D__CHECK_ENDIAN__
sparse warnings: (new ones prefixed by >>)
drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c:610:33: sparse: symbol 'pxtal_data' was not declared. Should it be static? drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c:643:6: sparse: symbol 'sp_tx_initialization' was not declared. Should it be static? drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c:2188:6: sparse: symbol 'sp_initialization' was not declared. Should it be static? drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c:649:30: sparse: cast truncates bits from constant value (ffffff7f becomes 7f)
drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c:2129:30: sparse: cast truncates bits from constant value (ffffff7f becomes 7f)
drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c:2140:38: sparse: cast truncates bits from constant value (ffffff1f becomes 1f)
Please review and possibly fold the followup patch.
--- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi Enric,
On Fri, Sep 25, 2015 at 09:29:28PM +0200, Enric Balletbo i Serra wrote:
At the moment it only supports ANX7814.
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
More comments. Please look at patterns (u8->bool, use bit_ctl, etc.): I did not comment on every single instance of these.
Best,
drivers/gpu/drm/bridge/Kconfig | 2 + drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/anx78xx/Kconfig | 7 + drivers/gpu/drm/bridge/anx78xx/Makefile | 4 + drivers/gpu/drm/bridge/anx78xx/anx78xx.h | 41 + drivers/gpu/drm/bridge/anx78xx/anx78xx_main.c | 228 ++ drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c | 3148 ++++++++++++++++++++++ drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.h | 214 ++ drivers/gpu/drm/bridge/anx78xx/slimport_tx_reg.h | 807 ++++++ 9 files changed, 4452 insertions(+) create mode 100644 drivers/gpu/drm/bridge/anx78xx/Kconfig create mode 100644 drivers/gpu/drm/bridge/anx78xx/Makefile create mode 100644 drivers/gpu/drm/bridge/anx78xx/anx78xx.h create mode 100644 drivers/gpu/drm/bridge/anx78xx/anx78xx_main.c create mode 100644 drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c create mode 100644 drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.h create mode 100644 drivers/gpu/drm/bridge/anx78xx/slimport_tx_reg.h
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 2de52a5..aa6fe12 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -29,4 +29,6 @@ config DRM_PARADE_PS8622 ---help--- Parade eDP-LVDS bridge chip driver.
+source "drivers/gpu/drm/bridge/anx78xx/Kconfig"
endmenu diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index e2eef1c..e5bd38b 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -3,3 +3,4 @@ ccflags-y := -Iinclude/drm obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o +obj-$(CONFIG_DRM_ANX78XX) += anx78xx/ diff --git a/drivers/gpu/drm/bridge/anx78xx/Kconfig b/drivers/gpu/drm/bridge/anx78xx/Kconfig new file mode 100644 index 0000000..08f9c08 --- /dev/null +++ b/drivers/gpu/drm/bridge/anx78xx/Kconfig @@ -0,0 +1,7 @@ +config DRM_ANX78XX
- tristate "Analogix ANX78XX bridge"
- help
ANX78XX is a HD video transmitter chip over micro-USB
connector for smartphone device.
diff --git a/drivers/gpu/drm/bridge/anx78xx/Makefile b/drivers/gpu/drm/bridge/anx78xx/Makefile new file mode 100644 index 0000000..a843733 --- /dev/null +++ b/drivers/gpu/drm/bridge/anx78xx/Makefile @@ -0,0 +1,4 @@ +obj-${CONFIG_DRM_ANX78XX} := anx78xx.o
+anx78xx-y += anx78xx_main.o +anx78xx-y += slimport_tx_drv.o diff --git a/drivers/gpu/drm/bridge/anx78xx/anx78xx.h b/drivers/gpu/drm/bridge/anx78xx/anx78xx.h new file mode 100644 index 0000000..f62c8e7 --- /dev/null +++ b/drivers/gpu/drm/bridge/anx78xx/anx78xx.h @@ -0,0 +1,41 @@ +/*
- 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 __ANX78xx_H +#define __ANX78xx_H
+#include <linux/i2c.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <linux/gpio/consumer.h>
+struct anx78xx_platform_data {
- struct gpio_desc *gpiod_pd;
- struct gpio_desc *gpiod_reset;
- spinlock_t lock;
+};
+struct anx78xx {
- struct i2c_client *client;
- struct anx78xx_platform_data *pdata;
- struct delayed_work work;
- struct workqueue_struct *workqueue;
- struct mutex lock;
+};
+void anx78xx_poweron(struct anx78xx *data); +void anx78xx_poweroff(struct anx78xx *data);
+#endif diff --git a/drivers/gpu/drm/bridge/anx78xx/anx78xx_main.c b/drivers/gpu/drm/bridge/anx78xx/anx78xx_main.c new file mode 100644 index 0000000..1e4a87e --- /dev/null +++ b/drivers/gpu/drm/bridge/anx78xx/anx78xx_main.c @@ -0,0 +1,228 @@ +/*
- 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 "anx78xx.h" +#include "slimport_tx_drv.h"
+void anx78xx_poweron(struct anx78xx *anx78xx) +{
- struct anx78xx_platform_data *pdata = anx78xx->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);
+}
+void anx78xx_poweroff(struct anx78xx *anx78xx) +{
- struct anx78xx_platform_data *pdata = anx78xx->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);
+}
+static int anx78xx_init_gpio(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- struct anx78xx_platform_data *pdata = anx78xx->pdata;
- /* 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");
return PTR_ERR(pdata->gpiod_pd);
- }
- /* 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");
return PTR_ERR(pdata->gpiod_reset);
- }
- return 0;
+}
+static int anx78xx_system_init(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- if (!sp_chip_detect(anx78xx)) {
anx78xx_poweroff(anx78xx);
dev_err(dev, "failed to detect anx78xx\n");
return -ENODEV;
- }
- sp_tx_variable_init();
- return 0;
+}
I think this function might be better off as "sp_system_init" in tx_drv.c, since sp_chip_detect and sp_tx_variable_init are only called from here anyway.
+static void anx78xx_work_func(struct work_struct *work) +{
- struct anx78xx *anx78xx = container_of(work, struct anx78xx,
work.work);
- int workqueue_timer = 0;
- if (sp_tx_current_state() >= STATE_PLAY_BACK)
workqueue_timer = 500;
- else
workqueue_timer = 100;
So whenever the bridge is not outputing anything, the workqueue will be exectuted every 100ms? That seems like a lot...
- mutex_lock(&anx78xx->lock);
- sp_main_process(anx78xx);
- mutex_unlock(&anx78xx->lock);
- queue_delayed_work(anx78xx->workqueue, &anx78xx->work,
msecs_to_jiffies(workqueue_timer));
+}
+static int anx78xx_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
+{
- struct anx78xx *anx78xx;
- int 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;
- }
- anx78xx = devm_kzalloc(&client->dev, sizeof(*anx78xx), GFP_KERNEL);
- if (!anx78xx)
return -ENOMEM;
- anx78xx->pdata = devm_kzalloc(&client->dev,
sizeof(struct anx78xx_platform_data),
GFP_KERNEL);
- if (!anx78xx->pdata)
return -ENOMEM;
- anx78xx->client = client;
- i2c_set_clientdata(client, anx78xx);
- mutex_init(&anx78xx->lock);
- ret = anx78xx_init_gpio(anx78xx);
- if (ret) {
dev_err(&client->dev, "failed to initialize gpios\n");
return ret;
- }
- INIT_DELAYED_WORK(&anx78xx->work, anx78xx_work_func);
- anx78xx->workqueue = create_singlethread_workqueue("anx78xx_work");
- if (!anx78xx->workqueue) {
dev_err(&client->dev, "failed to create work queue\n");
return -ENOMEM;
- }
- ret = anx78xx_system_init(anx78xx);
- if (ret) {
dev_err(&client->dev, "failed to initialize anx78xx\n");
goto cleanup;
- }
- /* enable driver */
- queue_delayed_work(anx78xx->workqueue, &anx78xx->work, 0);
- return 0;
+cleanup:
- destroy_workqueue(anx78xx->workqueue);
- return ret;
+}
+static int anx78xx_i2c_remove(struct i2c_client *client) +{
- struct anx78xx *anx78xx = i2c_get_clientdata(client);
- destroy_workqueue(anx78xx->workqueue);
- return 0;
+}
+static int anx78xx_i2c_suspend(struct device *dev) +{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
- struct anx78xx *anx78xx = i2c_get_clientdata(client);
- cancel_delayed_work_sync(&anx78xx->work);
- flush_workqueue(anx78xx->workqueue);
- anx78xx_poweroff(anx78xx);
- sp_tx_clean_state_machine();
- return 0;
+}
+static int anx78xx_i2c_resume(struct device *dev) +{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
- struct anx78xx *anx78xx = i2c_get_clientdata(client);
- queue_delayed_work(anx78xx->workqueue, &anx78xx->work, 0);
- return 0;
+}
+static SIMPLE_DEV_PM_OPS(anx78xx_i2c_pm_ops,
anx78xx_i2c_suspend, anx78xx_i2c_resume);
+static const struct i2c_device_id anx78xx_id[] = {
- {"anx7814", 0},
- { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, anx78xx_id);
+static const struct of_device_id anx78xx_match_table[] = {
- {.compatible = "analogix,anx7814",},
- { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, anx78xx_match_table);
This should be protected by CONFIG_OF.
+static struct i2c_driver anx78xx_driver = {
- .driver = {
.name = "anx7814",
.pm = &anx78xx_i2c_pm_ops,
.of_match_table = of_match_ptr(anx78xx_match_table),
},
- .probe = anx78xx_i2c_probe,
- .remove = anx78xx_i2c_remove,
- .id_table = anx78xx_id,
+};
+module_i2c_driver(anx78xx_driver);
+MODULE_DESCRIPTION("Slimport transmitter ANX78XX driver"); +MODULE_AUTHOR("Junhua Xia jxia@analogixsemi.com"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("1.1"); diff --git a/drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c b/drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c new file mode 100644 index 0000000..7721326 --- /dev/null +++ b/drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.c @@ -0,0 +1,3148 @@ +/*
- 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 "anx78xx.h" +#include "slimport_tx_drv.h"
+struct slimport {
- int block_en; /* HDCP control enable/ disable from AP */
- u8 tx_test_bw;
- bool tx_test_lt;
- bool tx_test_edid;
I think these variables, and the ones below, could do we more descriptive, or at least more systematic names. E.g. the last 2 tx_test variables above are bool, but the first one is u8, this is a little confusing.
- u8 changed_bandwidth;
- u8 hdmi_dvi_status;
- u8 need_clean_status;
bool
- u8 ds_vid_stb_cntr;
Only set to 0, once, then never used.
- u8 hdcp_fail_count;
- u8 edid_break;
- u8 edid_checksum;
- u8 edid_blocks[256];
This variable is only used in sp_edid_process: allocate the buffer there.
- u8 read_edid_flag;
- u8 down_sample_en;
- struct packet_avi tx_packet_avi;
- struct packet_spd tx_packet_spd;
- struct packet_mpeg tx_packet_mpeg;
- struct audio_info_frame tx_audioinfoframe;
- struct common_int common_int_status;
- struct hdmi_rx_int hdmi_rx_int_status;
- enum sp_tx_state tx_system_state;
- enum sp_tx_state tx_system_state_bak;
- enum audio_output_status tx_ao_state;
- enum video_output_status tx_vo_state;
- enum sink_connection_status tx_sc_state;
- enum sp_tx_lt_status tx_lt_state;
- enum hdcp_status hcdp_state;
+};
+static struct slimport sp;
+static const u16 chipid_list[] = {
- 0x7818,
- 0x7816,
- 0x7814,
- 0x7812,
- 0x7810,
- 0x7806,
- 0x7802
Add a comma after the last entry, and reverse the order.
+};
+static void sp_hdmi_rx_new_vsi_int(struct anx78xx *anx78xx); +static u8 sp_hdcp_cap_check(struct anx78xx *anx78xx); +static void sp_tx_show_information(struct anx78xx *anx78xx); +static void sp_print_system_state(struct anx78xx *anx78xx, u8 ss);
+static int sp_read_reg(struct anx78xx *anx78xx, u8 slave_addr,
u8 offset, u8 *buf)
+{
- int ret;
- struct i2c_client *client = anx78xx->client;
- client->addr = slave_addr >> 1;
- ret = i2c_smbus_read_byte_data(client, offset);
- if (ret < 0) {
dev_err(&client->dev, "failed to read i2c addr=%x\n",
slave_addr);
return ret;
- }
- *buf = ret;
- return 0;
+}
This function, and write_reg below, returns error values, but those are ignored by all callers... I think callers should propagate errors.
+static int sp_write_reg(struct anx78xx *anx78xx, u8 slave_addr,
u8 offset, u8 value)
+{
- int ret;
- struct i2c_client *client = anx78xx->client;
- client->addr = slave_addr >> 1;
- ret = i2c_smbus_write_byte_data(client, offset, value);
- if (ret < 0)
dev_err(&client->dev, "failed to write i2c addr=%x\n",
slave_addr);
- return ret;
+}
+static u8 sp_i2c_read_byte(struct anx78xx *anx78xx,
u8 dev, u8 offset)
+{
- u8 ret;
- sp_read_reg(anx78xx, dev, offset, &ret);
- return ret;
+}
I don't think this function should exist: it is a simple wrapper that ignores errors (and returns random values on error).
+static void sp_reg_bit_ctl(struct anx78xx *anx78xx, u8 addr, u8 offset,
u8 data, bool enable)
+{
- u8 regval;
- sp_read_reg(anx78xx, addr, offset, ®val);
- if (enable) {
if ((regval & data) != data) {
regval |= data;
sp_write_reg(anx78xx, addr, offset, regval);
}
- } else {
if ((regval & data) == data) {
regval &= ~data;
sp_write_reg(anx78xx, addr, offset, regval);
}
- }
+}
+static inline void sp_write_reg_or(struct anx78xx *anx78xx, u8 address,
u8 offset, u8 mask)
+{
- sp_write_reg(anx78xx, address, offset,
sp_i2c_read_byte(anx78xx, address, offset) | mask);
+}
+static inline void sp_write_reg_and(struct anx78xx *anx78xx, u8 address,
u8 offset, u8 mask)
+{
- sp_write_reg(anx78xx, address, offset,
sp_i2c_read_byte(anx78xx, address, offset) & mask);
+}
+static inline void sp_write_reg_and_or(struct anx78xx *anx78xx, u8 address,
u8 offset, u8 and_mask, u8 or_mask)
+{
- sp_write_reg(anx78xx, address, offset,
(sp_i2c_read_byte(anx78xx, address, offset) & and_mask)
| or_mask);
+}
+static inline void sp_write_reg_or_and(struct anx78xx *anx78xx, u8 address,
u8 offset, u8 or_mask, u8 and_mask)
+{
- sp_write_reg(anx78xx, address, offset,
(sp_i2c_read_byte(anx78xx, address, offset) | or_mask)
& and_mask);
+}
+static inline void sp_tx_video_mute(struct anx78xx *anx78xx, bool enable) +{
- sp_reg_bit_ctl(anx78xx, TX_P2, VID_CTRL1, VIDEO_MUTE, enable);
+}
+static inline void hdmi_rx_mute_audio(struct anx78xx *anx78xx, bool enable) +{
- sp_reg_bit_ctl(anx78xx, RX_P0, RX_MUTE_CTRL, AUD_MUTE, enable);
+}
+static inline void hdmi_rx_mute_video(struct anx78xx *anx78xx, bool enable) +{
- sp_reg_bit_ctl(anx78xx, RX_P0, RX_MUTE_CTRL, VID_MUTE, enable);
+}
+static inline void sp_tx_addronly_set(struct anx78xx *anx78xx, bool enable) +{
- sp_reg_bit_ctl(anx78xx, TX_P0, AUX_CTRL2, ADDR_ONLY_BIT, enable);
+}
+static inline void sp_tx_set_link_bw(struct anx78xx *anx78xx, u8 bw) +{
- sp_write_reg(anx78xx, TX_P0, SP_TX_LINK_BW_SET_REG, bw);
+}
+static inline u8 sp_tx_get_link_bw(struct anx78xx *anx78xx) +{
- return (sp_i2c_read_byte(anx78xx, TX_P0, SP_TX_LINK_BW_SET_REG) &
LINK_BW_SET_MASK);
+}
+static inline bool sp_tx_get_pll_lock_status(struct anx78xx *anx78xx) +{
- u8 byte;
- byte = sp_i2c_read_byte(anx78xx, TX_P0, TX_DEBUG1);
- return (byte & DEBUG_PLL_LOCK) != 0;
+}
+static inline void gen_m_clk_with_downspeading(struct anx78xx *anx78xx)
downspeeding? downspreading?
+{
- sp_write_reg_or(anx78xx, TX_P0, SP_TX_M_CALCU_CTRL, M_GEN_CLK_SEL);
+}
+static inline void gen_m_clk_without_downspeading(struct anx78xx *anx78xx) +{
- sp_write_reg_and(anx78xx, TX_P0, SP_TX_M_CALCU_CTRL, (~M_GEN_CLK_SEL));
+}
Can't you use bit_ctl for these 2?
+static inline void hdmi_rx_set_hpd(struct anx78xx *anx78xx, bool enable) +{
- if (enable)
sp_write_reg_or(anx78xx, TX_P2, SP_TX_VID_CTRL3_REG, HPD_OUT);
- else
sp_write_reg_and(anx78xx, TX_P2, SP_TX_VID_CTRL3_REG,
~HPD_OUT);
+}
+static inline void hdmi_rx_set_termination(struct anx78xx *anx78xx,
bool enable)
+{
- if (enable)
sp_write_reg_and(anx78xx, RX_P0, HDMI_RX_TMDS_CTRL_REG7,
~TERM_PD);
- else
sp_write_reg_or(anx78xx, RX_P0, HDMI_RX_TMDS_CTRL_REG7,
TERM_PD);
+}
bit_ctl for these 2 as well, and please check the rest of the code too.
+static inline void sp_tx_clean_hdcp_status(struct anx78xx *anx78xx) +{
- sp_write_reg(anx78xx, TX_P0, TX_HDCP_CTRL0, 0x03);
- sp_write_reg_or(anx78xx, TX_P0, TX_HDCP_CTRL0, RE_AUTH);
- usleep_range(2000, 4000);
+}
+static inline void sp_tx_link_phy_initialization(struct anx78xx *anx78xx)
Please do not force inline, especially for these long-ish functions, the compiler will do the right thing.
+{
- sp_write_reg(anx78xx, TX_P2, SP_TX_ANALOG_CTRL0, 0x02);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG0, 0x01);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG10, 0x00);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG1, 0x03);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG11, 0x00);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG2, 0x07);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG12, 0x00);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG3, 0x7f);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG13, 0x00);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG4, 0x71);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG14, 0x0c);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG5, 0x6b);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG15, 0x42);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG6, 0x7f);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG16, 0x1e);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG7, 0x73);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG17, 0x3e);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG8, 0x7f);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG18, 0x72);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG9, 0x7f);
- sp_write_reg(anx78xx, TX_P1, SP_TX_LT_CTRL_REG19, 0x7e);
Weird order, any reason not to write those from 1 to 19?
+}
+static inline void sp_tx_set_sys_state(struct anx78xx *anx78xx, u8 ss) +{
- struct device *dev = &anx78xx->client->dev;
- dev_dbg(dev, "set: clean_status: %x,\n", sp.need_clean_status);
- if ((sp.tx_system_state >= STATE_LINK_TRAINING) &&
(ss < STATE_LINK_TRAINING))
sp_write_reg_or(anx78xx, TX_P0, SP_TX_ANALOG_PD_REG, CH0_PD);
- sp.tx_system_state_bak = sp.tx_system_state;
- sp.tx_system_state = ss;
- sp.need_clean_status = 1;
- sp_print_system_state(anx78xx, sp.tx_system_state);
+}
+static inline void reg_hardware_reset(struct anx78xx *anx78xx) +{
- sp_write_reg_or(anx78xx, TX_P2, SP_TX_RST_CTRL_REG, HW_RST);
- sp_tx_clean_state_machine();
- sp_tx_set_sys_state(anx78xx, STATE_SP_INITIALIZED);
- msleep(500);
+}
+static inline void write_dpcd_addr(struct anx78xx *anx78xx, u8 addrh,
u8 addrm, u8 addrl)
+{
- u8 regval;
- if (sp_i2c_read_byte(anx78xx, TX_P0, AUX_ADDR_7_0) != addrl)
sp_write_reg(anx78xx, TX_P0, AUX_ADDR_7_0, addrl);
- if (sp_i2c_read_byte(anx78xx, TX_P0, AUX_ADDR_15_8) != addrm)
sp_write_reg(anx78xx, TX_P0, AUX_ADDR_15_8, addrm);
- sp_read_reg(anx78xx, TX_P0, AUX_ADDR_19_16, ®val);
This is confusing, both sp_i2c_read_byte and sp_read_reg are used in the same function. Pick one.
- if ((regval & 0x0f) != (addrh & 0x0f))
sp_write_reg(anx78xx, TX_P0, AUX_ADDR_19_16,
(regval & 0xf0) | addrh);
1 space before &
+}
+static inline void goto_next_system_state(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- dev_dbg(dev, "next: clean_status: %x,\n", sp.need_clean_status);
- sp.tx_system_state_bak = sp.tx_system_state;
- sp.tx_system_state++;
- sp_print_system_state(anx78xx, sp.tx_system_state);
+}
+static inline void redo_cur_system_state(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- dev_dbg(dev, "redo: clean_status: %x,\n", sp.need_clean_status);
- sp.need_clean_status = 1;
- sp.tx_system_state_bak = sp.tx_system_state;
- sp_print_system_state(anx78xx, sp.tx_system_state);
+}
+static inline void system_state_change_with_case(struct anx78xx *anx78xx,
u8 status)
+{
- struct device *dev = &anx78xx->client->dev;
- if (sp.tx_system_state < status)
return;
- dev_dbg(dev, "change_case: clean_status: %xm,\n",
sp.need_clean_status);
- if (sp.tx_system_state >= STATE_LINK_TRAINING &&
status < STATE_LINK_TRAINING)
sp_write_reg_or(anx78xx, TX_P0, SP_TX_ANALOG_PD_REG,
CH0_PD);
- sp.need_clean_status = 1;
- sp.tx_system_state_bak = sp.tx_system_state;
- sp.tx_system_state = status;
- sp_print_system_state(anx78xx, sp.tx_system_state);
+}
+static void sp_wait_aux_op_finish(struct anx78xx *anx78xx, u8 *err_flag)
Return an int and use that as error flag.
+{
- u8 cnt;
- u8 regval;
- struct device *dev = &anx78xx->client->dev;
- *err_flag = 0;
- cnt = 150;
- while (sp_i2c_read_byte(anx78xx, TX_P0, AUX_CTRL2) & AUX_OP_EN) {
usleep_range(2000, 4000);
if (cnt-- == 0) {
dev_err(dev, "aux operate failed!\n");
*err_flag = 1;
break;
}
- }
- sp_read_reg(anx78xx, TX_P0, SP_TX_AUX_STATUS, ®val);
- if (regval & 0x0f) {
dev_err(dev, "wait aux operation status %.2x\n", regval);
*err_flag = 1;
- }
+}
+static void sp_print_system_state(struct anx78xx *anx78xx, u8 ss) +{
- struct device *dev = &anx78xx->client->dev;
- switch (ss) {
- case STATE_WAITTING_CABLE_PLUG:
dev_dbg(dev, "-STATE_WAITTING_CABLE_PLUG-\n");
break;
- case STATE_SP_INITIALIZED:
dev_dbg(dev, "-STATE_SP_INITIALIZED-\n");
break;
- case STATE_SINK_CONNECTION:
dev_dbg(dev, "-STATE_SINK_CONNECTION-\n");
break;
- case STATE_PARSE_EDID:
dev_dbg(dev, "-STATE_PARSE_EDID-\n");
break;
- case STATE_LINK_TRAINING:
dev_dbg(dev, "-STATE_LINK_TRAINING-\n");
break;
- case STATE_VIDEO_OUTPUT:
dev_dbg(dev, "-STATE_VIDEO_OUTPUT-\n");
break;
- case STATE_HDCP_AUTH:
dev_dbg(dev, "-STATE_HDCP_AUTH-\n");
break;
- case STATE_AUDIO_OUTPUT:
dev_dbg(dev, "-STATE_AUDIO_OUTPUT-\n");
break;
- case STATE_PLAY_BACK:
dev_dbg(dev, "-STATE_PLAY_BACK-\n");
break;
- default:
dev_err(dev, "unknown system state\n");
break;
- }
+}
+static void sp_tx_rst_aux(struct anx78xx *anx78xx) +{
- sp_write_reg_or(anx78xx, TX_P2, RST_CTRL2, AUX_RST);
- sp_write_reg_and(anx78xx, TX_P2, RST_CTRL2, ~AUX_RST);
bit_ctl?
+}
+static u8 sp_tx_aux_dpcdread_bytes(struct anx78xx *anx78xx, u8 addrh,
u8 addrm, u8 addrl, u8 ccount, u8 *pbuf)
+{
- u8 regval, regval1, i;
- u8 bok;
- struct device *dev = &anx78xx->client->dev;
- sp_write_reg(anx78xx, TX_P0, BUF_DATA_COUNT, 0x80);
- sp_write_reg(anx78xx, TX_P0, AUX_CTRL, ((ccount - 1) << 4) | 0x09);
- write_dpcd_addr(anx78xx, addrh, addrm, addrl);
- sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, AUX_OP_EN);
- usleep_range(2000, 4000);
- sp_wait_aux_op_finish(anx78xx, &bok);
- if (bok) {
dev_err(dev, "aux read failed\n");
sp_read_reg(anx78xx, TX_P2, SP_TX_INT_STATUS1, ®val);
sp_read_reg(anx78xx, TX_P0, TX_DEBUG1, ®val1);
if (!(regval1 & POLLING_EN) || (regval & POLLING_ERR))
sp_tx_rst_aux(anx78xx);
return 1;
- }
- for (i = 0; i < ccount; i++) {
sp_read_reg(anx78xx, TX_P0, BUF_DATA_0 + i, ®val);
*(pbuf + i) = regval;
if (i >= MAX_BUF_CNT)
break;
- }
- return 0;
+}
+static u8 sp_tx_aux_dpcdwrite_bytes(struct anx78xx *anx78xx, u8 addrh,
u8 addrm, u8 addrl, u8 ccount, u8 *pbuf)
+{
- u8 regval, i, ret;
- sp_write_reg(anx78xx, TX_P0, AUX_CTRL, ((ccount - 1) << 4) | 0x08);
- write_dpcd_addr(anx78xx, addrh, addrm, addrl);
- for (i = 0; i < ccount; i++) {
&& i < 16
regval = *pbuf;
pbuf++;
sp_write_reg(anx78xx, TX_P0, BUF_DATA_0 + i, regval);
, pbuf[i]); and drop regval.
if (i >= 15)
break;
- }
- sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, AUX_OP_EN);
- sp_wait_aux_op_finish(anx78xx, &ret);
- return ret;
+}
+static u8 sp_tx_aux_dpcdwrite_byte(struct anx78xx *anx78xx, u8 addrh,
u8 addrm, u8 addrl, u8 data1)
+{
- u8 ret;
- sp_write_reg(anx78xx, TX_P0, AUX_CTRL, 0x08);
- write_dpcd_addr(anx78xx, addrh, addrm, addrl);
- sp_write_reg(anx78xx, TX_P0, BUF_DATA_0, data1);
- sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, AUX_OP_EN);
- sp_wait_aux_op_finish(anx78xx, &ret);
- return ret;
+}
+static void sp_block_power_ctrl(struct anx78xx *anx78xx,
enum sp_tx_power_block sp_tx_pd_block,
u8 power)
AFAICS, power is only ON or OFF. Use a bool.
+{
- struct device *dev = &anx78xx->client->dev;
- if (power == SP_POWER_ON)
sp_write_reg_and(anx78xx, TX_P2, SP_POWERD_CTRL_REG,
~sp_tx_pd_block);
- else
sp_write_reg_or(anx78xx, TX_P2, SP_POWERD_CTRL_REG,
sp_tx_pd_block);
Again, would be simple with bit_ctl.
- dev_dbg(dev, "sp_tx_power_on: %.2x\n", sp_tx_pd_block);
+}
+static void sp_vbus_power_off(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- int i;
- for (i = 0; i < 5; i++) {
sp_write_reg_and(anx78xx, TX_P2, TX_PLL_FILTER5,
~P5V_PROTECT_PD & ~SHORT_PROTECT_PD);
sp_write_reg_or(anx78xx, TX_P2, TX_PLL_FILTER, V33_SWITCH_ON);
if (!(sp_i2c_read_byte(anx78xx, TX_P2, TX_PLL_FILTER5)
& 0xc0)) {
dev_dbg(dev, "3.3V output enabled\n");
break;
}
- }
+}
+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;
- sp.hcdp_state = HDCP_CAPABLE_CHECK;
- sp.tx_vo_state = VO_WAIT_VIDEO_STABLE;
- sp.tx_ao_state = AO_INIT;
+}
+enum sp_tx_state sp_tx_current_state(void) +{
- return sp.tx_system_state;
+}
+void sp_tx_variable_init(void) +{
- sp.block_en = 1;
- sp.tx_system_state = STATE_WAITTING_CABLE_PLUG;
- sp.tx_system_state_bak = STATE_WAITTING_CABLE_PLUG;
- sp.edid_break = 0;
- sp.read_edid_flag = 0;
- sp.edid_checksum = 0;
- memset(sp.edid_blocks, 0, 256);
- sp.tx_lt_state = LT_INIT;
- sp.hcdp_state = HDCP_CAPABLE_CHECK;
- sp.need_clean_status = 0;
- sp.tx_sc_state = SC_INIT;
- sp.tx_vo_state = VO_WAIT_VIDEO_STABLE;
- sp.tx_ao_state = AO_INIT;
- sp.changed_bandwidth = LINK_5P4G;
- sp.hdmi_dvi_status = HDMI_MODE;
- sp.tx_test_lt = 0;
- sp.tx_test_bw = 0;
- sp.tx_test_edid = 0;
- sp.ds_vid_stb_cntr = 0;
- sp.hdcp_fail_count = 0;
+}
+static void hdmi_rx_tmds_phy_initialization(struct anx78xx *anx78xx) +{
- sp_write_reg(anx78xx, RX_P0, HDMI_RX_TMDS_CTRL_REG2, 0xa9);
- sp_write_reg(anx78xx, RX_P0, HDMI_RX_TMDS_CTRL_REG7, 0x80);
- sp_write_reg(anx78xx, RX_P0, HDMI_RX_TMDS_CTRL_REG1, 0x90);
- sp_write_reg(anx78xx, RX_P0, HDMI_RX_TMDS_CTRL_REG6, 0x92);
- sp_write_reg(anx78xx, RX_P0, HDMI_RX_TMDS_CTRL_REG20, 0xf2);
+}
+static void hdmi_rx_initialization(struct anx78xx *anx78xx) +{
- sp_write_reg(anx78xx, RX_P0, RX_MUTE_CTRL, AUD_MUTE | VID_MUTE);
- sp_write_reg_or(anx78xx, RX_P0, RX_CHIP_CTRL,
MAN_HDMI5V_DET | PLLLOCK_CKDT_EN | DIGITAL_CKDT_EN);
- sp_write_reg_or(anx78xx, RX_P0, RX_SRST, HDCP_MAN_RST | SW_MAN_RST |
TMDS_RST | VIDEO_RST);
- sp_write_reg_and(anx78xx, RX_P0, RX_SRST, ~HDCP_MAN_RST &
~SW_MAN_RST & ~TMDS_RST & ~VIDEO_RST);
- sp_write_reg_or(anx78xx, RX_P0, RX_AEC_EN0, AEC_EN06 | AEC_EN05);
- sp_write_reg_or(anx78xx, RX_P0, RX_AEC_EN2, AEC_EN21);
- sp_write_reg_or(anx78xx, RX_P0, RX_AEC_CTRL, AVC_EN | AAC_OE | AAC_EN);
- sp_write_reg_and(anx78xx, RX_P0, RX_SYS_PWDN1, ~PWDN_CTRL);
- sp_write_reg_or(anx78xx, RX_P0, RX_VID_DATA_RNG, R2Y_INPUT_LIMIT);
- sp_write_reg(anx78xx, RX_P0, 0x65, 0xc4);
- sp_write_reg(anx78xx, RX_P0, 0x66, 0x18);
- /* enable DDC stretch */
- sp_write_reg(anx78xx, TX_P0, TX_EXTRA_ADDR, 0x50);
- hdmi_rx_tmds_phy_initialization(anx78xx);
- hdmi_rx_set_hpd(anx78xx, 0);
- hdmi_rx_set_termination(anx78xx, 0);
+}
+struct anx78xx_clock_data const pxtal_data[XTAL_CLK_NUM] = {
- {19, 192},
- {24, 240},
- {25, 250},
- {26, 260},
- {27, 270},
- {38, 384},
- {52, 520},
- {27, 270},
+};
+static void xtal_clk_sel(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- dev_dbg(dev, "define XTAL_CLK: %x\n", XTAL_27M);
- sp_write_reg_and_or(anx78xx, TX_P2,
TX_ANALOG_DEBUG2, ~0x3c, 0x3c & (XTAL_27M << 2));
- sp_write_reg(anx78xx, TX_P0, 0xec, pxtal_data[XTAL_27M].xtal_clk_m10);
- sp_write_reg(anx78xx, TX_P0, 0xed,
0xec, 0xed, etc: Please define these magic numbers.
((pxtal_data[XTAL_27M].xtal_clk_m10 & 0xff00) >> 2)
| pxtal_data[XTAL_27M].xtal_clk);
- sp_write_reg(anx78xx, TX_P0, I2C_GEN_10US_TIMER0,
pxtal_data[XTAL_27M].xtal_clk_m10);
- sp_write_reg(anx78xx, TX_P0, I2C_GEN_10US_TIMER1,
(pxtal_data[XTAL_27M].xtal_clk_m10 & 0xff00) >> 8);
- sp_write_reg(anx78xx, TX_P0, 0xbf, pxtal_data[XTAL_27M].xtal_clk - 1);
- sp_write_reg_and_or(anx78xx, RX_P0, 0x49, 0x07,
((pxtal_data[XTAL_27M].xtal_clk >> 1) - 2) << 3);
+}
+void sp_tx_initialization(struct anx78xx *anx78xx) +{
- sp_write_reg(anx78xx, TX_P0, AUX_CTRL2, 0x30);
- sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, 0x08);
- sp_write_reg_and(anx78xx, TX_P0, TX_HDCP_CTRL,
(u8)~AUTO_EN & ~AUTO_START);
- sp_write_reg(anx78xx, TX_P0, OTP_KEY_PROTECT1, OTP_PSW1);
- sp_write_reg(anx78xx, TX_P0, OTP_KEY_PROTECT2, OTP_PSW2);
- sp_write_reg(anx78xx, TX_P0, OTP_KEY_PROTECT3, OTP_PSW3);
- sp_write_reg_or(anx78xx, TX_P0, HDCP_KEY_CMD, DISABLE_SYNC_HDCP);
- sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL8_REG, VID_VRES_TH);
- sp_write_reg(anx78xx, TX_P0, HDCP_AUTO_TIMER, HDCP_AUTO_TIMER_VAL);
- sp_write_reg_or(anx78xx, TX_P0, TX_HDCP_CTRL, LINK_POLLING);
- sp_write_reg_or(anx78xx, TX_P0, TX_LINK_DEBUG, M_VID_DEBUG);
- sp_write_reg_or(anx78xx, TX_P2, TX_ANALOG_DEBUG2, POWERON_TIME_1P5MS);
- xtal_clk_sel(anx78xx);
- sp_write_reg(anx78xx, TX_P0, AUX_DEFER_CTRL, 0x8c);
- sp_write_reg_or(anx78xx, 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(anx78xx, TX_P0, SP_TX_LINK_CHK_TIMER, 0x1d);
- sp_write_reg_or(anx78xx, TX_P0, TX_MISC, EQ_TRAINING_LOOP);
- sp_write_reg_or(anx78xx, TX_P0, SP_TX_ANALOG_PD_REG, CH0_PD);
- sp_write_reg(anx78xx, TX_P2, SP_TX_INT_CTRL_REG, 0x01);
- /* disable HDCP mismatch function for VGA dongle */
- sp_tx_link_phy_initialization(anx78xx);
- gen_m_clk_with_downspeading(anx78xx);
- sp.down_sample_en = 0;
+}
+bool sp_chip_detect(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u16 id;
- u8 idh = 0, idl = 0;
- int i;
- anx78xx_poweron(anx78xx);
- /* check chip id */
- sp_read_reg(anx78xx, TX_P2, SP_TX_DEV_IDL_REG, &idl);
- sp_read_reg(anx78xx, TX_P2, SP_TX_DEV_IDH_REG, &idh);
- id = idl | (idh << 8);
- dev_dbg(dev, "CHIPID: ANX%x\n", id & 0xffff);
- for (i = 0; i < ARRAY_SIZE(chipid_list); i++) {
if (id == chipid_list[i])
return true;
- }
- return false;
+}
+static void sp_waiting_cable_plug_process(struct anx78xx *anx78xx) +{
- sp_tx_variable_init();
- anx78xx_poweron(anx78xx);
- goto_next_system_state(anx78xx);
+}
+/*
- Check if it is ANALOGIX dongle.
- */
+static const u8 ANX_OUI[3] = {0x00, 0x22, 0xb9};
+static u8 is_anx_dongle(struct anx78xx *anx78xx)
Return a bool.
+{
- u8 buf[3];
- /* 0x0500~0x0502: BRANCH_IEEE_OUI */
- sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x05, 0x00, 3, buf);
- if (!memcmp(buf, ANX_OUI, 3))
return 1;
- return 0;
+}
+static void sp_tx_get_rx_bw(struct anx78xx *anx78xx, u8 *bw) +{
- if (is_anx_dongle(anx78xx))
*bw = LINK_6P75G; /* just for debug */
- else
sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x00,
DPCD_MAX_LINK_RATE, 1, bw);
I don't understand what this does, and what is the "just for debug" part.
Also, if nothing can fail, return the bandwidth directly.
+}
+static u8 sp_tx_get_cable_type(struct anx78xx *anx78xx,
enum cable_type_status det_cable_type_state)
+{
- struct device *dev = &anx78xx->client->dev;
- 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(anx78xx, 0x00, 0x00, 0x05, 1,
&ds_port_preset);
- dev_dbg(dev, "DPCD 0x005: %x\n", (int)ds_port_preset);
Cast is not necessary.
- switch (det_cable_type_state) {
- case CHECK_AUXCH:
if (aux_status == 0) {
sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x00, 0, 0x0c,
data_buf);
det_cable_type_state = GETTED_CABLE_TYPE;
} else {
dev_err(dev, "AUX access error\n");
break;
}
- case GETTED_CABLE_TYPE:
switch ((ds_port_preset & (BIT(1) | BIT(2))) >> 1) {
case 0x00:
cur_cable_type = DWN_STRM_IS_DIGITAL;
dev_dbg(dev, "Downstream is DP dongle.\n");
break;
case 0x01:
case 0x03:
cur_cable_type = DWN_STRM_IS_ANALOG;
dev_dbg(dev, "Downstream is VGA dongle.\n");
break;
case 0x02:
cur_cable_type = DWN_STRM_IS_HDMI;
dev_dbg(dev, "Downstream is HDMI dongle.\n");
break;
default:
cur_cable_type = DWN_STRM_IS_NULL;
dev_err(dev, "Downstream can not recognized.\n");
break;
}
- default:
break;
- }
- return cur_cable_type;
+}
+static u8 sp_tx_get_dp_connection(struct anx78xx *anx78xx)
bool?
+{
- u8 regval;
- if (sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02,
DPCD_SINK_COUNT, 1, ®val))
return 0;
- if (regval & 0x1f) {
if (!(regval & 0x1f)) return 0;
sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x00, 0x04, 1, ®val);
if (regval & 0x20) {
sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x06, 0x00, 1,
®val);
/*
* Bit 5 = SET_DN_DEVICE_DP_PWR_5V
* Bit 6 = SET_DN_DEVICE_DP_PWR_12V
* Bit 7 = SET_DN_DEVICE_DP_PWR_18V
*/
regval = regval & 0x1f;
sp_tx_aux_dpcdwrite_byte(anx78xx, 0x00, 0x06, 0x00,
regval | 0x20);
}
return 1;
- } else {
return 0;
- }
+}
+static void sp_sink_connection(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- 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(anx78xx, CHECK_AUXCH) ==
DWN_STRM_IS_NULL) {
sp.tx_sc_state++;
if (sp.tx_sc_state >= SC_WAITTING_CABLE_TYPE) {
WAITING. +. Also, you are hiding the logic in the enum definition: you are doing 5 attempts before giving up. Please find another way.
sp.tx_sc_state = SC_NOT_CABLE;
dev_dbg(dev, "Can not get cable type!\n");
}
break;
}
sp.tx_sc_state = SC_SINK_CONNECTED;
- case SC_SINK_CONNECTED:
if (sp_tx_get_dp_connection(anx78xx))
goto_next_system_state(anx78xx);
break;
- case SC_NOT_CABLE:
sp_vbus_power_off(anx78xx);
reg_hardware_reset(anx78xx);
break;
- }
+}
+/******************start EDID process********************/ +static void sp_tx_enable_video_input(struct anx78xx *anx78xx, u8 enable)
bool enable (please replace all u8 by bool where appropriate, I'll ignore them from now on)
+{
- struct device *dev = &anx78xx->client->dev;
- u8 regval;
- sp_read_reg(anx78xx, TX_P2, VID_CTRL1, ®val);
- if (enable) {
sp_write_reg(anx78xx, TX_P2, VID_CTRL1,
(regval & 0xf7) | VIDEO_EN);
dev_dbg(dev, "Slimport Video is enabled!\n");
- } else {
sp_write_reg(anx78xx, TX_P2, VID_CTRL1, regval & ~VIDEO_EN);
dev_dbg(dev, "Slimport Video is disabled!\n");
- }
+}
+static u8 sp_get_edid_detail(u8 *data_buf)
get_edid_bandwidth
+{
- u16 pixclock_edid;
- pixclock_edid = (((u16)data_buf[1] << 8) | ((u16)data_buf[0] & 0xff));
- if (pixclock_edid <= 5300)
return LINK_1P62G;
- else if ((pixclock_edid > 5300) && (pixclock_edid <= 8900))
5300 already covered in previous test.
return LINK_2P7G;
- else if ((pixclock_edid > 8900) && (pixclock_edid <= 18000))
return LINK_5P4G;
- else
return LINK_6P75G;
+}
+static u8 sp_parse_edid_to_get_bandwidth(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 i, bandwidth, temp;
- bandwidth = LINK_1P62G;
- for (i = 0; i < 4; i++) {
if (sp.edid_blocks[0x36 + 0x12 * i] == 0)
break;
temp = sp_get_edid_detail(sp.edid_blocks + 0x36 + 0x12 * i);
dev_dbg(dev, "bandwidth via EDID : %x\n", temp);
if (bandwidth < temp)
bandwidth = temp;
if (bandwidth >= LINK_6P75G)
break;
- }
- return bandwidth;
+}
+static void sp_tx_aux_wr(struct anx78xx *anx78xx, u8 offset) +{
- sp_write_reg(anx78xx, TX_P0, BUF_DATA_0, offset);
- sp_write_reg(anx78xx, TX_P0, AUX_CTRL, 0x04);
- sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, AUX_OP_EN);
- sp_wait_aux_op_finish(anx78xx, &sp.edid_break);
+}
+static void sp_tx_aux_rd(struct anx78xx *anx78xx, u8 len_cmd) +{
- sp_write_reg(anx78xx, TX_P0, AUX_CTRL, len_cmd);
- sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, AUX_OP_EN);
- sp_wait_aux_op_finish(anx78xx, &sp.edid_break);
+}
+static u8 sp_tx_get_edid_block(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 regval;
- sp_tx_aux_wr(anx78xx, 0x7e);
- sp_tx_aux_rd(anx78xx, 0x01);
- sp_read_reg(anx78xx, TX_P0, BUF_DATA_0, ®val);
- dev_dbg(dev, "EDID Block = %d\n", regval + 1);
- if (regval > 3)
regval = 1;
- return regval;
+}
+static void sp_edid_read(struct anx78xx *anx78xx, u8 offset,
u8 *pblock_buf)
+{
- u8 data_cnt, error_cnt;
- u8 regval;
- sp_tx_aux_wr(anx78xx, offset);
- sp_tx_aux_rd(anx78xx, 0xf5);
- data_cnt = 0;
- error_cnt = 0;
- while ((data_cnt) < 16) {
data_cnt < 16
sp_read_reg(anx78xx, TX_P0, BUF_DATA_COUNT, ®val);
if (regval & 0x1f) {
data_cnt = data_cnt + (regval & 0x1f);
do {
sp_read_reg(anx78xx, TX_P0,
BUF_DATA_0 + regval - 1,
&pblock_buf[regval - 1]);
} while (--regval);
I think this would gain in clarity if you used a for loop.
} else {
if (error_cnt++ <= 2) {
sp_tx_rst_aux(anx78xx);
regval = 0x05 | ((0x0f - data_cnt) << 4);
sp_tx_aux_rd(anx78xx, regval);
} else {
sp.edid_break = 1;
break;
}
}
- }
- sp_write_reg(anx78xx, TX_P0, AUX_CTRL, 0x01);
- sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, ADDR_ONLY_BIT | AUX_OP_EN);
- sp_wait_aux_op_finish(anx78xx, &sp.edid_break);
- sp_tx_addronly_set(anx78xx, 0);
+}
+static void sp_tx_edid_read_initial(struct anx78xx *anx78xx) +{
- sp_write_reg(anx78xx, TX_P0, AUX_ADDR_7_0, 0x50);
- sp_write_reg(anx78xx, TX_P0, AUX_ADDR_15_8, 0);
- sp_write_reg_and(anx78xx, TX_P0, AUX_ADDR_19_16, 0xf0);
+}
+static void sp_seg_edid_read(struct anx78xx *anx78xx,
u8 segment, u8 offset)
+{
- struct device *dev = &anx78xx->client->dev;
- u8 regval, cnt;
- int i;
- sp_write_reg(anx78xx, TX_P0, AUX_CTRL, 0x04);
- sp_write_reg(anx78xx, TX_P0, AUX_ADDR_7_0, 0x30);
- sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, ADDR_ONLY_BIT | AUX_OP_EN);
- sp_read_reg(anx78xx, TX_P0, AUX_CTRL2, ®val);
- sp_wait_aux_op_finish(anx78xx, &sp.edid_break);
- sp_read_reg(anx78xx, TX_P0, AUX_CTRL, ®val);
- sp_write_reg(anx78xx, TX_P0, BUF_DATA_0, segment);
- sp_write_reg(anx78xx, TX_P0, AUX_CTRL, 0x04);
- sp_write_reg_and_or(anx78xx, TX_P0, AUX_CTRL2, ~ADDR_ONLY_BIT,
AUX_OP_EN);
- cnt = 0;
- sp_read_reg(anx78xx, TX_P0, AUX_CTRL2, ®val);
- while (regval & AUX_OP_EN) {
usleep_range(1000, 2000);
cnt++;
if (cnt == 10) {
dev_err(dev, "read AUX_CTRL2 failed.\n");
sp_tx_rst_aux(anx78xx);
cnt = 0;
That does not seem necessary...
sp.edid_break = 1;
You are using sp.edid_break as a return value, please return an int and drop that variable.
return;
}
sp_read_reg(anx78xx, TX_P0, AUX_CTRL2, ®val);
- }
- sp_write_reg(anx78xx, TX_P0, AUX_ADDR_7_0, 0x50);
- sp_tx_aux_wr(anx78xx, offset);
- sp_tx_aux_rd(anx78xx, 0xf5);
- cnt = 0;
- for (i = 0; i < 16; i++) {
sp_read_reg(anx78xx, TX_P0, BUF_DATA_COUNT, ®val);
while ((regval & 0x1f) == 0) {
usleep_range(2000, 4000);
cnt++;
sp_read_reg(anx78xx, TX_P0, BUF_DATA_COUNT, ®val);
if (cnt == 10) {
dev_err(dev,
"read BUF_DATA_COUNT failed.\n");
dev_dbg(dev, "read break");
sp_tx_rst_aux(anx78xx);
sp.edid_break = 1;
return;
}
}
sp_read_reg(anx78xx, TX_P0, BUF_DATA_0 + i, ®val);
- }
- sp_write_reg(anx78xx, TX_P0, AUX_CTRL, 0x01);
- sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, ADDR_ONLY_BIT | AUX_OP_EN);
- sp_write_reg_and(anx78xx, TX_P0, AUX_CTRL2, ~ADDR_ONLY_BIT);
- sp_read_reg(anx78xx, TX_P0, AUX_CTRL2, ®val);
- cnt = 0;
- while (regval & AUX_OP_EN) {
usleep_range(1000, 2000);
cnt++;
if (cnt == 10) {
dev_err(dev, "read AUX_CTRL2 failed.\n");
sp_tx_rst_aux(anx78xx);
cnt = 0;
sp.edid_break = 1;
return;
}
sp_read_reg(anx78xx, TX_P0, AUX_CTRL2, ®val);
- }
+}
+static bool sp_edid_checksum_result(u8 *pbuf) +{
- u8 cnt, checksum;
- checksum = 0;
- for (cnt = 0; cnt < 0x80; cnt++)
checksum = checksum + pbuf[cnt];
- sp.edid_checksum = checksum - pbuf[0x7f];
- sp.edid_checksum = ~sp.edid_checksum + 1;
- return checksum == 0 ? 1 : 0;
return checksum == 0;
+}
+static void sp_check_edid_data(struct anx78xx *anx78xx, u8 *pbuf) +{
- struct device *dev = &anx78xx->client->dev;
- u8 i;
- if ((pbuf[0] == 0x00) && (pbuf[1] == 0xff) &&
(pbuf[2] == 0xff) && (pbuf[3] == 0xff) &&
(pbuf[4] == 0xff) && (pbuf[5] == 0xff) &&
(pbuf[6] == 0xff) && (pbuf[7] == 0x00))
dev_dbg(dev, "Good EDID header!\n");
- else
dev_err(dev, "Bad EDID header!\n");
- for (i = 0; i <= (pbuf[0x7e] > 1 ? 1 : pbuf[0x7e]); i++) {
if (!sp_edid_checksum_result(pbuf + i * 128))
dev_err(dev, "Block %x edid checksum error\n", i);
else
dev_dbg(dev, "Block %x edid checksum OK\n", i);
- }
+}
+static void sp_tx_edid_read(struct anx78xx *anx78xx, u8 *pedid_blocks_buf)
pedid_blocks_buf is always sp.edid_blocks.
+{
- struct device *dev = &anx78xx->client->dev;
- u8 offset = 0;
- u8 count, blocks_num;
- u8 pblock_buf[16];
- u8 i, j, regval;
- sp.edid_break = 0;
- sp_tx_edid_read_initial(anx78xx);
- sp_write_reg(anx78xx, TX_P0, AUX_CTRL, 0x04);
- sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, 0x03);
- sp_wait_aux_op_finish(anx78xx, &sp.edid_break);
- sp_tx_addronly_set(anx78xx, 0);
- blocks_num = sp_tx_get_edid_block(anx78xx);
- count = 0;
- do {
switch (count) {
case 0:
case 1:
for (i = 0; i < 8; i++) {
offset = (i + count * 8) * 16;
sp_edid_read(anx78xx, offset, pblock_buf);
if (sp.edid_break == 1)
break;
for (j = 0; j < 16; j++) {
pedid_blocks_buf[offset + j]
= pblock_buf[j];
}
}
break;
case 2:
case 3:
if (count == 2)
offset = 0x00;
else /* count == 3 */
offset = 0x80;
for (j = 0; j < 8; j++) {
if (sp.edid_break == 1)
break;
sp_seg_edid_read(anx78xx, count / 2, offset);
offset = offset + 0x10;
}
break;
default:
break;
}
count++;
if (sp.edid_break == 1)
break;
- } while (blocks_num >= count);
- sp_tx_rst_aux(anx78xx);
- if (sp.read_edid_flag == 0) {
sp_check_edid_data(anx78xx, pedid_blocks_buf);
sp.read_edid_flag = 1;
- }
- sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x18, 1, ®val);
- if (regval & 0x04) {
dev_dbg(dev, "check sum = %.2x\n", sp.edid_checksum);
regval = sp.edid_checksum;
sp_tx_aux_dpcdwrite_bytes(anx78xx, 0x00, 0x02, 0x61, 1,
®val);
sp.tx_test_edid = 1;
regval = 0x04;
sp_tx_aux_dpcdwrite_bytes(anx78xx, 0x00, 0x02, 0x60, 1,
®val);
dev_dbg(dev, "Test EDID done\n");
- }
+}
+static bool sp_check_with_pre_edid(struct anx78xx *anx78xx, u8 *org_buf)
org_buf is always sp.edid_blocks, so I'm not sure what's the point of the parameter.
+{
- struct device *dev = &anx78xx->client->dev;
- u8 i;
- u8 buf[16];
- bool ret = false;
- sp.edid_break = 0;
- sp_tx_edid_read_initial(anx78xx);
- sp_write_reg(anx78xx, TX_P0, AUX_CTRL, 0x04);
- sp_write_reg_or(anx78xx, TX_P0, AUX_CTRL2, 0x03);
- sp_wait_aux_op_finish(anx78xx, &sp.edid_break);
- sp_tx_addronly_set(anx78xx, 0);
- sp_edid_read(anx78xx, 0x70, buf);
- if (sp.edid_break == 0) {
for (i = 0; i < 16; i++) {
if (org_buf[0x70 + i] != buf[i]) {
dev_dbg(dev, "%s\n",
"different checksum and blocks num\n");
goto return_point;
}
}
- } else {
goto return_point;
- }
- sp_edid_read(anx78xx, 0x08, buf);
- if (sp.edid_break == 0) {
for (i = 0; i < 16; i++) {
if (org_buf[i + 8] != buf[i]) {
dev_dbg(dev, "different edid information\n");
goto return_point;
}
}
- } else {
goto return_point;
- }
- ret = true;
+return_point:
- sp_tx_rst_aux(anx78xx);
- return ret;
+}
+static void sp_edid_process(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 temp_value, temp_value1;
- u8 i;
- dev_dbg(dev, "edid_process\n");
- if (sp.read_edid_flag == 1)
if (!sp_check_with_pre_edid(anx78xx, sp.edid_blocks))
sp.read_edid_flag = 0;
- if (sp.read_edid_flag == 0) {
boolean: !sp.read_edid_flag
sp_tx_edid_read(anx78xx, sp.edid_blocks);
if (sp.edid_break)
dev_err(dev, "ERR:EDID corruption!\n");
- }
- /* Release the HPD after the OTP loaddown */
- for (i = 0; i < 10; i++) {
if (sp_i2c_read_byte(anx78xx, TX_P0, HDCP_KEY_STATUS) & 0x01)
break;
dev_dbg(dev, "waiting HDCP KEY loaddown\n");
usleep_range(1000, 2000);
- }
- sp_write_reg(anx78xx, RX_P0, HDMI_RX_INT_MASK1_REG, 0xe2);
- hdmi_rx_set_hpd(anx78xx, 1);
- dev_dbg(dev, "hdmi_rx_set_hpd 1 !\n");
- hdmi_rx_set_termination(anx78xx, 1);
- sp_tx_get_rx_bw(anx78xx, &temp_value);
- dev_dbg(dev, "RX BW %x\n", temp_value);
- temp_value1 = sp_parse_edid_to_get_bandwidth(anx78xx);
- if (temp_value <= temp_value1)
temp_value1 = temp_value;
- dev_dbg(dev, "set link bw in edid %x\n", temp_value1);
- sp.changed_bandwidth = temp_value1;
- goto_next_system_state(anx78xx);
+}
+/******************End EDID process********************/
+/******************start Link training process********************/ +static void sp_tx_lvttl_bit_mapping(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 regval, colorspace;
- u8 vid_bit;
- vid_bit = 0;
- sp_read_reg(anx78xx, RX_P1, HDMI_RX_AVI_DATA00_REG, &colorspace);
- colorspace &= 0x60;
- switch (((sp_i2c_read_byte(anx78xx, RX_P0, HDMI_RX_VIDEO_STATUS_REG1)
& COLOR_DEPTH) >> 4)) {
- default:
- case HDMI_LEGACY:
regval = IN_BPC_8BIT;
vid_bit = 0;
break;
- case HDMI_24BIT:
regval = IN_BPC_8BIT;
if (colorspace == 0x20)
vid_bit = 5;
else
vid_bit = 1;
break;
- case HDMI_30BIT:
regval = IN_BPC_10BIT;
if (colorspace == 0x20)
vid_bit = 6;
else
vid_bit = 2;
break;
- case HDMI_36BIT:
regval = IN_BPC_12BIT;
if (colorspace == 0x20)
vid_bit = 6;
else
vid_bit = 3;
break;
- }
- /*
* For down sample video (12bit, 10bit ---> 8bit),
* this register doesn't change
*/
- if (sp.down_sample_en == 0)
sp_write_reg_and_or(anx78xx, TX_P2,
SP_TX_VID_CTRL2_REG, 0x8c,
colorspace >> 5 | regval);
- /* Patch: for 10bit video must be set this value to 12bit by someone */
- if (sp.down_sample_en == 1 && regval == IN_BPC_10BIT)
vid_bit = 3;
- sp_write_reg_and_or(anx78xx, TX_P2,
BIT_CTRL_SPECIFIC, 0x00,
ENABLE_BIT_CTRL | vid_bit << 1);
- if (sp.tx_test_edid) {
sp_write_reg_and(anx78xx, TX_P2, SP_TX_VID_CTRL2_REG, 0x8f);
dev_dbg(dev, "***color space is set to 18bit***\n");
- }
- if (colorspace) {
sp_write_reg(anx78xx, TX_P0, SP_TX_VID_BLANK_SET1, 0x80);
sp_write_reg(anx78xx, TX_P0, SP_TX_VID_BLANK_SET2, 0x00);
sp_write_reg(anx78xx, TX_P0, SP_TX_VID_BLANK_SET3, 0x80);
- } else {
sp_write_reg(anx78xx, TX_P0, SP_TX_VID_BLANK_SET1, 0x0);
sp_write_reg(anx78xx, TX_P0, SP_TX_VID_BLANK_SET2, 0x0);
sp_write_reg(anx78xx, TX_P0, SP_TX_VID_BLANK_SET3, 0x0);
- }
+}
+static unsigned long sp_tx_pclk_calc(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- unsigned long str_plck;
- u16 vid_counter;
- u8 regval;
- sp_read_reg(anx78xx, RX_P0, PCLK_HR_CNT2, ®val);
- vid_counter = regval << 8;
- sp_read_reg(anx78xx, RX_P0, PCLK_HR_CNT1, ®val);
- vid_counter |= regval;
- str_plck = (vid_counter * pxtal_data[XTAL_27M].xtal_clk_m10) >> 12;
Single space before >>
- dev_dbg(dev, "PCLK = %d.%d\n", (u16)str_plck / 10,
(u16)(str_plck - ((str_plck / 10) * 10)));
str_pclk % 10, and no cast.
- return str_plck;
+}
+static u8 sp_tx_bw_lc_sel(struct anx78xx *anx78xx, unsigned long pclk) +{
- struct device *dev = &anx78xx->client->dev;
- unsigned long pixel_clk;
- u8 link;
- switch (((sp_i2c_read_byte(anx78xx, 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;
- }
- dev_dbg(dev, "pixel_clk = %d.%d\n", (u16)pixel_clk / 10,
(u16)(pixel_clk - ((pixel_clk / 10) * 10)));
See above
- sp.down_sample_en = 0;
- if (pixel_clk <= 530) {
link = LINK_1P62G;
- } else if ((530 < pixel_clk) && (pixel_clk <= 890)) {
(530 < pixel_clk) is not necessary: you checked that just before.
link = LINK_2P7G;
- } else if ((890 < pixel_clk) && (pixel_clk <= 1800)) {
link = LINK_5P4G;
- } else {
link = LINK_6P75G;
if (pixel_clk > 2240)
sp.down_sample_en = 1;
- }
- if (sp_tx_get_link_bw(anx78xx) != link) {
sp.changed_bandwidth = link;
dev_dbg(dev,
"different bandwidth between sink and video %.2x",
link);
return 1;
- }
- return 0;
+}
+static void sp_tx_spread_enable(struct anx78xx *anx78xx, u8 benable) +{
- u8 regval;
- sp_read_reg(anx78xx, TX_P0, SP_TX_DOWN_SPREADING_CTRL1, ®val);
- if (benable) {
regval |= SP_TX_SSC_DWSPREAD;
sp_write_reg(anx78xx, TX_P0, SP_TX_DOWN_SPREADING_CTRL1,
regval);
sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x01,
DPCD_DOWNSPREAD_CTRL, 1, ®val);
regval |= SPREAD_AMPLITUDE;
sp_tx_aux_dpcdwrite_byte(anx78xx, 0x00, 0x01,
DPCD_DOWNSPREAD_CTRL, regval);
- } else {
regval &= ~SP_TX_SSC_DISABLE;
sp_write_reg(anx78xx, TX_P0, SP_TX_DOWN_SPREADING_CTRL1,
regval);
sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x01,
DPCD_DOWNSPREAD_CTRL, 1, ®val);
regval &= ~SPREAD_AMPLITUDE;
sp_tx_aux_dpcdwrite_byte(anx78xx, 0x00, 0x01,
DPCD_DOWNSPREAD_CTRL, regval);
- }
+}
+static void sp_tx_config_ssc(struct anx78xx *anx78xx,
enum sp_ssc_dep sscdep)
+{
- sp_write_reg(anx78xx, TX_P0, SP_TX_DOWN_SPREADING_CTRL1, 0x0);
- sp_write_reg(anx78xx, TX_P0, SP_TX_DOWN_SPREADING_CTRL1, sscdep);
- sp_tx_spread_enable(anx78xx, 1);
+}
+static void sp_tx_enhancemode_set(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 regval;
- sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x00, DPCD_MAX_LANE_COUNT,
1, ®val);
- if (regval & ENHANCED_FRAME_CAP) {
sp_write_reg_or(anx78xx, TX_P0, SP_TX_SYS_CTRL4_REG,
ENHANCED_MODE);
sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x01,
DPCD_LANE_COUNT_SET, 1, ®val);
regval |= ENHANCED_FRAME_EN;
sp_tx_aux_dpcdwrite_byte(anx78xx, 0x00, 0x01,
DPCD_LANE_COUNT_SET, regval);
dev_dbg(dev, "Enhance mode enabled\n");
- } else {
sp_write_reg_and(anx78xx, TX_P0, SP_TX_SYS_CTRL4_REG,
~ENHANCED_MODE);
sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x01,
DPCD_LANE_COUNT_SET, 1, ®val);
regval &= ~ENHANCED_FRAME_EN;
sp_tx_aux_dpcdwrite_byte(anx78xx, 0x00, 0x01,
DPCD_LANE_COUNT_SET, regval);
dev_dbg(dev, "Enhance mode disabled\n");
- }
This could be massively simplfied if you used your bit_ctl wrapper.
+}
+static u16 sp_tx_link_err_check(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u16 errl = 0, errh = 0;
- u8 bytebuf[2];
- sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x10, 2, bytebuf);
- usleep_range(5000, 10000);
- sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x10, 2, bytebuf);
- errh = bytebuf[1];
- if (errh & 0x80) {
errl = bytebuf[0];
errh = (errh & 0x7f) << 8;
errl = errh + errl;
return errl;
Then I think you don't need errh/errl intermediate variables.
- }
- dev_err(dev, " Err of Lane = %d\n", errl);
- return errl;
return 0;
+}
+static void sp_lt_finish(struct anx78xx *anx78xx, u8 temp_value) +{
- struct device *dev = &anx78xx->client->dev;
- sp_tx_aux_dpcdread_bytes(anx78xx, 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(anx78xx)) {
sp_read_reg(anx78xx, TX_P0,
SP_TX_LT_SET_REG, &temp_value);
if (!(temp_value & MAX_PRE_REACH)) {
sp_write_reg(anx78xx, TX_P0,
SP_TX_LT_SET_REG,
temp_value + 0x08);
if (sp_tx_link_err_check(anx78xx))
sp_write_reg(anx78xx, TX_P0,
SP_TX_LT_SET_REG,
temp_value);
}
}
temp_value = sp_tx_get_link_bw(anx78xx);
if (temp_value == sp.changed_bandwidth) {
dev_dbg(dev, "LT succeed, bw: %.2x",
temp_value);
dev_dbg(dev, "Lane0 Set: %.2x\n",
sp_i2c_read_byte(anx78xx, TX_P0,
SP_TX_LT_SET_REG));
sp.tx_lt_state = LT_INIT;
goto_next_system_state(anx78xx);
} else {
dev_dbg(dev, "cur:%.2x, per:%.2x\n",
temp_value,
sp.changed_bandwidth);
sp.tx_lt_state = LT_ERROR;
}
} else {
sp.tx_test_lt = 0;
sp.tx_lt_state = LT_INIT;
goto_next_system_state(anx78xx);
}
- } else {
dev_dbg(dev, "LANE0 Status error: %.2x\n",
temp_value & 0x07);
sp.tx_lt_state = LT_ERROR;
- }
+}
+static void sp_link_training(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 value, regval;
- dev_dbg(dev, "sp.tx_lt_state : %x\n", (int)sp.tx_lt_state);
- switch (sp.tx_lt_state) {
- case LT_INIT:
sp_block_power_ctrl(anx78xx, SP_TX_PWR_VIDEO, SP_POWER_ON);
sp_tx_video_mute(anx78xx, 1);
sp_tx_enable_video_input(anx78xx, 0);
sp.tx_lt_state++;
- /* fallthrough */
- case LT_WAIT_PLL_LOCK:
if (!sp_tx_get_pll_lock_status(anx78xx)) {
sp_read_reg(anx78xx, TX_P0, SP_TX_PLL_CTRL_REG,
&value);
value |= PLL_RST;
sp_write_reg(anx78xx, TX_P0, SP_TX_PLL_CTRL_REG,
value);
value &= ~PLL_RST;
sp_write_reg(anx78xx, TX_P0, SP_TX_PLL_CTRL_REG,
value);
dev_dbg(dev, "PLL not lock!\n");
} else {
sp.tx_lt_state = LT_CHECK_LINK_BW;
}
SP_BREAK(LT_WAIT_PLL_LOCK, sp.tx_lt_state);
These control-flow modifying macros make the code very hard to read, please remove.
- /* fallthrough */
- case LT_CHECK_LINK_BW:
sp_tx_get_rx_bw(anx78xx, &value);
if (value < sp.changed_bandwidth) {
dev_dbg(dev, "****Over bandwidth****\n");
sp.changed_bandwidth = value;
} else {
sp.tx_lt_state++;
}
- /* fallthrough */
- case LT_START:
if (sp.tx_test_lt) {
sp.changed_bandwidth = sp.tx_test_bw;
sp_write_reg_and(anx78xx, TX_P2, SP_TX_VID_CTRL2_REG,
0x8f);
} else {
sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG, 0x00);
}
sp_write_reg_and(anx78xx, TX_P0, SP_TX_ANALOG_PD_REG,
~CH0_PD);
sp_tx_config_ssc(anx78xx, SSC_DEP_4000PPM);
sp_tx_set_link_bw(anx78xx, sp.changed_bandwidth);
sp_tx_enhancemode_set(anx78xx);
sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x00, 0x00, 0x01,
®val);
sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x06, 0x00, 0x01,
&value);
if (regval >= 0x12)
value &= 0xf8;
else
value &= 0xfc;
value |= 0x01;
sp_tx_aux_dpcdwrite_byte(anx78xx, 0x00, 0x06, 0x00, value);
sp_write_reg(anx78xx, 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(anx78xx, TX_P2, RST_CTRL2, SERDES_FIFO_RST);
msleep(20);
sp_write_reg_and(anx78xx, TX_P2, RST_CTRL2, ~SERDES_FIFO_RST);
dev_err(dev, "LT ERROR Status: SERDES FIFO reset.");
redo_cur_system_state(anx78xx);
sp.tx_lt_state = LT_INIT;
break;
- case LT_FINISH:
sp_lt_finish(anx78xx, value);
break;
- default:
break;
- }
+}
+/******************End Link training process********************/
+/******************Start Output video process********************/ +static void sp_tx_set_colorspace(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 color_space;
- if (sp.down_sample_en) {
sp_read_reg(anx78xx, RX_P1, HDMI_RX_AVI_DATA00_REG,
&color_space);
color_space &= 0x60;
if (color_space == 0x20) {
dev_dbg(dev, "YCbCr4:2:2 ---> PASS THROUGH.\n");
sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL6_REG,
0x00);
sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL5_REG,
0x00);
sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL2_REG,
0x11);
} else if (color_space == 0x40) {
dev_dbg(dev, "YCbCr4:4:4 ---> YCbCr4:2:2\n");
sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL6_REG,
0x41);
sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL5_REG,
0x00);
sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL2_REG,
0x12);
} else if (color_space == 0x00) {
dev_dbg(dev, "RGB4:4:4 ---> YCbCr4:2:2\n");
sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL6_REG,
0x41);
sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL5_REG,
0x83);
sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL2_REG,
0x10);
}
- } else {
sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL6_REG, 0x00);
sp_write_reg(anx78xx, TX_P2, SP_TX_VID_CTRL5_REG, 0x00);
- }
+}
+static void sp_tx_avi_setup(struct anx78xx *anx78xx) +{
- u8 regval;
- int i;
- for (i = 0; i < 13; i++) {
sp_read_reg(anx78xx, RX_P1, (HDMI_RX_AVI_DATA00_REG + i),
®val);
sp.tx_packet_avi.avi_data[i] = regval;
- }
+}
+static void sp_tx_load_packet(struct anx78xx *anx78xx,
enum packets_type type)
+{
- int i;
- u8 regval;
- switch (type) {
- case AVI_PACKETS:
sp_write_reg(anx78xx, TX_P2, SP_TX_AVI_TYPE, 0x82);
sp_write_reg(anx78xx, TX_P2, SP_TX_AVI_VER, 0x02);
sp_write_reg(anx78xx, TX_P2, SP_TX_AVI_LEN, 0x0d);
for (i = 0; i < 13; i++) {
sp_write_reg(anx78xx, TX_P2, SP_TX_AVI_DB0 + i,
sp.tx_packet_avi.avi_data[i]);
}
break;
- case SPD_PACKETS:
sp_write_reg(anx78xx, TX_P2, SP_TX_SPD_TYPE, 0x83);
sp_write_reg(anx78xx, TX_P2, SP_TX_SPD_VER, 0x01);
sp_write_reg(anx78xx, TX_P2, SP_TX_SPD_LEN, 0x19);
for (i = 0; i < 25; i++) {
sp_write_reg(anx78xx, TX_P2, SP_TX_SPD_DB0 + i,
sp.tx_packet_spd.spd_data[i]);
}
break;
- case VSI_PACKETS:
sp_write_reg(anx78xx, TX_P2, SP_TX_MPEG_TYPE, 0x81);
sp_write_reg(anx78xx, TX_P2, SP_TX_MPEG_VER, 0x01);
sp_read_reg(anx78xx, RX_P1, HDMI_RX_MPEG_LEN_REG, ®val);
sp_write_reg(anx78xx, TX_P2, SP_TX_MPEG_LEN, regval);
for (i = 0; i < 10; i++) {
sp_write_reg(anx78xx, TX_P2, SP_TX_MPEG_DB0 + i,
sp.tx_packet_mpeg.mpeg_data[i]);
}
break;
- case MPEG_PACKETS:
sp_write_reg(anx78xx, TX_P2, SP_TX_MPEG_TYPE, 0x85);
sp_write_reg(anx78xx, TX_P2, SP_TX_MPEG_VER, 0x01);
sp_write_reg(anx78xx, TX_P2, SP_TX_MPEG_LEN, 0x0d);
for (i = 0; i < 10; i++) {
sp_write_reg(anx78xx, TX_P2, SP_TX_MPEG_DB0 + i,
sp.tx_packet_mpeg.mpeg_data[i]);
}
break;
- case AUDIF_PACKETS:
sp_write_reg(anx78xx, TX_P2, SP_TX_AUD_TYPE, 0x84);
sp_write_reg(anx78xx, TX_P2, SP_TX_AUD_VER, 0x01);
sp_write_reg(anx78xx, TX_P2, SP_TX_AUD_LEN, 0x0a);
for (i = 0; i < 10; i++) {
sp_write_reg(anx78xx, TX_P2, SP_TX_AUD_DB0 + i,
sp.tx_audioinfoframe.pb_byte[i]);
}
break;
- default:
break;
- }
+}
+static void sp_tx_config_packets(struct anx78xx *anx78xx,
enum packets_type type)
+{
- u8 regval;
- switch (type) {
- case AVI_PACKETS:
sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val);
regval &= ~AVI_IF_EN;
sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval);
sp_tx_load_packet(anx78xx, AVI_PACKETS);
sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val);
regval |= AVI_IF_UD;
sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval);
sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val);
regval |= AVI_IF_EN;
sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval);
break;
- case SPD_PACKETS:
sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val);
regval &= ~SPD_IF_EN;
sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval);
sp_tx_load_packet(anx78xx, SPD_PACKETS);
sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val);
regval |= SPD_IF_UD;
sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval);
sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val);
regval |= SPD_IF_EN;
sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval);
break;
- case VSI_PACKETS:
sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val);
regval &= ~MPEG_IF_EN;
sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval);
sp_tx_load_packet(anx78xx, VSI_PACKETS);
sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val);
regval |= MPEG_IF_UD;
sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval);
sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val);
regval |= MPEG_IF_EN;
sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval);
break;
- case MPEG_PACKETS:
sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val);
regval &= ~MPEG_IF_EN;
sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval);
sp_tx_load_packet(anx78xx, MPEG_PACKETS);
sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val);
regval |= MPEG_IF_UD;
sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval);
sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val);
regval |= MPEG_IF_EN;
sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval);
break;
- case AUDIF_PACKETS:
sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val);
regval &= ~AUD_IF_EN;
sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval);
sp_tx_load_packet(anx78xx, AUDIF_PACKETS);
sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val);
regval |= AUD_IF_UP;
sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval);
sp_read_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ®val);
regval |= AUD_IF_EN;
sp_write_reg(anx78xx, TX_P0, SP_TX_PKT_EN_REG, regval);
break;
- default:
break;
- }
+}
+static void sp_config_video_output(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 regval;
- switch (sp.tx_vo_state) {
- default:
- case VO_WAIT_VIDEO_STABLE:
sp_read_reg(anx78xx, RX_P0, HDMI_RX_SYS_STATUS_REG, ®val);
if ((regval & (TMDS_DE_DET | TMDS_CLOCK_DET)) == 0x03) {
0x03? Is that the same as (TMDS_DE_DET | TMDS_CLOCK_DET)?
sp_tx_bw_lc_sel(anx78xx, sp_tx_pclk_calc(anx78xx));
sp_tx_enable_video_input(anx78xx, 0);
sp_tx_avi_setup(anx78xx);
sp_tx_config_packets(anx78xx, AVI_PACKETS);
sp_tx_set_colorspace(anx78xx);
sp_tx_lvttl_bit_mapping(anx78xx);
if (sp_i2c_read_byte(anx78xx, RX_P0, RX_PACKET_REV_STA)
& VSI_RCVD)
sp_hdmi_rx_new_vsi_int(anx78xx);
sp_tx_enable_video_input(anx78xx, 1);
sp.tx_vo_state = VO_WAIT_TX_VIDEO_STABLE;
} else {
dev_dbg(dev, "HDMI input video not stable!\n");
}
SP_BREAK(VO_WAIT_VIDEO_STABLE, sp.tx_vo_state);
- /* fallthrough */
- case VO_WAIT_TX_VIDEO_STABLE:
sp_read_reg(anx78xx, TX_P0, SP_TX_SYS_CTRL2_REG, ®val);
sp_write_reg(anx78xx, TX_P0, SP_TX_SYS_CTRL2_REG, regval);
sp_read_reg(anx78xx, TX_P0, SP_TX_SYS_CTRL2_REG, ®val);
if (regval & CHA_STA) {
dev_dbg(dev, "Stream clock not stable!\n");
} else {
sp_read_reg(anx78xx, TX_P0, SP_TX_SYS_CTRL3_REG,
®val);
sp_write_reg(anx78xx, TX_P0, SP_TX_SYS_CTRL3_REG,
regval);
sp_read_reg(anx78xx, TX_P0, SP_TX_SYS_CTRL3_REG,
®val);
if (!(regval & STRM_VALID))
dev_err(dev, "video stream not valid!\n");
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(anx78xx, sp_tx_pclk_calc(anx78xx)))
sp.tx_vo_state++;
else
sp_tx_set_sys_state(anx78xx, STATE_LINK_TRAINING);
SP_BREAK(VO_CHECK_VIDEO_INFO, sp.tx_vo_state);
- /* fallthrough */
- case VO_FINISH:
sp_block_power_ctrl(anx78xx, SP_TX_PWR_AUDIO, SP_POWER_DOWN);
hdmi_rx_mute_video(anx78xx, 0);
sp_tx_video_mute(anx78xx, 0);
sp_tx_show_information(anx78xx);
goto_next_system_state(anx78xx);
break;
- }
+}
+/******************End Output video process********************/
+/******************Start HDCP process********************/ +static inline void sp_tx_hdcp_encryption_disable(struct anx78xx *anx78xx) +{
- sp_write_reg_and(anx78xx, TX_P0, TX_HDCP_CTRL0, ~ENC_EN);
+}
+static inline void sp_tx_hdcp_encryption_enable(struct anx78xx *anx78xx) +{
- sp_write_reg_or(anx78xx, TX_P0, TX_HDCP_CTRL0, ENC_EN);
+}
+static void sp_tx_hw_hdcp_enable(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 regval;
- sp_write_reg_and(anx78xx, TX_P0, TX_HDCP_CTRL0,
~ENC_EN & ~HARD_AUTH_EN);
- sp_write_reg_or(anx78xx, TX_P0, TX_HDCP_CTRL0,
HARD_AUTH_EN | BKSV_SRM_PASS | KSVLIST_VLD | ENC_EN);
- sp_read_reg(anx78xx, TX_P0, TX_HDCP_CTRL0, ®val);
- dev_dbg(dev, "TX_HDCP_CTRL0 = %.2x\n", regval);
- sp_write_reg(anx78xx, TX_P0, SP_TX_WAIT_R0_TIME, 0xb0);
- sp_write_reg(anx78xx, TX_P0, SP_TX_WAIT_KSVR_TIME, 0xc8);
- dev_dbg(dev, "Hardware HDCP is enabled.\n");
+}
+static void sp_hdcp_process(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- switch (sp.hcdp_state) {
- case HDCP_CAPABLE_CHECK:
sp.ds_vid_stb_cntr = 0;
sp.hdcp_fail_count = 0;
if (is_anx_dongle(anx78xx))
sp.hcdp_state = HDCP_WAITTING_VID_STB;
else
sp.hcdp_state = HDCP_HW_ENABLE;
if (sp.block_en == 0) {
if (sp_hdcp_cap_check(anx78xx) == 0)
sp.hcdp_state = HDCP_NOT_SUPPORT;
}
/*
* Just for debug, pin: P2-2
* There is a switch to disable/enable HDCP.
*/
sp.hcdp_state = HDCP_NOT_SUPPORT;
/*****************************************/
SP_BREAK(HDCP_CAPABLE_CHECK, sp.hcdp_state);
- /* fallthrough */
- case HDCP_WAITTING_VID_STB:
msleep(100);
sp.hcdp_state = HDCP_HW_ENABLE;
SP_BREAK(HDCP_WAITTING_VID_STB, sp.hcdp_state);
- /* fallthrough */
- case HDCP_HW_ENABLE:
sp_tx_video_mute(anx78xx, 1);
sp_tx_clean_hdcp_status(anx78xx);
sp_block_power_ctrl(anx78xx, SP_TX_PWR_HDCP, SP_POWER_DOWN);
msleep(20);
sp_block_power_ctrl(anx78xx, SP_TX_PWR_HDCP, SP_POWER_ON);
sp_write_reg(anx78xx, TX_P2, SP_COMMON_INT_MASK2, 0x01);
msleep(50);
sp_tx_hw_hdcp_enable(anx78xx);
sp.hcdp_state = HDCP_WAITTING_FINISH;
- /* fallthrough */
- case HDCP_WAITTING_FINISH:
break;
- case HDCP_FINISH:
sp_tx_hdcp_encryption_enable(anx78xx);
hdmi_rx_mute_video(anx78xx, 0);
sp_tx_video_mute(anx78xx, 0);
goto_next_system_state(anx78xx);
sp.hcdp_state = HDCP_CAPABLE_CHECK;
dev_dbg(dev, "@@@@@@@hdcp_auth_pass@@@@@@\n");
break;
- case HDCP_FAILED:
if (sp.hdcp_fail_count > 5) {
sp_vbus_power_off(anx78xx);
reg_hardware_reset(anx78xx);
sp.hcdp_state = HDCP_CAPABLE_CHECK;
sp.hdcp_fail_count = 0;
dev_dbg(dev, "*********hdcp_auth_failed*********\n");
} else {
sp.hdcp_fail_count++;
sp.hcdp_state = HDCP_WAITTING_VID_STB;
}
break;
- default:
- case HDCP_NOT_SUPPORT:
dev_dbg(dev, "Sink is not capable HDCP\n");
sp_block_power_ctrl(anx78xx, SP_TX_PWR_HDCP,
SP_POWER_DOWN);
sp_tx_video_mute(anx78xx, 0);
goto_next_system_state(anx78xx);
sp.hcdp_state = HDCP_CAPABLE_CHECK;
break;
- }
+}
+/******************End HDCP process********************/
+/******************Start Audio process********************/ +static void sp_tx_audioinfoframe_setup(struct anx78xx *anx78xx) +{
- int i;
- u8 regval;
- sp_read_reg(anx78xx, RX_P1, HDMI_RX_AUDIO_TYPE_REG, ®val);
- sp.tx_audioinfoframe.type = regval;
- sp_read_reg(anx78xx, RX_P1, HDMI_RX_AUDIO_VER_REG, ®val);
- sp.tx_audioinfoframe.version = regval;
- sp_read_reg(anx78xx, RX_P1, HDMI_RX_AUDIO_LEN_REG, ®val);
- sp.tx_audioinfoframe.length = regval;
- for (i = 0; i < 11; i++) {
sp_read_reg(anx78xx, RX_P1, HDMI_RX_AUDIO_DATA00_REG + i,
®val);
sp.tx_audioinfoframe.pb_byte[i] = regval;
- }
+}
+static void sp_tx_enable_audio_output(struct anx78xx *anx78xx, u8 enable) +{
- u8 regval;
- sp_read_reg(anx78xx, TX_P0, SP_TX_AUD_CTRL, ®val);
- if (enable) {
if (regval & AUD_EN) {
regval &= ~AUD_EN;
sp_write_reg(anx78xx, TX_P0, SP_TX_AUD_CTRL, regval);
}
sp_tx_audioinfoframe_setup(anx78xx);
sp_tx_config_packets(anx78xx, AUDIF_PACKETS);
regval |= AUD_EN;
sp_write_reg(anx78xx, TX_P0, SP_TX_AUD_CTRL, regval);
- } else {
regval &= ~AUD_EN;
sp_write_reg(anx78xx, TX_P0, SP_TX_AUD_CTRL, regval);
sp_write_reg_and(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ~AUD_IF_EN);
- }
+}
+static void sp_tx_config_audio(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 regval;
- int i;
- unsigned long m_aud, ls_clk = 0;
- unsigned long aud_freq = 0;
- sp_block_power_ctrl(anx78xx, SP_TX_PWR_AUDIO, SP_POWER_ON);
- sp_read_reg(anx78xx, RX_P0, AUD_SPDIF_CHST4, ®val);
- switch (regval & 0x0f) {
- case FS_FREQ_44100HZ:
aud_freq = 44100;
break;
- case FS_FREQ_48000HZ:
aud_freq = 48000;
break;
- case FS_FREQ_32000HZ:
aud_freq = 32000;
break;
- case FS_FREQ_88200HZ:
aud_freq = 88200;
break;
- case FS_FREQ_96000HZ:
aud_freq = 96000;
break;
- case FS_FREQ_176400HZ:
aud_freq = 176400;
break;
- case FS_FREQ_192000HZ:
aud_freq = 192000;
break;
- default:
break;
- }
- switch (sp_tx_get_link_bw(anx78xx)) {
- 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;
- }
- dev_dbg(dev, "aud_freq = %ld , LS_CLK = %ld\n", aud_freq, ls_clk);
- m_aud = ((512 * aud_freq) / ls_clk) * 32768;
- m_aud = m_aud + 0x05;
- sp_write_reg(anx78xx, TX_P1, SP_TX_AUD_INTERFACE_CTRL4, m_aud & 0xff);
- m_aud = m_aud >> 8;
- sp_write_reg(anx78xx, TX_P1, SP_TX_AUD_INTERFACE_CTRL5, m_aud & 0xff);
- sp_write_reg(anx78xx, TX_P1, SP_TX_AUD_INTERFACE_CTRL6, 0x00);
- sp_write_reg_and(anx78xx, TX_P1, SP_TX_AUD_INTERFACE_CTRL0,
(u8)~AUD_INTERFACE_DISABLE);
- sp_write_reg_or(anx78xx, TX_P1, SP_TX_AUD_INTERFACE_CTRL2,
M_AUD_ADJUST_ST);
- sp_read_reg(anx78xx, RX_P0, HDMI_STATUS, ®val);
- if (regval & HDMI_AUD_LAYOUT)
sp_write_reg_or(anx78xx, TX_P2, SP_TX_AUD_CH_NUM_REG5,
CH_NUM_8 | AUD_LAYOUT);
- else
sp_write_reg_and(anx78xx, TX_P2, SP_TX_AUD_CH_NUM_REG5,
(u8)~CH_NUM_8 & ~AUD_LAYOUT);
- /* transfer audio chaneel status from HDMI Rx to Slinmport Tx */
- for (i = 0; i < 5; i++) {
sp_read_reg(anx78xx, RX_P0, HDMI_RX_AUD_IN_CH_STATUS1_REG + i,
®val);
sp_write_reg(anx78xx, TX_P2, SP_TX_AUD_CH_STATUS_REG1 + i,
regval);
- }
- /* enable audio */
- sp_tx_enable_audio_output(anx78xx, 1);
+}
+static void sp_config_audio_output(struct anx78xx *anx78xx) +{
- 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(anx78xx, RX_P0, HDMI_STATUS)
& HDMI_MODE)) {
sp.tx_ao_state = AO_INIT;
goto_next_system_state(anx78xx);
}
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(anx78xx, 0);
sp_tx_config_audio(anx78xx);
goto_next_system_state(anx78xx);
break;
- }
+}
+/******************End Audio process********************/
+void sp_initialization(struct anx78xx *anx78xx) +{
- /* Waitting Hot plug event! */
- if (!(sp.common_int_status.common_int[3] & PLUG))
return;
- sp.read_edid_flag = 0;
- /* Power on all modules */
- sp_write_reg(anx78xx, TX_P2, SP_POWERD_CTRL_REG, 0x00);
- /* Driver Version */
- sp_write_reg(anx78xx, TX_P1, FW_VER_REG, FW_VERSION);
- hdmi_rx_initialization(anx78xx);
- sp_tx_initialization(anx78xx);
- msleep(200);
- goto_next_system_state(anx78xx);
+}
+static void sp_hdcp_external_ctrl_flag_monitor(struct anx78xx *anx78xx) +{
- static u8 cur_flag;
- if (sp.block_en != cur_flag) {
cur_flag = sp.block_en;
system_state_change_with_case(anx78xx, STATE_HDCP_AUTH);
- }
+}
+static void sp_state_process(struct anx78xx *anx78xx) +{
- switch (sp.tx_system_state) {
- case STATE_WAITTING_CABLE_PLUG:
sp_waiting_cable_plug_process(anx78xx);
SP_BREAK(STATE_WAITTING_CABLE_PLUG, sp.tx_system_state);
- /* fallthrough */
- case STATE_SP_INITIALIZED:
sp_initialization(anx78xx);
SP_BREAK(STATE_SP_INITIALIZED, sp.tx_system_state);
- /* fallthrough */
- case STATE_SINK_CONNECTION:
sp_sink_connection(anx78xx);
SP_BREAK(STATE_SINK_CONNECTION, sp.tx_system_state);
- /* fallthrough */
- case STATE_PARSE_EDID:
sp_edid_process(anx78xx);
SP_BREAK(STATE_PARSE_EDID, sp.tx_system_state);
- /* fallthrough */
- case STATE_LINK_TRAINING:
sp_link_training(anx78xx);
SP_BREAK(STATE_LINK_TRAINING, sp.tx_system_state);
- /* fallthrough */
- case STATE_VIDEO_OUTPUT:
sp_config_video_output(anx78xx);
SP_BREAK(STATE_VIDEO_OUTPUT, sp.tx_system_state);
- /* fallthrough */
- case STATE_HDCP_AUTH:
sp_hdcp_process(anx78xx);
SP_BREAK(STATE_HDCP_AUTH, sp.tx_system_state);
- /* fallthrough */
- case STATE_AUDIO_OUTPUT:
sp_config_audio_output(anx78xx);
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********************/ +static void sp_tx_int_rec(struct anx78xx *anx78xx) +{
- sp_read_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1,
&sp.common_int_status.common_int[0]);
- sp_write_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1,
sp.common_int_status.common_int[0]);
- sp_read_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1 + 1,
&sp.common_int_status.common_int[1]);
- sp_write_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1 + 1,
sp.common_int_status.common_int[1]);
- sp_read_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1 + 2,
&sp.common_int_status.common_int[2]);
- sp_write_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1 + 2,
sp.common_int_status.common_int[2]);
- sp_read_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1 + 3,
&sp.common_int_status.common_int[3]);
- sp_write_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1 + 3,
sp.common_int_status.common_int[3]);
- sp_read_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1 + 6,
&sp.common_int_status.common_int[4]);
- sp_write_reg(anx78xx, TX_P2, SP_COMMON_INT_STATUS1 + 6,
sp.common_int_status.common_int[4]);
Loop please.
+}
+static void sp_hdmi_rx_int_rec(struct anx78xx *anx78xx) +{
sp_read_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS1_REG,
&sp.hdmi_rx_int_status.hdmi_rx_int[0]);
sp_write_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS1_REG,
sp.hdmi_rx_int_status.hdmi_rx_int[0]);
sp_read_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS2_REG,
&sp.hdmi_rx_int_status.hdmi_rx_int[1]);
sp_write_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS2_REG,
sp.hdmi_rx_int_status.hdmi_rx_int[1]);
sp_read_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS3_REG,
&sp.hdmi_rx_int_status.hdmi_rx_int[2]);
sp_write_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS3_REG,
sp.hdmi_rx_int_status.hdmi_rx_int[2]);
sp_read_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS4_REG,
&sp.hdmi_rx_int_status.hdmi_rx_int[3]);
sp_write_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS4_REG,
sp.hdmi_rx_int_status.hdmi_rx_int[3]);
sp_read_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS5_REG,
&sp.hdmi_rx_int_status.hdmi_rx_int[4]);
sp_write_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS5_REG,
sp.hdmi_rx_int_status.hdmi_rx_int[4]);
sp_read_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS6_REG,
&sp.hdmi_rx_int_status.hdmi_rx_int[5]);
sp_write_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS6_REG,
sp.hdmi_rx_int_status.hdmi_rx_int[5]);
sp_read_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS7_REG,
&sp.hdmi_rx_int_status.hdmi_rx_int[6]);
sp_write_reg(anx78xx, RX_P0, HDMI_RX_INT_STATUS7_REG,
sp.hdmi_rx_int_status.hdmi_rx_int[6]);
Loop.
+}
+static void sp_int_rec(struct anx78xx *anx78xx) +{
- sp_tx_int_rec(anx78xx);
- sp_hdmi_rx_int_rec(anx78xx);
+}
+/******************End INT process********************/
+/******************Start task process********************/ +static void sp_tx_pll_changed_int_handler(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- if (sp.tx_system_state >= STATE_LINK_TRAINING) {
if (!sp_tx_get_pll_lock_status(anx78xx)) {
dev_dbg(dev, "PLL:PLL not lock!\n");
sp_tx_set_sys_state(anx78xx, STATE_LINK_TRAINING);
}
- }
+}
+static void sp_tx_hdcp_link_chk_fail_handler(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- system_state_change_with_case(anx78xx, STATE_HDCP_AUTH);
- dev_dbg(dev, "hdcp_link_chk_fail:HDCP Sync lost!\n");
+}
+static void sp_tx_phy_auto_test(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 b_sw;
- u8 bytebuf[16];
- /* DPCD 0x219 TEST_LINK_RATE */
- sp_tx_aux_dpcdread_bytes(anx78xx, 0x0, 0x02, 0x19, 1, bytebuf);
- dev_dbg(dev, "DPCD:0x00219 = %.2x\n", bytebuf[0]);
- switch (bytebuf[0]) {
- case LINK_1P62G:
- case LINK_2P7G:
- case LINK_5P4G:
- case LINK_6P75G:
sp_tx_set_link_bw(anx78xx, bytebuf[0]);
sp.tx_test_bw = bytebuf[0];
break;
- default:
sp_tx_set_link_bw(anx78xx, LINK_6P75G);
sp.tx_test_bw = LINK_6P75G;
break;
- }
- /* DPCD 0x248 PHY_TEST_PATTERN */
- sp_tx_aux_dpcdread_bytes(anx78xx, 0x0, 0x02, 0x48, 1, bytebuf);
- dev_dbg(dev, "DPCD:0x00248 = %.2x\n", bytebuf[0]);
- switch (bytebuf[0]) {
- case 0:
break;
- case 1:
sp_write_reg(anx78xx, TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x04);
break;
- case 2:
sp_write_reg(anx78xx, TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x08);
break;
- case 3:
sp_write_reg(anx78xx, TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x0c);
break;
- case 4:
sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x50, 0xa,
bytebuf);
sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG0,
bytebuf[0]);
sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG1,
bytebuf[1]);
sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG2,
bytebuf[2]);
sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG3,
bytebuf[3]);
sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG4,
bytebuf[4]);
sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG5,
bytebuf[5]);
sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG6,
bytebuf[6]);
sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG7,
bytebuf[7]);
sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG8,
bytebuf[8]);
sp_write_reg(anx78xx, TX_P1, SP_TX_LT_TEST_PATTERN_REG9,
bytebuf[9]);
Loop.
sp_write_reg(anx78xx, TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x30);
break;
- case 5:
sp_write_reg(anx78xx, TX_P0, ADDR_DP_CEP_TRAINING_CTRL0, 0x00);
sp_write_reg(anx78xx, TX_P0, ADDR_DP_CEP_TRAINING_CTRL1, 0x01);
sp_write_reg(anx78xx, TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x14);
break;
- }
- sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x00, 0x03, 1, bytebuf);
- dev_dbg(dev, "DPCD:0x00003 = %.2x\n", bytebuf[0]);
- if (bytebuf[0] & 0x01)
sp_tx_config_ssc(anx78xx, SSC_DEP_4000PPM);
- else
sp_tx_spread_enable(anx78xx, 0);
- /* get swing and emphasis adjust request */
- sp_read_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG, &b_sw);
- sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x06, 1, bytebuf);
- dev_dbg(dev, "DPCD:0x00206 = %.2x\n", bytebuf[0]);
- switch (bytebuf[0] & 0x0f) {
- case 0x00:
sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG,
(b_sw & ~TX_SW_SET_MASK) | 0x00);
break;
- case 0x01:
sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG,
(b_sw & ~TX_SW_SET_MASK) | 0x01);
break;
- case 0x02:
sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG,
(b_sw & ~TX_SW_SET_MASK) | 0x02);
break;
- case 0x03:
sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG,
(b_sw & ~TX_SW_SET_MASK) | 0x03);
break;
Those 4 are just | (bytebuf[0] & 0x0f)
- case 0x04:
sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG,
(b_sw & ~TX_SW_SET_MASK) | 0x08);
break;
- case 0x05:
sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG,
(b_sw & ~TX_SW_SET_MASK) | 0x09);
break;
- case 0x06:
sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG,
(b_sw & ~TX_SW_SET_MASK) | 0x0a);
break;
Those 4 are | ((bytebuf[0] & 0x0f) + 4)
- case 0x08:
sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG,
(b_sw & ~TX_SW_SET_MASK) | 0x10);
break;
- case 0x09:
sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG,
(b_sw & ~TX_SW_SET_MASK) | 0x11);
break;
- case 0x0c:
sp_write_reg(anx78xx, TX_P0, SP_TX_LT_SET_REG,
(b_sw & ~TX_SW_SET_MASK) | 0x18);
break;
- default:
break;
- }
+}
+static void sp_hpd_irq_process(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 regval;
- u8 test_vector;
- u8 data_buf[6];
- sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x00, 6, data_buf);
- dev_dbg(dev, "+++++++++++++Get HPD IRQ %x\n", (int)data_buf[1]);
- if (data_buf[1] != 0)
sp_tx_aux_dpcdwrite_bytes(anx78xx, 0x00, 0x02,
DPCD_SERVICE_IRQ_VECTOR, 1,
&data_buf[1]);
- /* HDCP IRQ */
- if (data_buf[1] & CP_IRQ) {
if (sp.hcdp_state > HDCP_WAITTING_FINISH ||
sp.tx_system_state > STATE_HDCP_AUTH) {
sp_tx_aux_dpcdread_bytes(anx78xx, 0x06, 0x80, 0x29, 1,
®val);
if (regval & 0x04) {
system_state_change_with_case(anx78xx,
STATE_HDCP_AUTH);
dev_dbg(dev, "IRQ:_______HDCP Sync lost!\n");
}
}
- }
- /* AUTOMATED TEST IRQ */
- if (data_buf[1] & TEST_IRQ) {
sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x18, 1,
&test_vector);
if (test_vector & 0x01) {
sp.tx_test_lt = 1;
sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x19, 1,
®val);
switch (regval) {
case LINK_1P62G:
case LINK_2P7G:
case LINK_5P4G:
case LINK_6P75G:
sp_tx_set_link_bw(anx78xx, regval);
sp.tx_test_bw = regval;
break;
default:
sp_tx_set_link_bw(anx78xx, LINK_6P75G);
sp.tx_test_bw = LINK_6P75G;
break;
}
dev_dbg(dev, " test_bw = %.2x\n", sp.tx_test_bw);
sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x60, 1,
®val);
regval = regval | TEST_ACK;
sp_tx_aux_dpcdwrite_bytes(anx78xx, 0x00, 0x02, 0x60, 1,
®val);
dev_dbg(dev, "Set TEST_ACK!\n");
if (sp.tx_system_state >= STATE_LINK_TRAINING) {
sp.tx_lt_state = LT_INIT;
sp_tx_set_sys_state(anx78xx,
STATE_LINK_TRAINING);
}
dev_dbg(dev, "IRQ:test-LT request!\n");
}
if (test_vector & 0x02) {
sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x60, 1,
®val);
regval = regval | TEST_ACK;
sp_tx_aux_dpcdwrite_bytes(anx78xx, 0x00, 0x02, 0x60, 1,
®val);
}
if (test_vector & 0x04) {
if (sp.tx_system_state > STATE_PARSE_EDID)
sp_tx_set_sys_state(anx78xx, STATE_PARSE_EDID);
sp.tx_test_edid = 1;
dev_dbg(dev, "Test EDID Requested!\n");
}
if (test_vector & 0x08) {
sp.tx_test_lt = 1;
sp_tx_phy_auto_test(anx78xx);
sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x02, 0x60, 1,
®val);
regval = regval | 0x01;
sp_tx_aux_dpcdwrite_bytes(anx78xx, 0x00, 0x02, 0x60, 1,
®val);
}
- }
- if (sp.tx_system_state > STATE_LINK_TRAINING) {
if (!(data_buf[4] & 0x01) ||
((data_buf[2] & (0x01 | 0x04)) != 0x05)) {
& 0x05) != 0x05
sp_tx_set_sys_state(anx78xx, STATE_LINK_TRAINING);
dev_dbg(dev, "INT:re-LT request!\n");
return;
}
dev_dbg(dev, "Lane align %x\n", data_buf[4]);
dev_dbg(dev, "Lane clock recovery %x\n", data_buf[2]);
- }
+}
+static void sp_tx_vsi_setup(struct anx78xx *anx78xx) +{
- u8 regval;
- int i;
- for (i = 0; i < 10; i++) {
sp_read_reg(anx78xx, RX_P1, (HDMI_RX_MPEG_DATA00_REG + i),
No parentheses.
®val);
sp.tx_packet_mpeg.mpeg_data[i] = regval;
- }
+}
+static void sp_tx_mpeg_setup(struct anx78xx *anx78xx) +{
- u8 regval;
- int i;
- for (i = 0; i < 10; i++) {
sp_read_reg(anx78xx, RX_P1, (HDMI_RX_MPEG_DATA00_REG + i),
®val);
sp.tx_packet_mpeg.mpeg_data[i] = regval;
- }
+}
+static void sp_tx_auth_done_int_handler(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 bytebuf[2];
- if (sp.hcdp_state > HDCP_HW_ENABLE &&
sp.tx_system_state == STATE_HDCP_AUTH) {
sp_read_reg(anx78xx, TX_P0, SP_TX_HDCP_STATUS, bytebuf);
if (bytebuf[0] & SP_TX_HDCP_AUTH_PASS) {
sp_tx_aux_dpcdread_bytes(anx78xx, 0x06, 0x80, 0x2a, 2,
bytebuf);
if ((bytebuf[1] & 0x08) || (bytebuf[0] & 0x80)) {
dev_dbg(dev, "max cascade/devs exceeded!\n");
sp_tx_hdcp_encryption_disable(anx78xx);
} else
dev_dbg(dev, "%s\n",
"Authentication pass in Auth_Done");
sp.hcdp_state = HDCP_FINISH;
} else {
dev_err(dev, "Authentication failed in AUTH_done\n");
sp_tx_video_mute(anx78xx, 1);
sp_tx_clean_hdcp_status(anx78xx);
sp.hcdp_state = HDCP_FAILED;
}
- }
+}
+static void sp_tx_lt_done_int_handler(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 regval;
- if (sp.tx_lt_state == LT_WAITTING_FINISH &&
sp.tx_system_state == STATE_LINK_TRAINING) {
sp_read_reg(anx78xx, TX_P0, LT_CTRL, ®val);
if (regval & 0x70) {
regval = (regval & 0x70) >> 4;
dev_dbg(dev, "LT failed in interrupt, ERR = %.2x\n",
regval);
sp.tx_lt_state = LT_ERROR;
} else {
dev_dbg(dev, "lt_done: LT Finish\n");
sp.tx_lt_state = LT_FINISH;
}
- }
+}
+static void sp_hdmi_rx_clk_det_int(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- dev_dbg(dev, "*HDMI_RX Interrupt: Pixel Clock Change.\n");
- if (sp.tx_system_state > STATE_VIDEO_OUTPUT) {
sp_tx_video_mute(anx78xx, 1);
sp_tx_enable_audio_output(anx78xx, 0);
sp_tx_set_sys_state(anx78xx, STATE_VIDEO_OUTPUT);
- }
+}
+static void sp_hdmi_rx_hdmi_dvi_int(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 regval;
- dev_dbg(dev, "sp_hdmi_rx_hdmi_dvi_int.\n");
- sp_read_reg(anx78xx, RX_P0, HDMI_STATUS, ®val);
- sp.hdmi_dvi_status = 1;
= 1? What does that mean?
- if ((regval & BIT(0)) != (sp.hdmi_dvi_status & BIT(0))) {
!= 1: you assigned that variable just above...
dev_dbg(dev, "hdmi_dvi_int: Is HDMI MODE: %x.\n",
regval & HDMI_MODE);
sp.hdmi_dvi_status = regval & BIT(0);
hdmi_rx_mute_audio(anx78xx, 1);
system_state_change_with_case(anx78xx, STATE_LINK_TRAINING);
- }
+}
+static void sp_hdmi_rx_new_avi_int(struct anx78xx *anx78xx) +{
- sp_tx_lvttl_bit_mapping(anx78xx);
- sp_tx_set_colorspace(anx78xx);
- sp_tx_avi_setup(anx78xx);
- sp_tx_config_packets(anx78xx, AVI_PACKETS);
+}
+static void sp_hdmi_rx_new_vsi_int(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 hdmi_video_format, v3d_structure;
- sp_write_reg_and(anx78xx, TX_P0, SP_TX_3D_VSC_CTRL,
~INFO_FRAME_VSC_EN);
- /* VSI package header */
- if ((sp_i2c_read_byte(anx78xx, RX_P1,
HDMI_RX_MPEG_TYPE_REG) != 0x81) ||
(sp_i2c_read_byte(anx78xx, RX_P1, HDMI_RX_MPEG_VER_REG) != 0x01))
return;
- dev_dbg(dev, "Setup VSI package!\n");
- sp_tx_vsi_setup(anx78xx);
- sp_tx_config_packets(anx78xx, VSI_PACKETS);
- sp_read_reg(anx78xx, RX_P1, HDMI_RX_MPEG_DATA03_REG,
&hdmi_video_format);
- if ((hdmi_video_format & 0xe0) == 0x40) {
dev_dbg(dev, "3D VSI packet detected. Config VSC packet\n");
sp_read_reg(anx78xx, 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;
dev_dbg(dev, "3D structure is not supported\n");
break;
}
sp_write_reg(anx78xx, TX_P0, SP_TX_VSC_DB1, v3d_structure);
- }
- sp_write_reg_or(anx78xx, TX_P0, SP_TX_3D_VSC_CTRL, INFO_FRAME_VSC_EN);
- sp_write_reg_and(anx78xx, TX_P0, SP_TX_PKT_EN_REG, ~SPD_IF_EN);
- sp_write_reg_or(anx78xx, TX_P0, SP_TX_PKT_EN_REG, SPD_IF_UD);
- sp_write_reg_or(anx78xx, TX_P0, SP_TX_PKT_EN_REG, SPD_IF_EN);
+}
+static void sp_hdmi_rx_no_vsi_int(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 regval;
- sp_read_reg(anx78xx, TX_P0, SP_TX_3D_VSC_CTRL, ®val);
- if (regval & INFO_FRAME_VSC_EN) {
dev_dbg(dev, "No new VSI is received, disable VSC packet\n");
regval &= ~INFO_FRAME_VSC_EN;
sp_write_reg(anx78xx, TX_P0, SP_TX_3D_VSC_CTRL, regval);
sp_tx_mpeg_setup(anx78xx);
sp_tx_config_packets(anx78xx, MPEG_PACKETS);
- }
+}
+static inline void sp_hdmi_rx_restart_audio_chk(struct anx78xx *anx78xx) +{
- system_state_change_with_case(anx78xx, STATE_AUDIO_OUTPUT);
+}
+static void sp_hdmi_rx_cts_rcv_int(struct anx78xx *anx78xx) +{
- 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 sp_hdmi_rx_audio_rcv_int(struct anx78xx *anx78xx) +{
- 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 sp_hdmi_rx_audio_samplechg_int(struct anx78xx *anx78xx) +{
- u16 i;
- u8 regval;
- /* transfer audio chaneel status from HDMI Rx to Slinmport Tx */
channel? Slimport?
- for (i = 0; i < 5; i++) {
sp_read_reg(anx78xx, RX_P0, HDMI_RX_AUD_IN_CH_STATUS1_REG + i,
®val);
sp_write_reg(anx78xx, TX_P2, SP_TX_AUD_CH_STATUS_REG1 + i,
regval);
- }
+}
+static void sp_hdmi_rx_hdcp_error_int(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- static u8 count;
- dev_dbg(dev, "*HDMI_RX Interrupt: hdcp error.\n");
- if (count >= 40) {
count = 0;
dev_dbg(dev, "Lots of hdcp error occurred ...\n");
hdmi_rx_mute_audio(anx78xx, 1);
hdmi_rx_mute_video(anx78xx, 1);
hdmi_rx_set_hpd(anx78xx, 0);
usleep_range(10000, 11000);
hdmi_rx_set_hpd(anx78xx, 1);
- } else {
count++;
- }
+}
+static void sp_hdmi_rx_new_gcp_int(struct anx78xx *anx78xx) +{
- u8 regval;
- sp_read_reg(anx78xx, RX_P1, HDMI_RX_GENERAL_CTRL, ®val);
- if (regval & SET_AVMUTE) {
hdmi_rx_mute_video(anx78xx, 1);
hdmi_rx_mute_audio(anx78xx, 1);
- } else if (regval & CLEAR_AVMUTE) {
hdmi_rx_mute_video(anx78xx, 0);
hdmi_rx_mute_audio(anx78xx, 0);
- }
+}
+static void sp_tx_hpd_int_handler(struct anx78xx *anx78xx, u8 hpd_source)
I'd split this function in 2 parts, one for LOST, the other for CHANGE, since they do not share any code anyway.
+{
- struct device *dev = &anx78xx->client->dev;
- switch (hpd_source) {
- case HPD_LOST:
hdmi_rx_set_hpd(anx78xx, 0);
sp_tx_set_sys_state(anx78xx, STATE_WAITTING_CABLE_PLUG);
break;
- case HPD_CHANGE:
dev_dbg(dev, "HPD:____________HPD changed!\n");
usleep_range(2000, 4000);
if (sp.common_int_status.common_int[3] & HPD_IRQ)
sp_hpd_irq_process(anx78xx);
if (sp_i2c_read_byte(anx78xx, TX_P0,
SP_TX_SYS_CTRL3_REG) & HPD_STATUS) {
if (sp.common_int_status.common_int[3] & HPD_IRQ)
sp_hpd_irq_process(anx78xx);
} else {
if (sp_i2c_read_byte(anx78xx, TX_P0,
SP_TX_SYS_CTRL3_REG) &
HPD_STATUS) {
hdmi_rx_set_hpd(anx78xx, 0);
sp_tx_set_sys_state(anx78xx,
STATE_WAITTING_CABLE_PLUG);
}
}
break;
- case PLUG:
This case is never called.
dev_dbg(dev, "HPD:____________HPD changed!\n");
if (sp.tx_system_state < STATE_SP_INITIALIZED)
sp_tx_set_sys_state(anx78xx, STATE_SP_INITIALIZED);
break;
- default:
break;
- }
+}
+static void sp_system_isr_handler(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- if (sp.common_int_status.common_int[3] & HPD_CHANGE)
sp_tx_hpd_int_handler(anx78xx, HPD_CHANGE);
- if (sp.common_int_status.common_int[3] & HPD_LOST)
sp_tx_hpd_int_handler(anx78xx, HPD_LOST);
- if (sp.common_int_status.common_int[3] & HPD_IRQ)
dev_dbg(dev, "++++++++++++++++========HDCP_IRQ interrupt\n");
- if (sp.common_int_status.common_int[0] & PLL_LOCK_CHG)
sp_tx_pll_changed_int_handler(anx78xx);
- if (sp.common_int_status.common_int[1] & HDCP_AUTH_DONE)
sp_tx_auth_done_int_handler(anx78xx);
- if (sp.common_int_status.common_int[2] & HDCP_LINK_CHECK_FAIL)
sp_tx_hdcp_link_chk_fail_handler(anx78xx);
- if (sp.common_int_status.common_int[4] & TRAINING_FINISH)
sp_tx_lt_done_int_handler(anx78xx);
- if (sp.tx_system_state > STATE_SINK_CONNECTION) {
if (sp.hdmi_rx_int_status.hdmi_rx_int[5] & NEW_AVI)
sp_hdmi_rx_new_avi_int(anx78xx);
- }
- if (sp.tx_system_state > STATE_VIDEO_OUTPUT) {
if (sp.hdmi_rx_int_status.hdmi_rx_int[6] & NEW_VS) {
sp.hdmi_rx_int_status.hdmi_rx_int[6] &= ~NO_VSI;
sp_hdmi_rx_new_vsi_int(anx78xx);
}
if (sp.hdmi_rx_int_status.hdmi_rx_int[6] & NO_VSI)
sp_hdmi_rx_no_vsi_int(anx78xx);
- }
- if (sp.tx_system_state >= STATE_VIDEO_OUTPUT) {
if (sp.hdmi_rx_int_status.hdmi_rx_int[0] & CKDT_CHANGE)
sp_hdmi_rx_clk_det_int(anx78xx);
if (sp.hdmi_rx_int_status.hdmi_rx_int[0] & SCDT_CHANGE)
dev_dbg(dev, "*HDMI_RX Interrupt: Sync Detect.\n");
if (sp.hdmi_rx_int_status.hdmi_rx_int[0] & HDMI_DVI)
sp_hdmi_rx_hdmi_dvi_int(anx78xx);
if ((sp.hdmi_rx_int_status.hdmi_rx_int[5] & NEW_AUD) ||
(sp.hdmi_rx_int_status.hdmi_rx_int[2] & AUD_MODE_CHANGE))
sp_hdmi_rx_restart_audio_chk(anx78xx);
if (sp.hdmi_rx_int_status.hdmi_rx_int[5] & CTS_RCV)
sp_hdmi_rx_cts_rcv_int(anx78xx);
if (sp.hdmi_rx_int_status.hdmi_rx_int[4] & AUDIO_RCV)
sp_hdmi_rx_audio_rcv_int(anx78xx);
if (sp.hdmi_rx_int_status.hdmi_rx_int[1] & HDCP_ERR)
sp_hdmi_rx_hdcp_error_int(anx78xx);
if (sp.hdmi_rx_int_status.hdmi_rx_int[5] & NEW_CP)
sp_hdmi_rx_new_gcp_int(anx78xx);
if (sp.hdmi_rx_int_status.hdmi_rx_int[1] & AUDIO_SAMPLE_CHANGE)
sp_hdmi_rx_audio_samplechg_int(anx78xx);
- }
+}
+static void sp_tx_show_information(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 regval, regval1;
- u16 h_res, h_act, v_res, v_act;
- u16 h_fp, h_sw, h_bp, v_fp, v_sw, v_bp;
- unsigned long fresh_rate;
- unsigned long pclk;
- dev_dbg(dev, "\n************* SP Video Information **************\n");
- switch (sp_tx_get_link_bw(anx78xx)) {
- case LINK_1P62G:
dev_dbg(dev, "BW = 1.62G\n");
break;
- case LINK_2P7G:
dev_dbg(dev, "BW = 2.7G\n");
break;
- case LINK_5P4G:
dev_dbg(dev, "BW = 5.4G\n");
break;
- case LINK_6P75G:
dev_dbg(dev, "BW = 6.75G\n");
break;
- default:
break;
- }
- pclk = sp_tx_pclk_calc(anx78xx);
- pclk = pclk / 10;
- sp_read_reg(anx78xx, TX_P2, SP_TX_TOTAL_LINE_STA_L, ®val);
- sp_read_reg(anx78xx, TX_P2, SP_TX_TOTAL_LINE_STA_H, ®val1);
- v_res = regval1;
- v_res = v_res << 8;
- v_res = v_res + regval;
- sp_read_reg(anx78xx, TX_P2, SP_TX_ACT_LINE_STA_L, ®val);
- sp_read_reg(anx78xx, TX_P2, SP_TX_ACT_LINE_STA_H, ®val1);
- v_act = regval1;
- v_act = v_act << 8;
- v_act = v_act + regval;
- sp_read_reg(anx78xx, TX_P2, SP_TX_TOTAL_PIXEL_STA_L, ®val);
- sp_read_reg(anx78xx, TX_P2, SP_TX_TOTAL_PIXEL_STA_H, ®val1);
- h_res = regval1;
- h_res = h_res << 8;
- h_res = h_res + regval;
- sp_read_reg(anx78xx, TX_P2, SP_TX_ACT_PIXEL_STA_L, ®val);
- sp_read_reg(anx78xx, TX_P2, SP_TX_ACT_PIXEL_STA_H, ®val1);
- h_act = regval1;
- h_act = h_act << 8;
- h_act = h_act + regval;
- sp_read_reg(anx78xx, TX_P2, SP_TX_H_F_PORCH_STA_L, ®val);
- sp_read_reg(anx78xx, TX_P2, SP_TX_H_F_PORCH_STA_H, ®val1);
- h_fp = regval1;
- h_fp = h_fp << 8;
- h_fp = h_fp + regval;
- sp_read_reg(anx78xx, TX_P2, SP_TX_H_SYNC_STA_L, ®val);
- sp_read_reg(anx78xx, TX_P2, SP_TX_H_SYNC_STA_H, ®val1);
- h_sw = regval1;
- h_sw = h_sw << 8;
- h_sw = h_sw + regval;
- sp_read_reg(anx78xx, TX_P2, SP_TX_H_B_PORCH_STA_L, ®val);
- sp_read_reg(anx78xx, TX_P2, SP_TX_H_B_PORCH_STA_H, ®val1);
- h_bp = regval1;
- h_bp = h_bp << 8;
- h_bp = h_bp + regval;
- sp_read_reg(anx78xx, TX_P2, SP_TX_V_F_PORCH_STA, ®val);
- v_fp = regval;
- sp_read_reg(anx78xx, TX_P2, SP_TX_V_SYNC_STA, ®val);
- v_sw = regval;
- sp_read_reg(anx78xx, TX_P2, SP_TX_V_B_PORCH_STA, ®val);
- v_bp = regval;
- dev_dbg(dev, "Total resolution is %d * %d\n", h_res, v_res);
- dev_dbg(dev, "HF=%d, HSW=%d, HBP=%d\n", h_fp, h_sw, h_bp);
- dev_dbg(dev, "VF=%d, VSW=%d, VBP=%d\n", v_fp, v_sw, v_bp);
- dev_dbg(dev, "Active resolution is %d * %d", 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;
- }
- dev_dbg(dev, " @ %ldHz\n", fresh_rate);
- sp_read_reg(anx78xx, TX_P0, SP_TX_VID_CTRL, ®val);
- if ((regval & 0x06) == 0x00)
dev_dbg(dev, "ColorSpace: RGB,");
- else if ((regval & 0x06) == 0x02)
dev_dbg(dev, "ColorSpace: YCbCr422,");
- else if ((regval & 0x06) == 0x04)
dev_dbg(dev, "ColorSpace: YCbCr444,");
- sp_read_reg(anx78xx, TX_P0, SP_TX_VID_CTRL, ®val);
- if ((regval & 0xe0) == 0x00)
dev_dbg(dev, "6 BPC\n");
- else if ((regval & 0xe0) == 0x20)
dev_dbg(dev, "8 BPC\n");
- else if ((regval & 0xe0) == 0x40)
dev_dbg(dev, "10 BPC\n");
- else if ((regval & 0xe0) == 0x60)
dev_dbg(dev, "12 BPC\n");
- if (is_anx_dongle(anx78xx)) {
sp_tx_aux_dpcdread_bytes(anx78xx, 0x00, 0x05, 0x23, 1, ®val);
dev_dbg(dev, "Analogix Dongle FW Ver %.2x\n", regval & 0x7f);
- }
- dev_dbg(dev, "\n**************************************************\n");
+}
+static void sp_clean_system_status(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- if (sp.need_clean_status) {
dev_dbg(dev, "sp_clean_system_status. A -> B;\n");
dev_dbg(dev, "A:");
sp_print_system_state(anx78xx, sp.tx_system_state_bak);
dev_dbg(dev, "B:");
sp_print_system_state(anx78xx, sp.tx_system_state);
sp.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(anx78xx, 1);
} else {
hdmi_rx_mute_video(anx78xx, 1);
sp_tx_video_mute(anx78xx, 1);
}
}
if (sp.tx_system_state_bak >= STATE_HDCP_AUTH &&
sp.tx_system_state <= STATE_HDCP_AUTH) {
if (sp_i2c_read_byte(anx78xx, TX_P0, TX_HDCP_CTRL0)
& 0xfc)
sp_tx_clean_hdcp_status(anx78xx);
}
if (sp.hcdp_state != HDCP_CAPABLE_CHECK)
sp.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********************/ +static u8 sp_hdcp_cap_check(struct anx78xx *anx78xx) +{
- struct device *dev = &anx78xx->client->dev;
- u8 g_hdcp_cap = 0;
- u8 value;
- if (sp_tx_aux_dpcdread_bytes(anx78xx, 0x06, 0x80, 0x28, 1, &value) == 0)
g_hdcp_cap = value & 0x01;
- else
dev_dbg(dev, "HDCP CAPABLE: read AUX err!\n");
- dev_dbg(dev, "hdcp cap check: %s Supported\n",
g_hdcp_cap ? "" : "No");
- return g_hdcp_cap;
+}
+/******************End HDCP cap check********************/
+static void sp_tasks_handler(struct anx78xx *anx78xx) +{
- sp_system_isr_handler(anx78xx);
- sp_hdcp_external_ctrl_flag_monitor(anx78xx);
- sp_clean_system_status(anx78xx);
- /*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 sp_main_process(struct anx78xx *anx78xx) +{
- sp_state_process(anx78xx);
- if (sp.tx_system_state > STATE_WAITTING_CABLE_PLUG) {
sp_int_rec(anx78xx);
sp_tasks_handler(anx78xx);
- }
+} diff --git a/drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.h b/drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.h new file mode 100644 index 0000000..04dbe06 --- /dev/null +++ b/drivers/gpu/drm/bridge/anx78xx/slimport_tx_drv.h @@ -0,0 +1,214 @@ +/*
- 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_TX_DRV_H +#define __SLIMPORT_TX_DRV_H
+#include "anx78xx.h" +#include "slimport_tx_reg.h"
+#define FW_VERSION 0x22
+#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; }
Please remove these control flow macros...
+enum rx_cbl_type {
- DWN_STRM_IS_NULL,
DOWN_STREAM_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_FAILED,
- 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 anx78xx_clock_data {
- unsigned char xtal_clk;
- unsigned int xtal_clk_m10;
+};
+bool sp_chip_detect(struct anx78xx *anx78xx);
+void sp_main_process(struct anx78xx *anx78xx);
+void sp_tx_variable_init(void);
+enum sp_tx_state sp_tx_current_state(void);
+void sp_tx_clean_state_machine(void);
+#endif diff --git a/drivers/gpu/drm/bridge/anx78xx/slimport_tx_reg.h b/drivers/gpu/drm/bridge/anx78xx/slimport_tx_reg.h new file mode 100644 index 0000000..56b575c --- /dev/null +++ b/drivers/gpu/drm/bridge/anx78xx/slimport_tx_reg.h @@ -0,0 +1,807 @@ +/*
- 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_TX_REG_DEF_H +#define __SLIMPORT_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
+/* Pixel Clock High Resolution Counter Register 1 */ +#define PCLK_HR_CNT1 0x8c +/* Pixel Clock High Resolution Counter Register 2 */ +#define PCLK_HR_CNT2 0x8d
+#define HDMI_RX_AUD_IN_CH_STATUS1_REG 0xc7
+/* Audio in S/PDIF Channel Status Register 4 */ +#define AUD_SPDIF_CHST4 0xca +#define FS_FREQ_44100HZ 0x00 +#define FS_FREQ_48000HZ 0x02 +#define FS_FREQ_32000HZ 0x03 +#define FS_FREQ_88200HZ 0x08 +#define FS_FREQ_96000HZ 0x0a +#define FS_FREQ_176400HZ 0x0c +#define FS_FREQ_192000HZ 0x0e
+#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_BW_SET_MASK 0x0f +#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 TX_SW_SET_MASK 0x1b +#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 ADDR_DP_CEP_TRAINING_CTRL0 0xa9 +#define ADDR_DP_CEP_TRAINING_CTRL1 0xaa +#define ADDR_DP_CEP_TRAINING_CTRL2 0xab
+#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_LT_TEST_PATTERN_REG0 0x80 +#define SP_TX_LT_TEST_PATTERN_REG1 0x81 +#define SP_TX_LT_TEST_PATTERN_REG2 0x82 +#define SP_TX_LT_TEST_PATTERN_REG3 0x83 +#define SP_TX_LT_TEST_PATTERN_REG4 0x84 +#define SP_TX_LT_TEST_PATTERN_REG5 0x85 +#define SP_TX_LT_TEST_PATTERN_REG6 0x86 +#define SP_TX_LT_TEST_PATTERN_REG7 0x87 +#define SP_TX_LT_TEST_PATTERN_REG8 0x88 +#define SP_TX_LT_TEST_PATTERN_REG9 0x89
+#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
dri-devel@lists.freedesktop.org