mdss: mhl3: Add driver for MHL Transmitter

Code drop from https://github.com/siliconimageinc/sii8620
taken from commit 20b4c581d705cffce422bc79c2bacf7ed5363beb

"Posting driver 1.03 release candidate.

Version 1.03.19

Signed-off-by: Mikhail Amchislavsky <Mikhail.Amchislavsky@siliconimage.com>"

Adding driver for SiI 8620 MHL transmitter.
Integrated the files into drivers/video/msm/mdss/mhl3/.

Removed unnecessary files:
apq8074_kernel_update/apq8074-dragonboard.dtsi
apq8074_kernel_update/board-8974-gpiomux.c
apq8074_kernel_update/msm8974.dtsi
apq8074_kernel_update/sii6031/msm_otg.c
apq_build.sh
build
build_num.txt
clean

Moved files relating to SiI 6031:
apq8074_kernel_update/sii6031/msm_otg.c
apq8074_kernel_update/sii6031/si_6031_switch.h
apq8074_kernel_update/sii6031/sii_6031/Kconfig
apq8074_kernel_update/sii6031/sii_6031/Makefile
apq8074_kernel_update/sii6031/sii_6031/si_6031_switch.c
into drivers/video/fbdev/msm/mhl3/sii6031/.

Change-Id: I29adf3bd4a02406bd9b47c0727d4093cdea94496
Signed-off-by: Casey Piper <cpiper@codeaurora.org>
[cip@codeaurora.org: Moved new file locations]
Signed-off-by: Clarence Ip <cip@codeaurora.org>
This commit is contained in:
Mikhail Amchislavsky 2014-05-22 13:34:38 -07:00 committed by David Keitel
parent 9d1c95d590
commit 3b9fec79f5
36 changed files with 36810 additions and 0 deletions

View file

@ -0,0 +1,17 @@
config MEDIA_DATA_TUNNEL_SUPPORT
bool
prompt "MHL Media Data Tunneling Support"
default n
---help---
This option controls whether or not Silicon Image MHL transmitter
drivers include support for Media Data Tunneling (MDT). MDT
support enables HID events generated by HID devices attached to
an MDT capable MHL sink to be passed over the MHL connection
to the system.
config SII8620_MHL_TX
tristate
prompt "Silicon Image 8620 HDMI to MHL Tx"
depends on I2C
default n

View file

@ -0,0 +1,165 @@
#
# Makefile for the Silicon Image 8620 MHL TX device driver
#
# example invocations:
# For regular Linux builds
# make ARCH=arm CROSS_COMPILE=arm-angstrom-linux-gnueabi- clean debug
# make ARCH=arm CROSS_COMPILE=arm-angstrom-linux-gnueabi- clean release
# make ARCH=arm CROSS_COMPILE=arm-angstrom-linux-gnueabi- clean clean
#
# For Android driver builds - Specify different tool-chain and kernel revision
# export PATH=~/rowboat-android/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin:$PATH
# make ARCH=arm KERNELPATH=~/rowboat-android/kernel CROSS_COMPILE=arm-eabi- clean debug
# make ARCH=arm KERNELPATH=~/rowboat-android/kernel CROSS_COMPILE=arm-eabi- clean release
# make ARCH=arm KERNELPATH=~/rowboat-android/kernel CROSS_COMPILE=arm-eabi- clean clean
#
# For Android 4.0.3 (ICS):
# export PATH=~/rowboat-android/TI-Android-ICS-4.0.3_AM37x_3.0.0/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin:$PATH
# make ARCH=arm KERNELPATH=~/rowboat-android/TI-Android-ICS-4.0.3_AM37x_3.0.0/kernel CROSS_COMPILE=arm-eabi- clean debug
# make ARCH=arm KERNELPATH=~/rowboat-android/TI-Android-ICS-4.0.3_AM37x_3.0.0/kernel CROSS_COMPILE=arm-eabi- clean release
# make ARCH=arm KERNELPATH=~/rowboat-android/TI-Android-ICS-4.0.3_AM37x_3.0.0/kernel CROSS_COMPILE=arm-eabi- clean clean
#
# For Android 4.2.2 (JB) Linaro release 13.04 for PandaBoard:
# export PATH=$PATH:~/Linaro-13.04/android/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7-linaro/bin
# make ARCH=arm KERNELPATH=~/Linaro-13.04/android/kernel/linaro/pandaboard CROSS_COMPILE=arm-eabi- clean debug
# make ARCH=arm KERNELPATH=~/Linaro-13.04/android/kernel/linaro/pandaboard CROSS_COMPILE=arm-eabi- clean release
# make ARCH=arm KERNELPATH=~/Linaro-13.04/android/kernel/linaro/pandaboard CROSS_COMPILE=arm-eabi- clean clean
#
# Silicon Image uses DEVELOPER_BUILD_ID for sandbox build to be identified during testing.
ifneq ($(DEVELOPER_BUILD_ID),)
DEVELOPER_BUILD_COPY=cp sii$(MHL_PRODUCT_NUM)drv.ko sii$(MHL_PRODUCT_NUM)drv$(DEVELOPER_BUILD_ID).ko
endif
ifneq ($(KERNELRELEASE),)
# kbuild part of makefile
#
# color annotations to use instead of leading newline chars
ccflags-y += -DANSI_COLORS
ccflags-y += -DBUILD_NUM_STRING=\"$(MHL_BUILD_NUM)$(DEVELOPER_BUILD_ID)\"
ccflags-y += -DMHL_PRODUCT_NUM=$(MHL_PRODUCT_NUM)
ccflags-y += -DMHL_DRIVER_NAME=\"sii$(MHL_PRODUCT_NUM)drv\"
ccflags-y += -DMHL_DEVICE_NAME=\"sii-$(MHL_PRODUCT_NUM)\"
# Support Device Tree?
ifeq ($(DT_SUPPORT),1)
ccflags-y += -DSIMG_USE_DTS
endif
# Kernel level supported
ccflags-y += -DLINUX_KERNEL_VER=$(LINUX_KERNEL_VER)
#
# FORCE_OCBUS_FOR_ECTS is used to identify code added for ECTS temporary fix that prohibits use of eCBUS.
# in addition module parameter force_ocbus_for_ects needs to be set as 1 to achieve ECTS operation.
ccflags-y += -DFORCE_OCBUS_FOR_ECTS
#
# PC_MODE_VIDEO_TIMING_SUPPORT is for cases where no VIC is available from either AVIF or VSIF.
ccflags-y += -DPC_MODE_VIDEO_TIMING_SUPPORT
#
# MANUAL_INFO_FRAME_CLEAR_AT_HPD_DRIVEN_HIGH is to clear all infoframes
# upon driving HPD high instead of when SCDT goes low.
ccflags-y += -DMANUAL_INFO_FRAME_CLEAR_AT_HPD_DRIVEN_HIGH
#
# MEDIA_DATA_TUNNEL_SUPPORT
# Default is enabled. Comment next line to disable.
ccflags-y += -DMEDIA_DATA_TUNNEL_SUPPORT
#
# Include REMOTE BUTTON PROTOCOL code or not
ccflags-$(CONFIG_DEBUG_DRIVER) += -DINCLUDE_RBP=1
ccflags-$(CONFIG_DEBUG_DRIVER) += -DINCLUDE_HID=$(INCLUDE_HID)
# Example of use of SiI6031 is wrapped under the following definition
# It also illustrates how 8620 driver may be integrated into MSM platform
# the flag should be disabled if not building for MSM
ccflags-$(CONFIG_DEBUG_DRIVER) += -DINCLUDE_SII6031=$(INCLUDE_SII6031)
#
# MANUAL_EDID_FETCH uses DDC master directly, instead of h/w automated method.
ccflags-y += -DMANUAL_EDID_FETCH
# If CI2CA pin is pulled HIGH, you must define the following flag
#ccflags-y += -DALT_I2C_ADDR
# PRINT_DDC_ABORTS enables logging of all DDC_ABORTs. Default "disabled" - helps MHL2 hot plug.
# Enable only if you must for debugging.
#ccflags-y += -DPRINT_DDC_ABORTS
# CoC_FSM_MONITORING exports CoC state machine to GPIO pins
# Enable only if you must for debugging.
ccflags-y += -DCoC_FSM_MONITORING -DBIST_MONITORING
#BIST_DONE_DEBUG adds register dump prior to RAP{CBUS_MODE_UP}
#ccflags-y += -DBIST_DONE_DEBUG
# For si_emsc_hid-mt.c
ccflags-y += -Idrivers/hid
# Optimzations and/or workaround
ccflags-y += -DDISABLE_SPI_DMA
ccflags-y += -DUSE_SPIOPTIMIZE
ccflags-y += -DGCS_QUIRKS_FOR_SIMG
ccflags-$(CONFIG_DEBUG_DRIVER) += -DDEBUG
# Enable VBUS sense and related operations
ccflags-$(CONFIG_DEBUG_DRIVER) += -DENABLE_VBUS_SENSE
#support for DVI sources and sinks in MHL3 mode.
ccflags-$(CONFIG_DEBUG_DRIVER) += -DMHL3_DVI_SUPPORT
#add HDMI VSDB to upstream EDID when downstream sink is DVI
#ccflags-$(CONFIG_DEBUG_DRIVER) += -DMHL3_DVI_SUPPORT_FORCE_HDMI
#
# the next lines are optional - they enable greater verbosity in debug output
#ccflags-$(CONFIG_DEBUG_DRIVER) += -DENABLE_EDID_DEBUG_PRINT
#ccflags-$(CONFIG_DEBUG_DRIVER) += -DENABLE_DUMP_INFOFRAME
#
# uncomment next line to prevent EDID parsing. Useful for debugging.
#ccflags-$(CONFIG_DEBUG_DRIVER) += -DEDID_PASSTHROUGH
obj-$(CONFIG_SII$(MHL_PRODUCT_NUM)_MHL_TX) += sii$(MHL_PRODUCT_NUM)drv.o
sii$(MHL_PRODUCT_NUM)drv-objs += platform.o
sii$(MHL_PRODUCT_NUM)drv-objs += mhl_linux_tx.o
sii$(MHL_PRODUCT_NUM)drv-objs += mhl_rcp_inputdev.o
sii$(MHL_PRODUCT_NUM)drv-objs += mhl_rbp_inputdev.o
sii$(MHL_PRODUCT_NUM)drv-objs += mhl_supp.o
sii$(MHL_PRODUCT_NUM)drv-objs += si_8620_drv.o
sii$(MHL_PRODUCT_NUM)drv-objs += si_mhl2_edid_3d.o
sii$(MHL_PRODUCT_NUM)drv-objs += si_mdt_inputdev.o
ifeq ($(INCLUDE_HID),1)
sii$(MHL_PRODUCT_NUM)drv-objs += si_emsc_hid.o
sii$(MHL_PRODUCT_NUM)drv-objs += si_emsc_hid-mt.o
endif
else
# Normal Makefile
# If a kernel is not specified, default to the kernel used with Android Ice Cream Sandwich
ifneq ($(KERNELPATH),)
KERNELDIR=$(KERNELPATH)
else
KERNELDIR=~/src/linux-2.6.36
#KERNELDIR=~/src/Android_ICS/kernel
endif
ARCH=arm
PWD := $(shell pwd)
.PHONY: clean
release:
make -C $(KERNELDIR) M=$(PWD) CONFIG_SII$(MHL_PRODUCT_NUM)_MHL_TX=m CONFIG_MEDIA_DATA_TUNNEL_SUPPORT=y modules
$(CROSS_COMPILE)strip --strip-debug sii$(MHL_PRODUCT_NUM)drv.ko
$(DEVELOPER_BUILD_COPY)
debug:
rm -f platform.o
make -C $(KERNELDIR) M=$(PWD) CONFIG_SII$(MHL_PRODUCT_NUM)_MHL_TX=m CONFIG_MEDIA_DATA_TUNNEL_SUPPORT=y CONFIG_DEBUG_DRIVER=y modules
$(DEVELOPER_BUILD_COPY)
clean:
make -C $(KERNELDIR) M=$(PWD) CONFIG_SII$(MHL_PRODUCT_NUM)_MHL_TX=m clean
endif

View file

@ -0,0 +1,39 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#if !defined(MHL_DEVICE_CFG_H)
#define MHL_DEVICE_CFG_H
#include "si_app_devcap.h"
/*
* This file contains SiI8620 driver and device configuration information
*
*/
/*
* Determine XDEVCAPS configurations allowed by this driver
*/
#if (INCLUDE_HID == 1)
#define XDEVCAP_VAL_DEV_ROLES (MHL_XDC_DEV_HOST | MHL_XDC_HID_HOST)
#else
#define XDEVCAP_VAL_DEV_ROLES MHL_XDC_DEV_HOST
#endif
#define XDEVCAP_VAL_LOG_DEV_MAPX MHL_XDC_LD_PHONE
#endif /* if !defined(MHL_DEVICE_CFG_H) */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,455 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#if !defined(MHL_LINUX_TX_H)
#define MHL_LINUX_TX_H
#if (INCLUDE_HID == 1)
#include "si_emsc_hid.h"
#endif
#include "si_app_devcap.h"
/*
* EMSC Block Transaction stuff
*/
#define EMSC_RCV_BUFFER_DEFAULT 256
#define EMSC_BLK_MAX_LENGTH 256
#define EMSC_BLK_STD_HDR_LEN 2
#define EMSC_BLK_CMD_MAX_LEN (EMSC_BLK_MAX_LENGTH - \
EMSC_BLK_STD_HDR_LEN)
#define LOCAL_BLK_RCV_BUFFER_SIZE 288
/*
* Event codes
*
*/
/* No event worth reporting */
#define MHL_TX_EVENT_NONE 0x00
/* MHL connection has been lost */
#define MHL_TX_EVENT_DISCONNECTION 0x01
/* MHL connection has been established */
#define MHL_TX_EVENT_CONNECTION 0x02
/* Received an RCP key code */
#define MHL_TX_EVENT_RCP_RECEIVED 0x04
/* Received an RCPK message */
#define MHL_TX_EVENT_RCPK_RECEIVED 0x05
/* Received an RCPE message */
#define MHL_TX_EVENT_RCPE_RECEIVED 0x06
/* Received an UTF-8 key code */
#define MHL_TX_EVENT_UCP_RECEIVED 0x07
/* Received an UCPK message */
#define MHL_TX_EVENT_UCPK_RECEIVED 0x08
/* Received an UCPE message */
#define MHL_TX_EVENT_UCPE_RECEIVED 0x09
/* Scratch Pad Data received */
#define MHL_TX_EVENT_SPAD_RECEIVED 0x0A
/* Peer's power capability has changed */
#define MHL_TX_EVENT_POW_BIT_CHG 0x0B
/* Received a Request Action Protocol (RAP) message */
#define MHL_TX_EVENT_RAP_RECEIVED 0x0C
#if (INCLUDE_RBP == 1)
/* Received an RBP button code */
#define MHL_TX_EVENT_RBP_RECEIVED 0x0D
/* Received an RBPK message */
#define MHL_TX_EVENT_RBPK_RECEIVED 0x0E
/* Received an RBPE message */
#define MHL_TX_EVENT_RBPE_RECEIVED 0x0F
#endif
/* Received a BIST_READY message */
#define MHL_TX_EVENT_BIST_READY_RECEIVED 0x10
/* A triggered BIST test has completed */
#define MHL_TX_EVENT_BIST_TEST_DONE 0x11
/* Received a BIST_STATUS message */
#define MHL_TX_EVENT_BIST_STATUS_RECEIVED 0x12
/* T_RAP_MAX expired */
#define MHL_TX_EVENT_T_RAP_MAX_EXPIRED 0x13
/* peer sent AUD_DELAY burst */
#define MHL_EVENT_AUD_DELAY_RCVD 0x14
#define ADOPTER_ID_SIZE 2
#define MAX_SCRATCH_PAD_TRANSFER_SIZE 16
#define SCRATCH_PAD_SIZE 64
#define SCRATCHPAD_SIZE 16
union scratch_pad_u {
struct MHL2_video_format_data_t videoFormatData;
struct MHL3_hev_vic_data_t hev_vic_data;
struct MHL3_hev_dtd_a_data_t hev_dtd_a_data;
struct MHL3_hev_dtd_b_data_t hev_dtd_b_data;
uint8_t asBytes[SCRATCHPAD_SIZE];
};
struct timer_obj {
struct list_head list_link;
struct work_struct work_item;
struct hrtimer hr_timer;
struct mhl_dev_context *dev_context;
uint8_t flags;
#define TIMER_OBJ_FLAG_WORK_IP 0x01
#define TIMER_OBJ_FLAG_DEL_REQ 0x02
void *callback_param;
void (*timer_callback_handler) (void *callback_param);
};
union misc_flags_u {
struct {
unsigned rcv_scratchpad_busy:1;
unsigned req_wrt_pending:1;
unsigned write_burst_pending:1;
unsigned have_complete_devcap:1;
unsigned sent_dcap_rdy:1;
unsigned sent_path_en:1;
unsigned rap_content_on:1;
unsigned mhl_hpd:1;
unsigned mhl_rsen:1;
unsigned edid_loop_active:1;
unsigned cbus_abort_delay_active:1;
unsigned have_complete_xdevcap:1;
unsigned bist_role_TE:1;
unsigned reserved:19;
} flags;
uint32_t as_uint32;
};
struct mhl_device_status {
uint8_t write_stat[3];
uint8_t write_xstat[4];
};
/*
* structure used by interrupt handler to return
* information about an interrupt.
*/
struct interrupt_info {
uint16_t flags;
/* Flags returned by low level driver interrupt handler */
#define DRV_INTR_MSC_DONE 0x0001 /* message send done */
#define DRV_INTR_MSC_RECVD 0x0002 /* MSC message received */
#define DRV_INTR_MSC_NAK 0x0004 /* message send unsuccessful */
#define DRV_INTR_WRITE_STAT 0x0008 /* write stat msg received */
#define DRV_INTR_SET_INT 0x0010 /* set int message received */
#define DRV_INTR_WRITE_BURST 0x0020 /* write burst received */
#define DRV_INTR_HPD_CHANGE 0x0040 /* Hot plug detect change */
#define DRV_INTR_CONNECT 0x0080 /* MHL connection established */
#define DRV_INTR_DISCONNECT 0x0100 /* MHL connection lost */
#define DRV_INTR_CBUS_ABORT 0x0200 /* CBUS msg transfer aborted */
#define DRV_INTR_COC_CAL 0x0400 /* CoC Calibration done */
#define DRV_INTR_TDM_SYNC 0x0800 /* TDM Sync Complete */
#define DRV_INTR_EMSC_INCOMING 0x1000
void *edid_parser_context;
uint8_t msc_done_data;
uint8_t hpd_status; /* status of hot plug detect */
/* received write stat data for CONNECTED_RDY and/or LINK_MODE,
* and/or MHL_VERSION_STAT
*/
struct mhl_device_status dev_status;
uint8_t msc_msg[2]; /* received msc message data */
uint8_t int_msg[2]; /* received SET INT message data */
};
enum tdm_vc_assignments {
TDM_VC_CBUS1 = 0,
TDM_VC_E_MSC = 1,
TDM_VC_T_CBUS = 2,
TDM_VC_MAX = TDM_VC_T_CBUS + 1
};
/* allow for two WRITE_STAT, and one SET_INT immediately upon MHL_EST */
#define NUM_CBUS_EVENT_QUEUE_EVENTS 16
#define MHL_DEV_CONTEXT_SIGNATURE \
(('M' << 24) | ('H' << 16) | ('L' << 8) | ' ')
struct mhl_dev_context {
uint32_t signature; /* identifies an instance of
this struct */
struct mhl_drv_info const *drv_info;
#if (INCLUDE_SII6031 == 1)
struct completion sem_mhl_discovery_complete;
bool mhl_discovery_in_progress;
bool mhl_detected;
void (*notify_mhl)(int mhl_detected);
void *usb_ctxt;
#endif
struct i2c_client *client;
struct cdev mhl_cdev;
struct device *mhl_dev;
struct interrupt_info intr_info;
void *edid_parser_context;
u8 dev_flags;
#define DEV_FLAG_SHUTDOWN 0x01 /* Device is shutting down */
#define DEV_FLAG_COMM_MODE 0x02 /* Halt INTR processing */
u16 mhl_flags; /* various state flags */
#define MHL_STATE_FLAG_CONNECTED 0x0001 /* MHL connection
established */
#define MHL_STATE_FLAG_RCP_SENT 0x0002 /* last RCP event was a key
send */
#define MHL_STATE_FLAG_RCP_RECEIVED 0x0004 /* last RCP event was a key
code receive */
#define MHL_STATE_FLAG_RCP_ACK 0x0008 /* last RCP key code sent was
ACK'd */
#define MHL_STATE_FLAG_RCP_NAK 0x0010 /* last RCP key code sent was
NAK'd */
#define MHL_STATE_FLAG_UCP_SENT 0x0020 /* last UCP event was a key
send */
#define MHL_STATE_FLAG_UCP_RECEIVED 0x0040 /* last UCP event was a key
code receive */
#define MHL_STATE_FLAG_UCP_ACK 0x0080 /* last UCP key code sent was
ACK'd */
#define MHL_STATE_FLAG_UCP_NAK 0x0100 /* last UCP key code sent was
NAK'd */
#if (INCLUDE_RBP == 1)
#define MHL_STATE_FLAG_RBP_RECEIVED 0x0200 /* last RBP event was a button
code receive */
#define MHL_STATE_FLAG_RBP_ACK 0x0400 /* last RBP event was a button
code receive */
#define MHL_STATE_FLAG_RBP_NAK 0x0800 /* last RBP event was a button
code receive */
#define MHL_STATE_FLAG_RBP_SENT 0x1000 /* last RBP event was a button
send */
#endif
#define MHL_STATE_FLAG_SPAD_SENT 0x2000 /* scratch pad send in
process */
#define MHL_STATE_APPLICATION_RAP_BUSY 0x4000 /* application has indicated
that it is processing an
outstanding request */
u8 dev_cap_local_offset;
u8 dev_cap_remote_offset;
u8 rap_in_sub_command;
u8 rap_in_status;
u8 rap_out_sub_command;
u8 rap_out_status;
u8 rcp_in_key_code;
u8 rcp_out_key_code;
u8 rcp_err_code;
u8 rcp_send_status;
u8 ucp_in_key_code;
u8 ucp_out_key_code;
u8 ucp_err_code;
u8 ucp_send_status;
#if (INCLUDE_RBP == 1)
u8 rbp_in_button_code;
u8 rbp_out_button_code;
u8 rbp_err_code;
u8 rbp_send_status;
#endif
u8 spad_offset;
u8 spad_xfer_length;
u8 spad_send_status;
u8 debug_i2c_address;
u8 debug_i2c_offset;
u8 debug_i2c_xfer_length;
#ifdef MEDIA_DATA_TUNNEL_SUPPORT
struct mdt_inputdevs mdt_devs;
#endif
#if (INCLUDE_HID == 1)
struct mhl3_hid_global_data mhl_ghid;
struct mhl3_hid_data *mhl_hid[16];
struct workqueue_struct *hid_work_queue;
#endif
u8 error_key;
struct input_dev *rcp_input_dev;
#if (INCLUDE_RBP == 1)
struct input_dev *rbp_input_dev;
#endif
struct semaphore isr_lock; /* semaphore used to prevent driver
* access from user mode from colliding
* with the threaded interrupt handler
*/
u8 status_0; /* Received status from peer saved here */
u8 status_1;
u8 peer_mhl3_version;
u8 xstatus_1;
u8 xstatus_3;
bool msc_msg_arrived;
u8 msc_msg_sub_command;
u8 msc_msg_data;
u8 msc_msg_last_data;
u8 msc_save_rcp_key_code;
#if (INCLUDE_RBP == 1)
u8 msc_save_rbp_button_code;
#endif
u8 msc_save_ucp_key_code;
u8 link_mode; /* outgoing MHL LINK_MODE register value */
bool mhl_connection_event;
u8 mhl_connected;
struct workqueue_struct *timer_work_queue;
struct list_head timer_list;
struct list_head cbus_queue;
struct list_head cbus_free_list;
struct cbus_req cbus_req_entries[NUM_CBUS_EVENT_QUEUE_EVENTS];
struct cbus_req *current_cbus_req;
int sequence;
void *cbus_abort_timer;
void *dcap_rdy_timer;
void *dcap_chg_timer;
void *t_rap_max_timer;
union MHLDevCap_u dev_cap_cache;
union MHLXDevCap_u xdev_cap_cache;
u8 preferred_clk_mode;
union scratch_pad_u incoming_scratch_pad;
union scratch_pad_u outgoing_scratch_pad;
uint8_t virt_chan_slot_counts[TDM_VC_MAX];
uint8_t prev_virt_chan_slot_counts[TDM_VC_MAX];
void *cbus_mode_up_timer;
void *bist_timer;
uint32_t bist_timeout_value;
uint32_t bist_timeout_total;
struct bist_setup_info bist_setup;
struct bist_setup_info sysfs_bist_setup;
struct bist_stat_info bist_stat;
uint8_t bist_trigger_info;
uint8_t bist_ready_status;
union misc_flags_u misc_flags;
struct {
int sequence;
unsigned long local_blk_rx_buffer_size;
struct list_head queue;
struct list_head free_list;
#define NUM_BLOCK_QUEUE_REQUESTS 4
struct block_req *marshalling_req;
struct block_req req_entries[NUM_BLOCK_QUEUE_REQUESTS];
} block_protocol;
bool sii_adopter_id;
bool edid_valid;
uint8_t numEdidExtensions;
#ifndef OLD_KEYMAP_TABLE
void *timer_T_press_mode;
void *timer_T_hold_maintain;
#endif
void *drv_context; /* pointer aligned start of mhl
transmitter driver context area */
};
#define PACKED_PIXEL_AVAILABLE(dev_context) \
((MHL_DEV_VID_LINK_SUPP_PPIXEL & \
dev_context->dev_cap_cache.devcap_cache[DEVCAP_OFFSET_VID_LINK_MODE]) \
&& (MHL_DEV_VID_LINK_SUPP_PPIXEL & DEVCAP_VAL_VID_LINK_MODE))
#define _16_BPP_AVAILABLE(dev_context) \
((MHL_DEV_VID_LINK_SUPP_16BPP & \
dev_context->dev_cap_cache.devcap_cache[DEVCAP_OFFSET_VID_LINK_MODE]) \
&& (MHL_DEV_VID_LINK_SUPP_16BPP & DEVCAP_VAL_VID_LINK_MODE))
enum scratch_pad_status {
SCRATCHPAD_FAIL = -4,
SCRATCHPAD_BAD_PARAM = -3,
SCRATCHPAD_NOT_SUPPORTED = -2,
SCRATCHPAD_BUSY = -1,
SCRATCHPAD_SUCCESS = 0
};
struct drv_hw_context;
struct mhl_drv_info {
int drv_context_size;
struct {
uint8_t major:4;
uint8_t minor:4;
} mhl_version_support;
int irq;
/* APIs required to be supported by the low level MHL TX driver */
int (*mhl_device_initialize) (struct drv_hw_context *hw_context);
void (*mhl_device_isr) (struct drv_hw_context *hw_context,
struct interrupt_info *intr_info);
int (*mhl_device_dbg_i2c_reg_xfer) (void *dev_context, u8 page,
u8 offset, u16 count, bool rw_flag, u8 *buffer);
int (*mhl_device_get_aksv) (struct drv_hw_context *hw_context,
u8 *buffer);
};
/* APIs provided by the Linux layer to the lower level driver */
int mhl_handle_power_change_request(struct device *parent_dev, bool power_up);
int mhl_tx_init(struct mhl_drv_info const *drv_info, struct device *parent_dev);
int mhl_tx_remove(struct device *parent_dev);
void mhl_event_notify(struct mhl_dev_context *dev_context, u32 event,
u32 event_param, void *data);
struct mhl_dev_context *get_mhl_device_context(void *context);
void *si_mhl_tx_get_drv_context(void *dev_context);
int mhl_tx_create_timer(void *context,
void (*callback_handler) (void *callback_param), void *callback_param,
void **timer_handle);
int mhl_tx_delete_timer(void *context, void **timer_handle);
int mhl_tx_start_timer(void *context, void *timer_handle, uint32_t time_msec);
int mhl_tx_stop_timer(void *context, void *timer_handle);
void mhl_tx_stop_all_timers(struct mhl_dev_context *dev_context);
void si_mhl_tx_request_first_edid_block(struct mhl_dev_context *dev_context);
void si_mhl_tx_handle_atomic_hw_edid_read_complete(struct edid_3d_data_t
*mhl_edid_3d_data);
/* APIs used within the Linux layer of the driver. */
uint8_t si_mhl_tx_get_peer_dev_cap_entry(struct mhl_dev_context *dev_context,
uint8_t index, uint8_t *data);
enum scratch_pad_status si_get_scratch_pad_vector(struct mhl_dev_context
*dev_context, uint8_t offset, uint8_t length, uint8_t *data);
#if (INCLUDE_SII6031 == 1)
void mhl_tx_notify_otg(struct mhl_dev_context *dev_context, bool mhl_detected);
int otg_register_mhl_discovery(void *mhl_ctx, int (*mhl_discover_device)
(void *, int, void (*)(void *, int online), void *));
int otg_unregister_mhl_discovery(void);
void otg_mhl_notify(void *ctxt, int on);
#endif
#endif /* if !defined(MHL_LINUX_TX_H) */

View file

