text: // Copyright 2018 The Fuchsia Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef SRC_GRAPHICS_DISPLAY_DRIVERS_VIM_DISPLAY_HDMITX_H_
  #define SRC_GRAPHICS_DISPLAY_DRIVERS_VIM_DISPLAY_HDMITX_H_
  
  #include <assert.h>
  #include <fuchsia/hardware/platform/device/c/banjo.h>
  #include <stdint.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <threads.h>
  #include <zircon/listnode.h>
  #include <zircon/types.h>
  
  #include <ddk/device.h>
  #include <ddk/io-buffer.h>
  
  #include "dwc-hdmi.h"
  #include "vpu.h"
  
  __BEGIN_CDECLS
  
  #define DISPLAY_MASK(start, count) (((1 << (count)) - 1) << (start))
  #define DISPLAY_SET_MASK(mask, start, count, value) \
    ((mask & ~DISPLAY_MASK(start, count)) | (((value) << (start)) & DISPLAY_MASK(start, count)))
  
  #define READ32_PRESET_REG(a) display->mmio_preset->Read32(a)
  #define WRITE32_PRESET_REG(a, v) display->mmio_preset->Write32(v, a)
  
  #define READ32_HDMITX_REG(a) display->mmio_hdmitx->Read32(a)
  #define WRITE32_HDMITX_REG(a, v) display->mmio_hdmitx->Write32(v, a)
  
  #define READ32_HHI_REG(a) display->mmio_hiu->Read32(a)
  #define WRITE32_HHI_REG(a, v) display->mmio_hiu->Write32(v, a)
  
  #define READ32_VPU_REG(a) display->mmio_vpu->Read32(a)
  #define WRITE32_VPU_REG(a, v) display->mmio_vpu->Write32(v, a)
  
  #define READ32_HDMITX_SEC_REG(a) display->mmio_hdmitx_sec->Read32(a)
  #define WRITE32_HDMITX_SEC_REG(a, v) display->mmio_hdmitx_sec->Write32(v, a)
  
  #define READ32_CBUS_REG(a) display->mmio_cbus->Read32(0x400 + a)
  #define WRITE32_CBUS_REG(a, v) display->mmio_cbus->Write32(v, 0x400 + a)
  
  #define SET_BIT32(x, dest, value, count, start)                                    \
    WRITE32_##x##_REG(dest, (READ32_##x##_REG(dest) & ~DISPLAY_MASK(start, count)) | \
                                (((value) << (start)) & DISPLAY_MASK(start, count)))
  
  #define WRITE32_REG(x, a, v) WRITE32_##x##_REG(a, v)
  #define READ32_REG(x, a) READ32_##x##_REG(a)
  
  #define SEC_OFFSET (0x1UL << 24)
  #define TOP_OFFSET_MASK (0x0UL << 24)
  #define TOP_SEC_OFFSET_MASK ((TOP_OFFSET_MASK) | (SEC_OFFSET))
  #define DWC_OFFSET_MASK (0x10UL << 24)
  #define DWC_SEC_OFFSET_MASK ((DWC_OFFSET_MASK) | (SEC_OFFSET))
  
  #define DMC_CAV_LUT_DATAL (0x12 << 2)
  #define DMC_CAV_LUT_DATAH (0x13 << 2)
  #define DMC_CAV_LUT_ADDR (0x14 << 2)
  
  #define DMC_CAV_ADDR_LMASK 0x1fffffff
  #define DMC_CAV_WIDTH_LMASK 0x7
  #define DMC_CAV_WIDTH_LWID 3
  #define DMC_CAV_WIDTH_LBIT 29
  
  #define DMC_CAV_WIDTH_HMASK 0x1ff
  #define DMC_CAV_WIDTH_HBIT 0
  #define DMC_CAV_HEIGHT_MASK 0x1fff
  #define DMC_CAV_HEIGHT_BIT 9
  
  #define DMC_CAV_LUT_ADDR_INDEX_MASK 0x7
  #define DMC_CAV_LUT_ADDR_RD_EN (1 << 8)
  #define DMC_CAV_LUT_ADDR_WR_EN (2 << 8)
  
  // P RESET
  #define PRESET_REGISTER (0x400)
  #define PRESET0_REGISTER (0x404)
  #define PRESET2_REGISTER (0x40C)
  
  // HDMITX ADDRESS and DATA PORTS
  #define HDMITX_ADDR_PORT (0x00)
  #define HDMITX_DATA_PORT (0x04)
  #define HDMITX_CTRL_PORT (0x08)
  
  // HDMI TOP
  #define HDMITX_TOP_SW_RESET (TOP_OFFSET_MASK + 0x000)
  #define HDMITX_TOP_CLK_CNTL (TOP_OFFSET_MASK + 0x001)
  #define HDMITX_TOP_HPD_FILTER (TOP_OFFSET_MASK + 0x002)
  #define HDMITX_TOP_INTR_MASKN (TOP_OFFSET_MASK + 0x003)
  #define HDMITX_TOP_INTR_STAT (TOP_OFFSET_MASK + 0x004)
  #define HDMITX_TOP_INTR_STAT_CLR (TOP_OFFSET_MASK + 0x005)
  #define HDMITX_TOP_BIST_CNTL (TOP_OFFSET_MASK + 0x006)
  #define HDMITX_TOP_SHIFT_PTTN_012 (TOP_OFFSET_MASK + 0x007)
  #define HDMITX_TOP_SHIFT_PTTN_345 (TOP_OFFSET_MASK + 0x008)
  #define HDMITX_TOP_SHIFT_PTTN_67 (TOP_OFFSET_MASK + 0x009)
  #define HDMITX_TOP_TMDS_CLK_PTTN_01 (TOP_OFFSET_MASK + 0x00A)
  #define HDMITX_TOP_TMDS_CLK_PTTN_23 (TOP_OFFSET_MASK + 0x00B)
  #define HDMITX_TOP_TMDS_CLK_PTTN_CNTL (TOP_OFFSET_MASK + 0x00C)
  #define HDMITX_TOP_REVOCMEM_STAT (TOP_OFFSET_MASK + 0x00D)
  #define HDMITX_TOP_STAT0 (TOP_OFFSET_MASK + 0x00E)
  #define HDMITX_TOP_SKP_CNTL_STAT (TOP_SEC_OFFSET_MASK + 0x010)
  #define HDMITX_TOP_NONCE_0 (TOP_SEC_OFFSET_MASK + 0x011)
  #define HDMITX_TOP_NONCE_1 (TOP_SEC_OFFSET_MASK + 0x012)
  #define HDMITX_TOP_NONCE_2 (TOP_SEC_OFFSET_MASK + 0x013)
  #define HDMITX_TOP_NONCE_3 (TOP_SEC_OFFSET_MASK + 0x014)
  #define HDMITX_TOP_PKF_0 (TOP_SEC_OFFSET_MASK + 0x015)
  #define HDMITX_TOP_PKF_1 (TOP_SEC_OFFSET_MASK + 0x016)
  #define HDMITX_TOP_PKF_2 (TOP_SEC_OFFSET_MASK + 0x017)
  #define HDMITX_TOP_PKF_3 (TOP_SEC_OFFSET_MASK + 0x018)
  #define HDMITX_TOP_DUK_0 (TOP_SEC_OFFSET_MASK + 0x019)
  #define HDMITX_TOP_DUK_1 (TOP_SEC_OFFSET_MASK + 0x01A)
  #define HDMITX_TOP_DUK_2 (TOP_SEC_OFFSET_MASK + 0x01B)
  #define HDMITX_TOP_DUK_3 (TOP_SEC_OFFSET_MASK + 0x01C)
  #define HDMITX_TOP_INFILTER (TOP_OFFSET_MASK + 0x01D)
  #define HDMITX_TOP_NSEC_SCRATCH (TOP_OFFSET_MASK + 0x01E)
  #define HDMITX_TOP_SEC_SCRATCH (TOP_SEC_OFFSET_MASK + 0x01F)
  #define HDMITX_TOP_DONT_TOUCH0 (TOP_OFFSET_MASK + 0x0FE)
  #define HDMITX_TOP_DONT_TOUCH1 (TOP_OFFSET_MASK + 0x0FF)
  
  #define PAD_PULL_UP_EN_REG1 (0x49 << 2)
  #define PAD_PULL_UP_REG1 (0x3d << 2)
  #define P_PREG_PAD_GPIO1_EN_N (0x0f << 2)
  #define PERIPHS_PIN_MUX_6 (0x32 << 2)
  
  struct reg_val_pair {
    uint32_t reg;
    uint32_t val;
  };
  
  static const struct reg_val_pair ENC_LUT_GEN[] = {
      {
          VPU_ENCP_VIDEO_EN,
          0,
      },
      {
          VPU_ENCI_VIDEO_EN,
          0,
      },
      {
          VPU_ENCP_VIDEO_MODE,
          0x4040,
      },
      {
          VPU_ENCP_VIDEO_MODE_ADV,
          0x18,
      },
      {VPU_VPU_VIU_VENC_MUX_CTRL, 0xA},
      {VPU_ENCP_VIDEO_VSO_BEGIN, 16},
      {VPU_ENCP_VIDEO_VSO_END, 32},
      {VPU_ENCI_VIDEO_EN, 0},
      {VPU_ENCP_VIDEO_EN, 1},
      {0xFFFFFFFF, 0},
  };
  
  struct cea_timing {
    bool interlace_mode;
    uint32_t pfreq;
    uint8_t ln;
    uint8_t pixel_repeat;
    uint8_t venc_pixel_repeat;
  
    uint32_t hfreq;
    uint32_t hactive;
    uint32_t htotal;
    uint32_t hblank;
    uint32_t hfront;
    uint32_t hsync;
    uint32_t hback;
    bool hpol;
  
    uint32_t vfreq;
    uint32_t vactive;
    uint32_t vtotal;
    uint32_t vblank0;  // in case of interlace
    uint32_t vblank1;  // vblank0 + 1 for interlace
    uint32_t vfront;
    uint32_t vsync;
    uint32_t vback;
    bool vpol;
  };
  
  #define VID_PLL_DIV_1 0
  #define VID_PLL_DIV_2 1
  #define VID_PLL_DIV_3 2
  #define VID_PLL_DIV_3p5 3
  #define VID_PLL_DIV_3p75 4
  #define VID_PLL_DIV_4 5
  #define VID_PLL_DIV_5 6
  #define VID_PLL_DIV_6 7
  #define VID_PLL_DIV_6p25 8
  #define VID_PLL_DIV_7 9
  #define VID_PLL_DIV_7p5 10
  #define VID_PLL_DIV_12 11
  #define VID_PLL_DIV_14 12
  #define VID_PLL_DIV_15 13
  #define VID_PLL_DIV_2p5 14
  
  enum viu_type {
    VIU_ENCL = 0,
    VIU_ENCI,
    VIU_ENCP,
    VIU_ENCT,
  };
  
  struct pll_param {
    uint32_t mode;
    uint32_t viu_channel;
    uint32_t viu_type;
    uint32_t hpll_clk_out;
    uint32_t od1;
    uint32_t od2;
    uint32_t od3;
    uint32_t vid_pll_div;
    uint32_t vid_clk_div;
    uint32_t hdmi_tx_pixel_div;
    uint32_t encp_div;
    uint32_t enci_div;
  };
  
  struct hdmi_param {
    uint16_t vic;
    uint8_t aspect_ratio;
    uint8_t colorimetry;
    uint8_t phy_mode;
    struct pll_param pll_p_24b;
    struct cea_timing timings;
    bool is4K;
  };
  
  #define HDMI_COLOR_DEPTH_24B 4
  #define HDMI_COLOR_DEPTH_30B 5
  #define HDMI_COLOR_DEPTH_36B 6
  #define HDMI_COLOR_DEPTH_48B 7
  
  #define HDMI_COLOR_FORMAT_RGB 0
  #define HDMI_COLOR_FORMAT_444 1
  
  #define HDMI_ASPECT_RATIO_NONE 0
  #define HDMI_ASPECT_RATIO_4x3 1
  #define HDMI_ASPECT_RATIO_16x9 2
  
  #define HDMI_COLORIMETRY_ITU601 1
  #define HDMI_COLORIMETRY_ITU709 2
  
  /* VIC lookup */
  #define VIC_720x480p_60Hz_4x3 2
  #define VIC_720x480p_60Hz_16x9 3
  #define VIC_1280x720p_60Hz_16x9 4
  #define VIC_1920x1080i_60Hz_16x9 5
  #define VIC_720x480i_60Hz_4x3 6
  #define VIC_720x480i_60Hz_16x9 7
  #define VIC_720x240p_60Hz_4x3 8
  #define VIC_720x240p_60Hz_16x9 9
  #define VIC_2880x480i_60Hz_4x3 10
  #define VIC_2880x480i_60Hz_16x9 11
  #define VIC_2880x240p_60Hz_4x3 12
  #define VIC_2880x240p_60Hz_16x9 13
  #define VIC_1440x480p_60Hz_4x3 14
  #define VIC_1440x480p_60Hz_16x9 15
  #define VIC_1920x1080p_60Hz_16x9 16
  #define VIC_720x576p_50Hz_4x3 17
  #define VIC_720x576p_50Hz_16x9 18
  #define VIC_1280x720p_50Hz_16x9 19
  #define VIC_1920x1080i_50Hz_16x9 20
  #define VIC_720x576i_50Hz_4x3 21
  #define VIC_720x576i_50Hz_16x9 22
  #define VIC_720x288p_50Hz_4x3 23
  #define VIC_720x288p_50Hz_16x9 24
  #define VIC_2880x576i_50Hz_4x3 25
  #define VIC_2880x576i_50Hz_16x9 26
  #define VIC_2880x288p_50Hz_4x3 27
  #define VIC_2880x288p_50Hz_16x9 28
  #define VIC_1440x576p_50Hz_4x3 29
  #define VIC_1440x576p_50Hz_16x9 30
  #define VIC_1920x1080p_50Hz_16x9 31
  #define VIC_1920x1080p_24Hz_16x9 32
  #define VIC_1920x1080p_25Hz_16x9 33
  #define VIC_1920x1080p_30Hz_16x9 34
  #define VIC_2880x480p_60Hz_4x3 35
  #define VIC_2880x480p_60Hz_16x9 36
  #define VIC_2880x576p_50Hz_4x3 37
  #define VIC_2880x576p_50Hz_16x9 38
  #define VIC_1920x1080i_1250_50Hz_16x9 39
  #define VIC_1920x1080i_100Hz_16x9 40
  #define VIC_1280x720p_100Hz_16x9 41
  #define VIC_720x576p_100Hz_4x3 42
  #define VIC_720x576p_100Hz_16x9 43
  #define VIC_720x576i_100Hz_4x3 44
  #define VIC_720x576i_100Hz_16x9 45
  #define VIC_1920x1080i_120Hz_16x9 46
  #define VIC_1280x720p_120Hz_16x9 47
  #define VIC_720x480p_120Hz_4x3 48
  #define VIC_720x480p_120Hz_16x9 49
  #define VIC_720x480i_120Hz_4x3 50
  #define VIC_720x480i_120Hz_16x9 51
  #define VIC_720x576p_200Hz_4x3 52
  #define VIC_720x576p_200Hz_16x9 53
  #define VIC_720x576i_200Hz_4x3 54
  #define VIC_720x576i_200Hz_16x9 55
  #define VIC_720x480p_240Hz_4x3 56
  #define VIC_720x480p_240Hz_16x9 57
  #define VIC_720x480i_240Hz_4x3 58
  #define VIC_720x480i_240Hz_16x9 59
  #define VIC_1280x720p_24Hz_16x9 60
  #define VIC_1280x720p_25Hz_16x9 61
  #define VIC_1280x720p_30Hz_16x9 62
  #define VIC_1920x1080p_120Hz_16x9 63
  #define VIC_1920x1080p_100Hz_16x9 64
  #define VESA_OFFSET 300
  #define VIC_VESA_640x480p_60Hz_4x3 300
  #define VIC_VESA_1280x800p_60Hz_16x9 301
  #define VIC_VESA_1280x1024p_60Hz_5x4 302
  #define VIC_VESA_1920x1200p_60Hz_8x5 303
  #define VIC_VESA_800x600p_60Hz 304
  #define VIC_VESA_1024x768p_60Hz 305
  
  struct vim2_display;  // fwd decl
  
  void hdmitx_writereg(const struct vim2_display* display, uint32_t addr, uint32_t data);
  uint32_t hdmitx_readreg(const struct vim2_display* display, uint32_t addr);
  void init_hdmi_hardware(struct vim2_display* display);
  void dump_regs(struct vim2_display* display);
  void init_hdmi_interface(struct vim2_display* display, const struct hdmi_param* p);
  void hdmi_test(struct vim2_display* display, uint32_t width);
  zx_status_t configure_pll(struct vim2_display* display, const struct hdmi_param* p,
                            const struct pll_param* pll);
  void hdmi_shutdown(struct vim2_display* display);
  
  __END_CDECLS
  
  #endif  // SRC_GRAPHICS_DISPLAY_DRIVERS_VIM_DISPLAY_HDMITX_H_
  