/* * Samsung HDMI interface driver * * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. * * Jiun Yu, * * 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 Foundiation. either version 2 of the License, * or (at your option) any later version */ #ifndef SAMSUMG_HDMI_H #define SAMSUNG_HDMI_H #ifdef CONFIG_VIDEO_EXYNOS_HDMI_DEBUG #define DEBUG #endif #include #include #include #include #include #include #define INFOFRAME_CNT 2 #define HDMI_VSI_VERSION 0x01; #define HDMI_AVI_VERSION 0x02; #define HDMI_VSI_LENGTH 0x05; #define HDMI_AVI_LENGTH 0x0d; /* HDMI audio configuration value */ #define DEFAULT_SAMPLE_RATE 44100 #define DEFAULT_BITS_PER_SAMPLE 16 /* HDMI pad definitions */ #define HDMI_PAD_SINK 0 #define HDMI_PADS_NUM 1 /* HPD state definitions */ #define HPD_LOW 0 #define HPD_HIGH 1 enum HDMI_VIDEO_FORMAT { HDMI_VIDEO_FORMAT_2D = 0x0, /** refer to Table 8-12 HDMI_Video_Format in HDMI specification v1.4a */ HDMI_VIDEO_FORMAT_3D = 0x2 }; enum HDMI_3D_FORMAT { /** refer to Table 8-13 3D_Structure in HDMI specification v1.4a */ /** Frame Packing */ HDMI_3D_FORMAT_FP = 0x0, /** Top-and-Bottom */ HDMI_3D_FORMAT_TB = 0x6, /** Side-by-Side Half */ HDMI_3D_FORMAT_SB_HALF = 0x8 }; enum HDMI_3D_EXT_DATA { /* refer to Table H-3 3D_Ext_Data - Additional video format * information for Side-by-side(half) 3D structure */ /** Horizontal sub-sampleing */ HDMI_H_SUB_SAMPLE = 0x1 }; enum HDMI_OUTPUT_FMT { HDMI_OUTPUT_RGB888 = 0x0, HDMI_OUTPUT_YUV444 = 0x2 }; enum HDMI_PACKET_TYPE { /** refer to Table 5-8 Packet Type in HDMI specification v1.4a */ /** InfoFrame packet type */ HDMI_PACKET_TYPE_INFOFRAME = 0X80, /** Vendor-Specific InfoFrame */ HDMI_PACKET_TYPE_VSI = HDMI_PACKET_TYPE_INFOFRAME + 1, /** Auxiliary Video information InfoFrame */ HDMI_PACKET_TYPE_AVI = HDMI_PACKET_TYPE_INFOFRAME + 2 }; enum HDMI_AUDIO_CODEC { HDMI_AUDIO_PCM, HDMI_AUDIO_AC3, HDMI_AUDIO_MP3 }; enum HDCP_EVENT { HDCP_EVENT_STOP = 1 << 0, HDCP_EVENT_START = 1 << 1, HDCP_EVENT_READ_BKSV_START = 1 << 2, HDCP_EVENT_WRITE_AKSV_START = 1 << 4, HDCP_EVENT_CHECK_RI_START = 1 << 8, HDCP_EVENT_SECOND_AUTH_START = 1 << 16 }; enum HDCP_STATE { NOT_AUTHENTICATED, RECEIVER_READ_READY, BCAPS_READ_DONE, BKSV_READ_DONE, AN_WRITE_DONE, AKSV_WRITE_DONE, FIRST_AUTHENTICATION_DONE, SECOND_AUTHENTICATION_RDY, SECOND_AUTHENTICATION_DONE, }; #define DEFAULT_AUDIO_CODEC HDMI_AUDIO_PCM struct hdmi_resources { struct clk *hdmi; struct clk *sclk_hdmi; struct clk *sclk_pixel; struct clk *sclk_hdmiphy; struct clk *hdmiphy; struct regulator_bulk_data *regul_bulk; int regul_count; }; struct hdmi_tg_regs { u8 cmd; u8 h_fsz_l; u8 h_fsz_h; u8 hact_st_l; u8 hact_st_h; u8 hact_sz_l; u8 hact_sz_h; u8 v_fsz_l; u8 v_fsz_h; u8 vsync_l; u8 vsync_h; u8 vsync2_l; u8 vsync2_h; u8 vact_st_l; u8 vact_st_h; u8 vact_sz_l; u8 vact_sz_h; u8 field_chg_l; u8 field_chg_h; u8 vact_st2_l; u8 vact_st2_h; #ifndef CONFIG_CPU_EXYNOS4210 u8 vact_st3_l; u8 vact_st3_h; u8 vact_st4_l; u8 vact_st4_h; #endif u8 vsync_top_hdmi_l; u8 vsync_top_hdmi_h; u8 vsync_bot_hdmi_l; u8 vsync_bot_hdmi_h; u8 field_top_hdmi_l; u8 field_top_hdmi_h; u8 field_bot_hdmi_l; u8 field_bot_hdmi_h; #ifndef CONFIG_CPU_EXYNOS4210 u8 tg_3d; #endif }; struct hdmi_core_regs { #ifndef CONFIG_CPU_EXYNOS4210 u8 h_blank[2]; u8 v2_blank[2]; u8 v1_blank[2]; u8 v_line[2]; u8 h_line[2]; u8 hsync_pol[1]; u8 vsync_pol[1]; u8 int_pro_mode[1]; u8 v_blank_f0[2]; u8 v_blank_f1[2]; u8 h_sync_start[2]; u8 h_sync_end[2]; u8 v_sync_line_bef_2[2]; u8 v_sync_line_bef_1[2]; u8 v_sync_line_aft_2[2]; u8 v_sync_line_aft_1[2]; u8 v_sync_line_aft_pxl_2[2]; u8 v_sync_line_aft_pxl_1[2]; u8 v_blank_f2[2]; /* for 3D mode */ u8 v_blank_f3[2]; /* for 3D mode */ u8 v_blank_f4[2]; /* for 3D mode */ u8 v_blank_f5[2]; /* for 3D mode */ u8 v_sync_line_aft_3[2]; u8 v_sync_line_aft_4[2]; u8 v_sync_line_aft_5[2]; u8 v_sync_line_aft_6[2]; u8 v_sync_line_aft_pxl_3[2]; u8 v_sync_line_aft_pxl_4[2]; u8 v_sync_line_aft_pxl_5[2]; u8 v_sync_line_aft_pxl_6[2]; u8 vact_space_1[2]; u8 vact_space_2[2]; u8 vact_space_3[2]; u8 vact_space_4[2]; u8 vact_space_5[2]; u8 vact_space_6[2]; #else u8 h_blank[2]; u8 v_blank[3]; u8 h_v_line[3]; u8 vsync_pol[1]; u8 int_pro_mode[1]; u8 v_blank_f[3]; u8 h_sync_gen[3]; u8 v_sync_gen1[3]; u8 v_sync_gen2[3]; u8 v_sync_gen3[3]; #endif }; struct hdmi_3d_info { enum HDMI_VIDEO_FORMAT is_3d; enum HDMI_3D_FORMAT fmt_3d; }; struct hdmi_preset_conf { struct hdmi_core_regs core; struct hdmi_tg_regs tg; struct v4l2_mbus_framefmt mbus_fmt; }; struct hdmi_driver_data { int hdmiphy_bus; }; struct hdmi_infoframe { enum HDMI_PACKET_TYPE type; u8 ver; u8 len; }; struct hdcp_info { u8 is_repeater; u32 hdcp_start; int hdcp_enable; spinlock_t reset_lock; enum HDCP_EVENT event; enum HDCP_STATE auth_status; }; struct hdmi_device { /** base address of HDMI registers */ void __iomem *regs; /** HDMI interrupt */ unsigned int int_irq; unsigned int ext_irq; unsigned int curr_irq; /** pointer to device parent */ struct device *dev; /** subdev generated by HDMI device */ struct v4l2_subdev sd; /** sink pad connected to mixer */ struct media_pad pad; /** V4L2 device structure */ struct v4l2_device v4l2_dev; /** subdev of HDMIPHY interface */ struct v4l2_subdev *phy_sd; /** configuration of current graphic mode */ const struct hdmi_preset_conf *cur_conf; /** current preset */ u32 cur_preset; /** other resources */ struct hdmi_resources res; /** HDMI is streaming or not */ int streaming; /** supported HDMI InfoFrame */ struct hdmi_infoframe infoframe[INFOFRAME_CNT]; /** audio on/off control flag */ int audio_enable; /** audio sample rate */ int sample_rate; /** audio bits per sample */ int bits_per_sample; /** current audio codec type */ enum HDMI_AUDIO_CODEC audio_codec; /** HDMI output format */ enum HDMI_OUTPUT_FMT output_fmt; /** HDCP information */ struct hdcp_info hdcp_info; struct work_struct work; struct work_struct hpd_work; struct workqueue_struct *hdcp_wq; struct workqueue_struct *hpd_wq; /* HPD releated */ bool hpd_user_checked; atomic_t hpd_state; spinlock_t hpd_lock; /* choose DVI or HDMI mode */ int dvi_mode; }; struct hdmi_conf { u32 preset; const struct hdmi_preset_conf *conf; const struct hdmi_3d_info *info; }; extern const struct hdmi_conf hdmi_conf[]; struct hdmiphy_conf { u32 preset; const u8 *data; }; extern const struct hdmiphy_conf hdmiphy_conf[]; extern const int hdmi_pre_cnt; extern const int hdmiphy_conf_cnt; const struct hdmi_3d_info *hdmi_preset2info(u32 preset); irqreturn_t hdmi_irq_handler(int irq, void *dev_data); int hdmi_conf_apply(struct hdmi_device *hdmi_dev); int is_hdmiphy_ready(struct hdmi_device *hdev); void hdmi_enable(struct hdmi_device *hdev, int on); void hdmi_hpd_enable(struct hdmi_device *hdev, int on); void hdmi_tg_enable(struct hdmi_device *hdev, int on); void hdmi_reg_stop_vsi(struct hdmi_device *hdev); void hdmi_reg_infoframe(struct hdmi_device *hdev, struct hdmi_infoframe *infoframe); void hdmi_reg_set_acr(struct hdmi_device *hdev); void hdmi_reg_spdif_audio_init(struct hdmi_device *hdev); void hdmi_reg_i2s_audio_init(struct hdmi_device *hdev); void hdmi_audio_enable(struct hdmi_device *hdev, int on); void hdmi_bluescreen_enable(struct hdmi_device *hdev, int on); void hdmi_reg_mute(struct hdmi_device *hdev, int on); int hdmi_hpd_status(struct hdmi_device *hdev); int is_hdmi_streaming(struct hdmi_device *hdev); u8 hdmi_get_int_mask(struct hdmi_device *hdev); void hdmi_set_int_mask(struct hdmi_device *hdev, u8 mask, int en); void hdmi_sw_hpd_enable(struct hdmi_device *hdev, int en); void hdmi_sw_hpd_plug(struct hdmi_device *hdev, int en); void hdmi_phy_sw_reset(struct hdmi_device *hdev); void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix); void hdmi_set_3d_info(struct hdmi_device *hdev); void hdmi_set_dvi_mode(struct hdmi_device *hdev); /** HDCP functions */ irqreturn_t hdcp_irq_handler(struct hdmi_device *hdev); int hdcp_stop(struct hdmi_device *hdev); int hdcp_start(struct hdmi_device *hdev); int hdcp_prepare(struct hdmi_device *hdev); int hdcp_i2c_read(struct hdmi_device *hdev, u8 offset, int bytes, u8 *buf); int hdcp_i2c_write(struct hdmi_device *hdev, u8 offset, int bytes, u8 *buf); static inline void hdmi_write(struct hdmi_device *hdev, u32 reg_id, u32 value) { writel(value, hdev->regs + reg_id); } static inline void hdmi_write_mask(struct hdmi_device *hdev, u32 reg_id, u32 value, u32 mask) { u32 old = readl(hdev->regs + reg_id); value = (value & mask) | (old & ~mask); writel(value, hdev->regs + reg_id); } static inline void hdmi_writeb(struct hdmi_device *hdev, u32 reg_id, u8 value) { writeb(value, hdev->regs + reg_id); } static inline void hdmi_write_bytes(struct hdmi_device *hdev, u32 reg_id, u8 *buf, int bytes) { int i; for (i = 0; i < bytes; ++i) writeb(buf[i], hdev->regs + reg_id + i * 4); } static inline u32 hdmi_read(struct hdmi_device *hdev, u32 reg_id) { return readl(hdev->regs + reg_id); } static inline u8 hdmi_readb(struct hdmi_device *hdev, u32 reg_id) { return readb(hdev->regs + reg_id); } static inline void hdmi_read_bytes(struct hdmi_device *hdev, u32 reg_id, u8 *buf, int bytes) { int i; for (i = 0; i < bytes; ++i) buf[i] = readb(hdev->regs + reg_id + i * 4); } #endif /* SAMSUNG_HDMI_H */