@ -0,0 +1,350 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#if (INCLUDE_RBP == 1)
#include <linux/input.h>
#include <linux/cdev.h>
#include <linux/hrtimer.h>
#include "si_fw_macros.h"
#include "si_infoframe.h"
#include "si_edid.h"
#include "si_mhl_defs.h"
#include "si_mhl2_edid_3d_api.h"
#include "si_mhl_tx_hw_drv_api.h"
#ifdef MEDIA_DATA_TUNNEL_SUPPORT
#include "si_mdt_inputdev.h"
#endif
#include "mhl_linux_tx.h"
#include "platform.h"
#include "mhl_rbp_inputdev.h"
enum rbp_state_e {
ph0_idle,
ph3_press_and_hold_button,
ph8_hold_mode,
num_rbp_states
};
static char *state_strings[num_rbp_states] = {
"idle",
"press_and_hold_button",
"hold_mode"
};
enum rbp_event_e {
rbp_normal_button_press,
rbp_normal_button_press_same,
rbp_normal_button_release,
rbp_normal_button_release_same,
rbp_press_and_hold_button_press,
rbp_press_and_hold_button_press_same,
rbp_press_and_hold_button_release,
rbp_press_and_hold_button_release_same,
rbp_T_hold_maintain_expired,
rbp_T_press_mode_expired,
num_rbp_events
};
static char *event_strings[num_rbp_events] = {
"normal_button_press",
"normal_button_press_same",
"normal_button_release",
"normal_button_release_same",
"press_and_hold_button_press",
"press_and_hold_button_press_same",
"press_and_hold_button_release",
"press_and_hold_button_release_same",
"rbp_T_hold_maintain_expired",
"rbp_T_press_mode_expired"
};
enum rbp_state_e current_rbp_state = ph0_idle;
uint8_t rbp_previous_button = 0, rbp_current_button = 0;
static int rbp_trigger_button_action(struct mhl_dev_context *dev_context,
uint8_t index, bool press_release)
{
int status = -EINVAL;
if (dev_context->rbp_input_dev) {
input_report_key(dev_context->rbp_input_dev, index,
press_release);
input_sync(dev_context->rbp_input_dev);
status = 0;
}
return status;
}
static int handle_rbp_event(struct mhl_dev_context *dev_context,
uint8_t current_button, uint8_t prev_button, enum rbp_event_e event)
{
int status = 0;
uint8_t current_index = current_button & MHL_RBP_BUTTON_ID_MASK;
uint8_t prev_index = prev_button & MHL_RBP_BUTTON_ID_MASK;
MHL_TX_DBG_ERR("received 0x%02x: %s(%d) in state: %s(%d)\n",
current_button, event_strings[event], event,
state_strings[current_rbp_state], current_rbp_state);
/* now process the event according to the current state */
switch (current_rbp_state) {
case ph0_idle:
switch (event) {
case rbp_normal_button_press:
case rbp_normal_button_press_same:
status =
rbp_trigger_button_action(dev_context,
current_index, 1);
/* no update for current_rbp_state */
break;
case rbp_normal_button_release:
case rbp_normal_button_release_same:
status =
rbp_trigger_button_action(dev_context,
current_index, 0);
/* no update for current_rbp_state */
break;
case rbp_press_and_hold_button_press:
case rbp_press_and_hold_button_press_same:
mhl_tx_start_timer(dev_context,
dev_context->timer_T_press_mode,
T_PRESS_MODE);
current_rbp_state = ph3_press_and_hold_button;
break;
case rbp_press_and_hold_button_release:
case rbp_press_and_hold_button_release_same:
MHL_TX_DBG_ERR("unexpected %s(%d) in state: %s(%d)\n",
event_strings[event], event,
state_strings[current_rbp_state],
current_rbp_state);
break;
default:
MHL_TX_DBG_ERR("unexpected event: %d in state: %d\n",
event, current_rbp_state);
/* no update for current_rbp_state */
status = -EINVAL;
}
break;
case ph3_press_and_hold_button:
switch (event) {
case rbp_normal_button_press:
case rbp_normal_button_press_same:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_press_mode);
rbp_trigger_button_action(dev_context, prev_index, 0);
/* OK to overwrite status */
status =
rbp_trigger_button_action(dev_context,
current_index, 1);
current_rbp_state = ph0_idle;
break;
case rbp_normal_button_release:
case rbp_normal_button_release_same:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_press_mode);
rbp_trigger_button_action(dev_context, prev_index, 0);
rbp_trigger_button_action(dev_context, current_index,
1);
status =
rbp_trigger_button_action(dev_context,
current_index, 0);
current_rbp_state = ph0_idle;
break;
case rbp_press_and_hold_button_press:
mhl_tx_start_timer(dev_context,
dev_context->timer_T_press_mode,
T_PRESS_MODE);
status =
rbp_trigger_button_action(dev_context, prev_index,
1);
/* no update for current_rbp_state */
break;
case rbp_press_and_hold_button_press_same:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_press_mode);
mhl_tx_start_timer(dev_context,
dev_context->timer_T_hold_maintain,
T_HOLD_MAINTAIN);
status =
rbp_trigger_button_action(dev_context, prev_index,
1);
current_rbp_state = ph8_hold_mode;
break;
case rbp_press_and_hold_button_release:
case rbp_press_and_hold_button_release_same:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_press_mode);
status =
rbp_trigger_button_action(dev_context, prev_index,
0);
current_rbp_state = ph0_idle;
break;
case rbp_T_press_mode_expired:
mhl_tx_start_timer(dev_context,
dev_context->timer_T_hold_maintain,
T_HOLD_MAINTAIN);
status =
rbp_trigger_button_action(dev_context, prev_index,
0);
current_rbp_state = ph8_hold_mode;
break;
default:
MHL_TX_DBG_ERR("unexpected event: %d in state: %d\n",
event, current_rbp_state);
/* no update for current_rbp_state */
status = -EINVAL;
}
break;
case ph8_hold_mode:
switch (event) {
case rbp_normal_button_press:
case rbp_normal_button_press_same:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_hold_maintain);
rbp_trigger_button_action(dev_context, prev_index, 0);
status =
rbp_trigger_button_action(dev_context,
current_index, 1);
current_rbp_state = ph0_idle;
break;
case rbp_normal_button_release:
case rbp_normal_button_release_same:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_hold_maintain);
rbp_trigger_button_action(dev_context, prev_index, 0);
rbp_trigger_button_action(dev_context, current_index,
1);
status =
rbp_trigger_button_action(dev_context,
current_index, 0);
current_rbp_state = ph0_idle;
break;
case rbp_press_and_hold_button_press:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_hold_maintain);
mhl_tx_start_timer(dev_context,
dev_context->timer_T_press_mode,
T_PRESS_MODE);
status =
rbp_trigger_button_action(dev_context, prev_index,
1);
current_rbp_state = ph3_press_and_hold_button;
break;
case rbp_press_and_hold_button_press_same:
mhl_tx_start_timer(dev_context,
dev_context->timer_T_hold_maintain,
T_HOLD_MAINTAIN);
status =
rbp_trigger_button_action(dev_context, prev_index,
1);
/* no update for current_rbp_state */
break;
case rbp_press_and_hold_button_release:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_hold_maintain);
rbp_trigger_button_action(dev_context, prev_index, 0);
rbp_trigger_button_action(dev_context, current_index,
1);
status =
rbp_trigger_button_action(dev_context,
current_index, 0);
current_rbp_state = ph0_idle;
break;
case rbp_press_and_hold_button_release_same:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_hold_maintain);
status =
rbp_trigger_button_action(dev_context, prev_index,
0);
current_rbp_state = ph0_idle;
break;
case rbp_T_hold_maintain_expired:
status =
rbp_trigger_button_action(dev_context, prev_index,
0);
current_rbp_state = ph0_idle;
break;
default:
MHL_TX_DBG_ERR("unexpected event: %d in state: %d\n",
event, current_rbp_state);
/* no update for current_rbp_state */
status = -EINVAL;
}
break;
default:
MHL_TX_DBG_ERR("irrational state value:%d\n",
current_rbp_state);
}
return status;
}
int generate_rbp_input_event(struct mhl_dev_context *dev_context,
uint8_t rbp_buttoncode)
{
/*
Since, in MHL, bit 7 == 1 indicates button release,
and, in Linux, zero means button release,
we use XOR (^) to invert the sense.
*/
enum rbp_event_e event;
int mhl_button_press;
int status = -EINVAL;
int index = rbp_buttoncode & MHL_RBP_BUTTON_ID_MASK;
switch (index) {
case RBP_CALL_ANSWER:
case RBP_CALL_END:
case RBP_CALL_TOGGLE:
case RBP_CALL_MUTE:
case RBP_CALL_DECLINE:
case RBP_OCTOTHORPE:
case RBP_ASTERISK:
case RBP_ROTATE_CLKWISE:
case RBP_ROTATE_COUNTERCLKWISE:
case RBP_SCREEN_PAGE_NEXT:
case RBP_SCREEN_PAGE_PREV:
case RBP_SCREEN_PAGE_UP:
case RBP_SCREEN_PAGE_DN:
case RBP_SCREEN_PAGE_LEFT:
case RBP_SCREEN_PAGE_RIGHT:
break;
default:
return 1;
}
mhl_button_press =
(rbp_buttoncode & MHL_RBP_BUTTON_RELEASED_MASK) ? 0 : 1;
if (mhl_button_press) {
if (index == rbp_previous_button)
event = rbp_press_and_hold_button_press_same;
else
event = rbp_press_and_hold_button_press;
} else {
if (index == rbp_previous_button)
event = rbp_press_and_hold_button_release_same;
else
event = rbp_press_and_hold_button_release;
}
status = handle_rbp_event(dev_context, rbp_buttoncode,
rbp_current_button, event);
rbp_previous_button = rbp_current_button;
rbp_current_button = rbp_buttoncode;
return status;
}
#endif

View file

@ -0,0 +1,40 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#ifndef _MHL_RBP_INPUTDEV_H_
#define _MHL_RBP_INPUTDEV_H_
struct mhl_dev_context;
#define RBP_CALL_ANSWER 0x01
#define RBP_CALL_END 0x02
#define RBP_CALL_TOGGLE 0x03
#define RBP_CALL_MUTE 0x04
#define RBP_CALL_DECLINE 0x05
#define RBP_OCTOTHORPE 0x06
#define RBP_ASTERISK 0x07
#define RBP_ROTATE_CLKWISE 0x20
#define RBP_ROTATE_COUNTERCLKWISE 0x21
#define RBP_SCREEN_PAGE_NEXT 0x30
#define RBP_SCREEN_PAGE_PREV 0x31
#define RBP_SCREEN_PAGE_UP 0x32
#define RBP_SCREEN_PAGE_DN 0x33
#define RBP_SCREEN_PAGE_LEFT 0x34
#define RBP_SCREEN_PAGE_RIGHT 0x35
int generate_rbp_input_event(struct mhl_dev_context *dev_context,
uint8_t rbp_buttoncode);
#endif /* #ifndef _MHL_RBP_INPUTDEV_H_ */

View file

