1 /* 2 * JZ4780 HDMI peripheral support. 3 * 4 * Copyright (C) 2020 Paul Boddie <paul@boddie.org.uk> 5 * 6 * Techniques and operations introduced from the Linux DRM bridge driver for 7 * Synopsys DW-HDMI whose authors are as follows: 8 * 9 * Copyright (C) 2013-2015 Mentor Graphics Inc. 10 * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. 11 * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de> 12 * 13 * This program is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU General Public License as 15 * published by the Free Software Foundation; either version 2 of 16 * the License, or (at your option) any later version. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this program; if not, write to the Free Software 25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 26 * Boston, MA 02110-1301, USA 27 * 28 * ---- 29 * 30 * Some acronyms: 31 * 32 * CEC (Consumer Electronics Control) is a HDMI device control interface for up 33 * to 15 devices. 34 * 35 * CSC (Colour Space Conversion) is the processing needed to convert from one 36 * representation of colours to another. 37 * 38 * HEAC (HDMI Ethernet and Audio Return Channel) is a combination of HEC (HDMI 39 * Ethernet Channel) which provides a 100Mb/s bidirectional link and ARC (Audio 40 * Return Channel) which permits the consumption of audio data from the device. 41 * 42 * MHL (Mobile High-Definition Link) is an adaptation of HDMI for mobile 43 * devices. 44 * 45 * TMDS (Transition-Minimized Differential Signaling) is the method by which 46 * audio, control and video data are all sent to the device. 47 */ 48 49 #include <l4/devices/hdmi-jz4780.h> 50 #include <l4/devices/hw_mmio_register_block.h> 51 #include <l4/devices/lcd-jz4740-config.h> 52 53 #include <l4/sys/irq.h> 54 #include <l4/sys/rcv_endpoint.h> 55 #include <l4/util/util.h> 56 57 #include <pthread.h> 58 #include <pthread-l4.h> 59 60 /* 61 I2C pins: 62 63 HDMI: PF25/SMB4_SDA/DDCSDA, PF24/SMB4_SCK/DDCSCK 64 65 See: http://mipscreator.imgtec.com/CI20/hardware/board/ci20_jz4780_v2.0.pdf 66 */ 67 68 enum Regs 69 { 70 // Identification. 71 72 Design_id = 0x000, // DESIGN_ID 73 Revision_id = 0x001, // REVISION_ID 74 Product_id0 = 0x002, // PRODUCT_ID0 75 Product_id1 = 0x003, // PRODUCT_ID1 76 Config_id0 = 0x004, // CONFIG_ID0 77 Config_id1 = 0x005, // CONFIG_ID1 78 Config_id2 = 0x006, // CONFIG_ID2 79 Config_id3 = 0x007, // CONFIG_ID3 80 81 // Top-level interrupt control. 82 83 Int_mask = 0x1ff, // MUTE 84 85 // Interrupt status and mask for various functions. 86 87 Fc_int_status0 = 0x100, // FC_STAT0 88 Fc_int_status1 = 0x101, // FC_STAT1 89 Fc_int_status2 = 0x102, // FC_STAT2 90 As_int_status = 0x103, // AS_STAT0 91 Phy_int_status = 0x104, // PHY_STAT0 92 Cec_int_status = 0x106, // CEC_STAT0 93 Vp_int_status = 0x107, // VP_STAT0 94 Ahb_dma_audio_int_status = 0x109, // AHBDMAAUD_STAT0 95 96 Fc_int_mask0 = 0x180, // MUTE_FC_STAT0 97 Fc_int_mask1 = 0x181, // MUTE_FC_STAT1 98 Fc_int_mask2 = 0x182, // MUTE_FC_STAT2 99 As_int_mask = 0x183, // MUTE_AS_STAT0 100 Phy_int_mask = 0x184, // MUTE_PHY_STAT0 101 Cec_int_mask = 0x186, // MUTE_CEC_STAT0 102 Vp_int_mask = 0x187, // MUTE_VP_STAT0 103 Ahb_dma_audio_int_mask = 0x189, // MUTE_AHBDMAAUD_STAT0 104 105 // I2C for E-DDC. 106 107 I2c_int_status = 0x105, // I2CM_STAT0 108 I2c_int_mask = 0x185, // MUTE_I2CM_STAT0 109 110 I2c_device_address = 0x7e00, // I2CM_SLAVE 111 I2c_register = 0x7e01, // I2CM_ADDRESS 112 I2c_data_out = 0x7e02, // I2CM_DATAO 113 I2c_data_in = 0x7e03, // I2CM_DATAI 114 I2c_operation = 0x7e04, // I2CM_OPERATION 115 I2c_int_config0 = 0x7e05, // I2CM_INT 116 I2c_int_config1 = 0x7e06, // I2CM_CTLINT 117 I2c_divider = 0x7e07, // I2CM_DIV 118 I2c_segment_address = 0x7e08, // I2CM_SEGADDR 119 I2c_software_reset = 0x7e09, // I2CM_SOFTRSTZ 120 I2c_segment_pointer = 0x7e0a, // I2CM_SEGPTR 121 122 // I2C for PHY. 123 124 I2c_phy_int_status = 0x108, // I2CMPHY_STAT0 125 I2c_phy_int_mask = 0x188, // MUTE_I2CMPHY_STAT0 126 127 I2c_phy_device_address = 0x3020, // PHY_I2CM_SLAVE_ADDR 128 I2c_phy_register = 0x3021, // PHY_I2CM_ADDRESS_ADDR 129 I2c_phy_data_out1 = 0x3022, // PHY_I2CM_DATAO_1_ADDR 130 I2c_phy_data_out0 = 0x3023, // PHY_I2CM_DATAO_0_ADDR 131 I2c_phy_data_in1 = 0x3024, // PHY_I2CM_DATAI_1_ADDR 132 I2c_phy_data_in0 = 0x3025, // PHY_I2CM_DATAI_0_ADDR 133 I2c_phy_operation = 0x3026, // PHY_I2CM_OPERATION_ADDR 134 I2c_phy_int_config0 = 0x3027, // PHY_I2CM_INT_ADDR 135 I2c_phy_int_config1 = 0x3028, // PHY_I2CM_CTLINT_ADDR 136 I2c_phy_divider = 0x3029, // PHY_I2CM_DIV_ADDR 137 I2c_phy_software_reset = 0x302a, // PHY_I2CM_SOFTRSTZ_ADDR 138 139 // PHY registers. 140 141 Phy_config = 0x3000, // PHY_CONF0 142 Phy_test0 = 0x3001, // PHY_TST0 143 Phy_test1 = 0x3002, // PHY_TST1 144 Phy_test2 = 0x3003, // PHY_TST2 145 Phy_status = 0x3004, // PHY_STAT0 146 Phy_int_config = 0x3005, // PHY_INT0 147 Phy_mask = 0x3006, // PHY_MASK0 148 Phy_polarity = 0x3007, // PHY_POL0 149 150 // Main controller registers. 151 152 Main_clock_disable = 0x4001, // MC_CLKDIS 153 Main_software_reset = 0x4002, // MC_SWRSTZ 154 Main_flow_control = 0x4004, // MC_FLOWCTRL 155 Main_reset = 0x4005, // MC_PHYRSTZ 156 Main_heac_phy_reset = 0x4007, // MC_HEACPHY_RST 157 158 // Frame composer registers for input video. 159 160 Fc_video_config = 0x1000, // FC_INVIDCONF 161 Fc_horizontal_active_width0 = 0x1001, // FC_INHACTV0 162 Fc_horizontal_active_width1 = 0x1002, // FC_INHACTV1 163 Fc_horizontal_blank_width0 = 0x1003, // FC_INHBLANK0 164 Fc_horizontal_blank_width1 = 0x1004, // FC_INHBLANK1 165 Fc_vertical_active_height0 = 0x1005, // FC_INVACTV0 166 Fc_vertical_active_height1 = 0x1006, // FC_INVACTV1 167 Fc_vertical_blank_height = 0x1007, // FC_INVBLANK 168 169 // Frame composer registers for sync pulses. 170 171 Fc_hsync_delay0 = 0x1008, // FC_HSYNCINDELAY0 172 Fc_hsync_delay1 = 0x1009, // FC_HSYNCINDELAY1 173 Fc_hsync_width0 = 0x100A, // FC_HSYNCINWIDTH0 174 Fc_hsync_width1 = 0x100B, // FC_HSYNCINWIDTH1 175 Fc_vsync_delay = 0x100C, // FC_VSYNCINDELAY 176 Fc_vsync_height = 0x100D, // FC_VSYNCINWIDTH 177 178 // Frame composer registers for video path configuration. 179 180 Fc_control_duration = 0x1011, // FC_CTRLDUR 181 Fc_ex_control_duration = 0x1012, // FC_EXCTRLDUR 182 Fc_ex_control_space = 0x1013, // FC_EXCTRLSPAC 183 Fc_channel0_preamble = 0x1014, // FC_CH0PREAM 184 Fc_channel1_preamble = 0x1015, // FC_CH1PREAM 185 Fc_channel2_preamble = 0x1016, // FC_CH2PREAM 186 187 // Colour space conversion registers. 188 189 Csc_config = 0x4100, // CSC_CFG 190 Csc_scale = 0x4101, // CSC_SCALE 191 192 // HDCP registers. 193 194 Hdcp_config0 = 0x5000, // A_HDCPCFG0 195 Hdcp_config1 = 0x5001, // A_HDCPCFG1 196 Hdcp_video_polarity = 0x5009, // A_VIDPOLCFG 197 198 // Video sample registers. 199 200 Sample_video_config = 0x0200, // TX_INVID0 201 Sample_video_stuffing = 0x0201, // TX_INSTUFFING 202 Sample_gy_data0 = 0x0202, // TX_GYDATA0 203 Sample_gy_data1 = 0x0203, // TX_GYDATA1 204 Sample_rcr_data0 = 0x0204, // TX_RCRDATA0 205 Sample_rcr_data1 = 0x0205, // TX_RCRDATA1 206 Sample_bcb_data0 = 0x0206, // TX_BCBDATA0 207 Sample_bcb_data1 = 0x0207, // TX_BCBDATA1 208 209 // Video packetizer registers. 210 211 Packet_status = 0x0800, // VP_STATUS 212 Packet_pr_cd = 0x0801, // VP_PR_CD 213 Packet_stuffing = 0x0802, // VP_STUFF 214 Packet_remap = 0x0803, // VP_REMAP 215 Packet_config = 0x0804, // VP_CONF 216 }; 217 218 // Identification values. 219 220 enum Product_id_values : uint8_t 221 { 222 Product_id0_transmitter = 0xa0, // PRODUCT_ID0_HDMI_TX 223 224 Product_id1_hdcp = 0xc0, // PRODUCT_ID1_HDCP 225 Product_id1_receiver = 0x02, // PRODUCT_ID1_HDMI_RX 226 Product_id1_transmitter = 0x01, // PRODUCT_ID1_HDMI_TX 227 }; 228 229 // Configuration values. 230 231 enum Config_id_values : uint8_t 232 { 233 Config_id0_i2s = 0x10, // CONFIG0_I2S 234 Config_id0_cec = 0x02, // CONFIG0_CEC 235 236 Config_id1_ahb = 0x01, // CONFIG1_AHB 237 238 Config2_dwc_hdmi_tx_phy = 0x00, // DWC_HDMI_TX_PHY 239 Config2_dwc_mhl_phy_heac = 0xb2, // DWC_MHL_PHY_HEAC 240 Config2_dwc_mhl_phy = 0xc2, // DWC_MHL_PHY 241 Config2_dwc_hdmi_3d_tx_phy_heac = 0xe2, // DWC_HDMI_3D_TX_PHY_HEAC 242 Config2_dwc_hdmi_3d_tx_phy = 0xf2, // DWC_HDMI_3D_TX_PHY 243 Config2_dwc_hdmi20_tx_phy = 0xf3, // DWC_HDMI20_TX_PHY 244 Config2_vendor_phy = 0xfe, // VENDOR_PHY 245 246 Config_id3_ahb_audio_dma = 0x02, // CONFIG3_AHBAUDDMA 247 Config_id3_gp_audio = 0x01, // CONFIG3_GPAUD 248 }; 249 250 // Status and mask bits. 251 252 enum Int_mask_bits : uint8_t 253 { 254 Int_mask_wakeup = 0x02, 255 Int_mask_all = 0x01, 256 }; 257 258 // I2C status and mask bits, also for PHY I2C. 259 260 enum I2c_int_status_bits : uint8_t 261 { 262 I2c_int_status_done = 0x02, 263 I2c_int_status_error = 0x01, 264 }; 265 266 // I2C operation bits. 267 268 enum I2c_operation_bits : uint8_t 269 { 270 I2c_operation_write = 0x10, 271 I2c_operation_segment_read = 0x02, // not PHY I2C 272 I2c_operation_read = 0x01, 273 }; 274 275 // Device addresses. 276 277 enum I2c_phy_device_addresses : uint8_t 278 { 279 I2c_phy_device_phy_gen2 = 0x69, // PHY_I2CM_SLAVE_ADDR_PHY_GEN2 280 I2c_phy_device_phy_heac = 0x49, // PHY_I2CM_SLAVE_ADDR_HEAC_PHY 281 }; 282 283 // Device registers. 284 285 enum I2c_phy_device_registers : uint8_t 286 { 287 I2c_phy_3d_tx_clock_cal_ctrl = 0x05, // 3D_TX_PHY_CKCALCTRL 288 I2c_phy_3d_tx_cpce_ctrl = 0x06, // 3D_TX_PHY_CPCE_CTRL 289 I2c_phy_3d_tx_clock_symbol_ctrl = 0x09, // 3D_TX_PHY_CKSYMTXCTRL 290 I2c_phy_3d_tx_vlevel_ctrl = 0x0e, // 3D_TX_PHY_VLEVCTRL 291 I2c_phy_3d_tx_curr_ctrl = 0x10, // 3D_TX_PHY_CURRCTRL 292 I2c_phy_3d_tx_pll_phby_ctrl = 0x13, // 3D_TX_PHY_PLLPHBYCTRL 293 I2c_phy_3d_tx_gmp_ctrl = 0x15, // 3D_TX_PHY_GMPCTRL 294 I2c_phy_3d_tx_msm_ctrl = 0x17, // 3D_TX_PHY_MSM_CTRL 295 I2c_phy_3d_tx_term = 0x19, // 3D_TX_PHY_TXTERM 296 }; 297 298 // PHY I2C register values. 299 300 enum Msm_ctrl_bits : uint16_t 301 { 302 Msm_ctrl_clock_output_select_fb = 1 << 3, // 3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK 303 }; 304 305 enum Clock_cal_ctrl_bits : uint16_t 306 { 307 Clock_cal_ctrl_override = 1 << 15, // 3D_TX_PHY_CKCALCTRL_OVERRIDE 308 }; 309 310 // Interrupt configuration bits, also for PHY I2C. 311 312 enum I2c_int_config0_bits : uint8_t 313 { 314 I2c_int_config0_done_polarity = 0x08, 315 I2c_int_config0_done_mask = 0x04, 316 }; 317 318 enum I2c_int_config1_bits : uint8_t 319 { 320 I2c_int_config1_nack_polarity = 0x80, 321 I2c_int_config1_nack_mask = 0x40, 322 I2c_int_config1_arb_polarity = 0x08, 323 I2c_int_config1_arb_mask = 0x04, 324 }; 325 326 // PHY configuration values. 327 328 enum Phy_config_bits : uint8_t 329 { 330 Phy_config_powerdown_disable = 0x80, // PHY_CONF0_PDZ_MASK 331 Phy_config_tmds = 0x40, // PHY_CONF0_ENTMDS_MASK 332 Phy_config_svsret = 0x20, // PHY_CONF0_SVSRET_MASK 333 Phy_config_gen2_powerdown = 0x10, // PHY_CONF0_GEN2_PDDQ_MASK 334 Phy_config_gen2_tx_power = 0x08, // PHY_CONF0_GEN2_TXPWRON_MASK 335 Phy_config_gen2_hotplug_detect_rx_sense = 0x04, // PHY_CONF0_GEN2_ENHPDRXSENSE_MASK 336 Phy_config_select_data_enable_polarity = 0x02, // PHY_CONF0_SELDATAENPOL_MASK 337 Phy_config_select_interface_control = 0x01, // PHY_CONF0_SELDIPIF_MASK 338 }; 339 340 enum Phy_test_bits : uint8_t 341 { 342 Phy_test0_clear_mask = 0x20, // PHY_TST0_TSTCLR_MASK 343 Phy_test0_enable_mask = 0x10, // PHY_TST0_TSTEN_MASK 344 Phy_test0_clock_mask = 0x01, // PHY_TST0_TSTCLK_MASK 345 }; 346 347 // PHY status and mask values. 348 349 enum Phy_status_bits : uint8_t 350 { 351 Phy_status_all = 0xf3, 352 Phy_status_rx_sense_all = 0xf0, 353 Phy_status_rx_sense3 = 0x80, // PHY_RX_SENSE3 354 Phy_status_rx_sense2 = 0x40, // PHY_RX_SENSE2 355 Phy_status_rx_sense1 = 0x20, // PHY_RX_SENSE1 356 Phy_status_rx_sense0 = 0x10, // PHY_RX_SENSE0 357 Phy_status_hotplug_detect = 0x02, // PHY_HPD 358 Phy_status_tx_phy_lock = 0x01, // PHY_TX_PHY_LOCK 359 Phy_status_none = 0, 360 }; 361 362 // PHY interrupt status and mask values. 363 364 enum Phy_int_status_bits : uint8_t 365 { 366 Phy_int_status_all = 0x3f, 367 Phy_int_status_rx_sense_all = 0x3c, 368 Phy_int_status_rx_sense3 = 0x20, // IH_PHY_STAT0_RX_SENSE3 369 Phy_int_status_rx_sense2 = 0x10, // IH_PHY_STAT0_RX_SENSE2 370 Phy_int_status_rx_sense1 = 0x08, // IH_PHY_STAT0_RX_SENSE1 371 Phy_int_status_rx_sense0 = 0x04, // IH_PHY_STAT0_RX_SENSE0 372 Phy_int_status_tx_phy_lock = 0x02, // IH_PHY_STAT0_TX_PHY_LOCK 373 Phy_int_status_hotplug_detect = 0x01, // IH_PHY_STAT0_HPD 374 Phy_int_status_none = 0, 375 }; 376 377 // PHY main register values. 378 379 enum Main_heac_phy_reset_bits : uint8_t 380 { 381 Main_heac_phy_reset_assert = 0x01, // MC_HEACPHY_RST_ASSERT 382 }; 383 384 enum Main_flow_control_bits : uint8_t 385 { 386 Main_flow_control_csc_active = 0x01, // MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH 387 Main_flow_control_csc_inactive = 0x00, // MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS 388 }; 389 390 enum Main_clock_disable_bits : uint8_t 391 { 392 Main_clock_disable_hdcp = 0x40, // MC_CLKDIS_HDCPCLK_DISABLE 393 Main_clock_disable_cec = 0x20, // MC_CLKDIS_CECCLK_DISABLE 394 Main_clock_disable_csc = 0x10, // MC_CLKDIS_CSCCLK_DISABLE 395 Main_clock_disable_audio = 0x08, // MC_CLKDIS_AUDCLK_DISABLE 396 Main_clock_disable_prep = 0x04, // MC_CLKDIS_PREPCLK_DISABLE 397 Main_clock_disable_tmds = 0x02, // MC_CLKDIS_TMDSCLK_DISABLE 398 Main_clock_disable_pixel = 0x01, // MC_CLKDIS_PIXELCLK_DISABLE 399 }; 400 401 enum Main_software_reset_bits : uint8_t 402 { 403 Main_software_reset_tmds = 0x02, // MC_SWRSTZ_TMDSSWRST_REQ 404 }; 405 406 // Frame composer values. 407 408 enum Fc_video_config_bits : uint8_t 409 { 410 Fc_video_config_hdcp_keepout_active = 0x80, // FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE 411 Fc_video_config_hdcp_keepout_inactive = 0x00, // FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE 412 Fc_video_config_vsync_active_high = 0x40, // FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH 413 Fc_video_config_vsync_active_low = 0x00, // FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW 414 Fc_video_config_hsync_active_high = 0x20, // FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH 415 Fc_video_config_hsync_active_low = 0x00, // FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW 416 Fc_video_config_data_enable_active_high = 0x10, // FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH 417 Fc_video_config_data_enable_active_low = 0x00, // FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW 418 Fc_video_config_hdmi_mode = 0x08, // FC_INVIDCONF_DVI_MODEZ_HDMI_MODE 419 Fc_video_config_dvi_mode = 0x00, // FC_INVIDCONF_DVI_MODEZ_DVI_MODE 420 Fc_video_config_osc_active_high = 0x02, // FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH 421 Fc_video_config_osc_active_low = 0x00, // FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW 422 Fc_video_config_interlaced = 0x01, // FC_INVIDCONF_IN_I_P_INTERLACED 423 Fc_video_config_progressive = 0x00, // FC_INVIDCONF_IN_I_P_PROGRESSIVE 424 }; 425 426 enum Fc_int_status2_bits : uint8_t 427 { 428 Fc_int_status2_overflow = 0x03, // FC_STAT2_OVERFLOW_MASK 429 Fc_int_status2_overflow_low = 0x02, // FC_STAT2_LOW_PRIORITY_OVERFLOW 430 Fc_int_status2_overflow_high = 0x01 // FC_STAT2_HIGH_PRIORITY_OVERFLOW, 431 }; 432 433 // Colour space conversion values. 434 435 enum Csc_config_bits : uint8_t 436 { 437 Csc_config_interpolation_mask = 0x30, // CSC_CFG_INTMODE_MASK 438 Csc_config_interpolation_disable = 0x00, // CSC_CFG_INTMODE_DISABLE 439 Csc_config_interpolation_form1 = 0x10, // CSC_CFG_INTMODE_CHROMA_INT_FORMULA1 440 Csc_config_interpolation_form2 = 0x20, // CSC_CFG_INTMODE_CHROMA_INT_FORMULA2 441 Csc_config_decimation_mask = 0x3, // CSC_CFG_DECMODE_MASK 442 Csc_config_decimation_disable = 0x0, // CSC_CFG_DECMODE_DISABLE 443 Csc_config_decimation_form1 = 0x1, // CSC_CFG_DECMODE_CHROMA_INT_FORMULA1 444 Csc_config_decimation_form2 = 0x2, // CSC_CFG_DECMODE_CHROMA_INT_FORMULA2 445 Csc_config_decimation_form3 = 0x3, // CSC_CFG_DECMODE_CHROMA_INT_FORMULA3 446 }; 447 448 enum Csc_scale_bits : uint8_t 449 { 450 Csc_scale_colour_depth_mask = 0xf0, // CSC_SCALE_CSC_COLORDE_PTH_MASK 451 Csc_scale_colour_depth_24bpp = 0x00, // CSC_SCALE_CSC_COLORDE_PTH_24BPP 452 Csc_scale_colour_depth_30bpp = 0x50, // CSC_SCALE_CSC_COLORDE_PTH_30BPP 453 Csc_scale_colour_depth_36bpp = 0x60, // CSC_SCALE_CSC_COLORDE_PTH_36BPP 454 Csc_scale_colour_depth_48bpp = 0x70, // CSC_SCALE_CSC_COLORDE_PTH_48BPP 455 Csc_scale_mask = 0x03, // CSC_SCALE_CSCSCALE_MASK 456 }; 457 458 // HDCP register values. 459 460 enum Hdcp_config0_bits : uint8_t 461 { 462 Hdcp_config0_rxdetect_enable = 0x4, // A_HDCPCFG0_RXDETECT_ENABLE 463 }; 464 465 enum Hdcp_config1_bits : uint8_t 466 { 467 Hdcp_config1_encryption_disable = 0x2, // A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE 468 }; 469 470 enum Hdcp_video_polarity_bits : uint8_t 471 { 472 Hdcp_video_polarity_data_enable_active_high = 0x10, // A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH 473 }; 474 475 // Video sample register values. 476 477 enum Sample_video_config_bits : uint8_t 478 { 479 Sample_video_config_data_enable_active = 0x80, // TX_INVID0_INTERNAL_DE_GENERATOR_ENABLE 480 Sample_video_config_mapping_mask = 0x1f, // TX_INVID0_VIDEO_MAPPING_MASK 481 }; 482 483 enum Sample_video_stuffing_bits : uint8_t 484 { 485 Sample_video_stuffing_bdb_data = 0x04, // TX_INSTUFFING_BDBDATA_STUFFING_ENABLE 486 Sample_video_stuffing_rcr_data = 0x02, // TX_INSTUFFING_RCRDATA_STUFFING_ENABLE 487 Sample_video_stuffing_gy_data = 0x01, // TX_INSTUFFING_GYDATA_STUFFING_ENABLE 488 }; 489 490 // Video packetizer register values. 491 492 enum Packet_stuffing_bits : uint8_t 493 { 494 Packet_stuffing_default_phase = 0x20, // VP_STUFF_IDEFAULT_PHASE_MASK 495 Packet_stuffing_ifix_pp_to_last = 0x10, // VP_STUFF_IFIX_PP_TO_LAST_MASK 496 Packet_stuffing_icx = 0x08, // VP_STUFF_ICX_GOTO_P0_ST_MASK 497 Packet_stuffing_ycc422 = 0x04, // VP_STUFF_YCC422_STUFFING_STUFFING_MODE 498 Packet_stuffing_pp = 0x02, // VP_STUFF_PP_STUFFING_STUFFING_MODE 499 Packet_stuffing_pr = 0x01, // VP_STUFF_PR_STUFFING_STUFFING_MODE 500 }; 501 502 enum Packet_config_bits : uint8_t 503 { 504 Packet_config_bypass_enable = 0x40, // VP_CONF_BYPASS_EN_ENABLE 505 Packet_config_pp_enable = 0x20, // VP_CONF_PP_EN_ENABLE 506 Packet_config_pr_enable = 0x10, // VP_CONF_PR_EN_ENABLE 507 Packet_config_ycc422_enable = 0x8, // VP_CONF_YCC422_EN_ENABLE 508 Packet_config_bypass_select_packetizer = 0x4, // VP_CONF_BYPASS_SELECT_VID_PACKETIZER 509 Packet_config_output_selector_mask = 0x3, // VP_CONF_OUTPUT_SELECTOR_MASK 510 Packet_config_output_selector_bypass = 0x3, // VP_CONF_OUTPUT_SELECTOR_BYPASS 511 Packet_config_output_selector_ycc422 = 0x1, // VP_CONF_OUTPUT_SELECTOR_YCC422 512 Packet_config_output_selector_pp = 0x0, // VP_CONF_OUTPUT_SELECTOR_PP 513 }; 514 515 enum Packet_remap_bits : uint8_t 516 { 517 Packet_remap_mask = 0x3, // VP_REMAP_MASK 518 Packet_remap_ycc422_24bit = 0x2, // VP_REMAP_YCC422_24bit 519 Packet_remap_ycc422_20bit = 0x1, // VP_REMAP_YCC422_20bit 520 Packet_remap_ycc422_16bit = 0x0, // VP_REMAP_YCC422_16bit 521 }; 522 523 enum Packet_pr_cd_bits : uint8_t 524 { 525 Packet_pr_cd_depth_mask = 0xf0, // VP_PR_CD_COLOR_DEPTH_MASK 526 Packet_pr_cd_depth_offset = 4, // VP_PR_CD_COLOR_DEPTH_OFFSET 527 Packet_pr_cd_factor_mask = 0x0f, // VP_PR_CD_DESIRED_PR_FACTOR_MASK 528 Packet_pr_cd_factor_offset = 0, // VP_PR_CD_DESIRED_PR_FACTOR_OFFSET 529 }; 530 531 532 533 // PHY capabilities. 534 535 static const Phy_capabilities phy_capabilities[] = { 536 // name gen svsret configure 537 {Config2_dwc_hdmi_tx_phy, "DWC_HDMI_TX_PHY", 1, false, false}, 538 {Config2_dwc_mhl_phy_heac, "DWC_MHL_PHY_HEAC", 2, true, true}, 539 {Config2_dwc_mhl_phy, "DWC_MHL_PHY", 2, true, true}, 540 {Config2_dwc_hdmi_3d_tx_phy_heac, "DWC_HDMI_3D_TX_PHY_HEAC", 2, false, true}, 541 {Config2_dwc_hdmi_3d_tx_phy, "DWC_HDMI_3D_TX_PHY", 2, false, true}, 542 {Config2_dwc_hdmi20_tx_phy, "DWC_HDMI20_TX_PHY", 2, true, true}, 543 {0, "Vendor PHY", 0, false, false}, 544 }; 545 546 547 548 // PHY configuration, adopting the Linux driver's tables of values. 549 550 static const struct Phy_mpll_config phy_mpll_config[] = { 551 // 8bpc 10bpc 12bpc 552 // pixelclock cpce gmp cpce gmp cpce gmp 553 { 45250000, { {0x01e0, 0x0000}, {0x21e1, 0x0000}, {0x41e2, 0x0000} } }, 554 { 92500000, { {0x0140, 0x0005}, {0x2141, 0x0005}, {0x4142, 0x0005} } }, 555 { 148500000, { {0x00a0, 0x000a}, {0x20a1, 0x000a}, {0x40a2, 0x000a} } }, 556 { 216000000, { {0x00a0, 0x000a}, {0x2001, 0x000f}, {0x4002, 0x000f} } }, 557 { ~0UL, { {0x0000, 0x0000}, {0x0000, 0x0000}, {0x0000, 0x0000} } } 558 }; 559 560 static const struct Phy_curr_ctrl phy_curr_ctrl[] = { 561 // pixelclock 8bpc 10bpc 12bpc 562 { 54000000, {0x091c, 0x091c, 0x06dc} }, 563 { 58400000, {0x091c, 0x06dc, 0x06dc} }, 564 { 72000000, {0x06dc, 0x06dc, 0x091c} }, 565 { 74250000, {0x06dc, 0x0b5c, 0x091c} }, 566 { 118800000, {0x091c, 0x091c, 0x06dc} }, 567 { 216000000, {0x06dc, 0x0b5c, 0x091c} }, 568 { ~0UL, {0x0000, 0x0000, 0x0000} } 569 }; 570 571 static const struct Phy_config phy_config[] = { 572 // pixelclock symbol term vlevel 573 { 216000000, 0x800d, 0x0005, 0x01ad}, 574 { ~0UL, 0x0000, 0x0000, 0x0000} 575 }; 576 577 578 579 // Initialise the HDMI peripheral. 580 581 Hdmi_jz4780_chip::Hdmi_jz4780_chip(l4_addr_t start, l4_addr_t end, 582 l4_cap_idx_t irq, 583 struct Jz4740_lcd_panel *panel) 584 : _start(start), _end(end), _irq(irq), _panel(panel) 585 { 586 // 8-bit registers with 2-bit address shifting. 587 588 _regs = new Hw::Mmio_register_block<8>(start, 2); 589 590 // Initialise I2C state for DDC. 591 592 _segment_read = false; 593 _device_register = 0; 594 595 // Initialise I2C state for PHY initialisation. 596 597 _phy_device_register = 0; 598 599 // Initialise identifying details and capabilities of the hardware. 600 601 get_identification(); 602 603 // Reset interrupts to a minimal, enabled state. 604 605 irq_init(); 606 607 // Set up DDC and PHY communication. 608 609 i2c_init(I2c_software_reset, I2c_divider, I2c_int_config0, I2c_int_config1, 610 I2c_int_status, I2c_int_mask); 611 i2c_init(I2c_phy_software_reset, I2c_phy_divider, I2c_phy_int_config0, I2c_phy_int_config1, 612 I2c_phy_int_status, I2c_phy_int_mask); 613 614 // Enable PHY interrupts. 615 616 phy_irq_init(); 617 } 618 619 // Pixel clock frequency calculation. 620 621 unsigned long Hdmi_jz4780_chip::get_pixelclock() 622 { 623 return _pixelclock; 624 625 /* Calculated frequency, which may not be the actual pixelclock frequency... 626 627 return (_panel->line_start + _panel->width + _panel->line_end + _panel->hsync) * 628 (_panel->frame_start + _panel->height + _panel->frame_end + _panel->vsync) * 629 _panel->frame_rate; 630 */ 631 } 632 633 634 635 // Update a register by enabling/setting or disabling/clearing the given bits. 636 637 void Hdmi_jz4780_chip::reg_update(uint32_t reg, uint32_t bits, bool enable) 638 { 639 if (enable) 640 _regs[reg] = _regs[reg] | bits; 641 else 642 _regs[reg] = _regs[reg] & ~bits; 643 } 644 645 // Update a field. The bits must be shifted to coincide with the mask. 646 647 void Hdmi_jz4780_chip::reg_update_field(uint32_t reg, uint32_t mask, uint32_t bits) 648 { 649 _regs[reg] = (_regs[reg] & ~(mask)) | (bits & mask); 650 } 651 652 void Hdmi_jz4780_chip::reg_fill_field(uint32_t reg, uint32_t mask) 653 { 654 _regs[reg] = _regs[reg] | mask; 655 } 656 657 658 659 // Chipset querying. 660 661 void Hdmi_jz4780_chip::get_identification() 662 { 663 _version = (_regs[Design_id] << 8) | _regs[Revision_id]; 664 _phy_type = _regs[Config_id2]; 665 666 // Initialise a member to any matching capabilities or leave it as the "null" 667 // entry. 668 669 _phy_def = phy_capabilities; 670 671 while (_phy_def->gen && (_phy_def->type != _phy_type)) 672 _phy_def++; 673 } 674 675 void Hdmi_jz4780_chip::get_version(uint8_t *major, uint16_t *minor) 676 { 677 *major = (_version >> 12) & 0xfff; 678 *minor = _version & 0xfff; 679 } 680 681 void Hdmi_jz4780_chip::get_phy_capabilities(const struct Phy_capabilities **phy_def) 682 { 683 *phy_def = _phy_def; 684 } 685 686 687 688 // Initialisation. 689 690 void Hdmi_jz4780_chip::irq_init() 691 { 692 // Disable interrupts. 693 694 _regs[Int_mask] = _regs[Int_mask] | (Int_mask_wakeup | Int_mask_all); 695 696 // Mask all interrupts. 697 698 _regs[Fc_int_mask0] = 0xff; 699 _regs[Fc_int_mask1] = 0xff; 700 _regs[Fc_int_mask2] = 0xff; 701 _regs[As_int_mask] = 0xff; 702 _regs[Phy_int_mask] = 0xff; 703 _regs[I2c_int_mask] = 0xff; 704 _regs[I2c_phy_int_mask] = 0xff; 705 _regs[Cec_int_mask] = 0xff; 706 _regs[Vp_int_mask] = 0xff; 707 _regs[Ahb_dma_audio_int_mask] = 0xff; 708 709 // Enable interrupts. 710 711 _regs[Int_mask] = _regs[Int_mask] & ~(Int_mask_wakeup | Int_mask_all); 712 } 713 714 void Hdmi_jz4780_chip::phy_irq_init() 715 { 716 // Set PHY interrupt polarities. 717 718 _regs[Phy_polarity] = Phy_status_all; 719 720 // Enable/unmask second-level interrupts. 721 722 _regs[Phy_mask] = _regs[Phy_mask] & ~(Phy_status_all); 723 724 // Clear pending interrupts. 725 726 _regs[Phy_int_status] = Phy_int_status_all; 727 728 // Enable/unmask interrupts. 729 730 _regs[Phy_int_mask] = _regs[Phy_int_mask] & ~(Phy_int_status_all); 731 } 732 733 734 735 // I2C support. 736 737 void Hdmi_jz4780_chip::i2c_init(uint32_t reset, uint32_t divider, 738 uint32_t config0, uint32_t config1, 739 uint32_t status, uint32_t mask) 740 { 741 // Software reset. 742 743 _regs[reset] = 0; 744 745 // Standard mode (100kHz). 746 747 _regs[divider] = 0; 748 749 // Set interrupt polarities. 750 751 _regs[config0] = I2c_int_config0_done_polarity; 752 _regs[config1] = I2c_int_config1_nack_polarity | I2c_int_config1_arb_polarity; 753 754 // Clear and mask/mute interrupts. 755 756 _regs[status] = I2c_int_status_done | I2c_int_status_error; 757 _regs[mask] = I2c_int_status_done | I2c_int_status_error; 758 } 759 760 long Hdmi_jz4780_chip::i2c_wait(uint32_t status) 761 { 762 long err; 763 uint8_t int_status; 764 l4_msgtag_t tag; 765 766 err = l4_error(l4_rcv_ep_bind_thread(_irq, pthread_l4_cap(pthread_self()), 0)); 767 768 if (err) 769 return err; 770 771 do 772 { 773 tag = l4_irq_receive(_irq, L4_IPC_NEVER); 774 775 err = l4_ipc_error(tag, l4_utcb()); 776 if (err) 777 return err; 778 779 int_status = _regs[status]; 780 781 // Test for an error condition. 782 783 if (int_status & I2c_int_status_error) 784 return -L4_EIO; 785 786 // Acknowledge the interrupt. 787 788 _regs[status] = int_status; 789 790 } while (!(int_status & I2c_int_status_done)); 791 792 return L4_EOK; 793 } 794 795 int Hdmi_jz4780_chip::i2c_read(uint8_t *buf, unsigned int length) 796 { 797 unsigned int i; 798 long err; 799 800 // Unmask interrupts. 801 802 _regs[I2c_int_mask] = 0; 803 804 for (i = 0; i < length; i++) 805 { 806 // Increment the device register. 807 808 _regs[I2c_register] = _device_register++; 809 _regs[I2c_operation] = _segment_read ? I2c_operation_segment_read 810 : I2c_operation_read; 811 812 // Wait and then read. 813 814 err = i2c_wait(I2c_int_status); 815 if (err) 816 break; 817 818 buf[i] = _regs[I2c_data_in]; 819 } 820 821 // Mask interrupts again. 822 823 _regs[I2c_int_mask] = I2c_int_status_done | I2c_int_status_error; 824 825 return i; 826 } 827 828 int Hdmi_jz4780_chip::i2c_phy_write(uint8_t address, uint16_t value) 829 { 830 i2c_phy_set_address(address); 831 return i2c_phy_write(&value, 1); 832 } 833 834 int Hdmi_jz4780_chip::i2c_phy_write(uint16_t *buf, unsigned int length) 835 { 836 unsigned int i; 837 long err; 838 839 // Unmask interrupts. 840 841 _regs[I2c_phy_int_mask] = 0; 842 843 for (i = 0; i < length; i++) 844 { 845 // Increment the device register. 846 847 _regs[I2c_phy_register] = _device_register++; 848 _regs[I2c_phy_operation] = I2c_operation_write; 849 850 // Write and then wait. 851 852 _regs[I2c_phy_data_out1] = (buf[i] >> 8) & 0xff; 853 _regs[I2c_phy_data_out0] = buf[i] & 0xff; 854 855 err = i2c_wait(I2c_phy_int_status); 856 if (err) 857 break; 858 } 859 860 // Mask interrupts again. 861 862 _regs[I2c_phy_int_mask] = I2c_int_status_done | I2c_int_status_error; 863 864 return i; 865 } 866 867 void Hdmi_jz4780_chip::i2c_set_address(uint8_t address) 868 { 869 _regs[I2c_device_address] = address; 870 _segment_read = false; 871 i2c_set_register(0); 872 } 873 874 void Hdmi_jz4780_chip::i2c_phy_set_address(uint8_t address) 875 { 876 // The Linux drivers seem to set the clear field when changing the PHY device 877 // address, presumably because some manual says so. 878 879 _regs[Phy_test0] = _regs[Phy_test0] | Phy_test0_clear_mask; 880 _regs[I2c_phy_device_address] = address; 881 _regs[Phy_test0] = _regs[Phy_test0] & ~Phy_test0_clear_mask; 882 883 i2c_phy_set_register(0); 884 } 885 886 void Hdmi_jz4780_chip::i2c_set_segment(uint8_t segment) 887 { 888 _regs[I2c_segment_address] = 0x30; 889 _regs[I2c_segment_pointer] = segment; 890 _segment_read = true; 891 i2c_set_register(0); 892 } 893 894 void Hdmi_jz4780_chip::i2c_set_register(uint8_t device_register) 895 { 896 _device_register = device_register; 897 } 898 899 void Hdmi_jz4780_chip::i2c_phy_set_register(uint8_t device_register) 900 { 901 _phy_device_register = device_register; 902 } 903 904 905 906 // PHY operations. 907 908 void Hdmi_jz4780_chip::phy_enable_powerdown(bool enable) 909 { 910 reg_update(Phy_config, Phy_config_powerdown_disable, !enable); 911 } 912 913 void Hdmi_jz4780_chip::phy_enable_tmds(bool enable) 914 { 915 reg_update(Phy_config, Phy_config_tmds, enable); 916 } 917 918 void Hdmi_jz4780_chip::phy_enable_svsret(bool enable) 919 { 920 reg_update(Phy_config, Phy_config_svsret, enable); 921 } 922 923 void Hdmi_jz4780_chip::phy_enable_gen2_powerdown(bool enable) 924 { 925 reg_update(Phy_config, Phy_config_gen2_powerdown, enable); 926 } 927 928 void Hdmi_jz4780_chip::phy_enable_gen2_tx_power(bool enable) 929 { 930 reg_update(Phy_config, Phy_config_gen2_tx_power, enable); 931 } 932 933 void Hdmi_jz4780_chip::phy_enable_interface(bool enable) 934 { 935 reg_update(Phy_config, Phy_config_select_data_enable_polarity, enable); 936 reg_update(Phy_config, Phy_config_select_interface_control, !enable); 937 } 938 939 // Configure the PHY. Various things not supported by the JZ4780 PHY are ignored 940 // such as the TDMS clock ratio (dependent on HDMI 2 and content scrambling). 941 942 long Hdmi_jz4780_chip::phy_configure() 943 { 944 long err; 945 946 phy_power_off(); 947 948 if (_phy_def->svsret) 949 phy_enable_svsret(true); 950 951 phy_reset(); 952 953 _regs[Main_heac_phy_reset] = Main_heac_phy_reset_assert; 954 955 i2c_phy_set_address(I2c_phy_device_phy_gen2); 956 957 if (_phy_def->configure) 958 { 959 err = phy_configure_specific(); 960 if (err) 961 return err; 962 } 963 964 // NOTE: TMDS clock delay here in Linux driver. 965 966 phy_power_on(); 967 968 return L4_EOK; 969 } 970 971 // Configure for the JZ4780 specifically. 972 973 long Hdmi_jz4780_chip::phy_configure_specific() 974 { 975 const struct Phy_mpll_config *m = phy_mpll_config; 976 const struct Phy_curr_ctrl *c = phy_curr_ctrl; 977 const struct Phy_config *p = phy_config; 978 unsigned long pixelclock = get_pixelclock(); 979 980 // Find MPLL, CURR_CTRL and PHY configuration settings appropriate for the 981 // pixel clock frequency. 982 983 while (m->pixelclock && (pixelclock > m->pixelclock)) 984 m++; 985 986 while (c->pixelclock && (pixelclock > c->pixelclock)) 987 c++; 988 989 while (p->pixelclock && (pixelclock > p->pixelclock)) 990 p++; 991 992 if (!m->pixelclock || !c->pixelclock || !p->pixelclock) 993 return -L4_EINVAL; 994 995 // Using values for 8bpc from the tables. 996 997 // Initialise MPLL. 998 999 i2c_phy_write(I2c_phy_3d_tx_cpce_ctrl, m->res[Phy_resolution_8bpc].cpce); 1000 i2c_phy_write(I2c_phy_3d_tx_gmp_ctrl, m->res[Phy_resolution_8bpc].gmp); 1001 1002 // Initialise CURRCTRL. 1003 1004 i2c_phy_write(I2c_phy_3d_tx_cpce_ctrl, c->curr[Phy_resolution_8bpc]); 1005 1006 // Initialise PHY_CONFIG. 1007 1008 i2c_phy_write(I2c_phy_3d_tx_pll_phby_ctrl, 0); 1009 i2c_phy_write(I2c_phy_3d_tx_msm_ctrl, Msm_ctrl_clock_output_select_fb); 1010 1011 i2c_phy_write(I2c_phy_3d_tx_term, p->term); 1012 i2c_phy_write(I2c_phy_3d_tx_clock_symbol_ctrl, p->symbol); 1013 i2c_phy_write(I2c_phy_3d_tx_vlevel_ctrl, p->vlevel); 1014 1015 // Override and disable clock termination. 1016 1017 i2c_phy_write(I2c_phy_3d_tx_clock_cal_ctrl, Clock_cal_ctrl_override); 1018 1019 return L4_EOK; 1020 } 1021 1022 long Hdmi_jz4780_chip::phy_init() 1023 { 1024 long err; 1025 int i; 1026 1027 // Initialisation repeated for HDMI PHY specification reasons. 1028 1029 for (i = 0; i < 2; i++) 1030 { 1031 phy_enable_interface(true); 1032 err = phy_configure(); 1033 if (err) 1034 return err; 1035 } 1036 1037 return L4_EOK; 1038 } 1039 1040 void Hdmi_jz4780_chip::phy_reset() 1041 { 1042 _regs[Main_reset] = 1; 1043 _regs[Main_reset] = 0; 1044 } 1045 1046 void Hdmi_jz4780_chip::phy_power_off() 1047 { 1048 if (_phy_def && (_phy_def->gen == 1)) 1049 { 1050 phy_enable_tmds(false); 1051 phy_enable_powerdown(true); 1052 return; 1053 } 1054 1055 phy_enable_gen2_tx_power(false); 1056 1057 wait_for_tx_phy_lock(0); 1058 1059 phy_enable_gen2_powerdown(true); 1060 } 1061 1062 void Hdmi_jz4780_chip::phy_power_on() 1063 { 1064 if (_phy_def && (_phy_def->gen == 1)) 1065 { 1066 phy_enable_powerdown(false); 1067 phy_enable_tmds(false); 1068 phy_enable_tmds(true); 1069 return; 1070 } 1071 1072 phy_enable_gen2_tx_power(true); 1073 phy_enable_gen2_powerdown(false); 1074 1075 wait_for_tx_phy_lock(1); 1076 } 1077 1078 1079 1080 // Hotplug detection. 1081 1082 bool Hdmi_jz4780_chip::connected() 1083 { 1084 return (_regs[Phy_status] & Phy_status_hotplug_detect) != 0; 1085 } 1086 1087 long Hdmi_jz4780_chip::wait_for_connection() 1088 { 1089 return wait_for_phy_irq(Phy_int_status_hotplug_detect, Phy_status_hotplug_detect, 1090 Phy_status_hotplug_detect); 1091 } 1092 1093 // General PHY interrupt handling. 1094 1095 long Hdmi_jz4780_chip::wait_for_phy_irq(uint32_t int_status_flags, 1096 uint32_t status_flags, 1097 uint32_t status_values) 1098 { 1099 long err; 1100 uint8_t int_status, status; 1101 uint8_t status_unchanged = ~(status_values) & status_flags; 1102 l4_msgtag_t tag; 1103 1104 do 1105 { 1106 tag = l4_irq_receive(_irq, L4_IPC_NEVER); 1107 1108 err = l4_ipc_error(tag, l4_utcb()); 1109 if (err) 1110 return err; 1111 1112 // Obtain the details. 1113 1114 int_status = _regs[Phy_int_status]; 1115 status = _regs[Phy_status]; 1116 1117 // Acknowledge the interrupt. 1118 1119 _regs[Phy_int_status] = int_status_flags; 1120 1121 // Continue without a handled event. 1122 // An event is handled when detected and when the status differs from 1123 // the unchanged state. 1124 1125 } while (!((int_status & int_status_flags) && 1126 ((status & status_flags) ^ status_unchanged))); 1127 1128 return L4_EOK; 1129 } 1130 1131 // Wait for TX_PHY_LOCK to become high or low. 1132 1133 long Hdmi_jz4780_chip::wait_for_tx_phy_lock(int level) 1134 { 1135 if (!!(_regs[Phy_status] & Phy_status_tx_phy_lock) == level) 1136 return L4_EOK; 1137 1138 return wait_for_phy_irq(Phy_int_status_tx_phy_lock, Phy_status_tx_phy_lock, 1139 level ? Phy_status_tx_phy_lock : Phy_status_none); 1140 } 1141 1142 1143 1144 // Output setup operations. 1145 1146 long Hdmi_jz4780_chip::enable(unsigned long pixelclock) 1147 { 1148 _pixelclock = pixelclock; 1149 1150 // Disable frame composer overflow interrupts. 1151 1152 enable_overflow_irq(false); 1153 1154 // NOTE: Here, CEA modes are normally detected and thus the output encoding. 1155 // NOTE: Instead, a fixed RGB output encoding and format is used. 1156 // NOTE: Meanwhile, the input encoding and format will also be fixed to a RGB 1157 // NOTE: representation. 1158 1159 // _bits_per_channel = 8; 1160 // _data_enable_polarity = true; 1161 1162 // HDMI initialisation "step B.1": video frame initialisation. 1163 1164 frame_init(); 1165 1166 // HDMI initialisation "step B.2": PHY initialisation. 1167 1168 long err = phy_init(); 1169 if (err) 1170 return err; 1171 1172 // HDMI initialisation "step B.3": video signal initialisation. 1173 1174 data_path_init(); 1175 1176 // With audio, various clock updates are needed. 1177 1178 // NOTE: DVI mode is being assumed for now, for simplicity. 1179 1180 // In non-DVI mode, the AVI, vendor-specific infoframe and regular infoframe 1181 // are set up. 1182 1183 packet_init(); 1184 csc_init(); 1185 sample_init(); 1186 hdcp_init(); 1187 1188 // Enable frame composer overflow interrupts. 1189 1190 enable_overflow_irq(true); 1191 1192 return L4_EOK; 1193 } 1194 1195 void Hdmi_jz4780_chip::enable_overflow_irq(bool enable) 1196 { 1197 if (!enable) 1198 reg_update(Fc_int_mask2, Fc_int_status2_overflow, !enable); 1199 1200 // Apparent workaround required. 1201 1202 else 1203 { 1204 uint8_t config = _regs[Fc_video_config]; 1205 1206 _regs[Main_software_reset] = ~(Main_software_reset_tmds); 1207 1208 for (int i = 0; i < 4; i++) 1209 _regs[Fc_video_config] = config; 1210 } 1211 } 1212 1213 void Hdmi_jz4780_chip::frame_init() 1214 { 1215 // Initialise the video configuration. This is rather like the initialisation 1216 // of the LCD controller. The sync and data enable polarities are set up, plus 1217 // extras like HDCP, DVI mode, progressive/interlace. 1218 // NOTE: Here, the JZ4740-specific configuration is used to store the picture 1219 // NOTE: properties, but a neutral structure should be adopted. 1220 1221 uint8_t config = 0; 1222 1223 config |= (_panel->config & Jz4740_lcd_hsync_negative) 1224 ? Fc_video_config_hsync_active_low 1225 : Fc_video_config_hsync_active_high; 1226 1227 config |= (_panel->config & Jz4740_lcd_vsync_negative) 1228 ? Fc_video_config_vsync_active_low 1229 : Fc_video_config_vsync_active_high; 1230 1231 config |= (_panel->config & Jz4740_lcd_de_negative) 1232 ? Fc_video_config_data_enable_active_low 1233 : Fc_video_config_data_enable_active_high; 1234 1235 // NOTE: Only supporting DVI mode so far. 1236 1237 config |= Fc_video_config_dvi_mode; 1238 1239 // NOTE: Not supporting HDCP. 1240 1241 config |= Fc_video_config_hdcp_keepout_inactive; 1242 1243 // NOTE: Only supporting progressive scan so far. 1244 1245 config |= Fc_video_config_progressive; 1246 config |= Fc_video_config_osc_active_low; 1247 1248 _regs[Fc_video_config] = config; 1249 1250 // Then, the frame characteristics (visible area, sync pulse) are set. Indeed, 1251 // the frame area details should be practically the same as those used by the 1252 // LCD controller. 1253 1254 uint16_t hblank = _panel->line_start + _panel->line_end + _panel->hsync, 1255 vblank = _panel->frame_start + _panel->frame_end + _panel->vsync, 1256 hsync_delay = _panel->line_end, 1257 vsync_delay = _panel->frame_end, 1258 hsync_width = _panel->hsync, 1259 vsync_height = _panel->vsync; 1260 1261 _regs[Fc_horizontal_active_width1] = (_panel->width >> 8) & 0xff; 1262 _regs[Fc_horizontal_active_width0] = _panel->width & 0xff; 1263 1264 _regs[Fc_horizontal_blank_width1] = (hblank >> 8) & 0xff; 1265 _regs[Fc_horizontal_blank_width0] = hblank & 0xff; 1266 1267 _regs[Fc_vertical_active_height1] = (_panel->height >> 8) & 0xff; 1268 _regs[Fc_vertical_active_height0] = _panel->height & 0xff; 1269 1270 _regs[Fc_vertical_blank_height] = vblank & 0xff; 1271 1272 _regs[Fc_hsync_delay1] = (hsync_delay >> 8) & 0xff; 1273 _regs[Fc_hsync_delay0] = hsync_delay & 0xff; 1274 1275 _regs[Fc_vsync_delay] = vsync_delay & 0xff; 1276 1277 _regs[Fc_hsync_width1] = (hsync_width >> 8) & 0xff; 1278 _regs[Fc_hsync_width0] = hsync_width & 0xff; 1279 1280 _regs[Fc_vsync_height] = vsync_height & 0xff; 1281 } 1282 1283 void Hdmi_jz4780_chip::data_path_init() 1284 { 1285 // Initialise the path of the video data. Here, the elements of the data 1286 // stream are defined such as the control period duration, data channel 1287 // characteristics, pixel and TMDS clocks, and the involvement of colour space 1288 // conversion. 1289 1290 // Control period minimum duration. 1291 1292 _regs[Fc_control_duration] = 12; 1293 _regs[Fc_ex_control_duration] = 32; 1294 _regs[Fc_ex_control_space] = 1; 1295 1296 // Set to fill TMDS data channels. 1297 1298 _regs[Fc_channel0_preamble] = 0x0b; 1299 _regs[Fc_channel1_preamble] = 0x16; 1300 _regs[Fc_channel2_preamble] = 0x21; 1301 1302 // Apparent two-stage clock activation. 1303 1304 uint8_t clock_disable = Main_clock_disable_hdcp | 1305 Main_clock_disable_csc | 1306 Main_clock_disable_audio | 1307 Main_clock_disable_prep | 1308 Main_clock_disable_tmds; 1309 1310 // Activate the pixel clock. 1311 1312 _regs[Main_clock_disable] = clock_disable; 1313 1314 // Then activate the TMDS clock. 1315 1316 clock_disable &= ~(Main_clock_disable_tmds); 1317 _regs[Main_clock_disable] = clock_disable; 1318 1319 // NOTE: Bypass colour space conversion for now. 1320 1321 _regs[Main_flow_control] = Main_flow_control_csc_inactive; 1322 } 1323 1324 void Hdmi_jz4780_chip::packet_init() 1325 { 1326 // Initialise the video packet details. 1327 // NOTE: With 24bpp RGB output only for now, no pixel repetition. 1328 1329 int colour_depth = 4; 1330 1331 _regs[Packet_pr_cd] = 1332 ((colour_depth << Packet_pr_cd_depth_offset) & 1333 Packet_pr_cd_depth_mask); 1334 1335 _regs[Packet_remap] = Packet_remap_ycc422_16bit; 1336 1337 reg_fill_field(Packet_stuffing, Packet_stuffing_pr | 1338 Packet_stuffing_default_phase | 1339 Packet_stuffing_pp | 1340 Packet_stuffing_ycc422); 1341 1342 // Disable pixel repeater. 1343 1344 reg_update_field(Packet_config, Packet_config_bypass_enable | 1345 Packet_config_pr_enable | 1346 Packet_config_pp_enable | 1347 Packet_config_ycc422_enable | 1348 Packet_config_bypass_select_packetizer | 1349 Packet_config_output_selector_mask, 1350 Packet_config_bypass_enable | 1351 Packet_config_bypass_select_packetizer | 1352 Packet_config_output_selector_bypass); 1353 } 1354 1355 void Hdmi_jz4780_chip::csc_init() 1356 { 1357 // Initialise the colour space conversion details. 1358 // NOTE: No conversion will be done yet (see data_path_init). 1359 1360 _regs[Csc_config] = Csc_config_interpolation_disable | 1361 Csc_config_decimation_disable; 1362 1363 // NOTE: Use 8bpc (24bpp) for now. 1364 1365 reg_update_field(Csc_scale, Csc_scale_colour_depth_mask, Csc_scale_colour_depth_24bpp); 1366 1367 // NOTE: Coefficients should be set here. 1368 } 1369 1370 void Hdmi_jz4780_chip::sample_init() 1371 { 1372 // Initialise the mapping of video input data. 1373 // NOTE: With 24bpp RGB input only for now. 1374 1375 int colour_format = 0x01; 1376 1377 // Data enable inactive. 1378 1379 _regs[Sample_video_config] = (colour_format & Sample_video_config_mapping_mask); 1380 1381 // Transmission stuffing when data enable is inactive. 1382 1383 _regs[Sample_video_stuffing] = Sample_video_stuffing_bdb_data | 1384 Sample_video_stuffing_rcr_data | 1385 Sample_video_stuffing_gy_data; 1386 1387 _regs[Sample_gy_data0] = 0; 1388 _regs[Sample_gy_data1] = 0; 1389 _regs[Sample_rcr_data0] = 0; 1390 _regs[Sample_rcr_data1] = 0; 1391 _regs[Sample_bcb_data0] = 0; 1392 _regs[Sample_bcb_data1] = 0; 1393 } 1394 1395 void Hdmi_jz4780_chip::hdcp_init() 1396 { 1397 // Initialise HDCP registers, mostly turning things off. 1398 1399 reg_update(Hdcp_config0, Hdcp_config0_rxdetect_enable, false); 1400 1401 reg_update(Hdcp_video_polarity, 1402 Hdcp_video_polarity_data_enable_active_high, 1403 !(_panel->config & Jz4740_lcd_de_negative)); 1404 1405 reg_update(Hdcp_config1, Hdcp_config1_encryption_disable, true); 1406 } 1407 1408 1409 1410 // C language interface functions. 1411 1412 void *jz4780_hdmi_init(l4_addr_t start, l4_addr_t end, l4_cap_idx_t irq, 1413 struct Jz4740_lcd_panel *panel) 1414 { 1415 return (void *) new Hdmi_jz4780_chip(start, end, irq, panel); 1416 } 1417 1418 void jz4780_hdmi_get_version(void *hdmi, uint8_t *major, uint16_t *minor) 1419 { 1420 static_cast<Hdmi_jz4780_chip *>(hdmi)->get_version(major, minor); 1421 } 1422 1423 void jz4780_hdmi_get_phy_capabilities(void *hdmi, const struct Phy_capabilities **phy_def) 1424 { 1425 static_cast<Hdmi_jz4780_chip *>(hdmi)->get_phy_capabilities(phy_def); 1426 } 1427 1428 int jz4780_hdmi_i2c_read(void *hdmi, uint8_t *buf, unsigned int length) 1429 { 1430 return static_cast<Hdmi_jz4780_chip *>(hdmi)->i2c_read(buf, length); 1431 } 1432 1433 void jz4780_hdmi_i2c_set_address(void *hdmi, uint8_t address) 1434 { 1435 static_cast<Hdmi_jz4780_chip *>(hdmi)->i2c_set_address(address); 1436 } 1437 1438 void jz4780_hdmi_i2c_set_segment(void *hdmi, uint8_t segment) 1439 { 1440 static_cast<Hdmi_jz4780_chip *>(hdmi)->i2c_set_segment(segment); 1441 } 1442 1443 void jz4780_hdmi_i2c_set_register(void *hdmi, uint8_t device_register) 1444 { 1445 static_cast<Hdmi_jz4780_chip *>(hdmi)->i2c_set_register(device_register); 1446 } 1447 1448 int jz4780_hdmi_connected(void *hdmi) 1449 { 1450 return (int) static_cast<Hdmi_jz4780_chip *>(hdmi)->connected(); 1451 } 1452 1453 long jz4780_hdmi_wait_for_connection(void *hdmi) 1454 { 1455 return static_cast<Hdmi_jz4780_chip *>(hdmi)->wait_for_connection(); 1456 } 1457 1458 long jz4780_hdmi_enable(void *hdmi, unsigned long pixelclock) 1459 { 1460 return static_cast<Hdmi_jz4780_chip *>(hdmi)->enable(pixelclock); 1461 }