@ -0,0 +1,845 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#include <linux/input.h>
#include <linux/cdev.h>
#include <linux/hrtimer.h>
#include "si_fw_macros.h"
#include "si_infoframe.h"
#include "si_edid.h"
#include "si_mhl_defs.h"
#include "si_mhl2_edid_3d_api.h"
#include "si_mhl_tx_hw_drv_api.h"
#ifdef MEDIA_DATA_TUNNEL_SUPPORT
#include "si_mdt_inputdev.h"
#endif
#include "mhl_linux_tx.h"
#include "platform.h"
#include "mhl_rcp_inputdev.h"
enum rcp_state_e {
PH0_IDLE,
PH3_PRESS_AND_HOLD_KEY,
ph8_hold_mode,
num_rcp_states
};
static char *state_strings[num_rcp_states] = {
"idle",
"press_and_hold_key",
"hold_mode"
};
enum rcp_event_e {
RCP_NORMAL_KEY_PRESS,
RCP_NORMAL_KEY_PRESS_SAME,
RCP_NORMAL_KEY_RELEASE,
RCP_NORMAL_KEY_RELEASE_SAME,
RCP_HOLD_KEY_PRESS,
RCP_HOLD_KEY_PRESS_SAME,
RCP_HOLD_KEY_RELEASE,
RCP_HOLD_KEY_RELEASE_SAME,
RCP_T_HOLD_MAINTAIN_EXPIRED,
RCP_T_PRESS_MODE_EXPIRED,
NUM_RCP_EVENTS
};
static char *event_strings[NUM_RCP_EVENTS] = {
"normal_key_press",
"normal_key_press_same",
"normal_key_release",
"normal_key_release_same",
"press_and_hold_key_press",
"press_and_hold_key_press_same",
"press_and_hold_key_release",
"press_and_hold_key_release_same",
"rcp_T_hold_maintain_expired",
"rcp_T_press_mode_expired"
};
enum rcp_state_e current_rcp_state = PH0_IDLE;
uint8_t rcp_previous_key = 0, rcp_current_key = 0;
struct rcp_keymap_t rcpSupportTable[MHL_NUM_RCP_KEY_CODES] = {
{0, 0, 0, {KEY_SELECT, 0}, (MHL_DEV_LD_GUI)}, /* 0x00 */
{0, 1, 0, {KEY_UP, 0}, (MHL_DEV_LD_GUI)}, /* 0x01 */
{0, 1, 0, {KEY_DOWN, 0}, (MHL_DEV_LD_GUI)}, /* 0x02 */
{0, 1, 0, {KEY_LEFT, 0}, (MHL_DEV_LD_GUI)}, /* 0x03 */
{0, 1, 0, {KEY_RIGHT, 0}, (MHL_DEV_LD_GUI)}, /* 0x04 */
{1, 1, 0, {KEY_RIGHT, KEY_UP}, (MHL_DEV_LD_GUI)}, /* 0x05 */
{1, 1, 0, {KEY_RIGHT, KEY_DOWN}, (MHL_DEV_LD_GUI)}, /* 0x06 */
{1, 1, 0, {KEY_LEFT, KEY_UP}, (MHL_DEV_LD_GUI)}, /* 0x07 */
{1, 1, 0, {KEY_LEFT, KEY_DOWN}, (MHL_DEV_LD_GUI)}, /* 0x08 */
{0, 0, 0, {KEY_MENU, 0}, (MHL_DEV_LD_GUI)}, /* 0x09 */
{0, 0, 0, {KEY_UNKNOWN, 0}, 0}, /* 0x0A */
{0, 0, 0, {KEY_UNKNOWN, 0}, 0}, /* 0x0B */
{0, 0, 0, {KEY_BOOKMARKS, 0}, 0}, /* 0x0C */
{0, 0, 0, {KEY_EXIT, 0}, (MHL_DEV_LD_GUI)}, /* 0x0D */
/* 0x0E - 0x1F Reserved */
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
/* 0x20 Numeric 0 */
{0, 0, 0, {KEY_NUMERIC_0, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x21 Numeric 1 */
{0, 0, 0, {KEY_NUMERIC_1, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x22 Numeric 2 */
{0, 0, 0, {KEY_NUMERIC_2, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x23 Numeric 3 */
{0, 0, 0, {KEY_NUMERIC_3, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x24 Numeric 4 */
{0, 0, 0, {KEY_NUMERIC_4, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x25 Numeric 5 */
{0, 0, 0, {KEY_NUMERIC_5, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x26 Numeric 6 */
{0, 0, 0, {KEY_NUMERIC_6, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x27 Numeric 7 */
{0, 0, 0, {KEY_NUMERIC_7, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x28 Numeric 8 */
{0, 0, 0, {KEY_NUMERIC_8, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x29 Numeric 9 */
{0, 0, 0, {KEY_NUMERIC_9, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x2A Dot */
{0, 0, 0, {KEY_DOT, 0}, 0},
/* 0x2B Enter */
{0, 0, 0, {KEY_ENTER, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x2C Clear */
{0, 0, 0, {KEY_CLEAR, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x2D - 0x2F Reserved */
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
/* 0x30 Channel Up */
{0, 1, 0, {KEY_CHANNELUP, 0}, (MHL_DEV_LD_TUNER)},
/* 0x31 Channel Down */
{0, 1, 0, {KEY_CHANNELDOWN, 0}, (MHL_DEV_LD_TUNER)},
/* 0x32 Previous Channel */
{0, 0, 0, {KEY_UNKNOWN, 0}, (MHL_DEV_LD_TUNER)},
/* 0x33 Sound Select */
{0, 0, 0, {KEY_SOUND, 0}, (MHL_DEV_LD_AUDIO)},
/* 0x34 Input Select */
{0, 0, 0, {KEY_UNKNOWN, 0}, 0},
/* 0x35 Show Information */
{0, 0, 0, {KEY_PROGRAM, 0}, 0},
/* 0x36 Help */
{0, 0, 0, {KEY_UNKNOWN, 0}, 0},
/* 0x37 Page Up */
{0, 1, 0, {KEY_PAGEUP, 0}, 0},
/* 0x38 Page Down */
{0, 1, 0, {KEY_PAGEDOWN, 0}, 0},
/* 0x39 - 0x40 Reserved */
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
/* 0x41 Volume Up */
{0, 1, 0, {KEY_VOLUMEUP, 0}, (MHL_DEV_LD_SPEAKER)},
/* 0x42 Volume Down */
{0, 1, 0, {KEY_VOLUMEDOWN, 0}, (MHL_DEV_LD_SPEAKER)},
/* 0x43 Mute */
{0, 0, 0, {KEY_MUTE, 0}, (MHL_DEV_LD_SPEAKER)},
/* 0x44 Play */
{0, 0, 0, {KEY_PLAY, 0}, (MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO)},
/* 0x45 Stop */
{0, 0, 0, {KEY_STOP, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO | MHL_DEV_LD_RECORD)},
/* 0x46 Pause */
{0, 0, 0, {KEY_PLAYPAUSE, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO | MHL_DEV_LD_RECORD)},
/* 0x47 Record */
{0, 0, 0, {KEY_RECORD, 0}, (MHL_DEV_LD_RECORD)},
/* 0x48 Rewind */
{0, 1, 0, {KEY_REWIND, 0}, (MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO)},
/* 0x49 Fast Forward */
{0, 1, 0, {KEY_FASTFORWARD, 0}, (MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO)},
/* 0x4A Eject */
{0, 0, 0, {KEY_EJECTCD, 0}, (MHL_DEV_LD_MEDIA)},
/* 0x4B Forward */
{0, 1, 0, {KEY_NEXTSONG, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO | MHL_DEV_LD_MEDIA)},
/* 0x4C Backward */
{0, 1, 0, {KEY_PREVIOUSSONG, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO | MHL_DEV_LD_MEDIA)},
/* 0x4D - 0x4F Reserved */
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
/* 0x50 = Angle */
{0, 0, 0, {KEY_UNKNOWN, 0}, 0},
/* 0x51 = Subpicture */
{0, 0, 0, {KEY_UNKNOWN, 0}, 0},
/* 0x52 - 0x5F Reserved */
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
/* 0x60 Play */
{0, 0, 0, {KEY_PLAYPAUSE, 0}, (MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO)},
/* 0x60 = Pause the Play */
{0, 0, 0, {KEY_PLAYPAUSE, 0}, (MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO)},
/* 0x62 = Record */
{0, 0, 0, {KEY_RECORD, 0}, (MHL_DEV_LD_RECORD)},
/* 0x63 = Pause the Record */
{0, 0, 0, {KEY_PAUSE, 0}, (MHL_DEV_LD_RECORD)},
/* 0x64 = Stop */
{0, 0, 0, {KEY_STOP, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO | MHL_DEV_LD_RECORD)},
/* 0x65 = Mute */
{0, 0, 0, {KEY_MUTE, 0}, (MHL_DEV_LD_SPEAKER)},
/* 0x66 = Restore Mute */
{0, 0, 0, {KEY_MUTE, 0}, (MHL_DEV_LD_SPEAKER)},
/* 0x67 - 0x68 Undefined */
{0, 0, 0, {KEY_UNKNOWN, 0}, 0},
{0, 0, 0, {KEY_UNKNOWN, 0}, 0},
/* 0x69 - 0x70 Reserved */
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
/* 0x71 - 0x75 F1 - F5 */
{0, 0, 0, {KEY_F1, 0}, 0},
{0, 0, 0, {KEY_F2, 0}, 0},
{0, 0, 0, {KEY_F3, 0}, 0},
{0, 0, 0, {KEY_F4, 0}, 0},
{0, 0, 0, {KEY_F5, 0}, 0},
/* 0x76 - 0x7D Reserved */
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
/* 0x7E Vendor */
{0, 0, 0, {KEY_VENDOR, 0}, 0},
/* 0x7F reserved */
{0, 0, 0, {KEY_RESERVED, 0}, 0}
};
static u16 rcp_def_keymap[MHL_NUM_RCP_KEY_CODES]
#ifdef OLD_KEYMAP_TABLE
= {
KEY_SELECT,
KEY_UP,
KEY_DOWN,
KEY_LEFT,
KEY_RIGHT,
KEY_UNKNOWN, /* right-up */
KEY_UNKNOWN, /* right-down */
KEY_UNKNOWN, /* left-up */
KEY_UNKNOWN, /* left-down */
KEY_MENU,
KEY_UNKNOWN, /* setup */
KEY_UNKNOWN, /* contents */
KEY_UNKNOWN, /* favorite */
KEY_EXIT,
KEY_RESERVED, /* 0x0e */
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED, /* 0x1F */
KEY_NUMERIC_0,
KEY_NUMERIC_1,
KEY_NUMERIC_2,
KEY_NUMERIC_3,
KEY_NUMERIC_4,
KEY_NUMERIC_5,
KEY_NUMERIC_6,
KEY_NUMERIC_7,
KEY_NUMERIC_8,
KEY_NUMERIC_9,
KEY_DOT,
KEY_ENTER,
KEY_CLEAR,
KEY_RESERVED, /* 0x2D */
KEY_RESERVED,
KEY_RESERVED, /* 0x2F */
KEY_UNKNOWN, /* channel up */
KEY_UNKNOWN, /* channel down */
KEY_UNKNOWN, /* previous channel */
KEY_UNKNOWN, /* sound select */
KEY_UNKNOWN, /* input select */
KEY_UNKNOWN, /* show information */
KEY_UNKNOWN, /* help */
KEY_UNKNOWN, /* page up */
KEY_UNKNOWN, /* page down */
KEY_RESERVED, /* 0x39 */
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED, /* 0x3F */
KEY_RESERVED, /* 0x40 */
KEY_UNKNOWN, /* volume up */
KEY_UNKNOWN, /* volume down */
KEY_UNKNOWN, /* mute */
KEY_PLAY,
KEY_STOP,
KEY_PLAYPAUSE,
KEY_UNKNOWN, /* record */
KEY_REWIND,
KEY_FASTFORWARD,
KEY_UNKNOWN, /* eject */
KEY_NEXTSONG,
KEY_PREVIOUSSONG,
KEY_RESERVED, /* 0x4D */
KEY_RESERVED,
KEY_RESERVED, /* 0x4F */
KEY_UNKNOWN, /* angle */
KEY_UNKNOWN, /* subtitle */
KEY_RESERVED, /* 0x52 */
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED, /* 0x5F */
KEY_PLAY,
KEY_PAUSE,
KEY_UNKNOWN, /* record_function */
KEY_UNKNOWN, /* pause_record_function */
KEY_STOP,
KEY_UNKNOWN, /* mute_function */
KEY_UNKNOWN, /* restore_volume_function */
KEY_UNKNOWN, /* tune_function */
KEY_UNKNOWN, /* select_media_function */
KEY_RESERVED, /* 0x69 */
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED, /* 0x70 */
KEY_UNKNOWN, /* F1 */
KEY_UNKNOWN, /* F2 */
KEY_UNKNOWN, /* F3 */
KEY_UNKNOWN, /* F4 */
KEY_UNKNOWN, /* F5 */
KEY_RESERVED, /* 0x76 */
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED, /* 0x7D */
KEY_VENDOR,
KEY_RESERVED, /* 0x7F */
}
#endif
;
#ifdef OLD_KEYMAP_TABLE
int generate_rcp_input_event(struct mhl_dev_context *dev_context,
uint8_t rcp_keycode)
{
int status = -EINVAL;
if (dev_context->rcp_input_dev) {
if (rcp_keycode < ARRAY_SIZE(rcp_def_keymap) &&
rcp_def_keymap[rcp_keycode] != KEY_UNKNOWN &&
rcp_def_keymap[rcp_keycode] != KEY_RESERVED) {
input_report_key(dev_context->rcp_input_dev,
rcp_keycode, 1);
input_report_key(dev_context->rcp_input_dev,
rcp_keycode, 0);
input_sync(dev_context->rcp_input_dev);
status = 0;
}
}
return status;
}
#else
static int rcp_trigger_key_action(struct mhl_dev_context *dev_context,
uint8_t index, bool press_release)
{
int status = -EINVAL;
index &= MHL_RCP_KEY_ID_MASK;
if (dev_context->rcp_input_dev) {
input_report_key(dev_context->rcp_input_dev,
rcpSupportTable[index].map[0], press_release);
MHL_TX_DBG_ERR("input_report_key(0x%x,%d)\n",
rcpSupportTable[index].map[0], press_release)
if (rcpSupportTable[index].multicode) {
input_report_key(dev_context->rcp_input_dev,
rcpSupportTable[index].map[1], press_release);
MHL_TX_DBG_ERR("input_report_key(0x%x,%d)\n",
rcpSupportTable[index].map[1], press_release)
}
input_sync(dev_context->rcp_input_dev);
status = 0;
}
return status;
}
static int handle_rcp_event(struct mhl_dev_context *dev_context,
uint8_t current_key, uint8_t prev_key, enum rcp_event_e event)
{
int status = 0;
uint8_t current_index = current_key & MHL_RCP_KEY_ID_MASK;
uint8_t prev_index = prev_key & MHL_RCP_KEY_ID_MASK;
MHL_TX_DBG_ERR("received 0x%02x: %s(%d) in state: %s(%d)\n",
current_key, event_strings[event], event,
state_strings[current_rcp_state], current_rcp_state);
/* now process the event according to the current state */
switch (current_rcp_state) {
case PH0_IDLE:
switch (event) {
case RCP_NORMAL_KEY_PRESS:
case RCP_NORMAL_KEY_PRESS_SAME:
status =
rcp_trigger_key_action(dev_context, current_index,
1);
/* no update for current_rcp_state */
break;
case RCP_NORMAL_KEY_RELEASE:
case RCP_NORMAL_KEY_RELEASE_SAME:
status =
rcp_trigger_key_action(dev_context, current_index,
0);
/* no update for current_rcp_state */
break;
case RCP_HOLD_KEY_PRESS:
case RCP_HOLD_KEY_PRESS_SAME:
status =
rcp_trigger_key_action(dev_context, current_index,
1);
/* no break here */
mhl_tx_start_timer(dev_context,
dev_context->timer_T_press_mode,
T_PRESS_MODE);
current_rcp_state = PH3_PRESS_AND_HOLD_KEY;
break;
case RCP_HOLD_KEY_RELEASE:
case RCP_HOLD_KEY_RELEASE_SAME:
MHL_TX_DBG_ERR("unexpected %s(%d) in state: %s(%d)\n",
event_strings[event], event,
state_strings[current_rcp_state],
current_rcp_state);
break;
default:
MHL_TX_DBG_ERR("unexpected event: %d in state: %d\n",
event, current_rcp_state);
/* no update for current_rcp_state */
status = -EINVAL;
}
break;
case PH3_PRESS_AND_HOLD_KEY:
switch (event) {
case RCP_NORMAL_KEY_PRESS:
case RCP_NORMAL_KEY_PRESS_SAME:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_press_mode);
rcp_trigger_key_action(dev_context, prev_index, 0);
/* OK to overwrite status */
status =
rcp_trigger_key_action(dev_context, current_index,
1);
current_rcp_state = PH0_IDLE;
break;
case RCP_NORMAL_KEY_RELEASE:
case RCP_NORMAL_KEY_RELEASE_SAME:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_press_mode);
rcp_trigger_key_action(dev_context, prev_index, 0);
rcp_trigger_key_action(dev_context, current_index, 1);
status =
rcp_trigger_key_action(dev_context, current_index,
0);
current_rcp_state = PH0_IDLE;
break;
case RCP_HOLD_KEY_PRESS:
mhl_tx_start_timer(dev_context,
dev_context->timer_T_press_mode,
T_PRESS_MODE);
status =
rcp_trigger_key_action(dev_context, prev_index, 1);
/* no update for current_rcp_state */
break;
case RCP_HOLD_KEY_PRESS_SAME:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_press_mode);
mhl_tx_start_timer(dev_context,
dev_context->timer_T_hold_maintain,
T_HOLD_MAINTAIN);
status =
rcp_trigger_key_action(dev_context, prev_index, 1);
current_rcp_state = ph8_hold_mode;
break;
case RCP_HOLD_KEY_RELEASE:
case RCP_HOLD_KEY_RELEASE_SAME:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_press_mode);
status =
rcp_trigger_key_action(dev_context, prev_index, 0);
current_rcp_state = PH0_IDLE;
break;
case RCP_T_PRESS_MODE_EXPIRED:
mhl_tx_start_timer(dev_context,
dev_context->timer_T_hold_maintain,
T_HOLD_MAINTAIN);
status =
rcp_trigger_key_action(dev_context, prev_index, 0);
current_rcp_state = ph8_hold_mode;
break;
default:
MHL_TX_DBG_ERR("unexpected event: %d in state: %d\n",
event, current_rcp_state);
/* no update for current_rcp_state */
status = -EINVAL;
}
break;
case ph8_hold_mode:
switch (event) {
case RCP_NORMAL_KEY_PRESS:
case RCP_NORMAL_KEY_PRESS_SAME:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_hold_maintain);
rcp_trigger_key_action(dev_context, prev_index, 0);
status =
rcp_trigger_key_action(dev_context, current_index,
1);
current_rcp_state = PH0_IDLE;
break;
case RCP_NORMAL_KEY_RELEASE:
case RCP_NORMAL_KEY_RELEASE_SAME:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_hold_maintain);
rcp_trigger_key_action(dev_context, prev_index, 0);
rcp_trigger_key_action(dev_context, current_index, 1);
status =
rcp_trigger_key_action(dev_context, current_index,
0);
current_rcp_state = PH0_IDLE;
break;
case RCP_HOLD_KEY_PRESS:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_hold_maintain);
mhl_tx_start_timer(dev_context,
dev_context->timer_T_press_mode,
T_PRESS_MODE);
status =
rcp_trigger_key_action(dev_context, prev_index, 1);
current_rcp_state = PH3_PRESS_AND_HOLD_KEY;
break;
case RCP_HOLD_KEY_PRESS_SAME:
mhl_tx_start_timer(dev_context,
dev_context->timer_T_hold_maintain,
T_HOLD_MAINTAIN);
status =
rcp_trigger_key_action(dev_context, prev_index, 1);
/* no update for current_rcp_state */
break;
case RCP_HOLD_KEY_RELEASE:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_hold_maintain);
rcp_trigger_key_action(dev_context, prev_index, 0);
rcp_trigger_key_action(dev_context, current_index, 1);
status =
rcp_trigger_key_action(dev_context, current_index,
0);
current_rcp_state = PH0_IDLE;
break;
case RCP_HOLD_KEY_RELEASE_SAME:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_hold_maintain);
status =
rcp_trigger_key_action(dev_context, prev_index, 0);
current_rcp_state = PH0_IDLE;
break;
case RCP_T_HOLD_MAINTAIN_EXPIRED:
status =
rcp_trigger_key_action(dev_context, prev_index, 0);
current_rcp_state = PH0_IDLE;
break;
default:
MHL_TX_DBG_ERR("unexpected event: %d in state: %d\n",
event, current_rcp_state);
/* no update for current_rcp_state */
status = -EINVAL;
}
break;
default:
MHL_TX_DBG_ERR("irrational state value:%d\n",
current_rcp_state);
}
return status;
}
static void timer_callback_T_hold_maintain_handler(void *param)
{
struct mhl_dev_context *dev_context = (struct mhl_dev_context *)param;
handle_rcp_event(dev_context, rcp_current_key, rcp_previous_key,
RCP_T_HOLD_MAINTAIN_EXPIRED);
}
static void timer_callback_T_press_mode_handler(void *param)
{
struct mhl_dev_context *dev_context = (struct mhl_dev_context *)param;
handle_rcp_event(dev_context, rcp_current_key, rcp_previous_key,
RCP_T_PRESS_MODE_EXPIRED);
}
int generate_rcp_input_event(struct mhl_dev_context *dev_context,
uint8_t rcp_keycode)
{
/*
Since, in MHL, bit 7 == 1 indicates key release,
and, in Linux, zero means key release,
we use XOR (^) to invert the sense.
*/
int status = -EINVAL;
int index = rcp_keycode & MHL_RCP_KEY_ID_MASK;
if (rcp_def_keymap[index] != KEY_UNKNOWN &&
rcp_def_keymap[index] != KEY_RESERVED) {
enum rcp_event_e event;
int mhl_key_press =
(rcp_keycode & MHL_RCP_KEY_RELEASED_MASK) ? 0 : 1;
if (mhl_key_press) {
if (rcpSupportTable[index].press_and_hold_key) {
if (index == rcp_previous_key)
event = RCP_HOLD_KEY_PRESS_SAME;
else
event = RCP_HOLD_KEY_PRESS;
} else {
if (index == rcp_previous_key)
event = RCP_NORMAL_KEY_PRESS_SAME;
else
event = RCP_NORMAL_KEY_PRESS;
}
} else {
if (rcpSupportTable[index].press_and_hold_key) {
if (index == rcp_previous_key)
event = RCP_HOLD_KEY_RELEASE_SAME;
else
event = RCP_HOLD_KEY_RELEASE;
} else {
if (index == rcp_previous_key)
event = RCP_NORMAL_KEY_RELEASE_SAME;
else
event = RCP_NORMAL_KEY_RELEASE;
}
}
status =
handle_rcp_event(dev_context, rcp_keycode, rcp_current_key,
event);
}
rcp_previous_key = rcp_current_key;
rcp_current_key = rcp_keycode;
return status;
}
#endif
int init_rcp_input_dev(struct mhl_dev_context *dev_context)
{
unsigned int i;
struct input_dev *rcp_input_dev;
int ret;
if (dev_context->rcp_input_dev != NULL) {
MHL_TX_DBG_INFO("RCP input device already exists!\n");
return 0;
}
rcp_input_dev = input_allocate_device();
if (!rcp_input_dev) {
MHL_TX_DBG_ERR("Failed to allocate RCP input device\n");
return -ENOMEM;
}
set_bit(EV_KEY, rcp_input_dev->evbit);
rcp_input_dev->name = "MHL Remote Control";
rcp_input_dev->keycode = rcp_def_keymap;
rcp_input_dev->keycodesize = sizeof(u16);
rcp_input_dev->keycodemax = ARRAY_SIZE(rcp_def_keymap);
for (i = 0; i < ARRAY_SIZE(rcp_def_keymap); i++) {
#ifdef OLD_KEYMAP_TABLE
u16 keycode = rcp_def_keymap[i];
#else
u16 keycode = rcpSupportTable[i].map[0];
rcp_def_keymap[i] = keycode;
#endif
if (keycode != KEY_UNKNOWN && keycode != KEY_RESERVED)
set_bit(keycode, rcp_input_dev->keybit);
}
rcp_input_dev->id.bustype = BUS_VIRTUAL;
ret = input_register_device(rcp_input_dev);
if (ret) {
MHL_TX_DBG_ERR("Failed to register device\n");
input_free_device(rcp_input_dev);
return ret;
}
ret = mhl_tx_create_timer(dev_context,
timer_callback_T_press_mode_handler,
dev_context, &dev_context->timer_T_press_mode);
if (ret != 0) {
MHL_TX_DBG_ERR("failed in created timer_T_press_mode!\n");
} else {
ret = mhl_tx_create_timer(dev_context,
timer_callback_T_hold_maintain_handler,
dev_context, &dev_context->timer_T_hold_maintain);
if (ret != 0) {
MHL_TX_DBG_ERR
("failed to create timer_T_hold_maintain!\n");
} else {
MHL_TX_DBG_INFO("device created\n");
dev_context->rcp_input_dev = rcp_input_dev;
return 0;
}
mhl_tx_delete_timer(dev_context,
&dev_context->timer_T_press_mode);
}
return ret;
}
void destroy_rcp_input_dev(struct mhl_dev_context *dev_context)
{
if (dev_context->timer_T_press_mode) {
mhl_tx_delete_timer(dev_context,
&dev_context->timer_T_press_mode);
}
if (dev_context->timer_T_hold_maintain) {
mhl_tx_delete_timer(dev_context,
&dev_context->timer_T_hold_maintain);
}
if (dev_context->rcp_input_dev) {
input_unregister_device(dev_context->rcp_input_dev);
dev_context->rcp_input_dev = NULL;
}
}
void rcp_input_dev_one_time_init(struct mhl_dev_context *dev_context)
{
int i;
for (i = 0; i < MHL_NUM_RCP_KEY_CODES; ++i)
rcp_def_keymap[i] = rcpSupportTable[i].map[0];
}

View file

@ -0,0 +1,42 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#ifndef _MHL_RCP_INPUTDEV_H_
#define _MHL_RCP_INPUTDEV_H_
struct mhl_dev_context;
struct rcp_keymap_t {
unsigned multicode:1;
unsigned press_and_hold_key:1;
unsigned reserved:6;
uint16_t map[2];
uint8_t rcp_support;
};
#define MHL_LOGICAL_DEVICE_MAP (MHL_DEV_LD_AUDIO | MHL_DEV_LD_VIDEO | \
MHL_DEV_LD_MEDIA | MHL_DEV_LD_GUI)
#define MHL_NUM_RCP_KEY_CODES 0x80
extern struct rcp_keymap_t rcpSupportTable[MHL_NUM_RCP_KEY_CODES];
int generate_rcp_input_event(struct mhl_dev_context *dev_context,
uint8_t rcp_keycode);
int init_rcp_input_dev(struct mhl_dev_context *dev_context);
void destroy_rcp_input_dev(struct mhl_dev_context *dev_context);
void rcp_input_dev_one_time_init(struct mhl_dev_context *dev_context);
#endif /* #ifndef _MHL_RCP_INPUTDEV_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,108 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#if !defined(MHL_SUPP_H)
#define MHL_SUPP_H
/* APIs exported from mhl_supp.c */
int si_mhl_tx_get_num_block_reqs(void);
int si_mhl_tx_initialize(struct mhl_dev_context *dev_context);
int si_mhl_tx_reserve_resources(struct mhl_dev_context *dev_context);
void si_mhl_tx_initialize_block_transport(struct mhl_dev_context *dev_context);
void process_cbus_abort(struct mhl_dev_context *dev_context);
void si_mhl_tx_drive_states(struct mhl_dev_context *dev_context);
void si_mhl_tx_push_block_transactions(struct mhl_dev_context *dev_context);
bool invalid_bist_te_parms(struct mhl_dev_context *dev_context,
struct bist_setup_info *setup_info);
void initiate_bist_test(struct mhl_dev_context *dev_context);
void si_mhl_tx_process_events(struct mhl_dev_context *dev_context);
uint8_t si_mhl_tx_set_preferred_pixel_format(struct mhl_dev_context
*dev_context, uint8_t clkMode);
void si_mhl_tx_process_write_burst_data(struct mhl_dev_context *dev_context);
void si_mhl_tx_msc_command_done(struct mhl_dev_context *dev_context,
uint8_t data1);
void si_mhl_tx_notify_downstream_hpd_change(struct mhl_dev_context *dev_context,
uint8_t downstream_hpd);
void si_mhl_tx_got_mhl_status(struct mhl_dev_context *dev_context,
struct mhl_device_status *write_stat);
void si_mhl_tx_got_mhl_intr(struct mhl_dev_context *dev_context,
uint8_t intr_0, uint8_t intr_1);
void si_mhl_tx_bist_cleanup(struct mhl_dev_context *dev_context);
enum scratch_pad_status si_mhl_tx_request_write_burst(
struct mhl_dev_context *dev_context, uint8_t reg_offset,
uint8_t length, uint8_t *data);
bool si_mhl_tx_send_msc_msg(struct mhl_dev_context *dev_context,
uint8_t command, uint8_t cmdData,
struct cbus_req *(*completion)(struct mhl_dev_context *dev_context,
struct cbus_req *req, uint8_t data1));
bool si_mhl_tx_rcp_send(struct mhl_dev_context *dev_context,
uint8_t rcpKeyCode);
bool si_mhl_tx_rcpk_send(struct mhl_dev_context *dev_context,
uint8_t rcp_key_code);
bool si_mhl_tx_rcpe_send(struct mhl_dev_context *dev_context,
uint8_t rcpe_error_code);
bool si_mhl_tx_rbp_send(struct mhl_dev_context *dev_context,
uint8_t rbpButtonCode);
bool si_mhl_tx_rbpk_send(struct mhl_dev_context *dev_context,
uint8_t rbp_button_code);
bool si_mhl_tx_rbpe_send(struct mhl_dev_context *dev_context,
uint8_t rbpe_error_code);
bool si_mhl_tx_ucp_send(struct mhl_dev_context *dev_context,
uint8_t ucp_key_code);
bool si_mhl_tx_ucpk_send(struct mhl_dev_context *dev_context,
uint8_t ucp_key_code);
bool si_mhl_tx_ucpe_send(struct mhl_dev_context *dev_context,
uint8_t ucpe_error_code);
bool si_mhl_tx_rap_send(struct mhl_dev_context *dev_context,
uint8_t rap_action_code);
struct cbus_req *peek_next_cbus_transaction(struct mhl_dev_context
*dev_context);
bool si_mhl_tx_send_3d_req_or_feat_req(struct mhl_dev_context *dev_context);
void send_bist_ready(struct mhl_dev_context *dev_context);
enum bist_cmd_status {
BIST_STATUS_NO_ERROR,
BIST_STATUS_NOT_IN_OCBUS,
BIST_STATUS_NOT_IN_ECBUS,
BIST_STATUS_INVALID_SETUP,
BIST_STATUS_INVALID_TRIGGER,
BIST_STATUS_DUT_NOT_READY,
BIST_STATUS_NO_RESOURCES,
BIST_STATUS_TEST_IP,
BIST_STATUS_NO_TEST_IP
};
enum bist_cmd_status si_mhl_tx_bist_setup(struct mhl_dev_context *dev_context,
struct bist_setup_info *setup);
enum bist_cmd_status si_mhl_tx_bist_trigger(struct mhl_dev_context *dev_context,
uint8_t trigger_operand);
void si_mhl_tx_execute_bist(struct mhl_dev_context *dev_context,
struct bist_setup_info *setup_info);
void start_bist_initiator_test(struct mhl_dev_context *dev_context);
enum bist_cmd_status si_mhl_tx_bist_stop(struct mhl_dev_context *dev_context);
enum bist_cmd_status si_mhl_tx_bist_request_stat(struct mhl_dev_context
*dev_context,
uint8_t request_operand);
int si_mhl_tx_shutdown(struct mhl_dev_context *dev_context);
int si_mhl_tx_ecbus_started(struct mhl_dev_context *dev_context);
void si_mhl_tx_send_blk_rcv_buf_info(struct mhl_dev_context *dev_context);
void si_mhl_tx_initialize_block_transport(struct mhl_dev_context *dev_context);
void si_mhl_tx_set_bist_timer_impl(struct mhl_dev_context *dev_context,
const char *caller, int line_num);
#define si_mhl_tx_set_bist_timer(dev_context) \
si_mhl_tx_set_bist_timer_impl(dev_context, __func__, __LINE__)
#endif /* #if !defined(MHL_SUPP_H) */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,236 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#if !defined(PLATFORM_H)
#define PLATFORM_H
#define DEVICE_ID_8620 0x8620
#define DEBUG_I2C_WRITE 1
#define DEBUG_I2C_READ 0
#define MAX_DEBUG_TRANSFER_SIZE 32
enum dbg_msg_level {
DBG_MSG_LEVEL_ERR,
DBG_MSG_LEVEL_WARN,
DBG_MSG_LEVEL_INFO,
DBG_MSG_LEVEL_GPIO,
DBG_MSG_LEVEL_EDID_INFO,
DBG_MSG_LEVEL_COMM_INFO
};
enum tx_interface_types {
TX_INTERFACE_TYPE_I2C,
TX_INTERFACE_TYPE_SPI
};
#if defined(DEBUG)
void print_formatted_debug_msg(char *file_spec, const char *func_name,
int line_num, char *fmt, ...);
void dump_transfer(enum tx_interface_types if_type,
u8 page, u8 offset, u16 count, u8 *values, bool write);
#define MHL_TX_PROXY_DBG_PRINT(level, function, iLine, ...) \
{ \
if ((level) <= debug_level) \
print_formatted_debug_msg(NULL, function, iLine, __VA_ARGS__); \
}
#define MHL_TX_GENERIC_DBG_PRINT(level, ...) \
{ \
if ((level) <= debug_level) \
print_formatted_debug_msg(NULL, __func__, __LINE__, \
__VA_ARGS__); \
}
#define MHL_TX_COMM_INFO(...) \
MHL_TX_GENERIC_DBG_PRINT(DBG_MSG_LEVEL_COMM_INFO, __VA_ARGS__)
#define MHL_TX_EDID_INFO(...) \
MHL_TX_GENERIC_DBG_PRINT(DBG_MSG_LEVEL_EDID_INFO, __VA_ARGS__)
#define MHL_TX_DBG_GPIO(...) \
MHL_TX_GENERIC_DBG_PRINT(DBG_MSG_LEVEL_GPIO, __VA_ARGS__)
#define MHL_TX_DBG_INFO(...) \
MHL_TX_GENERIC_DBG_PRINT(DBG_MSG_LEVEL_INFO, __VA_ARGS__)
#define MHL_TX_DBG_WARN(...) \
MHL_TX_GENERIC_DBG_PRINT(DBG_MSG_LEVEL_WARN, __VA_ARGS__)
#define MHL_TX_DBG_ERR(...) \
MHL_TX_GENERIC_DBG_PRINT(DBG_MSG_LEVEL_ERR, __VA_ARGS__)
#define DUMP_I2C_TRANSFER(page, offset, count, values, write_flag) \
dump_transfer(TX_INTERFACE_TYPE_I2C, page, offset, \
count, values, write_flag);
#define DUMP_SPI_TRANSFER(page, offset, count, values, write_flag) \
dump_transfer(TX_INTERFACE_TYPE_SPI, page, offset, \
count, values, write_flag);
#else
#define MHL_TX_PROXY_DBG_PRINT(level, function, iLine, ...)
#define MHL_TX_GENERIC_DBG_PRINT(level, ...)
#define MHL_TX_COMM_INFO(fmt, ...)
#define MHL_TX_EDID_INFO(fmt, ...)
#define MHL_TX_DBG_GPIO(fmt, ...)
#define MHL_TX_DBG_INFO(fmt, ...)
#define MHL_TX_DBG_WARN(fmt, ...)
#define MHL_TX_DBG_ERR(fmt, ...)
#define DUMP_I2C_TRANSFER(page, offset, count, values, write_flag)
#define DUMP_SPI_TRANSFER(page, offset, count, values, write_flag)
#endif
void push_debug_level(int new_verbosity);
void pop_debug_level(void);
enum vbus_power_state {
VBUS_OFF,
VBUS_ON
};
enum hpd_control_mode {
HPD_CTRL_MODE_ERROR = -1,
HPD_CTRL_OPEN_DRAIN,
HPD_CTRL_PUSH_PULL
};
enum hpd_control_mode platform_get_hpd_control_mode(void);
void platform_mhl_tx_hw_reset(uint32_t reset_period, uint32_t reset_delay);
void mhl_tx_vbus_control(enum vbus_power_state power_state);
void mhl_tx_vbus_current_ctl(uint16_t max_current_in_milliamps);
struct platform_reg_pair {
uint8_t slave_addr;
uint8_t offset;
};
struct platform_signals_list {
char *name;
int16_t gpio_number;
struct platform_reg_pair gpio_reg_PCA950x;
uint8_t gpio_mask_PCA950x;
uint8_t *gpio_bank_value;
bool *param;
};
struct block_buffer_info_t {
uint8_t *buffer;
uint8_t payload_offset;
size_t req_size;
};
void si_mhl_tx_platform_get_block_buffer_info(
struct block_buffer_info_t *block_buffer_info);
int mhl_tx_write_block_spi_emsc(void *drv_context, struct block_req *req);
int mhl_tx_read_spi_emsc(void *drv_context, u16 count, u8 *values);
void mhl_tx_clear_emsc_read_err(void *drv_context);
int mhl_tx_write_reg(void *drv_context, u16 address, u8 value);
int mhl_tx_read_reg(void *drv_context, u16 address);
int mhl_tx_write_reg_block(void *drv_context, u16 address, u16 count,
u8 *values);
int mhl_tx_read_reg_block(void *drv_context, u16 address, u16 count,
u8 *values);
int mhl_tx_modify_reg(void *drv_context, u16 address, u8 mask, u8 value);
#ifdef DEBUG
int si_8620_power_control(bool power_up);
#endif
uint32_t platform_get_flags(void);
#define PLATFORM_FLAG_HEARTBEAT_MASK 0x00000030
#define PLATFORM_VALUE_ISSUE_HEARTBEAT 0x00000010
#define PLATFORM_VALUE_DISCONN_HEARTBEAT 0x00000020
#define PLATFORM_FLAG_LINK_SPEED 0x000000C0
#define PLATFORM_FLAG_6GBPS 0x000000C0
#define PLATFORM_FLAG_3GBPS 0x00000080
#define PLATFORM_FLAG_1_5GBPS 0x00000040
int is_interrupt_asserted(void);
int get_config(void *dev_context, int config_idx);
#define GPIO_LED_ON 0
#define GPIO_LED_OFF 1
void set_pin_impl(/*void *dev_context,*/ int pin_idx, int value,
const char *function_name, int line_num);
#define set_pin(/*dev_context,*/ pin_idx, value) \
set_pin_impl(/*dev_context,*/ pin_idx, value, __func__, __LINE__)
extern bool source_vbus_on;
extern bool bpp_on_wb;
extern bool use_spi;
extern bool wait_for_user_intr;
extern int debug_level;
extern bool debug_reg_dump;
extern bool force_ocbus_for_ects;
extern int crystal_khz;
extern int gpio_index;
extern int hdcp_content_type;
extern bool input_dev_rap;
#if (INCLUDE_RBP == 1)
extern bool input_dev_rbp;
#endif
extern bool input_dev_rcp;
extern bool input_dev_ucp;
/* Starter kit board signal control index definitions */
#define TX_HW_RESET 0
#define TX_FW_WAKE 1
#define CHG_DET 2
#define XO3_SINK_VBUS_SENSE 3
#define TWELVE_VOLT_PS_SENSE 4
#define EEPROM_WR_EN 5
#define TX2MHLRX_PWR 6
#define M2U_VBUS_CTRL 7
#define LED_3D 8
#define LED_PACKED_PIXEL 9
#define LED_HDCP 10
#define LED_USB_MODE 11
#define LED_SPARE_2 12
#define LED_SPARE_3 13
#define LED_SPARE_4 14
#define X02_USB_SW_CTRL 15
#define X02_USB_SW_CTRL0 16
#define X02_USB_SW_CTRL1 17
#define X02_USB_LED15_AMBER 18
#define X02_USB_LED15_GREEN 19
#ifdef ANSI_COLORS
#define ANSI_ESC_RESET_TEXT "\x1b[0m"
#define ANSI_ESC_YELLOW_BG "\x1b[43m"
#define ANSI_ESC_WHITE_BG "\x1b[47m"
#define ANSI_ESC_RED_TEXT "\x1b[31m"
#define ANSI_ESC_YELLOW_TEXT "\x1b[33m"
#define ANSI_ESC_GREEN_TEXT "\x1b[32m"
#define ANSI_ESC_BLACK_TEXT "\1b[30m"
#define ANSI_ESC_WHITE_TEXT "\x1b[37m\x1b[1m"
#define ANSI_ESC_MAGENTA_TEXT "\x1b[35m"
#define ANSI_ESC_CYAN_TEXT "\x1b[36m"
#else
#define ANSI_ESC_RESET_TEXT ""
#define ANSI_ESC_WHITE_BG ""
#define ANSI_ESC_RED_TEXT "\n\n"
#define ANSI_ESC_YELLOW_TEXT "\n\n"
#define ANSI_ESC_GREEN_TEXT "\n\n"
#define ANSI_ESC_BLACK_TEXT ""
#define ANSI_ESC_WHITE_TEXT ""
#define ANSI_ESC_MAGENTA_TEXT ""
#define ANSI_ESC_CYAN_TEXT ""
#endif
#endif /* if !defined(PLATFORM_H) */

View file

@ -0,0 +1 @@
-DMHL_BUILD_NUM=$BUILD_NUM -DI2C_BUS_NUM=4 -DMHL_PRODUCT_NUM=8620 mhl_linux_tx.c mhl_rcp_inputdev.c mhl_supp.c platform.c si_8620_drv.c si_mdt_inputdev.c si_mhl2_edid_3d.c

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,113 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#if !defined(SI_8620_DRV_H)
#define SI_8620_DRV_H
extern uint8_t dev_cap_values[16];
enum pp_16bpp_override_t {
pp_16bpp_automatic = 0x00,
pp_16bpp_override_24bpp = 0x01,
pp_16bpp_override_16bpp = 0x02
};
struct drv_hw_context {
struct interrupt_info *intr_info;
uint8_t chip_rev_id;
uint16_t chip_device_id;
uint8_t cbus_status;
uint8_t gen2_write_burst_rcv;
uint8_t gen2_write_burst_xmit;
uint8_t hawb_write_pending;
enum {
CBUS1_IDLE_RCV_DISABLED,
CBUS1_IDLE_RCV_ENABLED,
CBUS1_IDLE_RCV_PEND,
CBUS1_MSC_PEND_DLY_RCV_EN,
CBUS1_MSC_PEND_DLY_RCV_DIS,
CBUS1_XMIT_PEND_XMIT_RCV_EN,
CBUS1_XMIT_PEND_XMIT_RCV_PEND
} cbus1_state;
uint8_t delayed_hawb_enable_reg_val;
uint8_t video_path;
uint8_t video_ready;
uint8_t mhl_peer_version_stat;
enum cbus_mode_e cbus_mode;
uint8_t current_edid_req_blk;
uint8_t edid_fifo_block_number;
uint8_t valid_vsif;
#ifdef NEVER_USED
uint8_t valid_avif;
#endif
uint8_t rx_hdmi_ctrl2_defval;
uint8_t aksv[5];
struct avi_info_frame_t current_avi_info_frame;
union SI_PACK_THIS_STRUCT vsif_mhl3_or_hdmi_u current_vsif;
union hw_avi_payload_t outgoingAviPayLoad;
struct mhl3_vsif_t outgoing_mhl3_vsif;
uint8_t write_burst_data[MHL_SCRATCHPAD_SIZE];
struct cbus_req current_cbus_req;
uint8_t tdm_virt_chan_slot_counts[VC_MAX];
struct {
uint16_t received_byte_count;
unsigned long peer_blk_rx_buf_avail;
unsigned long peer_blk_rx_buf_max;
#define NUM_BLOCK_INPUT_BUFFERS 8
uint8_t input_buffers[NUM_BLOCK_INPUT_BUFFERS][256];
int input_buffer_lengths[NUM_BLOCK_INPUT_BUFFERS];
uint16_t head;
uint16_t tail;
} block_protocol;
struct si_mhl_callback_api_t callbacks;
union avif_or_cea_861_dtd_u avif_or_dtd_from_callback;
union vsif_mhl3_or_hdmi_u vsif_mhl3_or_hdmi_from_callback;
int hpd_high_callback_status;
#ifdef MANUAL_EDID_FETCH
uint8_t edid_block[EDID_BLOCK_SIZE];
#endif
void *input_field_rate_measurement_timer;
uint8_t idx_pixel_clock_history;
uint32_t pixel_clock_history[16];
bool hdcp2_started;
enum pp_16bpp_override_t pp_16bpp_override;
uint8_t prev_bist_coc_status[6];
};
bool si_mhl_tx_set_status(struct mhl_dev_context *dev_context,
bool xstat, uint8_t reg_to_write, uint8_t value);
void *si_mhl_tx_get_sub_payload_buffer(struct mhl_dev_context *dev_context,
uint8_t size);
bool si_mhl_tx_send_write_burst(struct mhl_dev_context *dev_context,
void *buffer);
int si_mhl_tx_drv_cbus_ready_for_edid(struct mhl_dev_context *dev_context);
int si_mhl_tx_drv_set_display_mode(struct mhl_dev_context *dev_context,
enum hpd_high_callback_status status);
int si_mhl_tx_drv_sample_edid_buffer(struct drv_hw_context *hw_context,
uint8_t *edid_buffer);
void si_set_cbus_mode_leds_impl(enum cbus_mode_e mode_sel,
const char *func_name, int line_num);
#define si_set_cbus_mode_leds(mode_sel) \
si_set_cbus_mode_leds_impl(mode_sel, \
__func__, __LINE__)
void si_dump_important_regs(struct drv_hw_context *hw_context);
int si_mhl_tx_drv_get_pp_16bpp_override(struct mhl_dev_context *dev_context);
void si_mhl_tx_drv_set_pp_16bpp_override(struct mhl_dev_context *dev_context,
int override);
int si_mhl_tx_drv_get_hpd_status(struct mhl_dev_context *dev_context);
uint32_t si_mhl_tx_drv_get_hdcp2_status(struct mhl_dev_context *dev_context);
#endif /* if !defined(SI_8620_DRV_H) */

View file

@ -0,0 +1,30 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
struct drv_hw_context;
void si_mhl_tx_drv_skip_to_next_edid_block(struct drv_hw_context *hw_context);
int si_mhl_tx_drv_get_edid_fifo_partial_block(struct drv_hw_context *hw_context,
uint8_t start, uint8_t length, uint8_t *edid_buf);
int si_mhl_tx_drv_get_edid_fifo_next_block(struct drv_hw_context *hw_context,
uint8_t *edid_buf);
int si_mhl_tx_drv_set_upstream_edid(struct drv_hw_context *hw_context,
uint8_t *edid, uint16_t length);
void setup_sans_cbus1(struct mhl_dev_context *dev_context);
uint8_t si_get_peer_mhl_version(struct mhl_dev_context *drv_context);
int si_peer_supports_packed_pixel(void *drv_context);
uint16_t si_mhl_tx_drv_get_incoming_timing(struct drv_hw_context *hw_context,
struct si_incoming_timing_t *p_timing);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,67 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#ifndef _SI_APP_DEVCAP_H_
#define _SI_APP_DEVCAP_H_
#define DEVCAP_VAL_DEV_STATE 0
#define DEVCAP_VAL_MHL_VERSION MHL_VERSION
#define DEVCAP_VAL_DEV_CAT (MHL_DEV_CAT_SOURCE | \
MHL_DEV_CATEGORY_POW_BIT)
#define DEVCAP_VAL_ADOPTER_ID_H (uint8_t)(SILICON_IMAGE_ADOPTER_ID >> 8)
#define DEVCAP_VAL_ADOPTER_ID_L (uint8_t)(SILICON_IMAGE_ADOPTER_ID & 0xFF)
#define DEVCAP_VAL_VID_LINK_MODE (MHL_DEV_VID_LINK_SUPP_RGB444 | \
MHL_DEV_VID_LINK_SUPP_YCBCR422 | MHL_DEV_VID_LINK_SUPP_YCBCR444 | \
MHL_DEV_VID_LINK_SUPP_PPIXEL | MHL_DEV_VID_LINK_SUPP_ISLANDS | \
MHL_DEV_VID_LINK_SUPP_VGA | MHL_DEV_VID_LINK_SUPP_16BPP)
#define DEVCAP_VAL_AUD_LINK_MODE (MHL_DEV_AUD_LINK_2CH | \
MHL_DEV_AUD_LINK_8CH)
#define DEVCAP_VAL_VIDEO_TYPE 0
#define DEVCAP_VAL_LOG_DEV_MAP MHL_LOGICAL_DEVICE_MAP
#define DEVCAP_VAL_BANDWIDTH 0x0F
#define DEVCAP_VAL_FEATURE_FLAG_UCP_SEND MHL_FEATURE_UCP_SEND_SUPPORT
#define DEVCAP_VAL_FEATURE_FLAG_UCP_RECV MHL_FEATURE_UCP_RECV_SUPPORT
#if (INCLUDE_RBP == 1)
#define DEVCAP_VAL_FEATURE_FLAG_RBP MHL_FEATURE_RBP_SUPPORT
#else
#define DEVCAP_VAL_FEATURE_FLAG_RBP 0
#endif
#define DEVCAP_VAL_FEATURE_FLAG (MHL_FEATURE_RCP_SUPPORT | \
MHL_FEATURE_RAP_SUPPORT | \
MHL_FEATURE_SP_SUPPORT | \
DEVCAP_VAL_FEATURE_FLAG_UCP_SEND | \
DEVCAP_VAL_FEATURE_FLAG_UCP_RECV | \
DEVCAP_VAL_FEATURE_FLAG_RBP) \
#define DEVCAP_VAL_SCRATCHPAD_SIZE MHL_SCRATCHPAD_SIZE
#define DEVCAP_VAL_INT_STAT_SIZE MHL_INT_AND_STATUS_SIZE
#define DEVCAP_VAL_RESERVED 0
#define XDEVCAP_VAL_ECBUS_SPEEDS (MHL_XDC_ECBUS_S_075 | \
MHL_XDC_ECBUS_S_8BIT | MHL_XDC_ECBUS_S_12BIT)
#define XDEVCAP_VAL_TMDS_SPEEDS (MHL_XDC_TMDS_150 | \
MHL_XDC_TMDS_300 | MHL_XDC_TMDS_600)
#endif

View file

@ -0,0 +1,667 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#if !defined(SI_EDID_H)
#define SI_EDID_H
SI_PUSH_STRUCT_PACKING
struct SI_PACK_THIS_STRUCT two_bytes_t {
unsigned char low;
unsigned char high;
};
#define EDID_EXTENSION_TAG 0x02
#define EDID_EXTENSION_BLOCK_MAP 0xF0
#define EDID_REV_THREE 0x03
#define EDID_BLOCK_0 0x00
#define EDID_BLOCK_2_3 0x01
enum data_block_tag_code_e {
DBTC_TERMINATOR,
DBTC_AUDIO_DATA_BLOCK,
DBTC_VIDEO_DATA_BLOCK,
DBTC_VENDOR_SPECIFIC_DATA_BLOCK,
DBTC_SPEAKER_ALLOCATION_DATA_BLOCK,
DBTC_VESA_DTC_DATA_BLOCK,
/* reserved = 6 */
DBTC_USE_EXTENDED_TAG = 7
};
struct SI_PACK_THIS_STRUCT data_block_header_fields_t {
uint8_t length_following_header:5;
enum data_block_tag_code_e tag_code:3;
};
union SI_PACK_THIS_STRUCT data_block_header_byte_t {
struct data_block_header_fields_t fields;
uint8_t as_byte;
};
enum extended_tag_code_e {
ETC_VIDEO_CAPABILITY_DATA_BLOCK,
ETC_VENDOR_SPECIFIC_VIDEO_DATA_BLOCK,
ETC_VESA_VIDEO_DISPLAY_DEVICE_INFORMATION_DATA_BLOCK,
ETC_VESA_VIDEO_DATA_BLOCK,
ETC_HDMI_VIDEO_DATA_BLOCK,
ETC_COLORIMETRY_DATA_BLOCK,
ETC_VIDEO_RELATED,
ETC_CEA_MISC_AUDIO_FIELDS = 16,
ETC_VENDOR_SPECIFIC_AUDIO_DATA_BLOCK,
ETC_HDMI_AUDIO_DATA_BLOCK,
ETC_AUDIO_RELATED,
ETC_GENERAL = 32
};
struct SI_PACK_THIS_STRUCT extended_tag_code_t {
enum extended_tag_code_e etc:8;
};
struct SI_PACK_THIS_STRUCT cea_short_descriptor_t {
unsigned char VIC:7;
unsigned char native:1;
};
#if 0
struct SI_PACK_THIS_STRUCT MHL_short_desc_t {
cea_short_descriptor_t cea_short_desc;
MHL2_video_descriptor_t mhl_vid_desc;
};
#endif
struct SI_PACK_THIS_STRUCT video_data_block_t {
union data_block_header_byte_t header;
struct cea_short_descriptor_t short_descriptors[1]; /*open ended */
};
enum AudioFormatCodes_e {
/* reserved = 0 */
afd_linear_PCM_IEC60958 = 1,
afd_AC3,
afd_MPEG1_layers_1_2,
afd_MPEG1_layer_3,
afdMPEG2_MultiChannel,
afd_AAC,
afd_DTS,
afd_ATRAC,
afd_one_bit_audio,
afd_dolby_digital,
afd_DTS_HD,
afd_MAT_MLP,
afd_DST,
afd_WMA_Pro
/* reserved = 15 */
};
struct SI_PACK_THIS_STRUCT CEA_short_audio_descriptor_t {
unsigned char max_channels_minus_one:3;
enum AudioFormatCodes_e audio_format_code:4;
unsigned char F17:1;
unsigned char freq_32_Khz:1;
unsigned char freq_44_1_KHz:1;
unsigned char freq_48_KHz:1;
unsigned char freq_88_2_KHz:1;
unsigned char freq_96_KHz:1;
unsigned char freq_176_4_KHz:1;
unsigned char freq_192_KHz:1;
unsigned char F27:1;
union {
struct SI_PACK_THIS_STRUCT {
unsigned res_16_bit:1;
unsigned res_20_bit:1;
unsigned res_24_bit:1;
unsigned F33_37:5;
} audio_code_1_LPCM;
struct SI_PACK_THIS_STRUCT {
uint8_t max_bit_rate_div_by_8_KHz;
} audio_codes_2_8;
struct SI_PACK_THIS_STRUCT {
uint8_t default_zero;
} audio_codes_9_15;
} byte3;
};
struct SI_PACK_THIS_STRUCT audio_data_block_t {
union data_block_header_byte_t header;
/* open ended */
struct CEA_short_audio_descriptor_t short_audio_descriptors[1];
};
struct SI_PACK_THIS_STRUCT speaker_allocation_flags_t {
unsigned char spk_front_left_front_right:1;
unsigned char spk_LFE:1;
unsigned char spk_front_center:1;
unsigned char spk_rear_left_rear_right:1;
unsigned char spk_rear_center:1;
unsigned char spk_front_left_center_front_right_center:1;
unsigned char spk_rear_left_center_rear_right_center:1;
unsigned char spk_reserved:1;
};
struct SI_PACK_THIS_STRUCT speaker_allocation_data_block_payload_t {
struct speaker_allocation_flags_t speaker_alloc_flags;
uint8_t reserved[2];
};
struct SI_PACK_THIS_STRUCT speaker_allocation_data_block_t {
union data_block_header_byte_t header;
struct speaker_allocation_data_block_payload_t payload;
};
struct SI_PACK_THIS_STRUCT HDMI_LLC_BA_t {
unsigned char B:4;
unsigned char A:4;
};
struct SI_PACK_THIS_STRUCT HDMI_LLC_DC_t {
unsigned char D:4;
unsigned char C:4;
};
struct SI_PACK_THIS_STRUCT HDMI_LLC_Byte6_t {
unsigned char DVI_dual:1;
unsigned char reserved:2;
unsigned char DC_Y444:1;
unsigned char DC_30bit:1;
unsigned char DC_36bit:1;
unsigned char DC_48bit:1;
unsigned char supports_AI:1;
};
struct SI_PACK_THIS_STRUCT HDMI_LLC_byte8_t {
unsigned char CNC0_adjacent_pixels_independent:1;
unsigned char CNC1_specific_processing_still_pictures:1;
unsigned char CNC2_specific_processing_cinema_content:1;
unsigned char CNC3_specific_processing_low_AV_latency:1;
unsigned char reserved:1;
unsigned char HDMI_video_present:1;
unsigned char I_latency_fields_present:1;
unsigned char latency_fields_present:1;
};
enum image_size_e {
imsz_NO_ADDITIONAL,
imsz_ASPECT_RATIO_CORRECT_BUT_NO_GUARRANTEE_OF_CORRECT_SIZE,
imsz_CORRECT_SIZES_ROUNDED_TO_NEAREST_1_CM,
imsz_CORRECT_SIZES_DIVIDED_BY_5_ROUNDED_TO_NEAREST_5_CM
};
struct SI_PACK_THIS_STRUCT HDMI_LLC_Byte13_t {
unsigned char reserved:3;
enum image_size_e image_size:2;
unsigned char _3D_multi_present:2;
unsigned char _3D_present:1;
};
struct SI_PACK_THIS_STRUCT HDMI_LLC_Byte14_t {
unsigned char HDMI_3D_len:5;
unsigned char HDMI_VIC_len:3;
};
struct SI_PACK_THIS_STRUCT VSDB_byte_13_through_byte_15_t {
struct HDMI_LLC_Byte13_t byte13;
struct HDMI_LLC_Byte14_t byte14;
uint8_t vicList[1]; /* variable length list base on HDMI_VIC_len */
};
struct SI_PACK_THIS_STRUCT VSDB_all_fields_b9_thru_b15_t {
uint8_t video_latency;
uint8_t audio_latency;
uint8_t interlaced_video_latency;
uint8_t interlaced_audio_latency;
struct VSDB_byte_13_through_byte_15_t byte_13_through_byte_15;
/* There must be no fields after here */
};
struct SI_PACK_THIS_STRUCT
VSDB_all_fields_b9_thru_b15_sans_progressive_latency_t {
uint8_t interlaced_video_latency;
uint8_t interlaced_audio_latency;
struct VSDB_byte_13_through_byte_15_t byte_13_through_byte_15;
/* There must be no fields after here */
};
struct SI_PACK_THIS_STRUCT
VSDB_all_fields_b9_thru_b15_sans_interlaced_latency_t {
uint8_t video_latency;
uint8_t audio_latency;
struct VSDB_byte_13_through_byte_15_t byte_13_through_byte_15;
/* There must be no fields after here */
};
struct SI_PACK_THIS_STRUCT
VSDB_all_fields_b9_thru_b15_sans_all_latency_t {
struct VSDB_byte_13_through_byte_15_t byte_13_through_byte_15;
/* There must be no fields after here */
};
struct SI_PACK_THIS_STRUCT HDMI_LLC_vsdb_payload_t {
struct HDMI_LLC_BA_t B_A;
struct HDMI_LLC_DC_t D_C;
struct HDMI_LLC_Byte6_t byte6;
uint8_t maxTMDSclock;
struct HDMI_LLC_byte8_t byte8;
union {
struct VSDB_all_fields_b9_thru_b15_sans_all_latency_t
vsdb_b9_to_b15_no_latency;
struct VSDB_all_fields_b9_thru_b15_sans_progressive_latency_t
vsdb_b9_to_b15_no_p_latency;
struct VSDB_all_fields_b9_thru_b15_sans_interlaced_latency_t
vsdb_b9_to_b15_no_i_latency;
struct VSDB_all_fields_b9_thru_b15_t vsdb_all_fields_b9_thru_b15;
} vsdb_fields_b9_thru_b15;
/* There must be no fields after here */
};
struct SI_PACK_THIS_STRUCT _3D_structure_all_15_8_t {
uint8_t frame_packing:1;
uint8_t reserved1:5;
uint8_t top_bottom:1;
uint8_t reserved2:1;
};
struct SI_PACK_THIS_STRUCT _3D_structure_all_7_0_t {
uint8_t side_by_side:1;
uint8_t reserved:7;
};
struct SI_PACK_THIS_STRUCT _3D_structure_all_t {
struct _3D_structure_all_15_8_t _3D_structure_all_15_8;
struct _3D_structure_all_7_0_t _3D_structure_all_7_0;
};
struct SI_PACK_THIS_STRUCT _3D_mask_t {
uint8_t _3D_mask_15_8;
uint8_t _3D_mask_7_0;
};
struct SI_PACK_THIS_STRUCT _2D_VIC_order_3D_structure_t {
enum _3D_structure_e _3D_structure:4; /* definition from infoframe */
unsigned _2D_VIC_order:4;
};
struct SI_PACK_THIS_STRUCT _3D_detail_t {
unsigned char reserved:4;
unsigned char _3D_detail:4;
};
struct SI_PACK_THIS_STRUCT _3D_structure_and_detail_entry_sans_byte1_t {
struct _2D_VIC_order_3D_structure_t byte0;
/*see HDMI 1.4 spec w.r.t. contents of 3D_structure_X */
};
struct SI_PACK_THIS_STRUCT _3D_structure_and_detail_entry_with_byte1_t {
struct _2D_VIC_order_3D_structure_t byte0;
struct _3D_detail_t byte1;
};
union _3D_structure_and_detail_entry_u {
struct _3D_structure_and_detail_entry_sans_byte1_t sans_byte1;
struct _3D_structure_and_detail_entry_with_byte1_t with_byte1;
};
struct SI_PACK_THIS_STRUCT HDMI_3D_sub_block_sans_all_AND_mask_t {
union _3D_structure_and_detail_entry_u
_3D_structure_and_detail_list[1];
};
struct SI_PACK_THIS_STRUCT HDMI_3D_sub_block_sans_mask_t {
struct _3D_structure_all_t _3D_structure_all;
union _3D_structure_and_detail_entry_u _3D_structure_and_detail_list[1];
};
struct SI_PACK_THIS_STRUCT HDMI_3D_sub_block_with_all_AND_mask_t {
struct _3D_structure_all_t _3D_structure_all;
struct _3D_mask_t _3D_mask;
union _3D_structure_and_detail_entry_u
_3D_structure_and_detail_list[1];
};
union HDMI_3D_sub_block_t {
struct HDMI_3D_sub_block_sans_all_AND_mask_t
HDMI_3D_sub_block_sans_all_AND_mask;
struct HDMI_3D_sub_block_sans_mask_t HDMI_3D_sub_block_sans_mask;
struct HDMI_3D_sub_block_with_all_AND_mask_t
HDMI_3D_sub_block_with_all_AND_mask;
};
struct SI_PACK_THIS_STRUCT vsdb_t {
union data_block_header_byte_t header;
uint8_t IEEE_OUI[3];
union {
struct HDMI_LLC_vsdb_payload_t HDMI_LLC;
uint8_t payload[1]; /* open ended */
} payload_u;
};
enum colorimetry_xvYCC_e {
xvYCC_601 = 1,
xvYCC_709 = 2
};
struct SI_PACK_THIS_STRUCT colorimetry_xvYCC_t {
enum colorimetry_xvYCC_e xvYCC:2;
unsigned char reserved1:6;
};
struct SI_PACK_THIS_STRUCT colorimetry_meta_data_t {
unsigned char meta_data:3;
unsigned char reserved2:5;
};
struct SI_PACK_THIS_STRUCT colorimetry_data_payload_t {
struct colorimetry_xvYCC_t ci_data;
struct colorimetry_meta_data_t cm_meta_data;
};
struct SI_PACK_THIS_STRUCT colorimetry_data_block_t {
union data_block_header_byte_t header;
struct extended_tag_code_t extended_tag;
struct colorimetry_data_payload_t payload;
};
enum CE_overscan_underscan_behavior_e {
ceou_NEITHER,
ceou_ALWAYS_OVERSCANNED,
ceou_ALWAYS_UNDERSCANNED,
ceou_BOTH
};
enum IT_overscan_underscan_behavior_e {
itou_NEITHER,
itou_ALWAYS_OVERSCANNED,
itou_ALWAYS_UNDERSCANNED,
itou_BOTH
};
enum PT_overscan_underscan_behavior_e {
ptou_NEITHER,
ptou_ALWAYS_OVERSCANNED,
ptou_ALWAYS_UNDERSCANNED,
ptou_BOTH,
};
struct SI_PACK_THIS_STRUCT video_capability_data_payload_t {
enum CE_overscan_underscan_behavior_e S_CE:2;
enum IT_overscan_underscan_behavior_e S_IT:2;
enum PT_overscan_underscan_behavior_e S_PT:2;
unsigned QS:1;
unsigned quantization_range_selectable:1;
};
struct SI_PACK_THIS_STRUCT video_capability_data_block_t {
union data_block_header_byte_t header;
struct extended_tag_code_t extended_tag;
struct video_capability_data_payload_t payload;
};
struct SI_PACK_THIS_STRUCT CEA_data_block_collection_t {
union data_block_header_byte_t header;
union {
struct extended_tag_code_t extended_tag;
struct cea_short_descriptor_t short_descriptor;
} payload_u;
/* open ended array of cea_short_descriptor_t starts here */
};
struct SI_PACK_THIS_STRUCT CEA_extension_version_1_t {
uint8_t reservedMustBeZero;
uint8_t reserved[123];
};
struct SI_PACK_THIS_STRUCT CEA_extension_2_3_misc_support_t {
uint8_t total_number_native_dtds_in_entire_EDID:4;
uint8_t YCrCb422_support:1;
uint8_t YCrCb444_support:1;
uint8_t basic_audio_support:1;
uint8_t underscan_IT_formats_by_default:1;
};
struct SI_PACK_THIS_STRUCT CEA_extension_version_2_t {
struct CEA_extension_2_3_misc_support_t misc_support;
uint8_t reserved[123];
};
struct SI_PACK_THIS_STRUCT CEA_extension_version_3_t {
struct CEA_extension_2_3_misc_support_t misc_support;
union {
uint8_t data_block_collection[123];
uint8_t reserved[123];
} Offset4_u;
};
struct SI_PACK_THIS_STRUCT block_map_t {
uint8_t tag;
uint8_t block_tags[126];
uint8_t checksum;
};
struct SI_PACK_THIS_STRUCT CEA_extension_t {
uint8_t tag;
uint8_t revision;
uint8_t byte_offset_to_18_byte_descriptors;
union {
struct CEA_extension_version_1_t version1;
struct CEA_extension_version_2_t version2;
struct CEA_extension_version_3_t version3;
} version_u;
uint8_t checksum;
};
struct SI_PACK_THIS_STRUCT detailed_timing_descriptor_t {
uint8_t pixel_clock_low;
uint8_t pixel_clock_high;
uint8_t horz_active_7_0;
uint8_t horz_blanking_7_0;
struct SI_PACK_THIS_STRUCT {
unsigned char horz_blanking_11_8:4;
unsigned char horz_active_11_8:4;
} horz_active_blanking_high;
uint8_t vert_active_7_0;
uint8_t vert_blanking_7_0;
struct SI_PACK_THIS_STRUCT {
unsigned char vert_blanking_11_8:4;
unsigned char vert_active_11_8:4;
} vert_active_blanking_high;
uint8_t horz_sync_offset_7_0;
uint8_t horz_sync_pulse_width7_0;
struct SI_PACK_THIS_STRUCT {
unsigned char vert_sync_pulse_width_3_0:4;
unsigned char vert_sync_offset_3_0:4;
} vert_sync_offset_width;
struct SI_PACK_THIS_STRUCT {
unsigned char vert_sync_pulse_width_5_4:2;
unsigned char vert_sync_offset_5_4:2;
unsigned char horz_sync_pulse_width_9_8:2;
unsigned char horz_sync_offset_9_8:2;
} hs_vs_offset_pulse_width;
uint8_t horz_image_size_in_mm_7_0;
uint8_t vert_image_size_in_mm_7_0;
struct SI_PACK_THIS_STRUCT {
unsigned char vert_image_size_in_mm_11_8:4;
unsigned char horz_image_size_in_mm_11_8:4;
} image_size_high;
uint8_t horz_border_in_lines;
uint8_t vert_border_in_pixels;
struct SI_PACK_THIS_STRUCT {
unsigned char stereo_bit_0:1;
unsigned char sync_signal_options:2;
unsigned char sync_signal_type:2;
unsigned char stereo_bits_2_1:2;
unsigned char interlaced:1;
} flags;
};
struct SI_PACK_THIS_STRUCT red_green_bits_1_0_t {
unsigned char green_y:2;
unsigned char green_x:2;
unsigned char red_y:2;
unsigned char red_x:2;
};
struct SI_PACK_THIS_STRUCT blue_white_bits_1_0_t {
unsigned char white_y:2;
unsigned char white_x:2;
unsigned char blue_y:2;
unsigned char blue_x:2;
};
struct SI_PACK_THIS_STRUCT established_timings_I_t {
unsigned char et800x600_60p:1;
unsigned char et800x600_56p:1;
unsigned char et640x480_75p:1;
unsigned char et640x480_72p:1;
unsigned char et640x480_67p:1;
unsigned char et640x480_60p:1;
unsigned char et720x400_88p:1;
unsigned char et720x400_70p:1;
};
struct SI_PACK_THIS_STRUCT established_timings_II_t {
unsigned char et1280x1024_75p:1;
unsigned char et1024x768_75p:1;
unsigned char et1024x768_70p:1;
unsigned char et1024x768_60p:1;
unsigned char et1024x768_87i:1;
unsigned char et832x624_75p:1;
unsigned char et800x600_75p:1;
unsigned char et800x600_72p:1;
};
struct SI_PACK_THIS_STRUCT manufacturers_timings_t {
unsigned char reserved:7;
unsigned char et1152x870_75p:1;
};
enum image_aspect_ratio_e {
iar_16_to_10,
iar_4_to_3,
iar_5_to_4,
iar_16_to_9
};
struct SI_PACK_THIS_STRUCT standard_timing_t {
unsigned char horz_pix_div_8_minus_31;
unsigned char field_refresh_rate_minus_60:6;
enum image_aspect_ratio_e image_aspect_ratio:2;
};
struct SI_PACK_THIS_STRUCT EDID_block0_t {
unsigned char header_data[8];
struct two_bytes_t id_manufacturer_name;
struct two_bytes_t id_product_code;
unsigned char serial_number[4];
unsigned char week_of_manufacture;
unsigned char year_of_manufacture;
unsigned char EDID_version;
unsigned char EDID_revision;
unsigned char video_input_definition;
unsigned char horz_screen_size_or_aspect_ratio;
unsigned char vert_screen_size_or_aspect_ratio;
unsigned char display_transfer_characteristic;
unsigned char feature_support;
struct red_green_bits_1_0_t red_green_bits_1_0;
struct blue_white_bits_1_0_t blue_white_bits_1_0;
unsigned char red_x;
unsigned char red_y;
unsigned char green_x;
unsigned char green_y;
unsigned char blue_x;
unsigned char blue_y;
unsigned char white_x;
unsigned char white_y;
struct established_timings_I_t established_timings_I;
struct established_timings_II_t established_timings_II;
struct manufacturers_timings_t manufacturers_timings;
struct standard_timing_t standard_timings[8];
struct detailed_timing_descriptor_t detailed_timing_descriptors[4];
unsigned char extension_flag;
unsigned char checksum;
};
struct SI_PACK_THIS_STRUCT monitor_name_t {
uint8_t flag_required[2];
uint8_t flag_reserved;
uint8_t data_type_tag;
uint8_t flag;
uint8_t ascii_name[13];
};
struct SI_PACK_THIS_STRUCT monitor_range_limits_t {
uint8_t flag_required[2];
uint8_t flag_reserved;
uint8_t data_type_tag;
uint8_t flag;
uint8_t min_vertical_rate_in_Hz;
uint8_t max_vertical_rate_in_Hz;
uint8_t min_horizontal_rate_in_KHz;
uint8_t max_horizontal_rate_in_KHz;
uint8_t max_pixel_clock_in_MHz_div_10;
uint8_t tag_secondary_formula;
uint8_t filler[7];
};
union _18_byte_descriptor_u {
struct detailed_timing_descriptor_t dtd;
struct monitor_name_t name;
struct monitor_range_limits_t range_limits;
};
struct SI_PACK_THIS_STRUCT display_mode_3D_info_t {
unsigned char dmi_3D_supported:1;
unsigned char dmi_sufficient_bandwidth:1;
};
#ifdef ENABLE_EDID_DEBUG_PRINT
void dump_EDID_block_impl(const char *pszFunction, int iLineNum,
uint8_t override, uint8_t *pData, uint16_t length);
void clear_EDID_block_impl(uint8_t *pData);
#define DUMP_EDID_BLOCK(override, pData, length) \
dump_EDID_block_impl(__func__, __LINE__, override, (uint8_t *)pData, \
length)
#define CLEAR_EDID_BLOCK(pData) clear_EDID_block_impl(pData)
#else
#define DUMP_EDID_BLOCK(override, pData, length) /* nothing to do */
#define CLEAR_EDID_BLOCK(pData) /* nothing to do */
#endif
enum EDID_error_codes {
EDID_OK,
EDID_INCORRECT_HEADER,
EDID_CHECKSUM_ERROR,
EDID_NO_861_EXTENSIONS,
EDID_SHORT_DESCRIPTORS_OK,
EDID_LONG_DESCRIPTORS_OK,
EDID_EXT_TAG_ERROR,
EDID_REV_ADDR_ERROR,
EDID_V_DESCR_OVERFLOW,
EDID_UNKNOWN_TAG_CODE,
EDID_NO_DETAILED_DESCRIPTORS,
EDID_DDC_BUS_REQ_FAILURE,
EDID_DDC_BUS_RELEASE_FAILURE,
EDID_READ_TIMEOUT
};
SI_POP_STRUCT_PACKING
#endif /* #if !defined(SI_EDID_H) */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,278 @@
/*
* SiI8620 Linux Driver eMSC HID stuff
Copyright (C) 2013-2014 Silicon Image, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation version 2.
This program is distributed AS-IS WITHOUT ANY WARRANTY of any
kind, whether express or implied; INCLUDING without the implied warranty
of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
See the GNU General Public License for more details at
http://www.gnu.org/licenses/gpl-2.0.html.
*/
/*
@file si_emsc_hid.h
*/
#ifndef _SI_EMSC_HID_H_
#define _SI_EMSC_HID_H_
#include <linux/mod_devicetable.h>
#include <linux/hid.h>
#include "si_fw_macros.h"
#include "si_app_devcap.h"
#include "si_infoframe.h"
#include "si_edid.h"
#include "si_mhl_defs.h"
#include "si_mhl2_edid_3d_api.h"
#include "si_8620_internal_api.h"
#include "si_mhl_tx_hw_drv_api.h"
#include "platform.h"
extern int debug_level;
#define MHL3_HID_DBG_ERR(...) \
MHL_TX_GENERIC_DBG_PRINT(DBG_MSG_LEVEL_ERR, __VA_ARGS__)
#define MHL3_HID_DBG_WARN(...) \
MHL_TX_GENERIC_DBG_PRINT(DBG_MSG_LEVEL_WARN, __VA_ARGS__)
#define MHL3_HID_DBG_INFO(...) \
MHL_TX_GENERIC_DBG_PRINT(DBG_MSG_LEVEL_INFO, __VA_ARGS__)
/* mhl3_hid_data.flags */
#define MHL3_HID_STARTED (1 << 0)
#define MHL3_HID_CONNECTED (1 << 1)
#define HID_FLAGS_WQ_ACTIVE (1 << 2)
#define HID_FLAGS_WQ_CANCEL (1 << 3)
#define MHL3_HID_PWR_ON 0x00
#define MHL3_HID_PWR_SLEEP 0x01
#define MHL3_HID_MAX_DESC_STR_LEN 256
#define MAX_HID_MESSAGE_CHANNELS 16
/* TODO: Start
* The following belongs in the kernel mod_devicetable.h file, along
* with updating the scripts/mod/file2alias.c file to match
*/
#define MHL3_NAME_SIZE 20
#define MHL3_MODULE_PREFIX "mhl3:"
struct mhl3_device_id {
char name[MHL3_NAME_SIZE];
kernel_ulong_t driver_data; /* Data private to the driver */
};
/* TODO: End */
#define HID_BURST_ID_LEN (2 + 1)
#define HID_MSG_HEADER_LEN 2
#define HID_MSG_CHKSUM_LEN 2
#define HID_FRAG_HEADER_LEN 1
#define HID_ACK_PACKET_LEN 2
#define HID_FRAG_LEN_MAX (EMSC_BLK_MAX_LENGTH - \
(EMSC_BLK_STD_HDR_LEN + \
HID_BURST_ID_LEN + \
HID_FRAG_HEADER_LEN))
#define HID_FRAG_HB0_TYPE 0x80
#define HID_FRAG_HB0_TYPE_ACK 0x80
#define HID_FRAG_HB0_CNT_MSK 0x7F
#define HID_HB0_DEV_ID_MSK 0xF0
#define HID_HB0_ACHID_MSK 0x01
#define HID_ACHID_INT 0x01
#define EMSC_HID_HB1_ACK 0x80
#define EMSC_HID_HB1_MSG_CNT_FLD 0x7F
/* HID tunneling message IDs */
#define MHL3_HID_ACK 0x00
#define MHL3_REPORT 0x01
#define MHL3_GET_REPORT_DSCRPT 0x02
#define MHL3_REPORT_DSCRPT 0x03
#define MHL3_GET_MHID_DSCRPT 0x04
#define MHL3_MHID_DSCRPT 0x05
#define MHL3_GET_REPORT 0x06
#define MHL3_SET_REPORT 0x07
#define MHL3_DSCRPT_UPDATE 0x08
/* HID_ACK values */
#define HID_ACK_SUCCESS 0x00
#define HID_ACK_NODEV 0x01
#define HID_ACK_NODATA 0x02
#define HID_ACK_WAIT 0x03
#define HID_ACK_TIMEOUT 0x04
#define HID_ACK_PROTV 0x05
#define HID_ACK_WRTYPE 0x06
#define HID_ACK_WRID 0x07
#define HID_ACK_WRFMT 0x08
#define HID_ACK_WRMFMT 0x09
/* RHID Operand Codes */
#define MHL_RHID_REQUEST_HOST 0x00
#define MHL_RHID_RELINQUISH_HOST 0x01
/* RHIDK status codes */
#define MHL_RHID_NO_ERR 0x00
#define MHL_RHID_INVALID 0x01
#define MHL_RHID_DENY 0x02
#define OP_STATE_IDLE 0x00
#define OP_STATE_WAIT_MHID_DSCRPT 0x01
#define OP_STATE_WAIT_REPORT_DSCRPT 0x02
#define OP_STATE_WAIT_REPORT 0x03
#define OP_STATE_CONNECTED 0x04
/*
* This structure cannot be directly loaded from the MHL3 HID
* MHID_DSCRPT message data because the strings are variable length
* up to 255 characters each, not the full 255 UNICODE character buffer
* defined here. Note that the structure I derived this from in the
* USB driver used __le16 in place of the __u16 used below.
*/
struct mhl3_hid_desc {
__u8 bMHL3HIDmessageID;
__u16 wHIDVendorID;
__u16 wHIDProductID;
__u8 bCountryCode;
__u16 wBcdHID;
__u16 bBcdDevice;
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u16 wLanguageID;
__u8 bProductNameSize;
__u8 bManufacturerNameSize;
__u8 bSerialNumberSize;
} __packed;
static DEFINE_MUTEX(mhl3_hid_open_mutex);
struct mhl3_hid_global_data {
/* RHID/RHIDK host-device negotiation */
uint8_t is_host; /* 1- Successfully negotiated as host */
uint8_t is_device; /* 1- Relinquished host role */
uint8_t want_host; /* 1- Want the host role */
int hid_receive_state;
uint8_t hb0;
uint8_t hb1;
uint8_t in_buf[4096]; /* This buffer is shared by all
* MHL3 HID devices. This is
* OK because device messages
* must be sent sequentially
* if it is a multi-fragment
* message so that they will
* not get mixed up. */
int msg_length;
};
struct hid_add_work_struct {
struct work_struct work;
struct mhl3_hid_data *mhid;
};
struct wq_indata_t {
uint8_t *ptr;
int buffer_size;
};
#define MAX_HID_INQUEUE 4
/* The main HID Tunneling device structure */
struct mhl3_hid_data {
struct mhl_dev_context *mdev; /* MHL driver */
struct hid_device *hid; /* pointer to HID dev */
uint8_t *in_report_buf; /* Input report buffer. */
int bufsize; /* Size of report buffer */
/* MHL3 MHID_DSCRPT message in multiple parts */
struct mhl3_hid_desc *hdesc; /* The fixed length part */
__u8 desc_product_name[MHL3_HID_MAX_DESC_STR_LEN];
__u8 desc_mfg_name[MHL3_HID_MAX_DESC_STR_LEN];
__u8 desc_serial_number[MHL3_HID_MAX_DESC_STR_LEN];
uint8_t id; /* MHL HID device ID (0-15) */
uint8_t msg_count[2]; /* MSG_CNT for each channel */
unsigned long flags; /* device flags */
/* TODO: Lee - make this a constant of the correct size or
* make this an allocated buffer.
*/
uint8_t report_desc[1024];/* Device report descriptor */
uint8_t in_data[4096]; /* Contains the last HID message
* received if it was not
* consumed directly. */
int in_data_length;
uint8_t out_data[4096]; /* Holds the MHL3 HID wrapped
* version of the HID message
* to be sent. */
int opState; /* Determines the type of HID
* messages that will be
* accepted */
/* For deferred processing */
struct hid_add_work_struct mhl3_work;
struct semaphore data_wait_lock; /* Semaphore to wait for data
* requested from the remote
* device */
};
struct SI_PACK_THIS_STRUCT mhl_hid_report_msg {
uint8_t msg_id;
uint8_t type;
uint8_t id; /* According to MHL spec 3.2, this
* byte is ONLY present for numbered
* reports, but our driver has no way
* of determining if the reports are
* numbered or not, so we ALWAYS
* use it.
*/
uint8_t len_lo;
uint8_t len_hi;
uint8_t data; /* Actually the start of variable length
* report data of length specified in
* len_hi / len_lo
*/
};
void mhl_tx_hid_host_role_request(struct mhl_dev_context *context, int request);
void mhl_tx_hid_host_negotiation(struct mhl_dev_context *context);
int mhl3_hid_report_desc_parse(struct mhl3_hid_data *mhid);
void build_received_hid_message(struct mhl_dev_context *context,
uint8_t *pmsg, int length);
void mhl3_hid_remove_all(struct mhl_dev_context *context);
int mhl3_mt_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value);
int mhl3_mt_add(struct mhl3_hid_data *mhid, struct hid_device_id *id);
int mhl3_mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max);
int mhl3_mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max);
void mt_feature_mapping(struct hid_device *hdev,
struct hid_field *field, struct hid_usage *usage);
void dump_array(int level, char *ptitle, uint8_t *pdata, int count);
#if (LINUX_KERNEL_VER >= 311)
void mt_input_configured(struct hid_device *hdev, struct hid_input *hi);
void mt_report(struct hid_device *hid, struct hid_report *report);
#endif
#endif /* #ifndef _SI_EMSC_HID_H_ */

View file

@ -0,0 +1,40 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#ifndef _SI_FW_MACROS_H_
#define _SI_FW_MACROS_H_
/*
* Define Linux versions of macros used to cross compile driver code for other
* platforms.
*/
#define PLACE_IN_CODE_SEG
#define SI_PUSH_STRUCT_PACKING
#define SI_POP_STRUCT_PACKING
#define SI_PACK_THIS_STRUCT __attribute__((__packed__))
#define SII_OFFSETOF offsetof
#define SII_ASSERT(cond, ...) \
do { \
if (!(cond)) { \
printk(__VA_ARGS__); \
BUG(); \
} \
} while (0)
#endif

View file

@ -0,0 +1,219 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#if !defined(SI_INFOFRAME_H)
#define SI_INFOFRAME_H
struct __attribute__ ((__packed__)) info_frame_header_t {
uint8_t type_code;
uint8_t version_number;
uint8_t length;
};
enum AviColorSpace_e {
acsRGB,
acsYCbCr422,
acsYCbCr444,
acsYCbCr420
};
enum avi_quant_range_e {
aqr_default = 0,
aqr_limited_range,
aqr_full_range,
aqr_reserved
};
/*
* AVI Info Frame Structure
*/
struct __attribute__ ((__packed__)) avi_info_frame_data_byte_1_t {
uint8_t ScanInfo:2;
uint8_t BarInfo:2;
uint8_t ActiveFormatInfoPresent:1;
enum AviColorSpace_e colorSpace:2;
uint8_t futureMustBeZero:1;
};
struct __attribute__ ((__packed__)) avi_info_frame_data_byte_2_t {
uint8_t ActiveFormatAspectRatio:4;
uint8_t PictureAspectRatio:2;
uint8_t Colorimetry:2;
};
struct __attribute__ ((__packed__)) avi_info_frame_data_byte_3_t {
uint8_t NonUniformPictureScaling:2;
uint8_t RGBQuantizationRange:2;
uint8_t ExtendedColorimetry:3;
uint8_t ITContent:1;
};
struct __attribute__ ((__packed__)) avi_info_frame_data_byte_4_t {
uint8_t VIC:7;
uint8_t futureMustBeZero:1;
};
enum BitsContent_e {
cnGraphics,
cnPhoto,
cnCinema,
cnGame
};
enum AviQuantization_e {
aqLimitedRange,
aqFullRange,
aqReserved0,
aqReserved1
};
struct __attribute__ ((__packed__)) avi_info_frame_data_byte_5_t {
uint8_t pixelRepetionFactor:4;
enum BitsContent_e content:2;
enum AviQuantization_e quantization:2;
};
struct __attribute__ ((__packed__)) hw_avi_named_payload_t {
uint8_t checksum;
union {
struct __attribute__ ((__packed__)) {
struct avi_info_frame_data_byte_1_t pb1;
struct avi_info_frame_data_byte_2_t
colorimetryAspectRatio;
struct avi_info_frame_data_byte_3_t pb3;
struct avi_info_frame_data_byte_4_t VIC;
struct avi_info_frame_data_byte_5_t pb5;
uint8_t LineNumEndTopBarLow;
uint8_t LineNumEndTopBarHigh;
uint8_t LineNumStartBottomBarLow;
uint8_t LineNumStartBottomBarHigh;
uint8_t LineNumEndLeftBarLow;
uint8_t LineNumEndLeftBarHigh;
uint8_t LineNumStartRightBarLow;
uint8_t LineNumStartRightBarHigh;
} bitFields;
uint8_t infoFrameData[13];
} ifData_u;
};
/* this union overlays the TPI HW for AVI InfoFrames,
* starting at REG_TPI_AVI_CHSUM.
*/
union hw_avi_payload_t {
struct hw_avi_named_payload_t namedIfData;
uint8_t ifData[14];
};
struct __attribute__ ((__packed__)) avi_payload_t {
union hw_avi_payload_t hwPayLoad;
uint8_t byte_14;
uint8_t byte_15;
};
struct __attribute__ ((__packed__)) avi_info_frame_t {
struct info_frame_header_t header;
struct avi_payload_t payLoad;
};
/* these values determine the interpretation of PB5 */
enum HDMI_Video_Format_e {
hvfNoAdditionalHDMIVideoFormatPresent,
hvfExtendedResolutionFormatPresent,
hvf3DFormatIndicationPresent
};
enum _3D_structure_e {
tdsFramePacking,
tdsTopAndBottom = 0x06,
tdsSideBySide = 0x08
};
enum ThreeDExtData_e {
tdedHorizontalSubSampling,
tdedQuincunxOddLeftOddRight = 0x04,
tdedQuincunxOddLeftEvenRight,
tdedQuincunxEvenLeftOddRight,
tdedQuincunxEvenLeftEvenRight
};
enum ThreeDMetaDataType_e {
tdmdParallaxIso23022_3Section6_x_2_2
};
struct __attribute__ ((__packed__)) hdmi_vendor_specific_payload_t {
struct __attribute__ ((__packed__)) {
unsigned reserved:5;
enum HDMI_Video_Format_e HDMI_Video_Format:3;
} pb4;
union {
uint8_t HDMI_VIC;
struct __attribute__ ((__packed__)) _ThreeDStructure {
unsigned reserved:3;
unsigned ThreeDMetaPresent:1;
enum _3D_structure_e threeDStructure:4;
} ThreeDStructure;
} pb5;
struct __attribute__ ((__packed__)) {
uint8_t reserved:4;
uint8_t threeDExtData:4; /* ThreeDExtData_e */
} pb6;
struct __attribute__ ((__packed__)) _PB7 {
uint8_t threeDMetaDataLength:5;
uint8_t threeDMetaDataType:3; /* ThreeDMetaDataType_e */
} pb7;
};
#define IEEE_OUI_HDMI 0x000C03
#define VSIF_COMMON_FIELDS \
struct info_frame_header_t header; \
uint8_t checksum; \
uint8_t ieee_oui[3];
struct __attribute__ ((__packed__)) hdmi_vsif_t{
VSIF_COMMON_FIELDS
struct hdmi_vendor_specific_payload_t payLoad;
};
struct __attribute__ ((__packed__)) vsif_common_header_t {
VSIF_COMMON_FIELDS
};
/*
* MPEG Info Frame Structure
* Table 8-11 on page 141 of HDMI Spec v1.4
*/
struct __attribute__ ((__packed__)) unr_info_frame_t {
struct info_frame_header_t header;
uint8_t checksum;
uint8_t byte_1;
uint8_t byte_2;
uint8_t byte_3;
uint8_t byte_4;
uint8_t byte_5;
uint8_t byte_6;
};
#ifdef ENABLE_DUMP_INFOFRAME
void DumpIncomingInfoFrameImpl(char *pszId, char *pszFile, int iLine,
info_frame_t *pInfoFrame, uint8_t length);
#define DumpIncomingInfoFrame(pData, length) \
DumpIncomingInfoFrameImpl(#pData, __FILE__, __LINE__, \
(info_frame_t *)pData, length)
#else
#define DumpIncomingInfoFrame(pData, length) /* do nothing */
#endif
#endif /* if !defined(SI_INFOFRAME_H) */

View file

@ -0,0 +1,851 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#ifdef MEDIA_DATA_TUNNEL_SUPPORT
#include <linux/input.h>
#include <linux/cdev.h>
#include <linux/hrtimer.h>
#include "si_fw_macros.h"
#include "si_infoframe.h"
#include "si_edid.h"
#include "si_mhl_defs.h"
#include "si_mhl2_edid_3d_api.h"
#include "si_mhl_tx_hw_drv_api.h"
#include "si_mdt_inputdev.h"
#include "mhl_linux_tx.h"
#include "platform.h"
#ifdef KERNEL_2_6_38_AND_LATER
#include <linux/input/mt.h>
#endif
#ifdef DEBUG
#include <linux/kernel.h>
#endif
/* keycode map from usbkbd.c */
uint8_t usb_kbd_keycode[256] = {
0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 87, 88, 99, 70, 119, 110, 102, 104, 111, 107, 109, 106,
105, 108, 103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
72, 73, 82, 83, 86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 189,
190,
191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135,
136, 113,
115, 114, 0, 0, 0, 121, 0, 89, 93, 124, 92, 94, 95, 0, 0, 0,
122, 123, 90, 91, 85, 0, 0, 0, 0, 0, 150, 155, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
200, 201, 207, 208, 213, 215, 216, 217, 226, 139, 172, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
29, 42, 56, 125, 97, 54, 100, 126, 164, 166, 165, 163, 161, 115, 114,
113,
150, 158, 159, 128, 136, 177, 178, 176, 142, 152, 173, 140
};
static bool is_mdt_dev_active(struct mhl_dev_context *dev_context,
enum mdt_dev_types_e dev_type)
{
if (dev_context->mdt_devs.is_dev_registered[dev_type] == INPUT_ACTIVE)
return true;
else
return false;
}
static bool is_mdt_dev_waiting(struct mhl_dev_context *dev_context,
enum mdt_dev_types_e dev_type)
{
if (dev_context->mdt_devs.is_dev_registered[dev_type] ==
INPUT_WAITING_FOR_REGISTRATION)
return true;
else
return false;
}
static void destroy_mouse(struct mhl_dev_context *dev_context)
{
if (dev_context->mdt_devs.dev_mouse == NULL)
return;
MHL_TX_DBG_INFO("Unregistering mouse: %p\n",
dev_context->mdt_devs.dev_mouse);
input_unregister_device(dev_context->mdt_devs.dev_mouse);
MHL_TX_DBG_INFO("Freeing mouse: %p\n", dev_context->mdt_devs.dev_mouse);
input_free_device(dev_context->mdt_devs.dev_mouse);
dev_context->mdt_devs.dev_mouse = NULL;
}
static void destroy_keyboard(struct mhl_dev_context *dev_context)
{
if (dev_context->mdt_devs.dev_keyboard == NULL)
return;
MHL_TX_DBG_INFO("Unregistering keyboard: %p\n",
dev_context->mdt_devs.dev_keyboard);
input_unregister_device(dev_context->mdt_devs.dev_keyboard);
MHL_TX_DBG_INFO("Freeing keyboard: %p\n",
dev_context->mdt_devs.dev_keyboard);
input_free_device(dev_context->mdt_devs.dev_keyboard);
dev_context->mdt_devs.dev_keyboard = NULL;
}
static void destroy_touchscreen(struct mhl_dev_context *dev_context)
{
if (dev_context->mdt_devs.dev_touchscreen == NULL)
return;
MHL_TX_DBG_INFO("Unregistering mouse: %p\n",
dev_context->mdt_devs.dev_touchscreen);
input_unregister_device(dev_context->mdt_devs.dev_touchscreen);
MHL_TX_DBG_INFO("Freeing mouse: %p\n",
dev_context->mdt_devs.dev_touchscreen);
input_free_device(dev_context->mdt_devs.dev_touchscreen);
dev_context->mdt_devs.dev_touchscreen = NULL;
memset(dev_context->mdt_devs.prior_touch_events, 0,
MAX_TOUCH_CONTACTS *
sizeof(dev_context->mdt_devs.prior_touch_events[0]));
}
int init_mdt_keyboard(struct mhl_dev_context *dev_context)
{
int i;
uint8_t error;
struct input_dev *dev_keyboard;
dev_keyboard = input_allocate_device();
if (!dev_keyboard) {
MHL_TX_DBG_ERR("Not enough memory\n");
return -ENOMEM;
}
MHL_TX_DBG_INFO("Allocated keyboard: %p\n", dev_keyboard);
set_bit(EV_KEY, dev_keyboard->evbit);
set_bit(EV_REP, dev_keyboard->evbit);
dev_keyboard->phys = "mdt_kbd/input0";
dev_keyboard->name = "MDTkeyboard";
dev_keyboard->keycode = usb_kbd_keycode;
dev_keyboard->keycodesize = sizeof(unsigned char);
dev_keyboard->keycodemax = ARRAY_SIZE(usb_kbd_keycode);
for (i = 1; i < 256; i++)
set_bit(usb_kbd_keycode[i], dev_keyboard->keybit);
dev_keyboard->id.bustype = BUS_VIRTUAL;
dev_keyboard->id.vendor = 0x1095;
dev_keyboard->id.product = MHL_PRODUCT_NUM;
/* Use version to distinguish between devices */
dev_keyboard->id.version = 0xA;
error = input_register_device(dev_keyboard);
if (error) {
MHL_TX_DBG_ERR("Failed to register device\n");
input_free_device(dev_keyboard);
return error;
}
MHL_TX_DBG_INFO("Registered keyboard: %p\n", dev_keyboard);
dev_context->mdt_devs.dev_keyboard = dev_keyboard;
return 0;
}
int init_mdt_mouse(struct mhl_dev_context *dev_context)
{
uint8_t error;
struct input_dev *dev_mouse;
dev_mouse = input_allocate_device();
if (!dev_mouse) {
MHL_TX_DBG_ERR("Not enough memory\n");
return -ENOMEM;
}
MHL_TX_DBG_INFO("Allocated mouse: %p\n", dev_mouse);
set_bit(EV_REL, dev_mouse->evbit);
set_bit(EV_KEY, dev_mouse->evbit);
set_bit(BTN_LEFT, dev_mouse->keybit);
set_bit(BTN_RIGHT, dev_mouse->keybit);
set_bit(BTN_MIDDLE, dev_mouse->keybit);
set_bit(BTN_SIDE, dev_mouse->keybit);
set_bit(BTN_EXTRA, dev_mouse->keybit);
set_bit(REL_X, dev_mouse->relbit);
set_bit(REL_Y, dev_mouse->relbit);
set_bit(REL_WHEEL, dev_mouse->relbit);
#if (RIGHT_MOUSE_BUTTON_IS_ESC == 1)
set_bit(KEY_ESC, dev_mouse->keybit);
dev_context->mdt_devs.prior_right_button = 0;
#endif
dev_mouse->phys = "mdt_mouse/input0";
dev_mouse->name = "MDTmouse";
dev_mouse->id.bustype = BUS_VIRTUAL;
dev_mouse->id.vendor = 0x1095;
dev_mouse->id.product = MHL_PRODUCT_NUM;
/* Use version to distinguish between devices */
dev_mouse->id.version = 0xB;
error = input_register_device(dev_mouse);
if (error) {
MHL_TX_DBG_ERR("Failed to register device\n");
input_free_device(dev_mouse);
return error;
}
MHL_TX_DBG_INFO("Registered mouse: %p\n", dev_mouse);
dev_context->mdt_devs.dev_mouse = dev_mouse;
return 0;
}
int init_mdt_touchscreen(struct mhl_dev_context *dev_context)
{
uint8_t error;
struct input_dev *dev_touchscreen;
dev_touchscreen = input_allocate_device();
if (!dev_touchscreen) {
MHL_TX_DBG_ERR("Not enough memory\n");
return -ENOMEM;
}
MHL_TX_DBG_INFO("Allocated touch screen: %p\n", dev_touchscreen);
#if !defined(SINGLE_TOUCH) && defined(KERNEL_2_6_38_AND_LATER)
input_mt_init_slots(dev_touchscreen, MAX_TOUCH_CONTACTS);
#endif
dev_touchscreen->phys = "mdt_touch/input0";
dev_touchscreen->name = "MDTtouchscreen";
dev_touchscreen->id.bustype = BUS_VIRTUAL;
dev_touchscreen->id.vendor = 0x1095;
dev_touchscreen->id.product = MHL_PRODUCT_NUM;
/* use version to distinguish between devices */
dev_touchscreen->id.version = 0xC;
#if defined(SINGLE_TOUCH)
__set_bit(EV_ABS, dev_touchscreen->evbit);
__set_bit(ABS_X, dev_touchscreen->absbit);
__set_bit(ABS_Y, dev_touchscreen->absbit);
__set_bit(EV_KEY, dev_touchscreen->evbit);
#if (CORNER_BUTTON == 1)
__set_bit(KEY_ESC, dev_touchscreen->keybit);
#endif
__set_bit(BTN_TOUCH, dev_touchscreen->keybit);
#ifdef KERNEL_2_6_38_AND_LATER
__set_bit(INPUT_PROP_DIRECT, dev_touchscreen->propbit);
#endif
input_set_abs_params(dev_touchscreen, ABS_X, 0,
dev_context->mdt_devs.x_max, 0, 0);
input_set_abs_params(dev_touchscreen, ABS_Y, 0,
dev_context->mdt_devs.y_max, 0, 0);
#else
__set_bit(EV_ABS, dev_touchscreen->evbit);
__set_bit(EV_KEY, dev_touchscreen->evbit);
#ifdef KERNEL_2_6_38_AND_LATER
__set_bit(EV_SYN, dev_touchscreen->evbit);
__set_bit(MT_TOOL_FINGER, dev_touchscreen->keybit);
__set_bit(INPUT_PROP_DIRECT, dev_touchscreen->propbit);
input_mt_init_slots(dev_touchscreen, MAX_TOUCH_CONTACTS);
#else
__set_bit(BTN_TOUCH, dev_touchscreen->keybit);
input_set_abs_params(dev_touchscreen, ABS_MT_WIDTH_MAJOR, 0, 3, 0, 0);
input_set_abs_params(dev_touchscreen, ABS_MT_TRACKING_ID, 0, 3, 0, 0);
#endif
#if (CORNER_BUTTON == 1)
__set_bit(KEY_ESC, dev_touchscreen->keybit);
#endif
input_set_abs_params(dev_touchscreen, ABS_MT_TOUCH_MAJOR, 0, 30, 0, 0);
input_set_abs_params(dev_touchscreen, ABS_MT_PRESSURE, 0, 255, 0, 0);
input_set_abs_params(dev_touchscreen, ABS_MT_POSITION_X, 0,
dev_context->mdt_devs.x_max, 0, 0);
input_set_abs_params(dev_touchscreen, ABS_MT_POSITION_Y, 0,
dev_context->mdt_devs.y_max, 0, 0);
#endif
#if (JB_421 == 1) && (ICS_BAR == 1)
#if (Y_BUTTON_RECENTAPPS_TOP != 0)
__set_bit(KEY_MENU, dev_touchscreen->keybit);
#endif
#if (Y_BUTTON_HOME_TOP != 0)
__set_bit(KEY_HOMEPAGE, dev_touchscreen->keybit);
#endif
#if (Y_BUTTON_BACK_TOP != 0)
__set_bit(KEY_BACK, dev_touchscreen->keybit);
#endif
#endif
error = input_register_device(dev_touchscreen);
if (error) {
MHL_TX_DBG_ERR("Failed to register device\n");
input_free_device(dev_touchscreen);
return error;
}
MHL_TX_DBG_INFO("Registered touchscreen: %p\n", dev_touchscreen);
dev_context->mdt_devs.dev_touchscreen = dev_touchscreen;
/* initialize history; in parcitular initialize state elements with
* MDT_TOUCH_INACTIVE
*/
memset(dev_context->mdt_devs.prior_touch_events, 0,
MAX_TOUCH_CONTACTS *
sizeof(dev_context->mdt_devs.prior_touch_events[0]));
return 0;
}
static int destroy_device(struct mhl_dev_context *dev_context,
enum mdt_dev_types_e mdt_device_type)
{
if ((mdt_device_type >= MDT_TYPE_COUNT) ||
(is_mdt_dev_active(dev_context, mdt_device_type) == 0)) {
MHL_TX_DBG_INFO("FAILURE. Invalid disconnect request.\n",
mdt_device_type);
return REGISTRATION_ERROR;
}
switch (mdt_device_type) {
case MDT_TYPE_MOUSE:
destroy_mouse(dev_context);
break;
case MDT_TYPE_KEYBOARD:
destroy_keyboard(dev_context);
break;
case MDT_TYPE_TOUCHSCREEN:
destroy_touchscreen(dev_context);
break;
default:
/* redundant check to pacify the compiler */
break;
}
dev_context->mdt_devs.is_dev_registered[mdt_device_type] =
INPUT_WAITING_FOR_REGISTRATION;
MHL_TX_DBG_INFO
("SUCCESS. Disconnect event handled for %d device type.\n",
mdt_device_type);
return REGISTRATION_SUCCESS;
}
/* The recursive piece of the registration function. */
static int registration_helper(struct mhl_dev_context *dev_context,
enum mdt_dev_types_e mdt_device_type)
{
switch (mdt_device_type) {
case MDT_TYPE_KEYBOARD:
if (dev_context->mdt_devs.dev_keyboard != 0)
return REGISTRATION_SUCCESS;
return init_mdt_keyboard(dev_context);
break;
case MDT_TYPE_MOUSE:
if (dev_context->mdt_devs.dev_mouse != 0)
return REGISTRATION_SUCCESS;
if (init_mdt_mouse(dev_context) != REGISTRATION_SUCCESS)
return REGISTRATION_ERROR;
/* Do not support both a pointer and touch. */
destroy_device(dev_context, MDT_TYPE_TOUCHSCREEN);
break;
case MDT_TYPE_TOUCHSCREEN:
if (dev_context->mdt_devs.dev_touchscreen != 0)
return REGISTRATION_SUCCESS;
if (init_mdt_touchscreen(dev_context) != REGISTRATION_SUCCESS)
return REGISTRATION_ERROR;
/* Do not support both a pointer and touch. */
destroy_device(dev_context, MDT_TYPE_MOUSE);
break;
case MDT_TYPE_COUNT:
/*
* This case is out of range.
* Code is included to avoid compiler warning.
*/
break;
}
return REGISTRATION_SUCCESS;
}
static int register_device(struct mhl_dev_context *dev_context,
enum mdt_dev_types_e mdt_device_type)
{
uint8_t error = 0;
if ((mdt_device_type >= MDT_TYPE_COUNT) ||
(is_mdt_dev_waiting(dev_context, mdt_device_type) == false))
return REGISTRATION_ERROR;
/* Call recursive part of the function.
Don't update is_dev_registered there. */
error = registration_helper(dev_context, mdt_device_type);
if (error != REGISTRATION_SUCCESS) {
dev_context->mdt_devs.is_dev_registered[mdt_device_type] =
INPUT_DISABLED;
MHL_TX_DBG_INFO("SUCCESS. Device type %d registered.\n",
mdt_device_type);
} else {
dev_context->mdt_devs.is_dev_registered[mdt_device_type] =
INPUT_ACTIVE;
MHL_TX_DBG_INFO
("FAILURE. Device type %d registration failed.\n",
mdt_device_type);
}
return error;
}
void generate_event_keyboard(struct mhl_dev_context *dev_context,
struct mdt_packet *keyboard_packet)
{
struct input_dev *dev_keyboard = dev_context->mdt_devs.dev_keyboard;
uint8_t *keycodes_new = dev_context->mdt_devs.keycodes_new;
uint8_t *keycodes_old = dev_context->mdt_devs.keycodes_old;
int i;
register_device(dev_context, MDT_TYPE_KEYBOARD);
memcpy(keycodes_new, &keyboard_packet->header, HID_INPUT_REPORT_CNT);
MHL_TX_DBG_INFO("Key (scancode %02X) asserted.\n", keycodes_new[1]);
if (dev_keyboard == 0) {
MHL_TX_DBG_INFO("MDT_ERR_NOKEY\n");
return;
}
/* following code was copied from usbkbd.c */
/* generate events for CRL, SHIFT, and ALT keys */
for (i = 0; i < 3; i++)
input_report_key(dev_keyboard,
usb_kbd_keycode[i + 224],
(keycodes_new[0] >> i) & 1);
/*
* Generate key press/release events for the
* remaining bytes in the input packet
*/
for (i = 1; i < 7; i++) {
/* If keycode in pervious HID payload doesn't appear
* in NEW HID payload, generate de-assertion event
*/
if ((keycodes_old[i] > 3) &&
((uint8_t *) memscan(keycodes_new + 1, keycodes_old[i], 6)
== ((uint8_t *) (keycodes_new) + 7))) {
if (usb_kbd_keycode[keycodes_old[i]]) {
input_report_key(dev_keyboard,
usb_kbd_keycode[keycodes_old
[i]], 0);
} else {
MHL_TX_DBG_INFO("Unknown key (scancode %#x) "
"released.\n", keycodes_old[i]);
}
}
/* If keycode in NEW HID paylaod doesn't appear in previous
* HID payload, generate assertion event
*/
if (keycodes_new[i] > 3 &&
memscan(keycodes_old + 1, keycodes_new[i],
6) == keycodes_old + 7) {
if (usb_kbd_keycode[keycodes_new[i]]) {
input_report_key(dev_keyboard,
usb_kbd_keycode[keycodes_new
[i]], 1);
} else {
MHL_TX_DBG_INFO("Unknown key (scancode %#x) "
"pressed.\n", keycodes_new[i]);
}
}
}
input_sync(dev_keyboard);
/* NEW HID payload is now OLD */
memcpy(keycodes_old, keycodes_new, HID_INPUT_REPORT_CNT);
}
static void mdt_toggle_keycode(struct input_dev *hid_device,
unsigned char keycode)
{
if (NULL == hid_device)
return;
input_report_key(hid_device, keycode, KEY_PRESSED);
input_sync(hid_device);
input_report_key(hid_device, keycode, KEY_RELEASED);
input_sync(hid_device);
}
void mdt_toggle_keyboard_keycode(struct mhl_dev_context *dev_context,
unsigned char keycode)
{
mdt_toggle_keycode(dev_context->mdt_devs.dev_keyboard, keycode);
}
void generate_event_mouse(struct mhl_dev_context *dev_context,
struct mdt_packet *mousePacket)
{
struct input_dev *dev_mouse = dev_context->mdt_devs.dev_mouse;
register_device(dev_context, MDT_TYPE_MOUSE);
MHL_TX_DBG_INFO("mouse buttons (0x%02x)\n",
mousePacket->header & MDT_HDR_MOUSE_BUTTON_MASK);
if (dev_mouse == 0) {
MHL_TX_DBG_ERR("MDT_ERR_NOMOUSE\n");
return;
}
/* Translate and report mouse button changes */
input_report_key(dev_mouse, BTN_LEFT,
mousePacket->header & MDT_HDR_MOUSE_BUTTON_1);
#if (RIGHT_MOUSE_BUTTON_IS_ESC == 1)
if (mousePacket->header & MDT_HDR_MOUSE_BUTTON_2) {
if (!dev_context->mdt_devs.prior_right_button) {
dev_context->mdt_devs.prior_right_button = 1;
mdt_toggle_keycode(dev_mouse, KEY_ESC);
}
} else
dev_context->mdt_devs.prior_right_button = 0;
#else
input_report_key(dev_mouse, BTN_RIGHT,
mousePacket->header & MDT_HDR_MOUSE_BUTTON_2);
#endif
input_report_key(dev_mouse, BTN_MIDDLE,
mousePacket->header & MDT_HDR_MOUSE_BUTTON_3);
input_report_rel(dev_mouse, REL_X,
mousePacket->event.mouse.x_displacement);
input_report_rel(dev_mouse, REL_Y,
mousePacket->event.mouse.y_displacement);
input_report_rel(dev_mouse, REL_WHEEL,
mousePacket->event.mouse.z_displacement);
input_sync(dev_mouse);
}
static uint8_t process_touch_packet(struct mhl_dev_context *dev_context,
struct mdt_packet *touchPacket)
{
struct mdt_touch_history_t *prior_event;
int abs_x, abs_y;
uint8_t isTouched = (touchPacket->header & 0x01);
uint8_t contactID = ((touchPacket->header & 0x06) >> 1);
prior_event =
(struct mdt_touch_history_t *)&(dev_context->mdt_devs.
prior_touch_events[contactID]);
abs_x = touchPacket->event.touch_pad.x_abs_coordinate[MDT_TOUCH_X_LOW] |
(touchPacket->event.touch_pad.
x_abs_coordinate[MDT_TOUCH_X_HIGH] << 8);
abs_y =
touchPacket->event.touch_pad.
y_abs_coordinate[MDT_TOUCH_Y_LOW] | (touchPacket->event.touch_pad.
y_abs_coordinate
[MDT_TOUCH_Y_HIGH] << 8);
#if (CORNER_BUTTON == 1)
/* Handle LOWER RIGHT corner like a EXIT button (ESC key) */
if ((abs_x > X_CORNER_RIGHT_LOWER) && (abs_y > Y_CORNER_RIGHT_LOWER)) {
if (isTouched != dev_context->mdt_devs.prior_touch_button) {
dev_context->mdt_devs.prior_touch_button = isTouched;
if (isTouched)
mdt_toggle_keycode(dev_context->mdt_devs.
dev_touchscreen, KEY_ESC);
}
return 0xFF;
}
#elif (ICS_BAR == 1)
/* JB421 doesn't allow this driver to trigger buttons on the bar.
implement custom buttons to workaround the problem. */
if ((isTouched != dev_context->mdt_devs.prior_touch_button)
&& (abs_x >= X_BUTTON_BAR_START)) {
if ((abs_y > Y_BUTTON_RECENTAPPS_TOP)
&& (abs_y < Y_BUTTON_RECENTAPPS_BOTTOM))
mdt_toggle_keycode(dev_context->mdt_devs.
dev_touchscreen, KEY_MENU);
else if ((abs_y > Y_BUTTON_HOME_TOP)
&& (abs_y < Y_BUTTON_HOME_BOTTOM))
mdt_toggle_keycode(dev_context->mdt_devs.
dev_touchscreen, KEY_HOMEPAGE);
else if ((abs_y > Y_BUTTON_BACK_TOP)
&& (abs_y < Y_BUTTON_BACK_BOTTOM))
mdt_toggle_keycode(dev_context->mdt_devs.
dev_touchscreen, KEY_BACK);
return 0xFF;
}
#endif
/* support dynamic configuration through ATTRIBUTES */
if (dev_context->mdt_devs.swap_xy != 0) {
prior_event->abs_x = abs_y;
prior_event->abs_y = abs_x;
} else {
prior_event->abs_x = abs_x;
prior_event->abs_y = abs_y;
}
if ((dev_context->mdt_devs.x_raw != 0) &&
(dev_context->mdt_devs.x_screen != 0) &&
(prior_event->abs_x != 0)) {
prior_event->abs_x *= dev_context->mdt_devs.x_screen;
prior_event->abs_x /= dev_context->mdt_devs.x_raw;
}
if ((dev_context->mdt_devs.y_raw != 0) &&
(dev_context->mdt_devs.y_screen != 0) &&
(prior_event->abs_y != 0)) {
prior_event->abs_y *= dev_context->mdt_devs.y_screen;
prior_event->abs_y /= dev_context->mdt_devs.y_raw;
}
if ((dev_context->mdt_devs.swap_leftright) &&
(dev_context->mdt_devs.x_max >= prior_event->abs_x))
prior_event->abs_x =
(dev_context->mdt_devs.x_max - prior_event->abs_x);
if ((dev_context->mdt_devs.swap_updown) &&
(dev_context->mdt_devs.y_max >= prior_event->abs_y))
prior_event->abs_y =
(dev_context->mdt_devs.y_max - prior_event->abs_y);
prior_event->abs_x += dev_context->mdt_devs.x_shift;
prior_event->abs_y += dev_context->mdt_devs.y_shift;
if (isTouched == 0) {
if (prior_event->isTouched == 0)
/* Multiple release events;
* declare contact inactive & ignore
*/
prior_event->state = MDT_TOUCH_INACTIVE;
} else {
prior_event->state = MDT_TOUCH_ACTIVE;
}
prior_event->isTouched = isTouched;
return contactID;
}
#if defined(SINGLE_TOUCH)
static void submit_touchscreen_events_as_single_touch(
struct mhl_dev_context *dev_context)
{
struct input_dev *dev_ts = dev_context->mdt_devs.dev_touchscreen;
struct mdt_touch_history_t *prior_event;
prior_event = &(dev_context->mdt_devs.prior_touch_events[0]);
input_report_key(dev_ts, BTN_TOUCH, prior_event->isTouched);
input_report_abs(dev_ts, ABS_X, prior_event->abs_x);
input_report_abs(dev_ts, ABS_Y, prior_event->abs_y);
}
#elif defined(KERNEL_2_6_38_AND_LATER)
static void submit_touchscreen_events_with_proto_B(
struct mhl_dev_context *dev_context, uint8_t contactID)
{
struct input_dev *dev_ts = dev_context->mdt_devs.dev_touchscreen;
struct mdt_touch_history_t *prior_event;
uint8_t i;
uint8_t counter = 0;
for (i = 0; i < MAX_TOUCH_CONTACTS; i++) {
prior_event = &(dev_context->mdt_devs.prior_touch_events[i]);
if (prior_event->state == MDT_TOUCH_INACTIVE)
continue;
input_mt_slot(dev_ts, i);
input_mt_report_slot_state(dev_ts, MT_TOOL_FINGER,
prior_event->isTouched);
/* Event already handled; don't handle it again. */
if (prior_event->isTouched == 0) {
prior_event->state = MDT_TOUCH_INACTIVE;
} else {
counter++;
input_report_abs(dev_ts, ABS_MT_TOUCH_MAJOR, 15);
input_report_abs(dev_ts, ABS_MT_PRESSURE, 50);
input_report_abs(dev_ts, ABS_MT_POSITION_X,
prior_event->abs_x);
input_report_abs(dev_ts, ABS_MT_POSITION_Y,
prior_event->abs_y);
}
/* BTN_TOUCH breaks support brokend as of JB42 */
#if !defined(JB_421)
if (counter == 1)
input_report_key(dev_ts, BTN_TOUCH, 1);
else
input_report_key(dev_ts, BTN_TOUCH, 0);
#endif
}
#else
static void submit_touchscreen_events_with_proto_A(
struct mhl_dev_context *dev_context, uint8_t contactID)
{
struct input_dev *dev_ts = dev_context->mdt_devs.dev_touchscreen;
struct mdt_touch_history_t *prior_event;
uint8_t i;
uint8_t count = 0;
for (i = 0; i < MAX_TOUCH_CONTACTS; i++) {
prior_event = &(dev_context->mdt_devs.prior_touch_events[i]);
if (prior_event->state == MDT_TOUCH_INACTIVE)
continue;
count++;
if (prior_event->isTouched == 0)
/* Event handled; don't handle it again. */
prior_event->state = MDT_TOUCH_INACTIVE;
input_report_key(dev_ts, BTN_TOUCH, prior_event->isTouched);
input_report_abs(dev_ts, ABS_MT_TOUCH_MAJOR,
prior_event->isTouched);
input_report_abs(dev_ts, ABS_MT_TRACKING_ID, i);
input_report_abs(dev_ts, ABS_MT_WIDTH_MAJOR, 1);
input_report_abs(dev_ts, ABS_MT_POSITION_X, prior_event->abs_x);
input_report_abs(dev_ts, ABS_MT_POSITION_Y, prior_event->abs_y);
input_mt_sync(dev_ts);
}
if (count == 0)
input_mt_sync(dev_ts);
}
#endif
static void generate_event_touchscreen(struct mhl_dev_context *dev_context,
struct mdt_packet *touchPacket)
{
struct input_dev *dev_ts = dev_context->mdt_devs.dev_touchscreen;
uint8_t contactID;
register_device(dev_context, MDT_TYPE_TOUCHSCREEN);
if (dev_ts == 0) {
MHL_TX_DBG_ERR("MDT_ERR_NOTOUCHSCREEN\n");
return;
}
/* process touch packet into prior_touch_events */
contactID = process_touch_packet(dev_context, touchPacket);
if (contactID == 0xFF)
return;
#if defined(SINGLE_TOUCH)
submit_touchscreen_events_as_single_touch(dev_context);
#elif defined(KERNEL_2_6_38_AND_LATER)
submit_touchscreen_events_with_proto_B(dev_context, contactID);
#else
submit_touchscreen_events_with_proto_A(dev_context, contactID);
#endif
/* generate touchscreen assertion */
input_sync(dev_ts);
}
static bool process_hotplug_packet(struct mhl_dev_context *dev_context,
struct mdt_packet *hotplug_packet)
{
/* 'M' previoulsy found to be in the header byte */
if ((hotplug_packet->event.hotplug.sub_header_d != D_CHAR) &&
(hotplug_packet->event.hotplug.sub_header_t != T_CHAR) &&
(hotplug_packet->event.hotplug.mdt_version != MDT_VERSION))
return false;
/* in the future, support response with ACK or NACK */
MHL_TX_DBG_INFO("HP packet. Device type: %02x. Event: %02x.\n",
hotplug_packet->event.hotplug.device_type,
hotplug_packet->event.hotplug.event_code);
switch (hotplug_packet->event.hotplug.event_code) {
case NOTICE_DEV_PLUG:
register_device(dev_context,
hotplug_packet->event.hotplug.device_type);
break;
case NOTICE_DEV_UNPLUG:
destroy_device(dev_context,
hotplug_packet->event.hotplug.device_type);
break;
default:
return false;
}
return true;
}
bool si_mhl_tx_mdt_process_packet(struct mhl_dev_context *dev_context,
void *packet)
{
struct mdt_packet *mdt_event_packet = (struct mdt_packet *)packet;
if (!(MDT_HDR_IS_HID & mdt_event_packet->header)) {
if (M_CHAR == mdt_event_packet->header)
return process_hotplug_packet(dev_context,
mdt_event_packet);
MHL_TX_DBG_INFO("Ignoring non-HID packet\n");
return false;
}
if (MDT_HDR_IS_KEYBOARD & mdt_event_packet->header) {
generate_event_keyboard(dev_context, mdt_event_packet);
} else if (!(MDT_HDR_IS_KEYBOARD & mdt_event_packet->header) &&
(!(MDT_HDR_IS_NOT_MOUSE & mdt_event_packet->header))) {
generate_event_mouse(dev_context, mdt_event_packet);
} else if (!(MDT_HDR_IS_KEYBOARD & mdt_event_packet->header) &&
(MDT_HDR_IS_NOT_MOUSE & mdt_event_packet->header)) {
generate_event_touchscreen(dev_context, mdt_event_packet);
} else if (!(MDT_HDR_IS_KEYBOARD & mdt_event_packet->header) &&
(MDT_HDR_IS_NOT_MOUSE & mdt_event_packet->header) &&
(MDT_HDR_IS_NOT_LAST & mdt_event_packet->header)) {
MHL_TX_DBG_INFO("Unsupported gaming controller "
"event received\n");
} else {
MHL_TX_DBG_INFO("Event is either not an HID event or "
"is an an unknown HID event type\n");
return false;
}
/* Consume the write burst event as an MDT event */
return true;
}
void mdt_destroy(struct mhl_dev_context *dev_context)
{
destroy_device(dev_context, MDT_TYPE_KEYBOARD);
destroy_device(dev_context, MDT_TYPE_MOUSE);
destroy_device(dev_context, MDT_TYPE_TOUCHSCREEN);
}
#endif

View file

@ -0,0 +1,216 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#ifndef _SI_MDT_INPUTDEV_H_
#define _SI_MDT_INPUTDEV_H_
#define HID_INPUT_REPORT_CNT 7
#define MAX_TOUCH_CONTACTS 4
/* MDT header byte bit definitions */
#define REGISTRATION_SUCCESS 0
#define REGISTRATION_ERROR 1
#define KEY_PRESSED 1
#define KEY_RELEASED 0
#define MDT_TOUCH_INACTIVE 1
#define MDT_TOUCH_ACTIVE 2
/* Common header bit definitions */
#define MDT_HDR_IS_HID 0x80
#define MDT_HDR_IS_PORT_B 0x40
#define MDT_HDR_IS_KEYBOARD 0x20
#define MDT_HDR_IS_NOT_LAST 0x10
#define MDT_HDR_IS_NOT_MOUSE 0x08
/* Keyboard event specific header bit definitions */
#define MDT_HDR_KBD_LEFT_ALT 0x04
#define MDT_HDR_KBD_LEFT_SHIFT 0x02
#define MDT_HDR_KBD_LEFT_CTRL 0x01
/* Mouse event specific header bit definitions */
#define MDT_HDR_MOUSE_BUTTON_3 0x04
#define MDT_HDR_MOUSE_BUTTON_2 0x02
#define MDT_HDR_MOUSE_BUTTON_1 0x01
#define MDT_HDR_MOUSE_BUTTON_MASK 0x07
/* Touch pad event specific header bit definitions */
#define MDT_HDR_TOUCH_IS_TOUCHED 0x01
#define MDT_HDR_TOUCH_CONTACT_ID_MASK 0x06
/* Game controller event specific header bit definitions */
#define MDT_HDR_GAME_BUTTON_3 0x04
#define MDT_HDR_GAME_BUTTON_2 0x02
#define MDT_HDR_GAME_BUTTON_1 0x01
/* MDT hot-plug prefix and event information */
#define MDT_VERSION 1
#define M_CHAR 'M'
#define D_CHAR 'D'
#define T_CHAR 'T'
#define NOTICE_DEV_PLUG 'R'
#define NOTICE_DEV_UNPLUG 'U'
#define RESPONSE_ACK 'A'
#define RESPONSE_NACK 'N'
/* MDT Touch screen resources and parameters */
#define MDT_TOUCH_X 0
#define MDT_TOUCH_Y 1
#define BYTE_LOW 0
#define BYTE_HIGH 1
#define MDT_TOUCH_X_LOW BYTE_LOW
#define MDT_TOUCH_X_HIGH BYTE_HIGH
#define MDT_TOUCH_Y_LOW BYTE_LOW
#define MDT_TOUCH_Y_HIGH BYTE_HIGH
/* support 11 bit absolute addressing */
#define X_CORNER_RIGHT_LOWER 1870
#define Y_CORNER_RIGHT_LOWER 1870
#define ICS_BeagleboardxM 1
#define X_MAX 1920
#define Y_MAX 1920
#define SCALE_X_RAW 0
#define SCALE_X_SCREEN 0
#define SCALE_Y_RAW 0
#define SCALE_Y_SCREEN 0
#define X_SHIFT 0
#define Y_SHIFT 0
#define SWAP_LEFTRIGHT 0
#define SWAP_UPDOWN 0
#define SWAP_XY 0
#define SINGLE_TOUCH 1
#define CORNER_BUTTON 1
#define ICS_BAR 0
#define RIGHT_MOUSE_BUTTON_IS_ESC 1
/* requires installation of IDC file */
/* #define KERNEL_2_6_38_AND_LATER */
/* as of JB the IDC file is needed but, doesn't
guarantee acess to virtual buttons. */
#define JB_421 0
#if (JB_421 == 1)
#define X_BUTTON_BAR_START 0x4F0
#define Y_BUTTON_RECENTAPPS_TOP 0x050
#define Y_BUTTON_RECENTAPPS_BOTTOM 0x165
#define Y_BUTTON_HOME_TOP 0x185
#define Y_BUTTON_HOME_BOTTOM 0x2C0
#define Y_BUTTON_BACK_TOP 0x2E0
#define Y_BUTTON_BACK_BOTTOM 0x3E0
#endif
enum mdt_dev_state_e {
INPUT_DISABLED,
INPUT_WAITING_FOR_REGISTRATION,
INPUT_ACTIVE
};
enum mdt_dev_types_e {
MDT_TYPE_MOUSE,
MDT_TYPE_KEYBOARD,
MDT_TYPE_TOUCHSCREEN,
MDT_TYPE_COUNT
};
struct mdt_touch_history_t {
uint32_t abs_x;
uint32_t abs_y;
uint8_t isTouched;
uint8_t state;
};
struct mdt_inputdevs {
/* Prior HID input report */
uint8_t keycodes_old[HID_INPUT_REPORT_CNT];
/* Current HID input report */
uint8_t keycodes_new[HID_INPUT_REPORT_CNT];
struct input_dev *dev_keyboard;
struct input_dev *dev_mouse;
struct input_dev *dev_touchscreen;
/* Instance tracking variable */
uint8_t is_dev_registered[MDT_TYPE_COUNT];
struct mdt_touch_history_t prior_touch_events[MAX_TOUCH_CONTACTS];
unsigned char prior_touch_button;
#if (RIGHT_MOUSE_BUTTON_IS_ESC == 1)
unsigned char prior_right_button;
#endif
/* ser overrides to allow runtime calibration */
uint32_t x_max, y_max;
uint32_t x_screen, x_raw, x_shift;
uint32_t y_screen, y_raw, y_shift;
uint32_t swap_xy, swap_updown, swap_leftright;
};
struct keyboard_event_data {
uint8_t first_key[3];
uint8_t second_key[3];
};
struct mouse_event_data {
int8_t x_displacement;
int8_t y_displacement;
int8_t z_displacement;
uint8_t vendor_specific[2];
uint8_t vendor_specific_game_flag;
};
struct touch_pad_event_data {
uint8_t x_abs_coordinate[2];
uint8_t y_abs_coordinate[2];
uint8_t vendor_specific;
uint8_t vendor_specific_game_flag;
};
struct gaming_controller {
int8_t x_rel_displacement;
int8_t y_rel_displacement;
int8_t z_rel_displacement;
int8_t y2_rel_displacement;
uint8_t buttons_ext;
uint8_t id_dpad;
};
struct mdt_hotplug_data {
uint8_t sub_header_d;
uint8_t sub_header_t;
uint8_t event_code;
uint8_t device_type;
uint8_t mdt_version;
uint8_t reserved;
};
struct mdt_packet {
uint8_t adopter_id_h;
uint8_t adopter_id_l;
uint8_t header;
union {
struct keyboard_event_data keyboard;
struct mouse_event_data mouse;
struct touch_pad_event_data touch_pad;
struct gaming_controller game_controller;
struct mdt_hotplug_data hotplug;
uint8_t bytes[6];
} event;
};
struct mhl_dev_context;
extern struct attribute_group mdt_attr_group;
void mdt_toggle_keyboard_keycode(struct mhl_dev_context *dev_context,
unsigned char keycode);
bool si_mhl_tx_mdt_process_packet(struct mhl_dev_context *dev_context,
void *packet);
void mdt_destroy(struct mhl_dev_context *dev_context);
#endif /* #ifndef _SI_MDT_INPUTDEV_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,183 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#ifndef _SI_MHL2_EDID_3D_API_H_
#define _SI_MHL2_EDID_3D_API_H_
#define EDID_BLOCK_SIZE 128
#define BIT_EDID_FIELD_FORMAT_HDMI_TO_RGB 0x00
#define BIT_EDID_FIELD_FORMAT_YCbCr422 0x01
#define BIT_EDID_FIELD_FORMAT_YCbCr444 0x02
#define BIT_EDID_FIELD_FORMAT_DVI_TO_RGB 0x03
struct edid_3d_flags_t {
unsigned parse_3d_in_progress:1;
unsigned FLAGS_SENT_3D_REQ:1;
unsigned FLAGS_BURST_3D_VIC_DONE:1;
unsigned FLAGS_BURST_3D_DTD_DONE:1;
unsigned FLAGS_BURST_3D_DTD_VESA_DONE:1;
unsigned FLAGS_BURST_3D_DONE:1;
unsigned FLAGS_EDID_READ_DONE:1;
unsigned reserved:1;
};
#define MAX_V_DESCRIPTORS 21
#define MAX_A_DESCRIPTORS 10
#define MAX_SPEAKER_CONFIGURATIONS 4
#define AUDIO_DESCR_SIZE 3
#define NUM_VIDEO_DATA_BLOCKS_LIMIT 3
struct edid_parse_data_t {
struct edid_3d_flags_t flags;
struct vsdb_t *p_HDMI_vsdb;
struct video_data_block_t *
p_video_data_blocks_2d[NUM_VIDEO_DATA_BLOCKS_LIMIT];
struct video_capability_data_block_t *p_video_capability_data_block;
struct VSDB_byte_13_through_byte_15_t *p_byte_13_through_byte_15;
struct _3D_mask_t *p_3d_mask;
union _3D_structure_and_detail_entry_u *p_three_d;
uint8_t *p_3d_limit;
/* counter for initial EDID parsing, persists afterwards */
uint8_t num_video_data_blocks;
/* counter for 3D write burst parsing. */
uint8_t video_data_block_index;
uint8_t burst_entry_count_3d_vic;
uint8_t vic_2d_index;
uint8_t vic_3d_index;
uint8_t burst_entry_count_3d_dtd;
uint8_t vesa_dtd_index;
uint8_t cea_861_dtd_index;
uint8_t num_vesa_timing_dtds;
uint8_t num_cea_861_timing_dtds;
/* maximum number of audio descriptors */
struct CEA_short_audio_descriptor_t
audio_descriptors[MAX_A_DESCRIPTORS];
/* maximum number of speaker configurations */
uint8_t speaker_alloc[MAX_SPEAKER_CONFIGURATIONS];
/* "1" if DTV monitor underscans IT video formats by default */
bool underscan;
bool basic_audio; /* Sink supports Basic Audio */
bool YCbCr_4_4_4; /* Sink supports YCbCr 4:4:4 */
bool YCbCr_4_2_2; /* Sink supports YCbCr 4:2:2 */
bool HDMI_sink; /* "1" if HDMI signature found */
/* CEC Physical address. See HDMI 1.3 Table 8-6 */
uint8_t CEC_A_B;
uint8_t CEC_C_D;
uint8_t video_capability_flags;
/* IEC 61966-2-4 colorimetry support: 1 - xvYCC601; 2 - xvYCC709 */
uint8_t colorimetry_support_flags;
uint8_t meta_data_profile;
bool _3D_supported;
uint8_t num_EDID_extensions;
};
struct mhl_dev_context;
struct item_alloc_info_t {
size_t num_items;
size_t num_items_allocated;
size_t index;
};
struct edid_3d_data_t {
struct mhl_dev_context *dev_context;
struct drv_hw_context *drv_context;
struct MHL3_hev_dtd_item_t hev_dtd_payload;
struct MHL3_hev_dtd_item_t *hev_dtd_list;
struct item_alloc_info_t hev_dtd_info;
struct MHL3_hev_vic_item_t *hev_vic_list;
struct item_alloc_info_t hev_vic_info;
struct MHL3_3d_dtd_item_t *_3d_dtd_list;
struct item_alloc_info_t _3d_dtd_info;
struct MHL3_3d_vic_item_t *_3d_vic_list;
struct item_alloc_info_t _3d_vic_info;
struct edid_parse_data_t parse_data;
uint8_t num_emsc_edid_extensions;
uint8_t num_edid_emsc_blocks;
uint8_t cur_edid_emsc_block;
uint8_t *p_edid_emsc;
uint8_t EDID_block_data[4 * EDID_BLOCK_SIZE];
};
struct SI_PACK_THIS_STRUCT si_incoming_timing_t {
uint32_t calculated_pixel_clock;
uint16_t h_total;
uint16_t v_total;
uint16_t columns;
uint16_t rows;
uint16_t field_rate;
uint8_t mhl3_vic;
};
struct mhl_dev_context *si_edid_create_context(
struct mhl_dev_context *dev_context,
struct drv_hw_context *drv_context);
void *si_edid_get_processed_edid(struct edid_3d_data_t *mhl_edid_3d_data);
void si_edid_destroy_context(struct edid_3d_data_t *mhl_edid_3d_data);
void si_mhl_tx_initiate_edid_sequence(struct edid_3d_data_t *mhl_edid_3d_data);
void si_mhl_tx_process_3d_vic_burst(void *context,
struct MHL2_video_format_data_t *pWriteBurstData);
void si_mhl_tx_process_3d_dtd_burst(void *context,
struct MHL2_video_format_data_t *pWriteBurstData);
void si_mhl_tx_process_hev_vic_burst(struct edid_3d_data_t *mhl_edid_3d_data,
struct MHL3_hev_vic_data_t *p_write_burst_data);
void si_mhl_tx_process_hev_dtd_a_burst(struct edid_3d_data_t *mhl_edid_3d_data,
struct MHL3_hev_dtd_a_data_t *p_burst);
void si_mhl_tx_process_hev_dtd_b_burst(struct edid_3d_data_t *mhl_edid_3d_data,
struct MHL3_hev_dtd_b_data_t *p_burst);
uint32_t si_mhl_tx_find_timings_from_totals(
struct edid_3d_data_t *mhl_edid_3d_data,
struct si_incoming_timing_t *p_timing);
int si_edid_sink_is_hdmi(void *context);
int si_edid_quantization_range_selectable(void *context);
int si_edid_sink_supports_YCbCr422(void *context);
int si_edid_sink_supports_YCbCr444(void *context);
int si_edid_find_pixel_clock_from_HDMI_VIC(void *context, uint8_t vic);
int si_edid_find_pixel_clock_from_AVI_VIC(void *context, uint8_t vic);
uint8_t si_edid_map_hdmi_vic_to_mhl3_vic(void *context, uint8_t vic);
enum NumExtensions_e {
ne_NO_HPD = -4,
ne_BAD_DATA = -3,
ne_BAD_CHECKSUM = ne_BAD_DATA,
ne_BAD_HEADER = -2,
ne_BAD_HEADER_OFFSET_BY_1 = -1,
ne_SUCCESS = 0
};
#ifdef MANUAL_EDID_FETCH
bool si_mhl_tx_check_edid_header(struct edid_3d_data_t *mhl_edid_3d_data,
void *pdata);
#endif
int si_mhl_tx_get_num_cea_861_extensions(void *context, uint8_t block_number);
int si_edid_read_done(void *context);
void si_edid_reset(struct edid_3d_data_t *mhl_edid_3d_data);
uint8_t qualify_pixel_clock_for_mhl(struct edid_3d_data_t *mhl_edid_3d_data,
uint32_t pixel_clock_frequency, uint8_t bits_per_pixel);
uint8_t calculate_generic_checksum(void *infoFrameData, uint8_t checkSum,
uint8_t length);
uint32_t si_edid_find_pixel_clock_from_HEV_DTD(
struct edid_3d_data_t *mhl_edid_3d_data,
struct MHL_high_low_t hev_fmt);
void si_mhl_tx_display_timing_enumeration_end(
struct edid_3d_data_t *mhl_edid_3d_data);
int process_emsc_edid_sub_payload(struct edid_3d_data_t *edid_context,
struct si_adopter_id_data *p_burst);
#endif

View file

@ -0,0 +1,243 @@
#ifndef _SI_MHL_CALLBACK_API_H_
#define _SI_MHL_CALLBACK_API_H_
union __attribute__((__packed__)) avif_or_cea_861_dtd_u
{
struct detailed_timing_descriptor_t cea_861_dtd;
struct avi_info_frame_t avif;
};
enum hpd_high_callback_status {
/* successful return values for hpd_driven_high(): */
/* a DTD has been written to the p_avif_or_dtd buffer instead of an AVI
* infoframe
*/
HH_FMT_DVI = 0x00000000,
/* No Vendor Specific InfoFrame provided */
HH_FMT_HDMI_VSIF_NONE = 0x00000001,
/* HDMI vsif has been filled into p_vsif */
HH_FMT_HDMI_VSIF_HDMI = 0x00000002,
/* MHL3 vsif has been filled into p_vsif */
HH_FMT_HDMI_VSIF_MHL3 = 0x00000003,
/* a DTD has been written to the DTD buffer instead of an AVI infoframe
* and 8620 shall expect HDCP enabled on its HDMI input
*/
HH_FMT_DVI_HDCP_ON = 0x00000004,
/* No Vendor Specific InfoFrame provided and 8620 shall expect HDCP
* enabled on its HDMI input
*/
HH_FMT_HDMI_VSIF_NONE_HDCP_ON = 0x00000005,
/* HDMI vsif has been filled into p_vsif and 8620 shall expect HDCP
* enabled on its HDMI input
*/
HH_FMT_HDMI_VSIF_HDMI_HDCP_ON = 0x00000006,
/* MHL3 vsif has been filled into p_vsif and 8620 shall expect HDCP
* enabled on its HDMI input
*/
HH_FMT_HDMI_VSIF_MHL3_HDCP_ON = 0x00000007,
/* a DTD has been written to the DTD buffer instead of an AVI
* infoframe
*/
HH_FMT_DVI_NOT_RPT = 0x00000008,
/* No Vendor Specific InfoFrame provided */
HH_FMT_HDMI_VSIF_NONE_NOT_RPT = 0x00000009,
/* HDMI vsif has been filled into p_vsif */
HH_FMT_HDMI_VSIF_HDMI_NOT_RPT = 0x0000000A,
/* MHL3 vsif has been filled into p_vsif */
HH_FMT_HDMI_VSIF_MHL3_NOT_RPT = 0x0000000B,
/* a DTD has been written to the DTD buffer instead of an AVI infoframe
* and 8620 shall expect HDCP enabled on its HDMI input
*/
HH_FMT_DVI_HDCP_ON_NOT_RPT = 0x0000000C,
/* No Vendor Specific InfoFrame provided and 8620 shall expect HDCP
* enabled on its HDMI input
*/
HH_FMT_HDMI_VSIF_NONE_HDCP_ON_NOT_RPT = 0x0000000D,
/* HDMI vsif has been filled into p_vsif and 8620 shall expect HDCP
* enabled on its HDMI input
*/
HH_FMT_HDMI_VSIF_HDMI_HDCP_ON_NOT_RPT = 0x0000000E,
/* MHL3 vsif has been filled into p_vsif and 8620 shall expect HDCP
* enabled on its HDMI input
*/
HH_FMT_HDMI_VSIF_MHL3_HDCP_ON_NOT_RPT = 0x0000000F,
/* failure return values for hpd_driven_high(): */
/* avi_max_length not large enough for AVI info frame data. */
HH_AVI_BUFFER_TOO_SMALL = 0x80000001,
/* vsif_max_length not large enough for info frame data. */
HH_VSIF_BUFFER_TOO_SMALL = 0x80000002,
/* The callee is not ready to start video */
HH_VIDEO_NOT_RDY = 0x80000004
};
struct __attribute__((__packed__)) si_mhl_callback_api_t {
void *context;
#if 1
int (*display_timing_enum_begin) (void *context);
int (*display_timing_enum_item) (void *context, uint16_t columns,
uint16_t rows, uint8_t bits_per_pixel,
uint32_t vertical_refresh_rate_in_milliHz, uint16_t burst_id,
union video_burst_descriptor_u *p_descriptor);
int (*display_timing_enum_end) (void *context);
#endif
/*
hpd_driven_low:
This gets called in response to CLR_HPD messages from the MHL sink.
The upstream client that registers this callback should disable
video and all DDC access before returning.
*/
void (*hpd_driven_low) (void *context);
/*
hpd_driven_high:
This gets called when the driver is ready for upstream video
activity. The upstream client that registers this callback should
respond in the same way in which it would respond to a rising HPD
signal (which happens prior to the call).
Parameters:
*p_edid:
The processed EDID block(s) that the MHL driver has derived
from the downstream EDID and WRITE_BURST info associated with the
sink's responses to 3D_REQ (MHL 2.x) or FEAT_REQ (MHL 3.x and newer).
edid_length:
*p_emsc_edid:
The unprocessed EDID transferred via eMSC BLOCK
using SILICON_IMAGE_ADOPTER_ID
emsc_edid_length:
The length, in bytes of the data in *p_emsc_edid
The length, in bytes, of the data in *p_edid
*p_hev_dtd:
The processed result of all the HEV_DTDA/HEV_DTDB WRITE_BURSTs
including the associated 3D_DTD VDI for each HEV_DTD pair.
num_hev_dtds:
The number of MHL3_hev_dtd_t elements in *p_hev_dtd.
p_hev_vic:
The processed result of all the HEV_VIC WRITE_BURSTs including
the associated 3D_VIC VDI for each HEV_DTD pair.
num_hev_vic_items:
The number of MHL3_hev_vic_item_t elements in p_hev_vic.
*p_3d_dtd_items:
The processed result of all the 3D_DTD WRITE_BURSTs including
the associated DTD from the EDID when VDI_H.HEV_FMT is zero.
num_3d_dtd_items:
The number of MHL3_3d_dtd_item_t elements in p_3d_dtd_items;
*p_3d_vic:
The processed result of all the 3D_VIC WRITE_BURSTs including
the associated VIC code from the EDID.
num_3d_vic_items:
The number of MHL3_3d_vic_item_t elements in p_3d_vic.
p_avif_or_dtd:
If the callee sends HDMI content, it shall fill in *p_avif_or_dtd
with the contents of its outgoing AVI info frame, including the
checksum byte, and return one of the values described under the
parameter p_vsif.
If the callee, sends DVI content, is shall fill in *p_avif_or_dtd
with a Detailed Timing Descriptor (defined in CEA-861D) that
accurately describes the timing parameters of the video which is
presented at the 8620's HDMI input and return one of:
HH_FMT_DVI
HH_FMT_DVI_HDCP_ON
HH_FMT_DVI_NOT_REPEATABLE
HH_FMT_DVI_HDCP_ON_NOT_REPEATABLE.
This buffer will be pre-initialized to zeroes prior to the call.
avi_max_length:
The length of the buffer pointed to by p_avif_or_dtd.
p_vsif:
A buffer into which the upstream driver should
write the contents of its outgoing vendor specific
info frame, if any, including the checksum byte. This
buffer will be pre-initialized to zeroes prior to the call.
If the callee chooses to write an HDMI vendor specific info frame
into p_vsif, it shall return one of:
HH_FMT_HDMI_VSIF_HDMI
HH_FMT_HDMI_VSIF_HDMI_HDCP_ON
HH_FMT_HDMI_VSIF_HDMI_NOT_REPEATABLE
HH_FMT_HDMI_VSIF_HDMI_HDCP_ON_NOT_REPEATABLE.
If the callee chooses to write an MHL3 vendor specific info frame
into p_vsif, it shall return one of:
HH_FMT_HDMI_VSIF_MHL3
HH_FMT_HDMI_VSIF_MHL3_HDCP_ON
HH_FMT_HDMI_VSIF_MHL3_NOT_REPEATABLE
HH_FMT_HDMI_VSIF_MHL3_HDCP_ON_NOT_REPEATABLE.
If the callee does not write a vendor specific
info frame into this buffer, the callee shall return one of:
HH_FMT_HDMI_VSIF_NONE
HH_FMT_HDMI_VSIF_NONE_HDCP_ON
HH_FMT_HDMI_VSIF_NONE_NOT_RPT
HH_FMT_HDMI_VSIF_NONE_HDCP_ON_NOT_RPT
and the 8620 will infer the contents of the outgoing MHL3 VSIF from
the contents of the HDMI VSIF (if any) presented at the 8620's HDMI
input.
vsif_max_length:
The length of the buffer pointed to by p_vsif.
Return values for hpd_driven_high():
If the callee enabled video during the duration of this call, then
the callee shall return one of the values in
hpd_high_callback_status that do not have the sign bit set,
indicating the usage of parameters.
If the callee did not enable video during the duration of this call,
then the callee shall indicate specific reasons for not starting
video by returning the bitwise OR of the values in
hpd_high_callback_status that do have the sign bit set.
*/
enum hpd_high_callback_status(*hpd_driven_high) (void *context,
uint8_t *p_edid, size_t edid_length,
uint8_t *p_emsc_edid, size_t emsc_edid_length,
struct MHL3_hev_dtd_item_t *p_hev_dtd, size_t num_hev_dtds,
struct MHL3_hev_vic_item_t *p_hev_vic, size_t num_hev_vic_items,
struct MHL3_3d_dtd_item_t *p_3d_dtd_items,
size_t num_3d_dtd_items,
struct MHL3_3d_vic_item_t *p_3d_vic, size_t num_3d_vic_items,
union avif_or_cea_861_dtd_u *p_avif_or_dtd,
size_t avif_or_dtd_max_length,
union vsif_mhl3_or_hdmi_u *p_vsif,
size_t vsif_max_length);
};
/* call this function to register the callback structure */
int si_8620_register_callbacks(struct si_mhl_callback_api_t *p_callbacks);
/* call this function to change video modes */
int si_8620_info_frame_change(enum hpd_high_callback_status status,
union avif_or_cea_861_dtd_u *p_avif_or_dtd,
size_t avif_or_dtd_max_length,
union vsif_mhl3_or_hdmi_u *p_vsif,
size_t vsif_max_length);
/* call this function to query downstream HPD status */
int si_8620_get_hpd_status(int *hpd_status);
int si_8620_get_hdcp2_status(uint32_t *hdcp2_status);
#endif

View file

@ -0,0 +1,961 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#ifndef _SI_MHL_DEFS_H_
#define _SI_MHL_DEFS_H_
/*
* This file contains MHL Specs related definitions.
*/
/*
* DEVCAP offsets
*/
enum {
DEVCAP_OFFSET_DEV_STATE,
DEVCAP_OFFSET_MHL_VERSION,
DEVCAP_OFFSET_DEV_CAT,
DEVCAP_OFFSET_ADOPTER_ID_H,
DEVCAP_OFFSET_ADOPTER_ID_L,
DEVCAP_OFFSET_VID_LINK_MODE,
DEVCAP_OFFSET_AUD_LINK_MODE,
DEVCAP_OFFSET_VIDEO_TYPE,
DEVCAP_OFFSET_LOG_DEV_MAP,
DEVCAP_OFFSET_BANDWIDTH,
DEVCAP_OFFSET_FEATURE_FLAG,
DEVCAP_OFFSET_DEVICE_ID_H,
DEVCAP_OFFSET_DEVICE_ID_L,
DEVCAP_OFFSET_SCRATCHPAD_SIZE,
DEVCAP_OFFSET_INT_STAT_SIZE,
DEVCAP_OFFSET_RESERVED,
/* this one must be last */
DEVCAP_SIZE
};
SI_PUSH_STRUCT_PACKING
struct SI_PACK_THIS_STRUCT MHLDevCap_t {
uint8_t state;
uint8_t mhl_version;
uint8_t deviceCategory;
uint8_t adopterIdHigh;
uint8_t adopterIdLow;
uint8_t vid_link_mode;
uint8_t audLinkMode;
uint8_t videoType;
uint8_t logicalDeviceMap;
uint8_t bandWidth;
uint8_t featureFlag;
uint8_t deviceIdHigh;
uint8_t deviceIdLow;
uint8_t scratchPadSize;
uint8_t int_state_size;
uint8_t reserved;
};
union MHLDevCap_u {
struct MHLDevCap_t mdc;
uint8_t devcap_cache[DEVCAP_SIZE];
};
/* Version that this chip supports */
#define MHL_VER_MAJOR 0x30
#define MHL_VER_MINOR 0x02
#define MHL_VERSION (MHL_VER_MAJOR | MHL_VER_MINOR)
/* Device Category */
#define MHL_DEV_CATEGORY_OFFSET DEVCAP_OFFSET_DEV_CAT
#define MHL_DEV_CATEGORY_POW_BIT 0x10
#define MHL_DEV_CATEGORY_PLIM2_0 0xE0
#define I_VBUS_PRE_DISCOVERY 100
#define I_VBUS_SOURCE_TO_DONGLE 200
#define I_VBUS_POST_DISCOVERY 500
#define MHL_DEV_CAT_SINK 0x01
#define MHL_DEV_CAT_SOURCE 0x02
#define MHL_DEV_CAT_DONGLE 0x03
#define MHL_DEV_CAT_SELF_POWERED_DONGLE 0x13
/* Video Link Mode */
#define MHL_DEV_VID_LINK_SUPP_RGB444 0x01
#define MHL_DEV_VID_LINK_SUPP_YCBCR444 0x02
#define MHL_DEV_VID_LINK_SUPP_YCBCR422 0x04
#define MHL_DEV_VID_LINK_SUPP_PPIXEL 0x08
#define MHL_DEV_VID_LINK_SUPP_ISLANDS 0x10
#define MHL_DEV_VID_LINK_SUPP_VGA 0x20
#define MHL_DEV_VID_LINK_SUPP_16BPP 0x40
/* Audio Link Mode Support */
#define MHL_DEV_AUD_LINK_2CH 0x01
#define MHL_DEV_AUD_LINK_8CH 0x02
/* Feature Flag in the devcap */
#define MHL_DEV_FEATURE_FLAG_OFFSET DEVCAP_OFFSET_FEATURE_FLAG
#define MHL_FEATURE_RCP_SUPPORT 0x01
#define MHL_FEATURE_RAP_SUPPORT 0x02
#define MHL_FEATURE_SP_SUPPORT 0x04
#define MHL_FEATURE_UCP_SEND_SUPPORT 0x08
#define MHL_FEATURE_UCP_RECV_SUPPORT 0x10
#define MHL_FEATURE_RBP_SUPPORT 0x40
/* VIDEO TYPES */
#define MHL_VT_GRAPHICS 0x00
#define MHL_VT_PHOTO 0x02
#define MHL_VT_CINEMA 0x04
#define MHL_VT_GAMES 0x08
#define MHL_SUPP_VT 0x80
/* Logical Dev Map */
#define MHL_DEV_LD_DISPLAY 0x01
#define MHL_DEV_LD_VIDEO 0x02
#define MHL_DEV_LD_AUDIO 0x04
#define MHL_DEV_LD_MEDIA 0x08
#define MHL_DEV_LD_TUNER 0x10
#define MHL_DEV_LD_RECORD 0x20
#define MHL_DEV_LD_SPEAKER 0x40
#define MHL_DEV_LD_GUI 0x80
/* Bandwidth */
#define MHL_BANDWIDTH_LIMIT 22 /* 225 MHz */
#define MHL_STATUS_REG_CONNECTED_RDY 0x30
#define MHL_STATUS_REG_LINK_MODE 0x31
#define MHL_STATUS_REG_VERSION_STAT 0x32
#define MHL_STATUS_DCAP_RDY 0x01
#define MHL_STATUS_XDEVCAPP_SUPP 0x02
#define MHL_STATUS_POW_STAT 0x04
#define MHL_STATUS_PLIM_STAT_MASK 0x38
#define MHL_STATUS_CLK_MODE_MASK 0x07
#define MHL_STATUS_CLK_MODE_PACKED_PIXEL 0x02
#define MHL_STATUS_CLK_MODE_NORMAL 0x03
#define MHL_STATUS_PATH_EN_MASK 0x08
#define MHL_STATUS_PATH_ENABLED 0x08
#define MHL_STATUS_PATH_DISABLED 0x00
#define MHL_STATUS_MUTED_MASK 0x10
#define MHL_RCHANGE_INT 0x20
#define MHL_DCHANGE_INT 0x21
#define MHL_INT_DCAP_CHG 0x01
#define MHL_INT_DSCR_CHG 0x02
#define MHL_INT_REQ_WRT 0x04
#define MHL_INT_GRT_WRT 0x08
#define MHL2_INT_3D_REQ 0x10
#define MHL3_INT_FEAT_REQ 0x20
#define MHL3_INT_FEAT_COMPLETE 0x40
/* On INTR_1 the EDID_CHG is located at BIT 0 */
#define MHL_INT_EDID_CHG 0x02
/* This contains one nibble each - max offset */
#define MHL_INT_AND_STATUS_SIZE 0x33
#define MHL_SCRATCHPAD_SIZE 16
/* manually define highest number */
#define MHL_MAX_BUFFER_SIZE MHL_SCRATCHPAD_SIZE
#define SILICON_IMAGE_ADOPTER_ID 322
enum BurstId_e {
MHL_TEST_ADOPTER_ID = 0x0000,
burst_id_3D_VIC = 0x0010,
burst_id_3D_DTD = 0x0011,
burst_id_HEV_VIC = 0x0020,
burst_id_HEV_DTDA = 0x0021,
burst_id_HEV_DTDB = 0x0022,
burst_id_VC_ASSIGN = 0x0038,
burst_id_VC_CONFIRM = 0x0039,
burst_id_AUD_DELAY = 0x0040,
burst_id_ADT_BURSTID = 0x0041,
burst_id_BIST_SETUP = 0x0051,
burst_id_BIST_RETURN_STAT = 0x0052,
burst_id_BIST_DISCARD = 0x0053,
burst_id_BIST_ECHO_REQUEST = 0x0054,
burst_id_BIST_ECHO_RESPONSE = 0x0055,
burst_id_EMSC_SUPPORT = 0x0061,
burst_id_HID_PAYLOAD = 0x0062,
burst_id_BLK_RCV_BUFFER_INFO = 0x0063,
burst_id_BITS_PER_PIXEL_FMT = 0x0064,
adopter_id_RANGE_START = 0x0080,
LOCAL_ADOPTER_ID = SILICON_IMAGE_ADOPTER_ID,
/* add new burst ID's above here */
/* Burst ID's are a 16-bit big-endian quantity. */
burst_id_16_BITS_REQUIRED = 0x8000
};
struct SI_PACK_THIS_STRUCT MHL_high_low_t {
uint8_t high;
uint8_t low;
};
struct SI_PACK_THIS_STRUCT MHL_burst_id_t {
uint8_t high;
uint8_t low;
};
struct SI_PACK_THIS_STRUCT EMSC_BLK_ADOPT_ID_PAYLD_HDR {
struct MHL_burst_id_t burst_id;
uint8_t remaining_length;
};
#define ENDIAN_CONVERT_16(a) \
((((uint16_t)((a).high))<<8)|((uint16_t)((a).low)))
#define BURST_ID(bid) (enum BurstId_e)ENDIAN_CONVERT_16(bid)
#define HIGH_BYTE_16(x) (uint8_t)((x >> 8) & 0xFF)
#define LOW_BYTE_16(x) (uint8_t)(x & 0xFF)
#define ENCODE_BURST_ID(id) {HIGH_BYTE_16(id), LOW_BYTE_16(id)}
struct SI_PACK_THIS_STRUCT standard_transport_header_t {
uint8_t rx_unload_ack;
uint8_t length_remaining;
};
#define STD_TRANSPORT_HDR_SIZE \
sizeof(struct SI_PACK_THIS_STRUCT standard_transport_header_t)
struct SI_PACK_THIS_STRUCT block_rcv_buffer_info_t {
/* use the BURST_ID macro to access this */
struct MHL_burst_id_t burst_id;
uint8_t blk_rcv_buffer_size_low;
uint8_t blk_rcv_buffer_size_high;
};
/* see MHL2.0 spec section 5.9.1.2 */
struct SI_PACK_THIS_STRUCT MHL2_video_descriptor_t {
uint8_t reserved_high;
unsigned char frame_sequential:1; /*FB_SUPP*/
unsigned char top_bottom:1; /*TB_SUPP*/
unsigned char left_right:1; /*LR_SUPP*/
unsigned char reserved_low:5;
};
struct MHL3_vdi_l_t {
unsigned char frame_sequential:1; /*FB_SUPP*/
unsigned char top_bottom:1; /*TB_SUPP*/
unsigned char left_right:1; /*LR_SUPP*/
unsigned char reserved_low:5;
};
struct MHL3_vdi_h_t {
unsigned char reserved;
};
/* see MHL3.0 spec section 5.11 */
struct SI_PACK_THIS_STRUCT MHL3_video_descriptor_t {
/* VDI_H comes before VDI_L. See Table 5-5 */
struct MHL3_vdi_h_t vdi_h;
struct MHL3_vdi_l_t vdi_l;
};
struct SI_PACK_THIS_STRUCT MHL3_burst_header_t {
struct MHL_burst_id_t burst_id;
uint8_t checksum;
uint8_t total_entries;
uint8_t sequence_index;
};
struct SI_PACK_THIS_STRUCT MHL2_video_format_data_t {
struct MHL3_burst_header_t header;
uint8_t num_entries_this_burst;
struct MHL2_video_descriptor_t video_descriptors[5];
};
struct SI_PACK_THIS_STRUCT MHL3_hev_vic_descriptor_t {
uint8_t reserved;
uint8_t vic_cea861f;
};
struct SI_PACK_THIS_STRUCT MHL3_hev_vic_data_t {
struct MHL3_burst_header_t header;
uint8_t num_entries_this_burst;
struct MHL3_hev_vic_descriptor_t video_descriptors[5];
};
struct SI_PACK_THIS_STRUCT MHL3_hev_dtd_a_payload_t {
struct MHL_high_low_t pixel_clock_in_MHz;
struct MHL_high_low_t h_active_in_pixels;
struct MHL_high_low_t h_blank_in_pixels;
struct MHL_high_low_t h_front_porch_in_pixels;
struct MHL_high_low_t h_sync_width_in_pixels;
uint8_t h_flags;
};
struct SI_PACK_THIS_STRUCT MHL3_hev_dtd_b_payload_t {
struct MHL_high_low_t v_total_in_lines;
uint8_t v_blank_in_lines; /* note 7 for table 5-16 is wrong */
uint8_t v_front_porch_in_lines; /* note 7 for table 5-16 is wrong */
uint8_t v_sync_width_in_lines; /* note 7 for table 5-16 is wrong */
uint8_t v_refresh_rate_in_fields_per_second;
uint8_t v_flags;
uint8_t reserved[4];
};
struct SI_PACK_THIS_STRUCT MHL3_hev_dtd_a_data_t {
struct MHL3_burst_header_t header;
struct MHL3_hev_dtd_a_payload_t payload;
};
struct SI_PACK_THIS_STRUCT MHL3_hev_dtd_b_data_t {
struct MHL3_burst_header_t header;
struct MHL3_hev_dtd_b_payload_t payload;
};
struct SI_PACK_THIS_STRUCT MHL3_hev_dtd_item_t {
uint8_t sequence_index;
struct MHL3_hev_dtd_a_payload_t a;
struct MHL3_hev_dtd_b_payload_t b;
struct MHL3_video_descriptor_t _3d_info;
};
struct MHL3_hev_vic_item_t {
struct MHL3_hev_vic_descriptor_t mhl3_hev_vic_descriptor;
struct MHL3_video_descriptor_t _3d_info;
};
struct MHL3_3d_vic_item_t {
struct cea_short_descriptor_t svd;
struct MHL3_video_descriptor_t _3d_info;
};
struct MHL3_3d_dtd_item_t {
uint8_t index;
struct detailed_timing_descriptor_t dtd_cea_861;
struct MHL3_video_descriptor_t _3d_info;
};
struct SI_PACK_THIS_STRUCT MHL3_speaker_allocation_data_block_t {
uint8_t cea861f_spkr_alloc[3];
};
struct SI_PACK_THIS_STRUCT MHL3_adt_payload_t {
uint8_t format_flags;
union {
uint8_t short_descs[9];
struct MHL3_speaker_allocation_data_block_t spkr_alloc_db[3];
} descriptors;
uint8_t reserved;
};
struct SI_PACK_THIS_STRUCT MHL3_audio_delay_burst_t {
struct MHL_burst_id_t burst_id;
uint8_t checksum;
uint8_t delay_h;
uint8_t delay_m;
uint8_t delay_l;
uint8_t reserved[10];
};
struct SI_PACK_THIS_STRUCT MHL3_adt_data_t {
struct MHL3_burst_header_t header;
struct MHL3_adt_payload_t payload;
};
struct SI_PACK_THIS_STRUCT MHL3_emsc_support_payload_t {
struct MHL_burst_id_t burst_ids[5];
};
struct SI_PACK_THIS_STRUCT MHL3_emsc_support_data_t {
struct MHL3_burst_header_t header;
uint8_t num_entries_this_burst;
struct MHL3_emsc_support_payload_t payload;
};
enum view_pixel_fmt_e {
VIEW_PIX_FMT_24BPP,
VIEW_PIX_FMT_16BPP
};
struct SI_PACK_THIS_STRUCT MHL3_bits_per_pixel_fmt_descriptor_t {
uint8_t stream_id;
uint8_t stream_pixel_format;
};
struct SI_PACK_THIS_STRUCT MHL_bits_per_pixel_fmt_data_t {
struct MHL3_burst_header_t header;
uint8_t num_entries_this_burst;
/* reserve 5 for use with WRITE_BURST
actual length is variable, indicated by
num_entries_this_burst
*/
/* todo change this to 1 when WRITE_BURST OPTION is removed */
struct MHL3_bits_per_pixel_fmt_descriptor_t descriptors[5];
};
union SI_PACK_THIS_STRUCT video_burst_descriptor_u {
struct MHL2_video_descriptor_t mhl2_3d_descriptor;
struct MHL3_video_descriptor_t mhl3_3d_descriptor;
struct MHL3_hev_vic_descriptor_t mhl3_hev_vic_descriptor;
struct MHL3_hev_dtd_item_t mhl3_hev_dtd;
};
struct SI_PACK_THIS_STRUCT mhl3_vsif_t {
VSIF_COMMON_FIELDS
uint8_t pb4;
uint8_t pb5_reserved;
uint8_t pb6;
struct MHL_high_low_t mhl_hev_fmt_type;
uint8_t pb9;
struct MHL_high_low_t av_delay_sync;
};
/* the enum's in the following section are
defined "in position" to avoid
shifting on the fly
*/
#define MHL3_VSIF_TYPE 0x81
#define MHL3_VSIF_VERSION 0x03
#define IEEE_OUI_MHL 0x7CA61D
#define PB4_MASK_MHL_VID_FMT 0x03
enum mhl_vid_fmt_e {
mhl_vid_fmt_no_additional,
mhl_vid_fmt_3d_fmt_present,
mhl_vid_fmt_multi_view,
mhl_vid_fmt_dual_3d
};
#define PB4_MASK_MHL_3D_FMT_TYPE 0x1C
enum mhl_3d_fmt_type_e {
MHL_3D_FMT_TYPE_FS, /* Frame Sequential */
MHL_3D_FMT_TYPE_TB = 0x04, /* Top-Bottom */
MHL_3D_FMT_TYPE_LR = 0x08, /* Left-Right */
MHL_3D_FMT_TYPE_FS_TB = 0x0C, /* Frame Sequential Top-Bottom */
MHL_3D_FMT_TYPE_FS_LR = 0x10, /* Frame Sequential Left-Right */
MHL_3D_FMT_TYPE_TBLR = 0x14 /* Top-Bottom-Left-Right */
};
#define PB4_MASK_SEP_AUD 0x20
enum mhl_sep_audio_e {
mhl_sep_audio_not_available,
mhl_sep_audio_available = 0x20
};
#define PB4_MASK_RESERVED 0xC0
#define MHL3_VSIF_PB4(vid_fmt, _3d_fmt_type, sep_aud) \
(uint8_t)(((vid_fmt)&PB4_MASK_MHL_VID_FMT) | \
((_3d_fmt_type)&PB4_MASK_MHL_3D_FMT_TYPE) | \
((sep_aud)&PB4_MASK_SEP_AUD))
#define PB6_MASK_MHL_HEV_FMT 0x03
enum mhl_hev_fmt_e {
mhl_hev_fmt_no_additional,
mhl_hev_fmt_hev_present,
mhl_hev_fmt_reserved_2,
mhl_hev_fmt_reserved_3
};
#define PB6_MASK_RESERVED 0xFC
#define MHL3_VSIF_PB6(hev_fmt) (uint8_t)((hev_fmt) & PB6_MASK_MHL_HEV_FMT)
#define PB9_MASK_AV_DELAY_SYNC_19_16 0x0F
#define PB9_MASK_AV_DELAY_DIR 0x10
enum mhl_av_delay_dir_e {
mhl_av_delay_dir_audio_earlier,
mhl_av_delay_dir_video_earlier = 0x10
};
#define PB9_MASK_RESERVED 0xE0
#define MHL3_VSIF_PB9(delay_sync, delay_dir) \
(uint8_t)((((delay_sync) >> 16) & PB9_MASK_AV_DELAY_SYNC_19_16) | \
((delay_dir) & PB9_MASK_AV_DELAY_DIR))
struct SI_PACK_THIS_STRUCT info_frame_t {
union {
struct info_frame_header_t header;
struct avi_info_frame_t avi;
struct hdmi_vsif_t vendorSpecific;
struct mhl3_vsif_t mhl3_vsif;
struct unr_info_frame_t unr;
} body;
};
union SI_PACK_THIS_STRUCT vsif_mhl3_or_hdmi_u {
struct SI_PACK_THIS_STRUCT vsif_common_header_t common;
struct SI_PACK_THIS_STRUCT hdmi_vsif_t hdmi;
struct SI_PACK_THIS_STRUCT mhl3_vsif_t mhl3;
};
enum InfoFrameType_e {
InfoFrameType_AVI,
InfoFrameType_VendorSpecific,
InfoFrameType_VendorSpecific_MHL3,
InfoFrameType_Audio
};
SI_POP_STRUCT_PACKING
enum {
MHL_MSC_MSG_RCP = 0x10, /* RCP sub-command */
MHL_MSC_MSG_RCPK = 0x11, /* RCP Acknowledge sub-command */
MHL_MSC_MSG_RCPE = 0x12, /* RCP Error sub-command */
MHL_MSC_MSG_RAP = 0x20, /* Mode Change Warning sub-command */
MHL_MSC_MSG_RAPK = 0x21, /* MCW Acknowledge sub-command */
MHL_MSC_MSG_RBP = 0x22, /* Remote Button Protocol sub-command */
MHL_MSC_MSG_RBPK = 0x23, /* RBP Acknowledge sub-command */
MHL_MSC_MSG_RBPE = 0x24, /* RBP Error sub-command */
MHL_MSC_MSG_UCP = 0x30, /* UCP sub-command */
MHL_MSC_MSG_UCPK = 0x31, /* UCP Acknowledge sub-command */
MHL_MSC_MSG_UCPE = 0x32, /* UCP Error sub-command */
MHL_MSC_MSG_RUSB = 0x40, /* Request USB host role */
MHL_MSC_MSG_RUSBK = 0x41, /* Acknowledge request for USB host role */
MHL_MSC_MSG_RHID = 0x42, /* Request HID host role */
MHL_MSC_MSG_RHIDK = 0x43, /* Acknowledge request for HID host role */
MHL_MSC_MSG_ATT = 0x50, /* Request attention sub-command */
MHL_MSC_MSG_ATTK = 0x51, /* ATT Acknowledge sub-command */
MHL_MSC_MSG_BIST_TRIGGER = 0x60,
MHL_MSC_MSG_BIST_REQUEST_STAT = 0x61,
MHL_MSC_MSG_BIST_READY = 0x62,
MHL_MSC_MSG_BIST_STOP = 0x63,
};
#define BIST_TRIGGER_E_CBUS_TX 0x01
#define BIST_TRIGGER_E_CBUS_RX 0x02
#define BIST_TRIGGER_E_CBUS_TYPE_MASK 0x08
#define BIST_TRIGGER_TEST_E_CBUS_S 0x00
#define BIST_TRIGGER_TEST_E_CBUS_D 0x08
#define BIST_TRIGGER_AVLINK_TX 0x10
#define BIST_TRIGGER_AVLINK_RX 0x20
#define BIST_TRIGGER_IMPEDANCE_TEST 0x40
#define BIST_TRIGGER_ECBUS_AV_LINK_MASK (BIST_TRIGGER_AVLINK_TX | \
BIST_TRIGGER_AVLINK_RX)
#define BIST_TRIGGER_ECBUS_TX_RX_MASK (BIST_TRIGGER_E_CBUS_TX | \
BIST_TRIGGER_E_CBUS_RX)
#define BIST_TRIGGER_OPERAND_VALID_MASK 0x7B
#define BIST_READY_E_CBUS_READY 0x01
#define BIST_READY_AVLINK_READY 0x02
#define BIST_READY_TERM_READY 0x04
#define BIST_READY_E_CBUS_ERROR 0x10
#define BIST_READY_AVLINK_ERROR 0x20
#define BIST_READY_TERM_ERROR 0x40
#define RCPE_NO_ERROR 0x00
#define RCPE_INEFFECTIVE_KEY_CODE 0x01
#define RCPE_BUSY 0x02
#define MHL_RCP_KEY_RELEASED_MASK 0x80
#define MHL_RCP_KEY_ID_MASK 0x7F
#define RBPE_NO_ERROR 0x00
#define RBPE_INEFFECTIVE_BUTTON_CODE 0x01
#define RBPE_BUSY 0x02
#define MHL_RBP_BUTTON_RELEASED_MASK 0x80
#define MHL_RBP_BUTTON_ID_MASK 0x7F
#define T_PRESS_MODE 300
#define T_HOLD_MAINTAIN 2000
#define T_RAP_WAIT_MIN 100
#define T_RAP_WAIT_MAX 1000
enum {
/* Command or Data byte acknowledge */
MHL_ACK = 0x33,
/* Command or Data byte not acknowledge */
MHL_NACK = 0x34,
/* Transaction abort */
MHL_ABORT = 0x35,
/* Write one status register strip top bit */
MHL_WRITE_STAT = 0x60 | 0x80,
/* Write one interrupt register */
MHL_SET_INT = 0x60,
/* Read one register */
MHL_READ_DEVCAP_REG = 0x61,
/* Read CBUS revision level from follower */
MHL_GET_STATE = 0x62,
/* Read vendor ID value from follower */
MHL_GET_VENDOR_ID = 0x63,
/* Set Hot Plug Detect in follower */
MHL_SET_HPD = 0x64,
/* Clear Hot Plug Detect in follower */
MHL_CLR_HPD = 0x65,
/* Set Capture ID for downstream device */
MHL_SET_CAP_ID = 0x66,
/* Get Capture ID from downstream device */
MHL_GET_CAP_ID = 0x67,
/* VS command to send RCP sub-commands */
MHL_MSC_MSG = 0x68,
/* Get Vendor-Specific command error code */
MHL_GET_SC1_ERRORCODE = 0x69,
/* Get DDC channel command error code */
MHL_GET_DDC_ERRORCODE = 0x6A,
/* Get MSC command error code */
MHL_GET_MSC_ERRORCODE = 0x6B,
/* Write 1-16 bytes to responder's scratchpad */
MHL_WRITE_BURST = 0x6C,
/* Get channel 3 command error code */
MHL_GET_SC3_ERRORCODE = 0x6D,
/* Write one extended status register */
MHL_WRITE_XSTAT = 0x70,
/* Read one extended devcap register */
MHL_READ_XDEVCAP_REG = 0x71,
/* let the rest of these float, they are software specific */
MHL_READ_EDID_BLOCK,
MHL_SEND_3D_REQ_OR_FEAT_REQ,
MHL_READ_DEVCAP,
MHL_READ_XDEVCAP
};
/* RAP action codes */
#define MHL_RAP_POLL 0x00 /* Just do an ack */
#define MHL_RAP_CONTENT_ON 0x10 /* Turn content stream ON */
#define MHL_RAP_CONTENT_OFF 0x11 /* Turn content stream OFF */
#define MHL_RAP_CBUS_MODE_DOWN 0x20
#define MHL_RAP_CBUS_MODE_UP 0x21
/* RAPK status codes */
#define MHL_RAPK_NO_ERR 0x00 /* RAP action recognized & supported */
#define MHL_RAPK_UNRECOGNIZED 0x01 /* Unknown RAP action code received */
#define MHL_RAPK_UNSUPPORTED 0x02 /* Rcvd RAP action code not supported */
#define MHL_RAPK_BUSY 0x03 /* Responder too busy to respond */
/*
* Error status codes for RCPE messages
*/
/* No error. (Not allowed in RCPE messages) */
#define MHL_RCPE_STATUS_NO_ERROR 0x00
/* Unsupported/unrecognized key code */
#define MHL_RCPE_STATUS_INEFFECTIVE_KEY_CODE 0x01
/* Responder busy. Initiator may retry message */
#define MHL_RCPE_STATUS_BUSY 0x02
/*
* Error status codes for RBPE messages
*/
/* No error. (Not allowed in RBPE messages) */
#define MHL_RBPE_STATUS_NO_ERROR 0x00
/* Unsupported/unrecognized button code */
#define MHL_RBPE_STATUS_INEFFECTIVE_BUTTON_CODE 0x01
/* Responder busy. Initiator may retry message */
#define MHL_RBPE_STATUS_BUSY 0x02
/*
* Error status codes for UCPE messages
*/
/* No error. (Not allowed in UCPE messages) */
#define MHL_UCPE_STATUS_NO_ERROR 0x00
/* Unsupported/unrecognized key code */
#define MHL_UCPE_STATUS_INEFFECTIVE_KEY_CODE 0x01
/* Extended Device Capability Registers 7.12.1 */
enum {
XDEVCAP_START = 0x80,
XDEVCAP_ADDR_ECBUS_SPEEDS = XDEVCAP_START,
XDEVCAP_ADDR_TMDS_SPEEDS = 0x81,
XDEVCAP_ADDR_ECBUS_DEV_ROLES = 0x82,
XDEVCAP_ADDR_LOG_DEV_MAPX = 0x83,
XDEVCAP_LIMIT, /* don't hard-code this one */
XDEVCAP_ADDR_RESERVED_4 = 0x84,
XDEVCAP_ADDR_RESERVED_5 = 0x85,
XDEVCAP_ADDR_RESERVED_6 = 0x86,
XDEVCAP_ADDR_RESERVED_7 = 0x87,
XDEVCAP_ADDR_RESERVED_8 = 0x88,
XDEVCAP_ADDR_RESERVED_9 = 0x89,
XDEVCAP_ADDR_RESERVED_A = 0x8A,
XDEVCAP_ADDR_RESERVED_B = 0x8B,
XDEVCAP_ADDR_RESERVED_C = 0x8C,
XDEVCAP_ADDR_RESERVED_D = 0x8D,
XDEVCAP_ADDR_RESERVED_E = 0x8E,
XDEVCAP_ADDR_RESERVED_F = 0x8F,
XDEVCAP_ADDR_LAST, /* this one must be last */
XDEVCAP_SIZE = XDEVCAP_ADDR_LAST - XDEVCAP_START
};
#define XDEVCAP_OFFSET(reg) (reg - XDEVCAP_ADDR_ECBUS_SPEEDS)
SI_PUSH_STRUCT_PACKING
struct SI_PACK_THIS_STRUCT MHLXDevCap_t {
uint8_t ecbus_speeds;
uint8_t tmds_speeds;
uint8_t ecbus_dev_roles;
uint8_t log_dev_mapx;
uint8_t reserved_4;
uint8_t reserved_5;
uint8_t reserved_6;
uint8_t reserved_7;
uint8_t reserved_8;
uint8_t reserved_9;
uint8_t reserved_a;
uint8_t reserved_b;
uint8_t reserved_c;
uint8_t reserved_d;
uint8_t reserved_e;
uint8_t reserved_f;
};
union MHLXDevCap_u {
struct MHLXDevCap_t mxdc;
uint8_t xdevcap_cache[XDEVCAP_SIZE];
};
SI_POP_STRUCT_PACKING
/* XDEVCAP - eCBUS Speeds 7.12.1.1 */
#define MHL_XDC_ECBUS_S_075 0x01
#define MHL_XDC_ECBUS_S_8BIT 0x02
#define MHL_XDC_ECBUS_S_12BIT 0x04
#define MHL_XDC_ECBUS_D_150 0x10
#define MHL_XDC_ECBUS_D_8BIT 0x20
/* XDEVCAP - TMDS Speeds 7.12.1.2 */
#define MHL_XDC_TMDS_000 0x00
#define MHL_XDC_TMDS_150 0x01
#define MHL_XDC_TMDS_300 0x02
#define MHL_XDC_TMDS_600 0x04
/* XDEVCAP - Device Roles 7.12.1.3 */
#define MHL_XDC_DEV_HOST 0x01
#define MHL_XDC_DEV_DEVICE 0x02
#define MHL_XDC_DEV_CHARGER 0x04
#define MHL_XDC_HID_HOST 0x08
#define MHL_XDC_HID_DEVICE 0x10
/* XDEVCAP - Extended Logical Device Map 7.12.1.4 */
#define MHL_XDC_LD_PHONE 0x01
/* Extended Device Status Registers 7.12.2 */
enum {
XDEVSTAT_OFFSET_CURR_ECBUS_MODE,
XDEVSTAT_OFFSET_AVLINK_MODE_STATUS,
XDEVSTAT_OFFSET_AVLINK_MODE_CONTROL,
XDEVSTAT_OFFSET_MULTI_SINK_STATUS,
XDEVSTAT_OFFSET_RESERVED_04,
XDEVSTAT_OFFSET_RESERVED_05,
XDEVSTAT_OFFSET_RESERVED_06,
XDEVSTAT_OFFSET_RESERVED_07,
XDEVSTAT_OFFSET_RESERVED_08,
XDEVSTAT_OFFSET_RESERVED_09,
XDEVSTAT_OFFSET_RESERVED_0A,
XDEVSTAT_OFFSET_RESERVED_0B,
XDEVSTAT_OFFSET_RESERVED_0C,
XDEVSTAT_OFFSET_RESERVED_0D,
XDEVSTAT_OFFSET_RESERVED_0E,
XDEVSTAT_OFFSET_RESERVED_0F,
XDEVSTAT_OFFSET_RESERVED_10,
XDEVSTAT_OFFSET_RESERVED_11,
XDEVSTAT_OFFSET_RESERVED_12,
XDEVSTAT_OFFSET_RESERVED_13,
XDEVSTAT_OFFSET_RESERVED_14,
XDEVSTAT_OFFSET_RESERVED_15,
XDEVSTAT_OFFSET_RESERVED_16,
XDEVSTAT_OFFSET_RESERVED_17,
XDEVSTAT_OFFSET_RESERVED_18,
XDEVSTAT_OFFSET_RESERVED_19,
XDEVSTAT_OFFSET_RESERVED_1A,
XDEVSTAT_OFFSET_RESERVED_1B,
XDEVSTAT_OFFSET_RESERVED_1C,
XDEVSTAT_OFFSET_RESERVED_1D,
XDEVSTAT_OFFSET_RESERVED_1E,
XDEVSTAT_OFFSET_RESERVED_1F,
/* this one must be last */
XDEVSTAT_SIZE
};
/* XDEVSTAT - Current eCBUS Mode 7.12.2.1 */
#define MHL_XSTATUS_REG_CBUS_MODE 0x90
#define MHL_XDS_SLOT_MODE_8BIT 0x00
#define MHL_XDS_SLOT_MODE_6BIT 0x01
#define MHL_XDS_ECBUS_S 0x04
#define MHL_XDS_ECBUS_D 0x08
#define MHL_XDS_LINK_CLOCK_75MHZ 0x00
#define MHL_XDS_LINK_CLOCK_150MHZ 0x10
#define MHL_XDS_LINK_CLOCK_300MHZ 0x20
#define MHL_XDS_LINK_CLOCK_600MHZ 0x30
/* XDEVSTAT - AV Link Mode Status 7.12.2.2 */
#define MHL_XDS_LINK_STATUS_NO_SIGNAL 0x00
#define MHL_XDS_LINK_STATUS_CRU_LOCKED 0x01
#define MHL_XDS_LINK_STATUS_TMDS_NORMAL 0x02
#define MHL_XDS_LINK_STATUS_TMDS_RESERVED 0x03
/* XDEVSTAT - AV Link Mode Control 7.12.2.3 */
#define MHL_STATUS_REG_AV_LINK_MODE_CONTROL 0x92
#define MHL_XDS_LINK_RATE_1_5_GBPS 0x00
#define MHL_XDS_LINK_RATE_3_0_GBPS 0x01
#define MHL_XDS_LINK_RATE_6_0_GBPS 0x02
#define MHL_XDS_ATT_CAPABLE 0x08
/* XDEVSTAT - Multi-Sink Status 7.12.2.4 */
#define MHL_XDS_SINK_STATUS_1_HPD_LOW 0x00
#define MHL_XDS_SINK_STATUS_1_HPD_HIGH 0x01
#define MHL_XDS_SINK_STATUS_2_HPD_LOW 0x00
#define MHL_XDS_SINK_STATUS_2_HPD_HIGH 0x04
#define MHL_XDS_SINK_STATUS_3_HPD_LOW 0x00
#define MHL_XDS_SINK_STATUS_3_HPD_HIGH 0x10
#define MHL_XDS_SINK_STATUS_4_HPD_LOW 0x00
#define MHL_XDS_SINK_STATUS_4_HPD_HIGH 0x40
/*
* Define format of Write Burst used in MHL 3
* to assign TDM slots to virtual channels.
*/
struct SI_PACK_THIS_STRUCT virt_chan_info {
uint8_t vc_num;
uint8_t feature_id;
#define FEATURE_ID_E_MSC 0x00
#define FEATURE_ID_USB 0x01
#define FEATURE_ID_AUDIO 0x02
#define FEATURE_ID_IP 0x03
#define FEATURE_ID_COMP_VIDEO 0x04
#define FEATURE_ID_HID 0x05
#define FEATURE_ID_LAST FEATURE_ID_HID
union {
uint8_t channel_size;
uint8_t response;
#define VC_RESPONSE_ACCEPT 0x00
#define VC_RESPONSE_BAD_VC_NUM 0x01
#define VC_RESPONSE_BAD_FEATURE_ID 0x02
#define VC_RESPONSE_BAD_CHANNEL_SIZE 0x03
} req_resp;
};
#define MAX_VC_ENTRIES 3
struct SI_PACK_THIS_STRUCT tdm_alloc_burst {
struct MHL3_burst_header_t header;
uint8_t num_entries_this_burst;
struct virt_chan_info vc_info[MAX_VC_ENTRIES];
uint8_t reserved;
};
/* BIST_SETUP WRITE_BURST 15.1.1 */
#define BIST_ECBUS_PATTERN_UNSPECIFIED 0x00
#define BIST_ECBUS_PATTERN_PRBS 0x01
#define BIST_ECBUS_PATTERN_FIXED_8 0x02
#define BIST_ECBUS_PATTERN_FIXED_10 0x03
#define BIST_ECBUS_PATTERN_MAX BIST_ECBUS_PATTERN_FIXED_10
#define BIST_AVLINK_DATA_RATE_UNSPECIFIED 0x00
#define BIST_AVLINK_DATA_RATE_1500MBPS 0x01
#define BIST_AVLINK_DATA_RATE_3000MBPS 0x02
#define BIST_AVLINK_DATA_RATE_6000MBPS 0x03
#define BIST_AVLINK_DATA_RATE_MAX BIST_AVLINK_DATA_RATE_6000MBPS
#define BIST_AVLINK_PATTERN_UNSPECIFIED 0x00
#define BIST_AVLINK_PATTERN_PRBS 0x01
#define BIST_AVLINK_PATTERN_FIXED_8 0x02
#define BIST_AVLINK_PATTERN_FIXED_10 0x03
#define BIST_AVLINK_PATTERN_MAX BIST_AVLINK_PATTERN_FIXED_10
#define BIST_IMPEDANCE_MODE_AVLINK_TX_LOW 0x00
#define BIST_IMPEDANCE_MODE_AVLINK_TX_HIGH 0x01
#define BIST_IMPEDANCE_MODE_AVLINK_RX 0x02
#define BIST_IMPEDANCE_MODE_RESERVED_1 0x03
#define BIST_IMPEDANCE_MODE_ECBUS_D_TX_LOW 0x04
#define BIST_IMPEDANCE_MODE_ECBUS_D_TX_HIGH 0x05
#define BIST_IMPEDANCE_MODE_ECBUS_D_RX 0x06
#define BIST_IMPEDANCE_MODE_RESERVED_2 0x07
#define BIST_IMPEDANCE_MODE_ECBUS_S_TX_LOW 0x08
#define BIST_IMPEDANCE_MODE_ECBUS_S_TX_HIGH 0x09
#define BIST_IMPEDANCE_MODE_ECBUS_S_RX 0x0A
#define BIST_IMPEDANCE_MODE_MAX BIST_IMPEDANCE_MODE_ECBUS_S_RX
struct SI_PACK_THIS_STRUCT bist_setup_burst {
uint8_t burst_id_h;
uint8_t burst_id_l;
uint8_t checksum;
uint8_t e_cbus_duration;
uint8_t e_cbus_pattern;
uint8_t e_cbus_fixed_h;
uint8_t e_cbus_fixed_l;
uint8_t reserved;
uint8_t avlink_data_rate;
uint8_t avlink_pattern;
uint8_t avlink_video_mode;
uint8_t avlink_duration;
uint8_t avlink_fixed_h;
uint8_t avlink_fixed_l;
uint8_t avlink_randomizer;
uint8_t impedance_mode;
};
/* BIST_RETURN_STAT WRITE_BURST 15.1.2 */
struct SI_PACK_THIS_STRUCT bist_return_stat_burst {
uint8_t burst_id_h;
uint8_t burst_id_l;
uint8_t checksum;
uint8_t reserved[9];
uint8_t e_cbus_stat_h;
uint8_t e_cbus_stat_l;
uint8_t avlink_stat_h;
uint8_t avlink_stat_l;
};
struct SI_PACK_THIS_STRUCT bist_discard_burst_hdr {
struct MHL_burst_id_t burst_id;
uint8_t remaining_length;
};
struct SI_PACK_THIS_STRUCT bist_discard_burst {
struct bist_discard_burst_hdr hdr;
uint8_t payload[13];
};
struct SI_PACK_THIS_STRUCT bist_echo_request_burst_hdr {
struct MHL_burst_id_t burst_id;
uint8_t remaining_length;
};
struct SI_PACK_THIS_STRUCT bist_echo_request_burst {
struct bist_echo_request_burst_hdr hdr;
uint8_t payload[13];
};
struct SI_PACK_THIS_STRUCT bist_echo_response_burst_hdr {
struct MHL_burst_id_t burst_id;
uint8_t remaining_length;
};
struct SI_PACK_THIS_STRUCT bist_echo_response_burst {
struct bist_echo_response_burst_hdr hdr;
uint8_t payload[13];
};
struct SI_PACK_THIS_STRUCT si_adopter_id_sub_payload_hdr {
struct MHL_burst_id_t burst_id;
uint8_t remaining_length;
uint8_t checksum;
uint8_t op_code;
};
enum si_adopter_id_opcode {
EDID_BLOCK = 0,
EDID_STOP = 1,
};
struct SI_PACK_THIS_STRUCT si_opcode_data_edid_block {
uint8_t block_num;
uint8_t data[128];
};
struct SI_PACK_THIS_STRUCT si_adopter_id_data {
struct SI_PACK_THIS_STRUCT si_adopter_id_sub_payload_hdr hdr;
union {
struct SI_PACK_THIS_STRUCT si_opcode_data_edid_block edid_blk;
/* more members to come later */
} opcode_data;
};
#define MHL_T_src_vbus_cbus_stable_min 100
#define T_BIST_MODE_DOWN_MAX 5000
#define T_BIST_MODE_DOWN_MIN 2000
#endif

View file

@ -0,0 +1,222 @@
/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#if !defined(SI_MHL_TX_DRV_API_H)
#define SI_MHL_TX_DRV_API_H
/*
* Structure to hold command details from upper layer to CBUS module
*/
struct cbus_req {
struct list_head link;
union {
struct {
uint8_t cancel:1; /* this command has been canceled */
uint8_t resvd:7;
} flags;
uint8_t as_uint8;
} status;
uint8_t retry_count;
uint8_t command; /* VS_CMD or RCP opcode */
uint8_t reg;
uint8_t reg_data;
uint8_t burst_offset; /* register offset */
uint8_t length; /* Only applicable to write burst */
uint8_t msg_data[16]; /* scratch pad data area. */
const char *function;
int line;
int sequence;
struct cbus_req *(*completion)(struct mhl_dev_context *dev_context,
struct cbus_req *req,
uint8_t data1);
};
struct SI_PACK_THIS_STRUCT tport_hdr_and_burst_id_t {
/* waste two bytes to save on memory copying when submitting BLOCK
* transactions
*/
struct SI_PACK_THIS_STRUCT standard_transport_header_t tport_hdr;
/* sub-payloads start here */
struct MHL_burst_id_t burst_id;
};
union SI_PACK_THIS_STRUCT emsc_payload_t {
struct SI_PACK_THIS_STRUCT tport_hdr_and_burst_id_t hdr_and_burst_id;
uint8_t as_bytes[256];
};
struct SI_PACK_THIS_STRUCT block_req {
struct list_head link;
const char *function;
int line;
int sequence;
uint16_t count; /* (size - 1) see MHL spec section 13.5.7.2 */
uint8_t space_remaining;
uint8_t sub_payload_size;
uint8_t *platform_header;
union SI_PACK_THIS_STRUCT emsc_payload_t *payload;
};
enum quantization_settings_e {
qs_auto_select_by_color_space,
qs_full_range,
qs_limited_range,
qs_reserved
};
struct bist_setup_info {
uint8_t e_cbus_duration;
uint8_t e_cbus_pattern;
uint16_t e_cbus_fixed_pat;
uint8_t avlink_data_rate;
uint8_t avlink_pattern;
uint8_t avlink_video_mode;
uint8_t avlink_duration;
uint16_t avlink_fixed_pat;
uint8_t avlink_randomizer;
uint8_t impedance_mode;
uint8_t bist_trigger_parm;
uint8_t bist_stat_parm;
uint32_t t_bist_mode_down;
};
struct bist_stat_info {
uint16_t e_cbus_remote_stat;
int32_t e_cbus_next_local_stat;
int32_t e_cbus_local_stat;
int32_t e_cbus_prev_local_stat;
uint16_t avlink_stat;
};
/*
* The APIs listed below must be implemented by the MHL transmitter
* hardware support module.
*/
struct drv_hw_context;
struct interrupt_info;
int si_mhl_tx_chip_initialize(struct drv_hw_context *hw_context);
void si_mhl_tx_drv_device_isr(struct drv_hw_context *hw_context,
struct interrupt_info *intr_info);
void si_mhl_tx_drv_disable_video_path(struct drv_hw_context *hw_context);
void si_mhl_tx_drv_enable_video_path(struct drv_hw_context *hw_context);
void si_mhl_tx_drv_content_on(struct drv_hw_context *hw_context);
void si_mhl_tx_drv_content_off(struct drv_hw_context *hw_context);
uint8_t si_mhl_tx_drv_send_cbus_command(struct drv_hw_context *hw_context,
struct cbus_req *req);
void mhl_tx_drv_send_block(struct drv_hw_context *hw_context,
struct block_req *req);
int si_mhl_tx_drv_get_scratch_pad(struct drv_hw_context *hw_context,
uint8_t start_reg, uint8_t *data, uint8_t length);
void si_mhl_tx_read_devcap_fifo(struct drv_hw_context *hw_context,
union MHLDevCap_u *dev_cap_buf);
void si_mhl_tx_read_xdevcap_fifo(struct drv_hw_context *hw_context,
union MHLXDevCap_u *xdev_cap_buf);
int si_mhl_tx_drv_get_aksv(struct drv_hw_context *hw_context, uint8_t *buffer);
void si_mhl_tx_drv_start_avlink_bist(struct mhl_dev_context *dev_context,
struct bist_setup_info *test_info);
void si_mhl_tx_drv_stop_avlink_bist(struct drv_hw_context *hw_context);
void si_mhl_tx_drv_start_ecbus_bist(struct drv_hw_context *hw_context,
struct bist_setup_info *test_info);
uint8_t si_mhl_tx_drv_ecbus_connected(struct mhl_dev_context *dev_context);
void si_mhl_tx_drv_continue_ecbus_bist(
struct mhl_dev_context *dev_context);
int32_t si_mhl_tx_drv_get_ecbus_bist_status(
struct mhl_dev_context *dev_context,
uint8_t *rx_run_done,
uint8_t *tx_run_done);
#define BIST_LOCAL_COUNT_INVALID -2
void si_mhl_tx_drv_stop_ecbus_bist(struct drv_hw_context *hw_context,
struct bist_setup_info *test_info);
int si_mhl_tx_drv_start_impedance_bist(struct drv_hw_context *hw_context,
struct bist_setup_info *test_info);
void si_mhl_tx_drv_stop_impedance_bist(struct drv_hw_context *hw_context,
struct bist_setup_info *test_info);
void si_mhl_tx_drv_shutdown(struct drv_hw_context *hw_context);
int si_mhl_tx_drv_connection_is_mhl3(struct mhl_dev_context *dev_context);
int si_mhl_tx_drv_get_highest_tmds_link_speed(
struct mhl_dev_context *dev_context);
uint8_t si_mhl_tx_drv_hawb_xfifo_avail(struct mhl_dev_context *dev_context);
uint8_t si_mhl_tx_drv_get_pending_hawb_write_status(
struct mhl_dev_context *dev_context);
enum cbus_mode_e {
CM_NO_CONNECTION,
CM_NO_CONNECTION_BIST_SETUP,
CM_NO_CONNECTION_BIST_STAT,
CM_oCBUS_PEER_VERSION_PENDING,
CM_oCBUS_PEER_VERSION_PENDING_BIST_SETUP,
CM_oCBUS_PEER_VERSION_PENDING_BIST_STAT,
CM_oCBUS_PEER_IS_MHL1_2,
CM_oCBUS_PEER_IS_MHL3_BIST_SETUP,
CM_oCBUS_PEER_IS_MHL3_BIST_SETUP_SENT,
CM_oCBUS_PEER_IS_MHL3_BIST_SETUP_PEER_READY,
CM_oCBUS_PEER_IS_MHL3_BIST_STAT,
CM_oCBUS_PEER_IS_MHL3,
CM_TRANSITIONAL_TO_eCBUS_S_BIST,
CM_TRANSITIONAL_TO_eCBUS_D_BIST,
CM_TRANSITIONAL_TO_eCBUS_S,
CM_TRANSITIONAL_TO_eCBUS_D,
CM_TRANSITIONAL_TO_eCBUS_S_CAL_BIST,
CM_TRANSITIONAL_TO_eCBUS_D_CAL_BIST,
CM_TRANSITIONAL_TO_eCBUS_S_CALIBRATED,
CM_TRANSITIONAL_TO_eCBUS_D_CALIBRATED,
CM_eCBUS_S_BIST,
CM_eCBUS_D_BIST,
CM_BIST_DONE_PENDING_DISCONNECT,
CM_eCBUS_S,
CM_eCBUS_D,
CM_eCBUS_S_AV_BIST,
CM_eCBUS_D_AV_BIST,
NUM_CM_MODES
};
enum cbus_mode_e si_mhl_tx_drv_get_cbus_mode(
struct mhl_dev_context *dev_context);
char *si_mhl_tx_drv_get_cbus_mode_str(enum cbus_mode_e cbus_mode);
uint16_t si_mhl_tx_drv_get_blk_rcv_buf_size(void);
void si_mhl_tx_drv_start_cp(struct mhl_dev_context *dev_context);
void si_mhl_tx_drv_shut_down_HDCP2(struct drv_hw_context *hw_context);
bool si_mhl_tx_drv_support_e_cbus_d(struct drv_hw_context *hw_context);
int si_mhl_tx_drv_switch_cbus_mode(struct drv_hw_context *hw_context,
enum cbus_mode_e mode_sel);
void si_mhl_tx_drv_free_block_input_buffer(struct mhl_dev_context *dev_context);
int si_mhl_tx_drv_peek_block_input_buffer(struct mhl_dev_context *dev_context,
uint8_t **buffer, int *length);
enum tdm_vc_num {
VC_CBUS1,
VC_E_MSC,
VC_T_CBUS,
VC_MAX
};
int si_mhl_tx_drv_set_tdm_slot_allocation(struct drv_hw_context *hw_context,
uint8_t *vc_slot_counts, bool program);
#endif /* if !defined(SI_MHL_TX_DRV_API_H) */

View file

@ -0,0 +1,13 @@
comment "Driver for Silicon Image SiI6031 MHL/USB switch (Stark)"
config SII6031_MHL_SWITCH
bool "SIMG GPIO support"
depends on GPIOLIB
default y
help
yes links this driver.
This driver is required by Qualcomm APQ8074 platform
with modified usb otg driver (msm_otg.c) for SiI6031 switch.
If unsure, say N.

View file

@ -0,0 +1,2 @@
obj-$(CONFIG_SII6031_MHL_SWITCH) +=si_6031_switch.o
#si_6031_switch-objs := si_6031_switch.o

View file

@ -0,0 +1,151 @@
/*
* SIMG SiI6031 MHL-USB Switch driver
*
* Copyright 2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/mod_devicetable.h>
#include <linux/si_6031_switch.h>
struct gpio stark_gpio_ctrl[3] = {
{0, GPIOF_OUT_INIT_HIGH, "MHL_USB_0"},
{0, GPIOF_OUT_INIT_HIGH, "MHL_USB_1"},
{0, GPIOF_OUT_INIT_HIGH, "MHL_VBUS"}
};
void sii_switch_to_mhl(bool switch_to_mhl)
{
if(switch_to_mhl)
{
printk("%s(): SIMG: switch to MHL gpio [%d, %d] \n", __func__,
stark_gpio_ctrl[MHL_USB_0].gpio,
stark_gpio_ctrl[MHL_USB_1].gpio);
gpio_set_value(stark_gpio_ctrl[MHL_USB_0].gpio, 1);
gpio_set_value(stark_gpio_ctrl[MHL_USB_1].gpio, 1);
}
else {
printk("%s(): SIMG: switch to USB gpio [%d, %d] \n", __func__,
stark_gpio_ctrl[MHL_USB_0].gpio,
stark_gpio_ctrl[MHL_USB_1].gpio);
gpio_set_value(stark_gpio_ctrl[MHL_USB_0].gpio, 0);
gpio_set_value(stark_gpio_ctrl[MHL_USB_1].gpio, 0);
}
/*gpio_set_value(stark_gpio_ctrl[MHL_USB_VBUS].gpio, 1);*/
printk("%s(): exit\n", __func__);
}
EXPORT_SYMBOL(sii_switch_to_mhl);
int sii6031_gpio_init(void)
{
int ret;
printk("%s(): called\n", __func__);
ret = gpio_request_array(stark_gpio_ctrl, ARRAY_SIZE(stark_gpio_ctrl));
if (ret < 0)
printk("%s(): gpio_request_array failed, error code %d\n",__func__, ret);
return ret;
}
static int sii6031_parse_dt(struct device *dev)
{
struct device_node *np = dev->of_node;
int value;
value = of_get_named_gpio_flags(np, "simg,gpio_sel0", 0, NULL);
if (value >= 0)
stark_gpio_ctrl[MHL_USB_0].gpio = value;
value = of_get_named_gpio_flags(np, "simg,gpio_sel1", 0, NULL);
if (value >= 0)
stark_gpio_ctrl[MHL_USB_1].gpio = value;
value = of_get_named_gpio_flags(np, "simg,gpio_vbus", 0, NULL);
if (value >= 0)
stark_gpio_ctrl[MHL_USB_VBUS].gpio = value;
return 0;
}
static int __devinit sii6031_probe(struct platform_device *pdev)
{
int ret =0;
if(pdev->dev.of_node)
ret = sii6031_parse_dt(&pdev->dev);
if(ret)
return -1;
ret = sii6031_gpio_init();
if(ret)
return -1;
return 0;
}
static int __devexit sii6031_remove(struct platform_device *pdev)
{
gpio_free_array(stark_gpio_ctrl,ARRAY_SIZE(stark_gpio_ctrl));
return 0;
}
static const struct of_device_id sii6031_gpio_match[] = {
{ .compatible = "simg,sii-6031", },
{ },
};
MODULE_DEVICE_TABLE(of, sii6031_gpio_match);
static struct platform_driver sii6031_driver = {
.probe = sii6031_probe,
.remove = __devexit_p(sii6031_remove),
.driver = {
.name = "simg,sii-6031",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(sii6031_gpio_match),
},
};
static int __init sii6031_init(void)
{
return platform_driver_register(&sii6031_driver);
}
static void __exit sii6031_exit(void)
{
platform_driver_unregister(&sii6031_driver);
}
module_init(sii6031_init);
module_exit(sii6031_exit);
MODULE_AUTHOR("Praveen Kumar Vuppala<praveen.vuppala@siliconimage.com>");
MODULE_DESCRIPTION("SiI6031 Switch driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,20 @@
#ifndef __MHL_8620_H
#define __MHL_8620_H
#define MHL_USB_0 0
#define MHL_USB_1 1
#define MHL_USB_VBUS 2
void sii_switch_to_mhl(bool switch_to_mhl);
/*#ifdef CONFIG_SII8061_MHL_SWITCH
void sii_switch_to_mhl(bool switch_to_mhl);
#else
void inline sii_switch_to_mhl(bool switch_to_mhl)
{
return;
}
#endif
*/
#endif